diff options
author | Russ Cox <rsc@golang.org> | 2011-12-05 15:52:35 -0500 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2011-12-05 15:52:35 -0500 |
commit | 4feafeeea0cc0d489557881f9148143c305f2198 (patch) | |
tree | 0222cc24a0c04fdebd09d89412fb8d2a81fd0672 | |
parent | 2666b815a33edf3a9a1b7c335f9baabf27179d9f (diff) | |
download | go-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/Makefile | 1 | ||||
-rw-r--r-- | src/cmd/gofix/fix.go | 9 | ||||
-rw-r--r-- | src/cmd/gofix/strconv.go | 127 | ||||
-rw-r--r-- | src/cmd/gofix/strconv_test.go | 93 |
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) +} +`, + }, +} |