diff options
Diffstat (limited to 'src/cmd/fix/strconv.go')
-rw-r--r-- | src/cmd/fix/strconv.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/cmd/fix/strconv.go b/src/cmd/fix/strconv.go new file mode 100644 index 000000000..6cd69020b --- /dev/null +++ b/src/cmd/fix/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}} +} |