diff --git a/Makefile b/Makefile index 89053064b9..cd8f077027 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ fix: build $(GOBIN)/algofix */ modernize: - GOTOOLCHAIN=auto go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -category minmax,slicescontains,sortslice,stringscutprefix,mapsloop -fix -test ./... + GOTOOLCHAIN=auto go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -any=false -bloop=false -rangeint=false -fmtappendf=false -waitgroup=false -stringsbuilder=false -omitzero=false -fix ./... lint: deps $(GOBIN)/golangci-lint run -c .golangci.yml diff --git a/agreement/fuzzer/voteFilter_test.go b/agreement/fuzzer/voteFilter_test.go index 23c1bcb3be..c0fcbaf7cf 100644 --- a/agreement/fuzzer/voteFilter_test.go +++ b/agreement/fuzzer/voteFilter_test.go @@ -90,7 +90,7 @@ func MakeVoteFilter(voteFilterConfig *VoteFilterConfig) *VoteFilter { } } func (n *VoteFilter) Eval(tag protocol.Tag, data []byte, direction string) bool { - msgDecoder := n.fuzzer.facades[n.nodeID].GetFilterByType(reflect.TypeOf(&MessageDecoderFilter{})).(*MessageDecoderFilter) + msgDecoder := n.fuzzer.facades[n.nodeID].GetFilterByType(reflect.TypeFor[*MessageDecoderFilter]()).(*MessageDecoderFilter) if msgDecoder == nil { return true } diff --git a/cmd/algofix/deadlock_test.go b/cmd/algofix/deadlock_test.go index d4874d23f1..1f9103015b 100644 --- a/cmd/algofix/deadlock_test.go +++ b/cmd/algofix/deadlock_test.go @@ -144,7 +144,7 @@ func testGoFmt(fset *token.FileSet, node interface{}) (out string, err error) { var buf bytes.Buffer err = format.Node(&buf, fset, node) if err == nil { - out = string(buf.Bytes()) + out = buf.String() } return } diff --git a/cmd/algofix/fix.go b/cmd/algofix/fix.go index 03c828a581..a1a4251de9 100644 --- a/cmd/algofix/fix.go +++ b/cmd/algofix/fix.go @@ -7,13 +7,9 @@ package main import ( "fmt" "go/ast" - "go/parser" "go/token" - "os" "path" - "reflect" "strconv" - "strings" ) type fix struct { @@ -323,160 +319,12 @@ func declImports(gen *ast.GenDecl, path string) bool { return false } -// isPkgDot reports whether t is the expression "pkg.name" -// where pkg is an imported identifier. -func isPkgDot(t ast.Expr, pkg, name string) bool { - sel, ok := t.(*ast.SelectorExpr) - return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name -} - -// isPtrPkgDot reports whether f is the expression "*pkg.name" -// where pkg is an imported identifier. -func isPtrPkgDot(t ast.Expr, pkg, name string) bool { - ptr, ok := t.(*ast.StarExpr) - return ok && isPkgDot(ptr.X, pkg, name) -} - // isTopName reports whether n is a top-level unresolved identifier with the given name. func isTopName(n ast.Expr, name string) bool { id, ok := n.(*ast.Ident) return ok && id.Name == name && id.Obj == nil } -// isName reports whether n is an identifier with the given name. -func isName(n ast.Expr, name string) bool { - id, ok := n.(*ast.Ident) - return ok && id.String() == name -} - -// isCall reports whether t is a call to pkg.name. -func isCall(t ast.Expr, pkg, name string) bool { - call, ok := t.(*ast.CallExpr) - return ok && isPkgDot(call.Fun, pkg, name) -} - -// If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil. -func isIdent(n interface{}) *ast.Ident { - id, _ := n.(*ast.Ident) - return id -} - -// refersTo reports whether n is a reference to the same object as x. -func refersTo(n ast.Node, x *ast.Ident) bool { - id, ok := n.(*ast.Ident) - // The test of id.Name == x.Name handles top-level unresolved - // identifiers, which all have Obj == nil. - return ok && id.Obj == x.Obj && id.Name == x.Name -} - -// isBlank reports whether n is the blank identifier. -func isBlank(n ast.Expr) bool { - return isName(n, "_") -} - -// isEmptyString reports whether n is an empty string literal. -func isEmptyString(n ast.Expr) bool { - lit, ok := n.(*ast.BasicLit) - return ok && lit.Kind == token.STRING && len(lit.Value) == 2 -} - -func warn(pos token.Pos, msg string, args ...interface{}) { - if pos.IsValid() { - msg = "%s: " + msg - arg1 := []interface{}{fset.Position(pos).String()} - args = append(arg1, args...) - } - fmt.Fprintf(os.Stderr, msg+"\n", args...) -} - -// countUses returns the number of uses of the identifier x in scope. -func countUses(x *ast.Ident, scope []ast.Stmt) int { - count := 0 - ff := func(n interface{}) { - if n, ok := n.(ast.Node); ok && refersTo(n, x) { - count++ - } - } - for _, n := range scope { - walk(n, ff) - } - return count -} - -// rewriteUses replaces all uses of the identifier x and !x in scope -// with f(x.Pos()) and fnot(x.Pos()). -func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) { - var lastF ast.Expr - ff := func(n interface{}) { - ptr, ok := n.(*ast.Expr) - if !ok { - return - } - nn := *ptr - - // The child node was just walked and possibly replaced. - // If it was replaced and this is a negation, replace with fnot(p). - not, ok := nn.(*ast.UnaryExpr) - if ok && not.Op == token.NOT && not.X == lastF { - *ptr = fnot(nn.Pos()) - return - } - if refersTo(nn, x) { - lastF = f(nn.Pos()) - *ptr = lastF - } - } - for _, n := range scope { - walk(n, ff) - } -} - -// assignsTo reports whether any of the code in scope assigns to or takes the address of x. -func assignsTo(x *ast.Ident, scope []ast.Stmt) bool { - assigned := false - ff := func(n interface{}) { - if assigned { - return - } - switch n := n.(type) { - case *ast.UnaryExpr: - // use of &x - if n.Op == token.AND && refersTo(n.X, x) { - assigned = true - return - } - case *ast.AssignStmt: - for _, l := range n.Lhs { - if refersTo(l, x) { - assigned = true - return - } - } - } - } - for _, n := range scope { - if assigned { - break - } - walk(n, ff) - } - return assigned -} - -// newPkgDot returns an ast.Expr referring to "pkg.name" at position pos. -func newPkgDot(pos token.Pos, pkg, name string) ast.Expr { - return &ast.SelectorExpr{ - X: &ast.Ident{ - NamePos: pos, - Name: pkg, - }, - Sel: &ast.Ident{ - NamePos: pos, - Name: name, - }, - } -} - // renameTop renames all references to the top-level name old. // It returns true if it makes any changes. func renameTop(f *ast.File, old, new string) bool { @@ -640,210 +488,3 @@ func addImport(f *ast.File, ipath string) (added bool) { f.Imports = append(f.Imports, newImport) return true } - -// deleteImport deletes the import path from the file f, if present. -func deleteImport(f *ast.File, path string) (deleted bool) { - oldImport := importSpec(f, path) - - // Find the import node that imports path, if any. - for i, decl := range f.Decls { - gen, ok := decl.(*ast.GenDecl) - if !ok || gen.Tok != token.IMPORT { - continue - } - for j, spec := range gen.Specs { - impspec := spec.(*ast.ImportSpec) - if oldImport != impspec { - continue - } - - // We found an import spec that imports path. - // Delete it. - deleted = true - copy(gen.Specs[j:], gen.Specs[j+1:]) - gen.Specs = gen.Specs[:len(gen.Specs)-1] - - // If this was the last import spec in this decl, - // delete the decl, too. - if len(gen.Specs) == 0 { - copy(f.Decls[i:], f.Decls[i+1:]) - f.Decls = f.Decls[:len(f.Decls)-1] - } else if len(gen.Specs) == 1 { - gen.Lparen = token.NoPos // drop parens - } - if j > 0 { - // We deleted an entry but now there will be - // a blank line-sized hole where the import was. - // Close the hole by making the previous - // import appear to "end" where this one did. - gen.Specs[j-1].(*ast.ImportSpec).EndPos = impspec.End() - } - break - } - } - - // Delete it from f.Imports. - for i, imp := range f.Imports { - if imp == oldImport { - copy(f.Imports[i:], f.Imports[i+1:]) - f.Imports = f.Imports[:len(f.Imports)-1] - break - } - } - - return -} - -// rewriteImport rewrites any import of path oldPath to path newPath. -func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) { - for _, imp := range f.Imports { - if importPath(imp) == oldPath { - rewrote = true - // record old End, because the default is to compute - // it using the length of imp.Path.Value. - imp.EndPos = imp.End() - imp.Path.Value = strconv.Quote(newPath) - } - } - return -} - -func usesImport(f *ast.File, path string) (used bool) { - spec := importSpec(f, path) - if spec == nil { - return - } - - name := spec.Name.String() - switch name { - case "": - // If the package name is not explicitly specified, - // make an educated guess. This is not guaranteed to be correct. - lastSlash := strings.LastIndex(path, "/") - if lastSlash == -1 { - name = path - } else { - name = path[lastSlash+1:] - } - case "_", ".": - // Not sure if this import is used - err on the side of caution. - return true - } - - walk(f, func(n interface{}) { - sel, ok := n.(*ast.SelectorExpr) - if ok && isTopName(sel.X, name) { - used = true - } - }) - - return -} - -func expr(s string) ast.Expr { - x, err := parser.ParseExpr(s) - if err != nil { - panic("parsing " + s + ": " + err.Error()) - } - // Remove position information to avoid spurious newlines. - killPos(reflect.ValueOf(x)) - return x -} - -var posType = reflect.TypeOf(token.Pos(0)) - -func killPos(v reflect.Value) { - switch v.Kind() { - case reflect.Ptr, reflect.Interface: - if !v.IsNil() { - killPos(v.Elem()) - } - case reflect.Slice: - n := v.Len() - for i := 0; i < n; i++ { - killPos(v.Index(i)) - } - case reflect.Struct: - n := v.NumField() - for i := 0; i < n; i++ { - f := v.Field(i) - if f.Type() == posType { - f.SetInt(0) - continue - } - killPos(f) - } - } -} - -// A Rename describes a single renaming. -type rename struct { - OldImport string // only apply rename if this import is present - NewImport string // add this import during rewrite - Old string // old name: p.T or *p.T - New string // new name: p.T or *p.T -} - -func renameFix(tab []rename) func(*ast.File) bool { - return func(f *ast.File) bool { - return renameFixTab(f, tab) - } -} - -func parseName(s string) (ptr bool, pkg, nam string) { - i := strings.Index(s, ".") - if i < 0 { - panic("parseName: invalid name " + s) - } - if strings.HasPrefix(s, "*") { - ptr = true - s = s[1:] - i-- - } - pkg = s[:i] - nam = s[i+1:] - return -} - -func renameFixTab(f *ast.File, tab []rename) bool { - fixed := false - added := map[string]bool{} - check := map[string]bool{} - for _, t := range tab { - if !imports(f, t.OldImport) { - continue - } - optr, opkg, onam := parseName(t.Old) - walk(f, func(n interface{}) { - np, ok := n.(*ast.Expr) - if !ok { - return - } - x := *np - if optr { - p, ok := x.(*ast.StarExpr) - if !ok { - return - } - x = p.X - } - if !isPkgDot(x, opkg, onam) { - return - } - if t.NewImport != "" && !added[t.NewImport] { - addImport(f, t.NewImport) - added[t.NewImport] = true - } - *np = expr(t.New) - check[t.OldImport] = true - fixed = true - }) - } - - for ipath := range check { - if !usesImport(f, ipath) { - deleteImport(f, ipath) - } - } - return fixed -} diff --git a/cmd/algofix/import_test.go b/cmd/algofix/import_test.go deleted file mode 100644 index 8644e28f85..0000000000 --- a/cmd/algofix/import_test.go +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2011 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 main - -import "go/ast" - -func init() { - addTestCases(importTests, nil) -} - -var importTests = []testCase{ - { - Name: "import.0", - Fn: addImportFn("os"), - In: `package main - -import ( - "os" -) -`, - Out: `package main - -import ( - "os" -) -`, - }, - { - Name: "import.1", - Fn: addImportFn("os"), - In: `package main -`, - Out: `package main - -import "os" -`, - }, - { - Name: "import.2", - Fn: addImportFn("os"), - In: `package main - -// Comment -import "C" -`, - Out: `package main - -// Comment -import "C" -import "os" -`, - }, - { - Name: "import.3", - Fn: addImportFn("os"), - In: `package main - -// Comment -import "C" - -import ( - "io" - "utf8" -) -`, - Out: `package main - -// Comment -import "C" - -import ( - "io" - "os" - "utf8" -) -`, - }, - { - Name: "import.4", - Fn: deleteImportFn("os"), - In: `package main - -import ( - "os" -) -`, - Out: `package main -`, - }, - { - Name: "import.5", - Fn: deleteImportFn("os"), - In: `package main - -// Comment -import "C" -import "os" -`, - Out: `package main - -// Comment -import "C" -`, - }, - { - Name: "import.6", - Fn: deleteImportFn("os"), - In: `package main - -// Comment -import "C" - -import ( - "io" - "os" - "utf8" -) -`, - Out: `package main - -// Comment -import "C" - -import ( - "io" - "utf8" -) -`, - }, - { - Name: "import.7", - Fn: deleteImportFn("io"), - In: `package main - -import ( - "io" // a - "os" // b - "utf8" // c -) -`, - Out: `package main - -import ( - // a - "os" // b - "utf8" // c -) -`, - }, - { - Name: "import.8", - Fn: deleteImportFn("os"), - In: `package main - -import ( - "io" // a - "os" // b - "utf8" // c -) -`, - Out: `package main - -import ( - "io" // a - // b - "utf8" // c -) -`, - }, - { - Name: "import.9", - Fn: deleteImportFn("utf8"), - In: `package main - -import ( - "io" // a - "os" // b - "utf8" // c -) -`, - Out: `package main - -import ( - "io" // a - "os" // b - // c -) -`, - }, - { - Name: "import.10", - Fn: deleteImportFn("io"), - In: `package main - -import ( - "io" - "os" - "utf8" -) -`, - Out: `package main - -import ( - "os" - "utf8" -) -`, - }, - { - Name: "import.11", - Fn: deleteImportFn("os"), - In: `package main - -import ( - "io" - "os" - "utf8" -) -`, - Out: `package main - -import ( - "io" - "utf8" -) -`, - }, - { - Name: "import.12", - Fn: deleteImportFn("utf8"), - In: `package main - -import ( - "io" - "os" - "utf8" -) -`, - Out: `package main - -import ( - "io" - "os" -) -`, - }, - { - Name: "import.13", - Fn: rewriteImportFn("utf8", "encoding/utf8"), - In: `package main - -import ( - "io" - "os" - "utf8" // thanks ken -) -`, - Out: `package main - -import ( - "encoding/utf8" // thanks ken - "io" - "os" -) -`, - }, - { - Name: "import.14", - Fn: rewriteImportFn("asn1", "encoding/asn1"), - In: `package main - -import ( - "asn1" - "crypto" - "crypto/rsa" - _ "crypto/sha1" - "crypto/x509" - "crypto/x509/pkix" - "time" -) - -var x = 1 -`, - Out: `package main - -import ( - "crypto" - "crypto/rsa" - _ "crypto/sha1" - "crypto/x509" - "crypto/x509/pkix" - "encoding/asn1" - "time" -) - -var x = 1 -`, - }, - { - Name: "import.15", - Fn: rewriteImportFn("url", "net/url"), - In: `package main - -import ( - "bufio" - "net" - "path" - "url" -) - -var x = 1 // comment on x, not on url -`, - Out: `package main - -import ( - "bufio" - "net" - "net/url" - "path" -) - -var x = 1 // comment on x, not on url -`, - }, - { - Name: "import.16", - Fn: rewriteImportFn("http", "net/http", "template", "text/template"), - In: `package main - -import ( - "flag" - "http" - "log" - "template" -) - -var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 -`, - Out: `package main - -import ( - "flag" - "log" - "net/http" - "text/template" -) - -var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 -`, - }, - { - Name: "import.17", - Fn: addImportFn("x/y/z", "x/a/c"), - In: `package main - -// Comment -import "C" - -import ( - "a" - "b" - - "x/w" - - "d/f" -) -`, - Out: `package main - -// Comment -import "C" - -import ( - "a" - "b" - - "x/a/c" - "x/w" - "x/y/z" - - "d/f" -) -`, - }, - { - Name: "import.18", - Fn: addDelImportFn("e", "o"), - In: `package main - -import ( - "f" - "o" - "z" -) -`, - Out: `package main - -import ( - "e" - "f" - "z" -) -`, - }, -} - -func addImportFn(path ...string) func(*ast.File) bool { - return func(f *ast.File) bool { - fixed := false - for _, p := range path { - if !imports(f, p) { - addImport(f, p) - fixed = true - } - } - return fixed - } -} - -func deleteImportFn(path string) func(*ast.File) bool { - return func(f *ast.File) bool { - if imports(f, path) { - deleteImport(f, path) - return true - } - return false - } -} - -func addDelImportFn(p1 string, p2 string) func(*ast.File) bool { - return func(f *ast.File) bool { - fixed := false - if !imports(f, p1) { - addImport(f, p1) - fixed = true - } - if imports(f, p2) { - deleteImport(f, p2) - fixed = true - } - return fixed - } -} - -func rewriteImportFn(oldnew ...string) func(*ast.File) bool { - return func(f *ast.File) bool { - fixed := false - for i := 0; i < len(oldnew); i += 2 { - if imports(f, oldnew[i]) { - rewriteImport(f, oldnew[i], oldnew[i+1]) - fixed = true - } - } - return fixed - } -} diff --git a/cmd/algofix/main.go b/cmd/algofix/main.go index d3bb997c3d..848de29c77 100644 --- a/cmd/algofix/main.go +++ b/cmd/algofix/main.go @@ -70,14 +70,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 } } @@ -212,16 +212,6 @@ func processFile(filename string, useStdin bool) error { return os.WriteFile(f.Name(), newSrc, 0) } -var gofmtBuf bytes.Buffer - -func gofmt(n interface{}) string { - gofmtBuf.Reset() - if err := format.Node(&gofmtBuf, fset, n); err != nil { - return "<" + err.Error() + ">" - } - return gofmtBuf.String() -} - func report(err error) { scanner.PrintError(os.Stderr, err) exitCode = 2 diff --git a/cmd/algofix/main_test.go b/cmd/algofix/main_test.go index 2355214e23..bccc1778d1 100644 --- a/cmd/algofix/main_test.go +++ b/cmd/algofix/main_test.go @@ -22,18 +22,6 @@ type testCase struct { var testCases []testCase -func addTestCases(t []testCase, fn func(*ast.File) bool) { - // Fill in fn to avoid repetition in definitions. - if fn != nil { - for i := range t { - if t[i].Fn == nil { - t[i].Fn = fn - } - } - } - testCases = append(testCases, t...) -} - func fnop(*ast.File) bool { return false } func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string, mustBeGofmt bool) (out string, fixed, ok bool) { diff --git a/cmd/algofix/typecheck.go b/cmd/algofix/typecheck.go deleted file mode 100644 index e17cbf5963..0000000000 --- a/cmd/algofix/typecheck.go +++ /dev/null @@ -1,797 +0,0 @@ -// Copyright 2011 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 main - -import ( - "fmt" - "go/ast" - "go/parser" - "go/token" - "maps" - "os" - "os/exec" - "path/filepath" - "reflect" - "runtime" - "strings" -) - -// Partial type checker. -// -// The fact that it is partial is very important: the input is -// an AST and a description of some type information to -// assume about one or more packages, but not all the -// packages that the program imports. The checker is -// expected to do as much as it can with what it has been -// given. There is not enough information supplied to do -// a full type check, but the type checker is expected to -// apply information that can be derived from variable -// declarations, function and method returns, and type switches -// as far as it can, so that the caller can still tell the types -// of expression relevant to a particular fix. -// -// TODO(rsc,gri): Replace with go/typechecker. -// Doing that could be an interesting test case for go/typechecker: -// the constraints about working with partial information will -// likely exercise it in interesting ways. The ideal interface would -// be to pass typecheck a map from importpath to package API text -// (Go source code), but for now we use data structures (TypeConfig, Type). -// -// The strings mostly use gofmt form. -// -// A Field or FieldList has as its type a comma-separated list -// of the types of the fields. For example, the field list -// x, y, z int -// has type "int, int, int". - -// The prefix "type " is the type of a type. -// For example, given -// var x int -// type T int -// x's type is "int" but T's type is "type int". -// mkType inserts the "type " prefix. -// getType removes it. -// isType tests for it. - -func mkType(t string) string { - return "type " + t -} - -func getType(t string) string { - if !isType(t) { - return "" - } - return t[len("type "):] -} - -func isType(t string) bool { - return strings.HasPrefix(t, "type ") -} - -// TypeConfig describes the universe of relevant types. -// For ease of creation, the types are all referred to by string -// name (e.g., "reflect.Value"). TypeByName is the only place -// where the strings are resolved. -type TypeConfig struct { - Type map[string]*Type - Var map[string]string - Func map[string]string - - // External maps from a name to its type. - // It provides additional typings not present in the Go source itself. - // For now, the only additional typings are those generated by cgo. - External map[string]string -} - -// typeof returns the type of the given name, which may be of -// the form "x" or "p.X". -func (cfg *TypeConfig) typeof(name string) string { - if cfg.Var != nil { - if t := cfg.Var[name]; t != "" { - return t - } - } - if cfg.Func != nil { - if t := cfg.Func[name]; t != "" { - return "func()" + t - } - } - return "" -} - -// Type describes the Fields and Methods of a type. -// If the field or method cannot be found there, it is next -// looked for in the Embed list. -type Type struct { - Field map[string]string // map field name to type - Method map[string]string // map method name to comma-separated return types (should start with "func ") - Embed []string // list of types this type embeds (for extra methods) - Def string // definition of named type -} - -// dot returns the type of "typ.name", making its decision -// using the type information in cfg. -func (typ *Type) dot(cfg *TypeConfig, name string) string { - if typ.Field != nil { - if t := typ.Field[name]; t != "" { - return t - } - } - if typ.Method != nil { - if t := typ.Method[name]; t != "" { - return t - } - } - - for _, e := range typ.Embed { - etyp := cfg.Type[e] - if etyp != nil { - if t := etyp.dot(cfg, name); t != "" { - return t - } - } - } - - return "" -} - -// typecheck type checks the AST f assuming the information in cfg. -// It returns two maps with type information: -// typeof maps AST nodes to type information in gofmt string form. -// assign maps type strings to lists of expressions that were assigned -// to values of another type that were assigned to that type. -func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) { - typeof = make(map[interface{}]string) - assign = make(map[string][]interface{}) - cfg1 := &TypeConfig{} - *cfg1 = *cfg // make copy so we can add locally - copied := false - - // If we import "C", add types of cgo objects. - cfg.External = map[string]string{} - cfg1.External = cfg.External - if imports(f, "C") { - // Run cgo on gofmtFile(f) - // Parse, extract decls from _cgo_gotypes.go - // Map _Ctype_* types to C.* types. - err := func() error { - txt, err := gofmtFile(f) - if err != nil { - return err - } - dir, err := os.MkdirTemp(os.TempDir(), "fix_cgo_typecheck") - if err != nil { - return err - } - defer os.RemoveAll(dir) - err = os.WriteFile(filepath.Join(dir, "in.go"), txt, 0600) - if err != nil { - return err - } - cmd := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), "tool", "cgo", "-objdir", dir, "-srcdir", dir, "in.go") - err = cmd.Run() - if err != nil { - return err - } - out, err := os.ReadFile(filepath.Join(dir, "_cgo_gotypes.go")) - if err != nil { - return err - } - cgo, err := parser.ParseFile(token.NewFileSet(), "cgo.go", out, 0) - if err != nil { - return err - } - for _, decl := range cgo.Decls { - fn, ok := decl.(*ast.FuncDecl) - if !ok { - continue - } - if strings.HasPrefix(fn.Name.Name, "_Cfunc_") { - var params, results []string - for _, p := range fn.Type.Params.List { - t := gofmt(p.Type) - t = strings.Replace(t, "_Ctype_", "C.", -1) - params = append(params, t) - } - for _, r := range fn.Type.Results.List { - t := gofmt(r.Type) - t = strings.Replace(t, "_Ctype_", "C.", -1) - results = append(results, t) - } - cfg.External["C."+fn.Name.Name[7:]] = joinFunc(params, results) - } - } - return nil - }() - if err != nil { - fmt.Printf("warning: no cgo types: %s\n", err) - } - } - - // gather function declarations - for _, decl := range f.Decls { - fn, ok := decl.(*ast.FuncDecl) - if !ok { - continue - } - typecheck1(cfg, fn.Type, typeof, assign) - t := typeof[fn.Type] - if fn.Recv != nil { - // The receiver must be a type. - rcvr := typeof[fn.Recv] - if !isType(rcvr) { - if len(fn.Recv.List) != 1 { - continue - } - rcvr = mkType(gofmt(fn.Recv.List[0].Type)) - typeof[fn.Recv.List[0].Type] = rcvr - } - rcvr = getType(rcvr) - if rcvr != "" && rcvr[0] == '*' { - rcvr = rcvr[1:] - } - typeof[rcvr+"."+fn.Name.Name] = t - } else { - if isType(t) { - t = getType(t) - } else { - t = gofmt(fn.Type) - } - typeof[fn.Name] = t - - // Record typeof[fn.Name.Obj] for future references to fn.Name. - typeof[fn.Name.Obj] = t - } - } - - // gather struct declarations - for _, decl := range f.Decls { - d, ok := decl.(*ast.GenDecl) - if ok { - for _, s := range d.Specs { - switch s := s.(type) { - case *ast.TypeSpec: - if cfg1.Type[s.Name.Name] != nil { - break - } - if !copied { - copied = true - // Copy map lazily: it's time. - cfg1.Type = maps.Clone(cfg.Type) - } - t := &Type{Field: map[string]string{}} - cfg1.Type[s.Name.Name] = t - switch st := s.Type.(type) { - case *ast.StructType: - for _, f := range st.Fields.List { - for _, n := range f.Names { - t.Field[n.Name] = gofmt(f.Type) - } - } - case *ast.ArrayType, *ast.StarExpr, *ast.MapType: - t.Def = gofmt(st) - } - } - } - } - } - - typecheck1(cfg1, f, typeof, assign) - return typeof, assign -} - -func makeExprList(a []*ast.Ident) []ast.Expr { - var b []ast.Expr - for _, x := range a { - b = append(b, x) - } - return b -} - -// Typecheck1 is the recursive form of typecheck. -// It is like typecheck but adds to the information in typeof -// instead of allocating a new map. -func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, assign map[string][]interface{}) { - // set sets the type of n to typ. - // If isDecl is true, n is being declared. - set := func(n ast.Expr, typ string, isDecl bool) { - if typeof[n] != "" || typ == "" { - if typeof[n] != typ { - assign[typ] = append(assign[typ], n) - } - return - } - typeof[n] = typ - - // If we obtained typ from the declaration of x - // propagate the type to all the uses. - // The !isDecl case is a cheat here, but it makes - // up in some cases for not paying attention to - // struct fields. The real type checker will be - // more accurate so we won't need the cheat. - if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") { - typeof[id.Obj] = typ - } - } - - // Type-check an assignment lhs = rhs. - // If isDecl is true, this is := so we can update - // the types of the objects that lhs refers to. - typecheckAssign := func(lhs, rhs []ast.Expr, isDecl bool) { - if len(lhs) > 1 && len(rhs) == 1 { - if _, ok := rhs[0].(*ast.CallExpr); ok { - t := split(typeof[rhs[0]]) - // Lists should have same length but may not; pair what can be paired. - for i := 0; i < len(lhs) && i < len(t); i++ { - set(lhs[i], t[i], isDecl) - } - return - } - } - if len(lhs) == 1 && len(rhs) == 2 { - // x = y, ok - rhs = rhs[:1] - } else if len(lhs) == 2 && len(rhs) == 1 { - // x, ok = y - lhs = lhs[:1] - } - - // Match as much as we can. - for i := 0; i < len(lhs) && i < len(rhs); i++ { - x, y := lhs[i], rhs[i] - if typeof[y] != "" { - set(x, typeof[y], isDecl) - } else { - set(y, typeof[x], false) - } - } - } - - expand := func(s string) string { - typ := cfg.Type[s] - if typ != nil && typ.Def != "" { - return typ.Def - } - return s - } - - // The main type check is a recursive algorithm implemented - // by walkBeforeAfter(n, before, after). - // Most of it is bottom-up, but in a few places we need - // to know the type of the function we are checking. - // The before function records that information on - // the curfn stack. - var curfn []*ast.FuncType - - before := func(n interface{}) { - // push function type on stack - switch n := n.(type) { - case *ast.FuncDecl: - curfn = append(curfn, n.Type) - case *ast.FuncLit: - curfn = append(curfn, n.Type) - } - } - - // After is the real type checker. - after := func(n interface{}) { - if n == nil { - return - } - if false && reflect.TypeOf(n).Kind() == reflect.Ptr { // debugging trace - defer func() { - if t := typeof[n]; t != "" { - pos := fset.Position(n.(ast.Node).Pos()) - fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos, gofmt(n), t) - } - }() - } - - switch n := n.(type) { - case *ast.FuncDecl, *ast.FuncLit: - // pop function type off stack - curfn = curfn[:len(curfn)-1] - - case *ast.FuncType: - typeof[n] = mkType(joinFunc(split(typeof[n.Params]), split(typeof[n.Results]))) - - case *ast.FieldList: - // Field list is concatenation of sub-lists. - t := "" - for _, field := range n.List { - if t != "" { - t += ", " - } - t += typeof[field] - } - typeof[n] = t - - case *ast.Field: - // Field is one instance of the type per name. - all := "" - t := typeof[n.Type] - if !isType(t) { - // Create a type, because it is typically *T or *p.T - // and we might care about that type. - t = mkType(gofmt(n.Type)) - typeof[n.Type] = t - } - t = getType(t) - if len(n.Names) == 0 { - all = t - } else { - for _, id := range n.Names { - if all != "" { - all += ", " - } - all += t - typeof[id.Obj] = t - typeof[id] = t - } - } - typeof[n] = all - - case *ast.ValueSpec: - // var declaration. Use type if present. - if n.Type != nil { - t := typeof[n.Type] - if !isType(t) { - t = mkType(gofmt(n.Type)) - typeof[n.Type] = t - } - t = getType(t) - for _, id := range n.Names { - set(id, t, true) - } - } - // Now treat same as assignment. - typecheckAssign(makeExprList(n.Names), n.Values, true) - - case *ast.AssignStmt: - typecheckAssign(n.Lhs, n.Rhs, n.Tok == token.DEFINE) - - case *ast.Ident: - // Identifier can take its type from underlying object. - if t := typeof[n.Obj]; t != "" { - typeof[n] = t - } - - case *ast.SelectorExpr: - // Field or method. - name := n.Sel.Name - if t := typeof[n.X]; t != "" { - t = strings.TrimPrefix(t, "*") // implicit * - if typ := cfg.Type[t]; typ != nil { - if t := typ.dot(cfg, name); t != "" { - typeof[n] = t - return - } - } - tt := typeof[t+"."+name] - if isType(tt) { - typeof[n] = getType(tt) - return - } - } - // Package selector. - if x, ok := n.X.(*ast.Ident); ok && x.Obj == nil { - str := x.Name + "." + name - if cfg.Type[str] != nil { - typeof[n] = mkType(str) - return - } - if t := cfg.typeof(x.Name + "." + name); t != "" { - typeof[n] = t - return - } - } - - case *ast.CallExpr: - // make(T) has type T. - if isTopName(n.Fun, "make") && len(n.Args) >= 1 { - typeof[n] = gofmt(n.Args[0]) - return - } - // new(T) has type *T - if isTopName(n.Fun, "new") && len(n.Args) == 1 { - typeof[n] = "*" + gofmt(n.Args[0]) - return - } - // Otherwise, use type of function to determine arguments. - t := typeof[n.Fun] - if t == "" { - t = cfg.External[gofmt(n.Fun)] - } - in, out := splitFunc(t) - if in == nil && out == nil { - return - } - typeof[n] = join(out) - for i, arg := range n.Args { - if i >= len(in) { - break - } - if typeof[arg] == "" { - typeof[arg] = in[i] - } - } - - case *ast.TypeAssertExpr: - // x.(type) has type of x. - if n.Type == nil { - typeof[n] = typeof[n.X] - return - } - // x.(T) has type T. - if t := typeof[n.Type]; isType(t) { - typeof[n] = getType(t) - } else { - typeof[n] = gofmt(n.Type) - } - - case *ast.SliceExpr: - // x[i:j] has type of x. - typeof[n] = typeof[n.X] - - case *ast.IndexExpr: - // x[i] has key type of x's type. - t := expand(typeof[n.X]) - if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") { - // Lazy: assume there are no nested [] in the array - // length or map key type. - if i := strings.Index(t, "]"); i >= 0 { - typeof[n] = t[i+1:] - } - } - - case *ast.StarExpr: - // *x for x of type *T has type T when x is an expr. - // We don't use the result when *x is a type, but - // compute it anyway. - t := expand(typeof[n.X]) - if isType(t) { - typeof[n] = "type *" + getType(t) - } else if strings.HasPrefix(t, "*") { - typeof[n] = t[len("*"):] - } - - case *ast.UnaryExpr: - // &x for x of type T has type *T. - t := typeof[n.X] - if t != "" && n.Op == token.AND { - typeof[n] = "*" + t - } - - case *ast.CompositeLit: - // T{...} has type T. - typeof[n] = gofmt(n.Type) - - // Propagate types down to values used in the composite literal. - t := expand(typeof[n]) - if strings.HasPrefix(t, "[") { // array or slice - // Lazy: assume there are no nested [] in the array length. - if i := strings.Index(t, "]"); i >= 0 { - et := t[i+1:] - for _, e := range n.Elts { - if kv, ok := e.(*ast.KeyValueExpr); ok { - e = kv.Value - } - if typeof[e] == "" { - typeof[e] = et - } - } - } - } - if strings.HasPrefix(t, "map[") { // map - // Lazy: assume there are no nested [] in the map key type. - if i := strings.Index(t, "]"); i >= 0 { - kt, vt := t[4:i], t[i+1:] - for _, e := range n.Elts { - if kv, ok := e.(*ast.KeyValueExpr); ok { - if typeof[kv.Key] == "" { - typeof[kv.Key] = kt - } - if typeof[kv.Value] == "" { - typeof[kv.Value] = vt - } - } - } - } - } - if typ := cfg.Type[t]; typ != nil && len(typ.Field) > 0 { // struct - for _, e := range n.Elts { - if kv, ok := e.(*ast.KeyValueExpr); ok { - if ft := typ.Field[fmt.Sprintf("%s", kv.Key)]; ft != "" { - if typeof[kv.Value] == "" { - typeof[kv.Value] = ft - } - } - } - } - } - - case *ast.ParenExpr: - // (x) has type of x. - typeof[n] = typeof[n.X] - - case *ast.RangeStmt: - t := expand(typeof[n.X]) - if t == "" { - return - } - var key, value string - if t == "string" { - key, value = "int", "rune" - } else if strings.HasPrefix(t, "[") { - key = "int" - if i := strings.Index(t, "]"); i >= 0 { - value = t[i+1:] - } - } else if strings.HasPrefix(t, "map[") { - if i := strings.Index(t, "]"); i >= 0 { - key, value = t[4:i], t[i+1:] - } - } - changed := false - if n.Key != nil && key != "" { - changed = true - set(n.Key, key, n.Tok == token.DEFINE) - } - if n.Value != nil && value != "" { - changed = true - set(n.Value, value, n.Tok == token.DEFINE) - } - // Ugly failure of vision: already type-checked body. - // Do it again now that we have that type info. - if changed { - typecheck1(cfg, n.Body, typeof, assign) - } - - case *ast.TypeSwitchStmt: - // Type of variable changes for each case in type switch, - // but go/parser generates just one variable. - // Repeat type check for each case with more precise - // type information. - as, ok := n.Assign.(*ast.AssignStmt) - if !ok { - return - } - varx, ok := as.Lhs[0].(*ast.Ident) - if !ok { - return - } - t := typeof[varx] - for _, cas := range n.Body.List { - cas := cas.(*ast.CaseClause) - if len(cas.List) == 1 { - // Variable has specific type only when there is - // exactly one type in the case list. - if tt := typeof[cas.List[0]]; isType(tt) { - tt = getType(tt) - typeof[varx] = tt - typeof[varx.Obj] = tt - typecheck1(cfg, cas.Body, typeof, assign) - } - } - } - // Restore t. - typeof[varx] = t - typeof[varx.Obj] = t - - case *ast.ReturnStmt: - if len(curfn) == 0 { - // Probably can't happen. - return - } - f := curfn[len(curfn)-1] - res := n.Results - if f.Results != nil { - t := split(typeof[f.Results]) - for i := 0; i < len(res) && i < len(t); i++ { - set(res[i], t[i], false) - } - } - - case *ast.BinaryExpr: - // Propagate types across binary ops that require two args of the same type. - switch n.Op { - case token.EQL, token.NEQ: // TODO: more cases. This is enough for the cftype fix. - if typeof[n.X] != "" && typeof[n.Y] == "" { - typeof[n.Y] = typeof[n.X] - } - if typeof[n.X] == "" && typeof[n.Y] != "" { - typeof[n.X] = typeof[n.Y] - } - } - } - } - walkBeforeAfter(f, before, after) -} - -// Convert between function type strings and lists of types. -// Using strings makes this a little harder, but it makes -// a lot of the rest of the code easier. This will all go away -// when we can use go/typechecker directly. - -// splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"]. -func splitFunc(s string) (in, out []string) { - if !strings.HasPrefix(s, "func(") { - return nil, nil - } - - i := len("func(") // index of beginning of 'in' arguments - nparen := 0 - for j := i; j < len(s); j++ { - switch s[j] { - case '(': - nparen++ - case ')': - nparen-- - if nparen < 0 { - // found end of parameter list - out := strings.TrimSpace(s[j+1:]) - if len(out) >= 2 && out[0] == '(' && out[len(out)-1] == ')' { - out = out[1 : len(out)-1] - } - return split(s[i:j]), split(out) - } - } - } - return nil, nil -} - -// joinFunc is the inverse of splitFunc. -func joinFunc(in, out []string) string { - outs := "" - if len(out) == 1 { - outs = " " + out[0] - } else if len(out) > 1 { - outs = " (" + join(out) + ")" - } - return "func(" + join(in) + ")" + outs -} - -// split splits "int, float" into ["int", "float"] and splits "" into []. -func split(s string) []string { - out := []string{} - i := 0 // current type being scanned is s[i:j]. - nparen := 0 - for j := 0; j < len(s); j++ { - switch s[j] { - case ' ': - if i == j { - i++ - } - case '(': - nparen++ - case ')': - nparen-- - if nparen < 0 { - // probably can't happen - return nil - } - case ',': - if nparen == 0 { - if i < j { - out = append(out, s[i:j]) - } - i = j + 1 - } - } - } - if nparen != 0 { - // probably can't happen - return nil - } - if i < len(s) { - out = append(out, s[i:]) - } - return out -} - -// join is the inverse of split. -func join(x []string) string { - return strings.Join(x, ", ") -} diff --git a/cmd/goal/commands.go b/cmd/goal/commands.go index 453ae05d12..9b520a2644 100644 --- a/cmd/goal/commands.go +++ b/cmd/goal/commands.go @@ -438,7 +438,7 @@ func ensurePassword() []byte { } func reportInfoln(args ...interface{}) { - for _, line := range strings.Split(fmt.Sprint(args...), "\n") { + for line := range strings.SplitSeq(fmt.Sprint(args...), "\n") { printable, line := unicodePrintable(line) if !printable { fmt.Println(infoNonPrintableCharacters) @@ -454,7 +454,7 @@ func reportInfof(format string, args ...interface{}) { // reportWarnRawln prints a warning message to stderr. Only use this function if that warning // message already indicates that it's a warning. Otherwise, use reportWarnln func reportWarnRawln(args ...interface{}) { - for _, line := range strings.Split(fmt.Sprint(args...), "\n") { + for line := range strings.SplitSeq(fmt.Sprint(args...), "\n") { printable, line := unicodePrintable(line) if !printable { fmt.Fprintln(os.Stderr, infoNonPrintableCharacters) @@ -484,7 +484,7 @@ func reportWarnf(format string, args ...interface{}) { func reportErrorln(args ...interface{}) { outStr := fmt.Sprint(args...) - for _, line := range strings.Split(outStr, "\n") { + for line := range strings.SplitSeq(outStr, "\n") { printable, line := unicodePrintable(line) if !printable { fmt.Fprintln(os.Stderr, errorNonPrintableCharacters) diff --git a/cmd/goal/node.go b/cmd/goal/node.go index 5c423b1772..dd91319f97 100644 --- a/cmd/goal/node.go +++ b/cmd/goal/node.go @@ -714,7 +714,7 @@ func verifyPeerDialArg() bool { } // make sure that the format of each entry is valid: - for _, peer := range strings.Split(peerDial, ";") { + for peer := range strings.SplitSeq(peerDial, ";") { _, err := naddr.ParseHostOrURLOrMultiaddr(peer) if err != nil { reportErrorf("Provided peer '%s' is not a valid peer address : %v", peer, err) diff --git a/cmd/tealdbg/cdtState.go b/cmd/tealdbg/cdtState.go index b7dc3def64..b84d5916a7 100644 --- a/cmd/tealdbg/cdtState.go +++ b/cmd/tealdbg/cdtState.go @@ -600,8 +600,8 @@ func decodeNestedObjID(objID string) (string, []int, bool) { } groupIDs := objID[len(prefix)+1:] - parts := strings.Split(groupIDs, "_") - for _, id := range parts { + parts := strings.SplitSeq(groupIDs, "_") + for id := range parts { if val, err := strconv.ParseInt(id, 10, 32); err == nil { parsedIDs = append(parsedIDs, int(val)) } else { diff --git a/cmd/util/cmd.go b/cmd/util/cmd.go index ec72cfceac..f1f6c58022 100644 --- a/cmd/util/cmd.go +++ b/cmd/util/cmd.go @@ -106,8 +106,8 @@ func (c *CobraStringSliceValue) IsSet() bool { return c.isSet } // Set sets a value and fails if it is not allowed func (c *CobraStringSliceValue) Set(values string) error { - others := strings.Split(values, ",") - for _, other := range others { + others := strings.SplitSeq(values, ",") + for other := range others { other = strings.TrimSpace(other) if _, ok := c.allowedMap[other]; ok { c.value = append(c.value, other) diff --git a/config/config_test.go b/config/config_test.go index 68928d5908..571a96acba 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -525,7 +525,7 @@ func TestLocal_StructTags(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - localType := reflect.TypeOf(Local{}) + localType := reflect.TypeFor[Local]() versionField, ok := localType.FieldByName("Version") require.True(t, ok) @@ -580,7 +580,7 @@ func TestLocal_VersionField(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - localType := reflect.TypeOf(Local{}) + localType := reflect.TypeFor[Local]() field, ok := localType.FieldByName("Version") require.True(t, true, ok) ver := 0 diff --git a/config/defaultsGenerator/defaultsGenerator.go b/config/defaultsGenerator/defaultsGenerator.go index 385726201b..25bd60b165 100644 --- a/config/defaultsGenerator/defaultsGenerator.go +++ b/config/defaultsGenerator/defaultsGenerator.go @@ -111,7 +111,7 @@ func (a byFieldName) Less(i, j int) bool { } func prettyPrint(c config.Local, format string) (out string) { - localType := reflect.TypeOf(c) + localType := reflect.TypeFor[config.Local]() fields := []reflect.StructField{} for fieldNum := 0; fieldNum < localType.NumField(); fieldNum++ { diff --git a/config/localTemplate.go b/config/localTemplate.go index 003e1ddd62..9f5c6689f7 100644 --- a/config/localTemplate.go +++ b/config/localTemplate.go @@ -669,8 +669,8 @@ func (cfg Local) ValidateDNSBootstrapArray(networkID protocol.NetworkID) ([]*DNS func (cfg Local) internalValidateDNSBootstrapArray(networkID protocol.NetworkID) ( bootstrapArray []*DNSBootstrap, err error) { - bootstrapStringArray := strings.Split(cfg.DNSBootstrapID, ";") - for _, bootstrapString := range bootstrapStringArray { + bootstrapStringArray := strings.SplitSeq(cfg.DNSBootstrapID, ";") + for bootstrapString := range bootstrapStringArray { if len(strings.TrimSpace(bootstrapString)) == 0 { continue } diff --git a/config/migrate.go b/config/migrate.go index 5522454094..238725af47 100644 --- a/config/migrate.go +++ b/config/migrate.go @@ -54,7 +54,7 @@ func migrate(cfg Local) (newCfg Local, migrations []MigrationResult, err error) break } defaultCurrentConfig := GetVersionedDefaultLocalConfig(newCfg.Version) - localType := reflect.TypeOf(Local{}) + localType := reflect.TypeFor[Local]() nextVersion := newCfg.Version + 1 for fieldNum := 0; fieldNum < localType.NumField(); fieldNum++ { field := localType.Field(fieldNum) @@ -163,7 +163,7 @@ func migrate(cfg Local) (newCfg Local, migrations []MigrationResult, err error) } func getLatestConfigVersion() uint32 { - localType := reflect.TypeOf(Local{}) + localType := reflect.TypeFor[Local]() versionField, found := localType.FieldByName("Version") if !found { return 0 @@ -184,7 +184,7 @@ func GetVersionedDefaultLocalConfig(version uint32) (local Local) { local = GetVersionedDefaultLocalConfig(version - 1) } // apply version specific changes. - localType := reflect.TypeOf(local) + localType := reflect.TypeFor[Local]() for fieldNum := 0; fieldNum < localType.NumField(); fieldNum++ { field := localType.Field(fieldNum) versionDefaultValue, hasTag := reflect.StructTag(field.Tag).Lookup(fmt.Sprintf("version[%d]", version)) diff --git a/daemon/algod/api/server/v2/handlers_test.go b/daemon/algod/api/server/v2/handlers_test.go index debeffbb7a..6d013995c2 100644 --- a/daemon/algod/api/server/v2/handlers_test.go +++ b/daemon/algod/api/server/v2/handlers_test.go @@ -160,10 +160,10 @@ func TestPendingTransactionResponseStruct(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - generatedResponseType := reflect.TypeOf(model.PendingTransactionResponse{}) + generatedResponseType := reflect.TypeFor[model.PendingTransactionResponse]() generatedResponseGraph := makeTagGraph(generatedResponseType, make(map[reflect.Type]*tagNode)) - customResponseType := reflect.TypeOf(PreEncodedTxInfo{}) + customResponseType := reflect.TypeFor[PreEncodedTxInfo]() customResponseGraph := makeTagGraph(customResponseType, make(map[reflect.Type]*tagNode)) expectedGeneratedTxnGraph := map[string]*tagNode{ @@ -186,10 +186,10 @@ func TestSimulateResponseStruct(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - generatedResponseType := reflect.TypeOf(model.SimulateResponse{}) + generatedResponseType := reflect.TypeFor[model.SimulateResponse]() generatedResponseGraph := makeTagGraph(generatedResponseType, make(map[reflect.Type]*tagNode)) - customResponseType := reflect.TypeOf(PreEncodedSimulateResponse{}) + customResponseType := reflect.TypeFor[PreEncodedSimulateResponse]() customResponseGraph := makeTagGraph(customResponseType, make(map[reflect.Type]*tagNode)) expectedGeneratedTxnGraph := map[string]*tagNode{ @@ -216,10 +216,10 @@ func TestSimulateRequestStruct(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - generatedResponseType := reflect.TypeOf(model.SimulateRequest{}) + generatedResponseType := reflect.TypeFor[model.SimulateRequest]() generatedResponseGraph := makeTagGraph(generatedResponseType, make(map[reflect.Type]*tagNode)) - customResponseType := reflect.TypeOf(PreEncodedSimulateRequest{}) + customResponseType := reflect.TypeFor[PreEncodedSimulateRequest]() customResponseGraph := makeTagGraph(customResponseType, make(map[reflect.Type]*tagNode)) expectedGeneratedTxnGraph := map[string]*tagNode{ diff --git a/daemon/algod/api/server/v2/test/genesis_types_test.go b/daemon/algod/api/server/v2/test/genesis_types_test.go index 0860235f37..7f3e67b96e 100644 --- a/daemon/algod/api/server/v2/test/genesis_types_test.go +++ b/daemon/algod/api/server/v2/test/genesis_types_test.go @@ -48,10 +48,10 @@ func getJSONTag(field reflect.StructField) string { func TestGenesisTypeCompatibility(t *testing.T) { partitiontest.PartitionTest(t) // Test Genesis struct compatibility - verifyStructCompatibility(t, reflect.TypeOf(bookkeeping.Genesis{}), reflect.TypeOf(model.Genesis{})) + verifyStructCompatibility(t, reflect.TypeFor[bookkeeping.Genesis](), reflect.TypeFor[model.Genesis]()) // Test GenesisAllocation struct compatibility - verifyStructCompatibility(t, reflect.TypeOf(bookkeeping.GenesisAllocation{}), reflect.TypeOf(model.GenesisAllocation{})) + verifyStructCompatibility(t, reflect.TypeFor[bookkeeping.GenesisAllocation](), reflect.TypeFor[model.GenesisAllocation]()) } // isStructOrPtrToStruct returns true if the type is a struct or pointer to struct diff --git a/data/basics/fields_test.go b/data/basics/fields_test.go index d06cbede66..48717fc20e 100644 --- a/data/basics/fields_test.go +++ b/data/basics/fields_test.go @@ -58,7 +58,7 @@ func makeTypeCheckFunction(t *testing.T, exceptions []reflectionhelpers.TypePath func TestBlockFields(t *testing.T) { partitiontest.PartitionTest(t) - typeToCheck := reflect.TypeOf(bookkeeping.Block{}) + typeToCheck := reflect.TypeFor[bookkeeping.Block]() // These exceptions are for pre-existing usages of string. Only add to this list if you really need to use string. exceptions := []reflectionhelpers.TypePath{ @@ -84,7 +84,7 @@ func TestBlockFields(t *testing.T) { func TestAccountDataFields(t *testing.T) { partitiontest.PartitionTest(t) - typeToCheck := reflect.TypeOf(basics.AccountData{}) + typeToCheck := reflect.TypeFor[basics.AccountData]() // These exceptions are for pre-existing usages of string. Only add to this list if you really need to use string. exceptions := []reflectionhelpers.TypePath{ diff --git a/data/basics/testing/nearzero.go b/data/basics/testing/nearzero.go index 6eb26eb04f..e073cea496 100644 --- a/data/basics/testing/nearzero.go +++ b/data/basics/testing/nearzero.go @@ -69,7 +69,7 @@ func collectPaths(typ reflect.Type, prefix []int, pathStack []reflect.Type) [][] case reflect.Struct: // Special case: skip known value-type structs like time.Time - if typ == reflect.TypeOf(time.Time{}) { + if typ == reflect.TypeFor[time.Time]() { return [][]int{prefix} } diff --git a/data/transactions/verify/txnBatch_test.go b/data/transactions/verify/txnBatch_test.go index d7921ea3a6..036b1fc0b8 100644 --- a/data/transactions/verify/txnBatch_test.go +++ b/data/transactions/verify/txnBatch_test.go @@ -721,8 +721,7 @@ func TestStreamToBatchPostVBlocked(t *testing.T) { var badSigResultCounter int var goodSigResultCounter int - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() cache := MakeVerifiedTransactionCache(50) txBacklogSizeMod := txBacklogSize / 20 diff --git a/data/txHandler_test.go b/data/txHandler_test.go index 455b6195f0..49e25b9ac3 100644 --- a/data/txHandler_test.go +++ b/data/txHandler_test.go @@ -542,8 +542,7 @@ func BenchmarkTxHandlerIncDeDup(b *testing.B) { numPoolWorkers := runtime.NumCPU() dupFactor := test.dupFactor avgDelay := test.workerDelay / time.Duration(numPoolWorkers) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := b.Context() var handler *TxHandler if test.firstLevelOnly { @@ -922,8 +921,7 @@ func TestTxHandlerProcessIncomingCacheRotation(t *testing.T) { t.Run("scheduled", func(t *testing.T) { // double enqueue a single txn message, ensure it discarded - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() + ctx := t.Context() handler := makeTestTxHandlerOrphanedWithContext(ctx, txBacklogSize, txBacklogSize, txHandlerConfig{true, true}, 10*time.Millisecond) @@ -944,8 +942,7 @@ func TestTxHandlerProcessIncomingCacheRotation(t *testing.T) { t.Run("manual", func(t *testing.T) { // double enqueue a single txn message, ensure it discarded - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() + ctx := t.Context() handler := makeTestTxHandlerOrphanedWithContext(ctx, txBacklogSize, txBacklogSize, txHandlerConfig{true, true}, 10*time.Millisecond) diff --git a/ledger/simulation/simulator_test.go b/ledger/simulation/simulator_test.go index 07ba377d56..8e4a6d0b24 100644 --- a/ledger/simulation/simulator_test.go +++ b/ledger/simulation/simulator_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/data" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/data/transactions" @@ -43,8 +44,6 @@ func TestNonOverridenDataLedgerMethodsUseRoundParameter(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - env := simulationtesting.PrepareSimulatorTest(t) - // methods overridden by `simulatorLedger`` overriddenMethods := []string{ "Latest", @@ -67,7 +66,7 @@ func TestNonOverridenDataLedgerMethodsUseRoundParameter(t *testing.T) { } methodExistsInEvalLedger := func(methodName string) bool { - evalLedgerType := reflect.TypeOf((*eval.LedgerForEvaluator)(nil)).Elem() + evalLedgerType := reflect.TypeFor[eval.LedgerForEvaluator]() for i := 0; i < evalLedgerType.NumMethod(); i++ { if evalLedgerType.Method(i).Name == methodName { return true @@ -78,14 +77,14 @@ func TestNonOverridenDataLedgerMethodsUseRoundParameter(t *testing.T) { methodHasRoundParameter := func(methodType reflect.Type) bool { for i := 0; i < methodType.NumIn(); i++ { - if methodType.In(i) == reflect.TypeOf(basics.Round(0)) { + if methodType.In(i) == reflect.TypeFor[basics.Round]() { return true } } return false } - ledgerType := reflect.TypeOf(env.Ledger) + ledgerType := reflect.TypeFor[*data.Ledger]() for i := 0; i < ledgerType.NumMethod(); i++ { method := ledgerType.Method(i) if methodExistsInEvalLedger(method.Name) && !methodIsSkipped(method.Name) { diff --git a/ledger/store/trackerdb/data_test.go b/ledger/store/trackerdb/data_test.go index ba4efd94ef..1900ab3836 100644 --- a/ledger/store/trackerdb/data_test.go +++ b/ledger/store/trackerdb/data_test.go @@ -1249,14 +1249,14 @@ func TestBaseOnlineAccountDataReflect(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - require.Equal(t, 7, reflect.TypeOf(BaseOnlineAccountData{}).NumField(), "update all getters and setters for baseOnlineAccountData and change the field count") + require.Equal(t, 7, reflect.TypeFor[BaseOnlineAccountData]().NumField(), "update all getters and setters for baseOnlineAccountData and change the field count") } func TestBaseVotingDataReflect(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - require.Equal(t, 7, reflect.TypeOf(BaseVotingData{}).NumField(), "update all getters and setters for baseVotingData and change the field count") + require.Equal(t, 7, reflect.TypeFor[BaseVotingData]().NumField(), "update all getters and setters for baseVotingData and change the field count") } // TestBaseAccountDataDecodeEmpty ensures no surprises when decoding nil/empty data. diff --git a/ledger/testing/randomAccounts_test.go b/ledger/testing/randomAccounts_test.go index 927d63fe82..bb5d68df91 100644 --- a/ledger/testing/randomAccounts_test.go +++ b/ledger/testing/randomAccounts_test.go @@ -30,7 +30,7 @@ func TestAccounts(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - accountDataType := reflect.TypeOf(basics.AccountData{}) + accountDataType := reflect.TypeFor[basics.AccountData]() referencedAccountTypes := make([]reflectionhelpers.TypePath, 0) reflectionhelpers.IterateReferencedTypes(accountDataType, func(path reflectionhelpers.TypePath, stack []reflect.Type) bool { diff --git a/logging/telemetryspec/metric_test.go b/logging/telemetryspec/metric_test.go index a626494c9a..af5a08eba7 100644 --- a/logging/telemetryspec/metric_test.go +++ b/logging/telemetryspec/metric_test.go @@ -68,7 +68,7 @@ func TestAssembleBlockStatsString(t *testing.T) { partitiontest.PartitionTest(t) var abs AssembleBlockStats - localType := reflect.TypeOf(abs) + localType := reflect.TypeFor[AssembleBlockStats]() // Empty StateProofStats will not be reported. Set a filed to check it printed abs.StateProofStats.ProvenWeight = 1 diff --git a/network/msgOfInterest.go b/network/msgOfInterest.go index 2830659d2d..fd07e60c0d 100644 --- a/network/msgOfInterest.go +++ b/network/msgOfInterest.go @@ -46,7 +46,7 @@ func unmarshallMessageOfInterest(data []byte) (map[protocol.Tag]bool, error) { } // convert the tags into a tags map. msgTagsMap := make(map[protocol.Tag]bool, len(tags)) - for _, tag := range strings.Split(string(tags), topicsEncodingSeparator) { + for tag := range strings.SplitSeq(string(tags), topicsEncodingSeparator) { if len(tag) != protocol.TagLength { return nil, errInvalidMessageOfInterestInvalidTag } diff --git a/network/vpack/dynamic_vpack_test.go b/network/vpack/dynamic_vpack_test.go index 9f968294e6..af8ce5f747 100644 --- a/network/vpack/dynamic_vpack_test.go +++ b/network/vpack/dynamic_vpack_test.go @@ -225,7 +225,7 @@ func TestStatefulEncodeRef(t *testing.T) { partitiontest.PartitionTest(t) var id lruTableReferenceID require.Equal(t, uintptr(2), unsafe.Sizeof(id), "lruTableReferenceID should occupy 2 bytes (uint16)") - require.Equal(t, reflect.Uint16, reflect.TypeOf(id).Kind(), "lruTableReferenceID underlying kind should be uint16") + require.Equal(t, reflect.Uint16, reflect.TypeFor[lruTableReferenceID]().Kind(), "lruTableReferenceID underlying kind should be uint16") // Maximum table size we support is 2048 (1024 buckets, 2 slots each) // Last bucket would be 1023, last slot would be 1, so maxID = (1023<<1)|1 = 2047 maxTableSize := uint32(2048) diff --git a/network/wsPeer.go b/network/wsPeer.go index 4b5bc9955f..29f9d291ce 100644 --- a/network/wsPeer.go +++ b/network/wsPeer.go @@ -1111,8 +1111,8 @@ func decodePeerFeatures(version string, announcedFeatures string) peerFeatureFla } var features peerFeatureFlag - parts := strings.Split(announcedFeatures, ",") - for _, part := range parts { + parts := strings.SplitSeq(announcedFeatures, ",") + for part := range parts { part = strings.TrimSpace(part) if part == PeerFeatureProposalCompression { features |= pfCompressedProposal diff --git a/protocol/codec_tester.go b/protocol/codec_tester.go index 5e3e8ffde4..08ff7ee686 100644 --- a/protocol/codec_tester.go +++ b/protocol/codec_tester.go @@ -42,7 +42,7 @@ type msgpMarshalUnmarshal interface { msgp.Unmarshaler } -var rawMsgpType = reflect.TypeOf(msgp.Raw{}) +var rawMsgpType = reflect.TypeFor[msgp.Raw]() var errSkipRawMsgpTesting = fmt.Errorf("skipping msgp.Raw serializing, since it won't be the same across go-codec and msgp") func oneOf(n int) bool { @@ -122,7 +122,7 @@ func RandomizeObjectField(template interface{}, opts ...RandomizeObjectOption) ( func parseStructTags(structTag string) map[string]string { tagsMap := map[string]string{} - for _, tag := range strings.Split(reflect.StructTag(structTag).Get("codec"), ",") { + for tag := range strings.SplitSeq(reflect.StructTag(structTag).Get("codec"), ",") { elements := strings.Split(tag, "=") if len(elements) != 2 { continue diff --git a/rpcs/blockService.go b/rpcs/blockService.go index e1b296e12b..03a4c4ebb7 100644 --- a/rpcs/blockService.go +++ b/rpcs/blockService.go @@ -505,8 +505,8 @@ func makeFallbackEndpoints(log logging.Logger, customFallbackEndpoints string) ( if customFallbackEndpoints == "" { return } - endpoints := strings.Split(customFallbackEndpoints, ",") - for _, ep := range endpoints { + endpoints := strings.SplitSeq(customFallbackEndpoints, ",") + for ep := range endpoints { if addr.IsMultiaddr(ep) { fe.endpoints = append(fe.endpoints, ep) } else { diff --git a/test/e2e-go/restAPI/restClient_test.go b/test/e2e-go/restAPI/restClient_test.go index dc22235250..b6a4fc96cb 100644 --- a/test/e2e-go/restAPI/restClient_test.go +++ b/test/e2e-go/restAPI/restClient_test.go @@ -17,7 +17,6 @@ package restapi import ( - "context" "flag" "math" "os" @@ -455,8 +454,7 @@ func TestClientCanGetGoRoutines(t *testing.T) { a := require.New(fixtures.SynchronizedTest(t)) defer fixture.SetTestContext(t)() testClient := fixture.AlgodClient - ctx, ctxCancel := context.WithCancel(context.Background()) - defer ctxCancel() + ctx := t.Context() goRoutines, err := testClient.GetGoRoutines(ctx) a.NoError(err) a.NotEmpty(goRoutines) diff --git a/tools/debug/algodump/main.go b/tools/debug/algodump/main.go index 27233b3dbb..e42b893562 100644 --- a/tools/debug/algodump/main.go +++ b/tools/debug/algodump/main.go @@ -132,7 +132,7 @@ func setDumpHandlers(n network.GossipNode) { dh.tags = make(map[protocol.Tag]bool) } else { dh.tags = make(map[protocol.Tag]bool) - for _, t := range strings.Split(*tags, ",") { + for t := range strings.SplitSeq(*tags, ",") { dh.tags[protocol.Tag(t)] = true fmt.Printf("TAG <%s>\n", t) } diff --git a/util/execpool/stream_test.go b/util/execpool/stream_test.go index 887fc3f27f..b311acddd5 100644 --- a/util/execpool/stream_test.go +++ b/util/execpool/stream_test.go @@ -308,8 +308,7 @@ func TestErrors(t *testing.T) { asyncDelay: make(chan struct{}, 10), } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() inputChan := make(chan InputJob) mbp := mockBatchProcessor{} diff --git a/util/metrics/metrics_test.go b/util/metrics/metrics_test.go index bb0cfce78c..3f782d242f 100644 --- a/util/metrics/metrics_test.go +++ b/util/metrics/metrics_test.go @@ -69,8 +69,8 @@ func (p *MetricTest) testMetricsHandler(w http.ResponseWriter, r *http.Request) if err != nil { return } - lines := strings.Split(string(body), "\n") - for _, line := range lines { + lines := strings.SplitSeq(string(body), "\n") + for line := range lines { if len(line) < 5 { continue }