]> Cypherpunks repositories - gostls13.git/commitdiff
gofix: fix for strconv API change
authorRuss Cox <rsc@golang.org>
Mon, 5 Dec 2011 20:52:35 +0000 (15:52 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 5 Dec 2011 20:52:35 +0000 (15:52 -0500)
R=golang-dev, gri, adg, r
CC=golang-dev
https://golang.org/cl/5434098

src/cmd/gofix/Makefile
src/cmd/gofix/fix.go
src/cmd/gofix/strconv.go [new file with mode: 0644]
src/cmd/gofix/strconv_test.go [new file with mode: 0644]

index e6b9503faf91b2d762e6252f97cbf7734bda694c..6ae4acc248531313f280541b3b7fa2f20d11641a 100644 (file)
@@ -31,6 +31,7 @@ GOFILES=\
        signal.go\
        sorthelpers.go\
        sortslice.go\
+       strconv.go\
        stringssplit.go\
        template.go\
        timefileinfo.go\
index 0a49df1be3ac7ca979fd029aaf097d89134aeaaa..5d70e9cf9c71e67ec0ac0d647cd43160a251d2a5 100644 (file)
@@ -15,6 +15,7 @@ slice of named type (go/scanner)
 import (
        "fmt"
        "go/ast"
+       "go/parser"
        "go/token"
        "os"
        "path"
@@ -743,3 +744,11 @@ func usesImport(f *ast.File, path string) (used bool) {
 
        return
 }
+
+func expr(s string) ast.Expr {
+       x, err := parser.ParseExpr(fset, "", s)
+       if err != nil {
+               panic("parsing " + s + ": " + err.Error())
+       }
+       return x
+}
diff --git a/src/cmd/gofix/strconv.go b/src/cmd/gofix/strconv.go
new file mode 100644 (file)
index 0000000..6cd6902
--- /dev/null
@@ -0,0 +1,127 @@
+// 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() {
+       register(strconvFix)
+}
+
+var strconvFix = fix{
+       "strconv",
+       "2011-12-01",
+       strconvFn,
+       `Convert to new strconv API.
+
+http://codereview.appspot.com/5434095
+http://codereview.appspot.com/5434069
+`,
+}
+
+func strconvFn(f *ast.File) bool {
+       if !imports(f, "strconv") {
+               return false
+       }
+
+       fixed := false
+
+       walk(f, func(n interface{}) {
+               // Rename functions.
+               call, ok := n.(*ast.CallExpr)
+               if !ok || len(call.Args) < 1 {
+                       return
+               }
+               sel, ok := call.Fun.(*ast.SelectorExpr)
+               if !ok || !isTopName(sel.X, "strconv") {
+                       return
+               }
+               change := func(name string) {
+                       fixed = true
+                       sel.Sel.Name = name
+               }
+               add := func(s string) {
+                       call.Args = append(call.Args, expr(s))
+               }
+               switch sel.Sel.Name {
+               case "Atob":
+                       change("ParseBool")
+               case "Atof32":
+                       change("ParseFloat")
+                       add("32") // bitSize
+                       warn(call.Pos(), "rewrote strconv.Atof32(_) to strconv.ParseFloat(_, 32) but return value must be converted to float32")
+               case "Atof64":
+                       change("ParseFloat")
+                       add("64") // bitSize
+               case "AtofN":
+                       change("ParseFloat")
+               case "Atoi":
+                       // Atoi stayed as a convenience wrapper.
+               case "Atoi64":
+                       change("ParseInt")
+                       add("10") // base
+                       add("64") // bitSize
+               case "Atoui":
+                       change("ParseUint")
+                       add("10") // base
+                       add("0")  // bitSize
+                       warn(call.Pos(), "rewrote strconv.Atoui(_) to strconv.ParseUint(_, 10, 0) but return value must be converted to uint")
+               case "Atoui64":
+                       change("ParseUint")
+                       add("10") // base
+                       add("64") // bitSize
+               case "Btoa":
+                       change("FormatBool")
+               case "Btoi64":
+                       change("ParseInt")
+                       add("64") // bitSize
+               case "Btoui64":
+                       change("ParseUint")
+                       add("64") // bitSize
+               case "Ftoa32":
+                       change("FormatFloat")
+                       call.Args[0] = strconvRewrite("float32", "float64", call.Args[0])
+                       add("32") // bitSize
+               case "Ftoa64":
+                       change("FormatFloat")
+                       add("64") // bitSize
+               case "FtoaN":
+                       change("FormatFloat")
+               case "Itoa":
+                       // Itoa stayed as a convenience wrapper.
+               case "Itoa64":
+                       change("FormatInt")
+                       add("10") // base
+               case "Itob":
+                       change("FormatInt")
+                       call.Args[0] = strconvRewrite("int", "int64", call.Args[0])
+               case "Itob64":
+                       change("FormatInt")
+               case "Uitoa":
+                       change("FormatUint")
+                       call.Args[0] = strconvRewrite("uint", "uint64", call.Args[0])
+                       add("10") // base
+               case "Uitoa64":
+                       change("FormatUint")
+                       add("10") // base
+               case "Uitob":
+                       change("FormatUint")
+                       call.Args[0] = strconvRewrite("uint", "uint64", call.Args[0])
+               case "Uitob64":
+                       change("FormatUint")
+               }
+       })
+       return fixed
+}
+
+// rewrite from type t1 to type t2
+// If the expression x is of the form t1(_), use t2(_).  Otherwise use t2(x).
+func strconvRewrite(t1, t2 string, x ast.Expr) ast.Expr {
+       if call, ok := x.(*ast.CallExpr); ok && isTopName(call.Fun, t1) {
+               call.Fun.(*ast.Ident).Name = t2
+               return x
+       }
+       return &ast.CallExpr{Fun: ast.NewIdent(t2), Args: []ast.Expr{x}}
+}
diff --git a/src/cmd/gofix/strconv_test.go b/src/cmd/gofix/strconv_test.go
new file mode 100644 (file)
index 0000000..7fbd4e4
--- /dev/null
@@ -0,0 +1,93 @@
+// 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
+
+func init() {
+       addTestCases(strconvTests, strconvFn)
+}
+
+var strconvTests = []testCase{
+       {
+               Name: "strconv.0",
+               In: `package main
+
+import "strconv"
+
+func f() {
+       foo.Atob("abc")
+
+       strconv.Atob("true")
+       strconv.Btoa(false)
+
+       strconv.Atof32("1.2")
+       strconv.Atof64("1.2")
+       strconv.AtofN("1.2", 64)
+       strconv.Ftoa32(1.2, 'g', 17)
+       strconv.Ftoa64(1.2, 'g', 17)
+       strconv.FtoaN(1.2, 'g', 17, 64)
+
+       strconv.Atoi("3")
+       strconv.Atoi64("3")
+       strconv.Btoi64("1234", 5)
+
+       strconv.Atoui("3")
+       strconv.Atoui64("3")
+       strconv.Btoui64("1234", 5)
+
+       strconv.Itoa(123)
+       strconv.Itoa64(1234)
+       strconv.Itob(123, 5)
+       strconv.Itob64(1234, 5)
+
+       strconv.Uitoa(123)
+       strconv.Uitoa64(1234)
+       strconv.Uitob(123, 5)
+       strconv.Uitob64(1234, 5)
+
+       strconv.Uitoa(uint(x))
+       strconv.Uitoa(f(x))
+}
+`,
+               Out: `package main
+
+import "strconv"
+
+func f() {
+       foo.Atob("abc")
+
+       strconv.ParseBool("true")
+       strconv.FormatBool(false)
+
+       strconv.ParseFloat("1.2", 32)
+       strconv.ParseFloat("1.2", 64)
+       strconv.ParseFloat("1.2", 64)
+       strconv.FormatFloat(float64(1.2), 'g', 17, 32)
+       strconv.FormatFloat(1.2, 'g', 17, 64)
+       strconv.FormatFloat(1.2, 'g', 17, 64)
+
+       strconv.Atoi("3")
+       strconv.ParseInt("3", 10, 64)
+       strconv.ParseInt("1234", 5, 64)
+
+       strconv.ParseUint("3", 10, 0)
+       strconv.ParseUint("3", 10, 64)
+       strconv.ParseUint("1234", 5, 64)
+
+       strconv.Itoa(123)
+       strconv.FormatInt(1234, 10)
+       strconv.FormatInt(int64(123), 5)
+       strconv.FormatInt(1234, 5)
+
+       strconv.FormatUint(uint64(123), 10)
+       strconv.FormatUint(1234, 10)
+       strconv.FormatUint(uint64(123), 5)
+       strconv.FormatUint(1234, 5)
+
+       strconv.FormatUint(uint64(x), 10)
+       strconv.FormatUint(uint64(f(x)), 10)
+}
+`,
+       },
+}