aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-12-05 15:52:35 -0500
committerRuss Cox <rsc@golang.org>2011-12-05 15:52:35 -0500
commit4feafeeea0cc0d489557881f9148143c305f2198 (patch)
tree0222cc24a0c04fdebd09d89412fb8d2a81fd0672
parent2666b815a33edf3a9a1b7c335f9baabf27179d9f (diff)
downloadgo-4feafeeea0cc0d489557881f9148143c305f2198.tar.gz
go-4feafeeea0cc0d489557881f9148143c305f2198.zip
gofix: fix for strconv API change
R=golang-dev, gri, adg, r CC=golang-dev https://golang.org/cl/5434098
-rw-r--r--src/cmd/gofix/Makefile1
-rw-r--r--src/cmd/gofix/fix.go9
-rw-r--r--src/cmd/gofix/strconv.go127
-rw-r--r--src/cmd/gofix/strconv_test.go93
4 files changed, 230 insertions, 0 deletions
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index e6b9503faf..6ae4acc248 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -31,6 +31,7 @@ GOFILES=\
signal.go\
sorthelpers.go\
sortslice.go\
+ strconv.go\
stringssplit.go\
template.go\
timefileinfo.go\
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
index 0a49df1be3..5d70e9cf9c 100644
--- a/src/cmd/gofix/fix.go
+++ b/src/cmd/gofix/fix.go
@@ -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
index 0000000000..6cd69020b2
--- /dev/null
+++ b/src/cmd/gofix/strconv.go
@@ -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
index 0000000000..7fbd4e42eb
--- /dev/null
+++ b/src/cmd/gofix/strconv_test.go
@@ -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)
+}
+`,
+ },
+}