1
0
mirror of https://github.com/golang/go synced 2024-11-24 09:10:24 -07:00

gofix: fix for strconv API change

R=golang-dev, gri, adg, r
CC=golang-dev
https://golang.org/cl/5434098
This commit is contained in:
Russ Cox 2011-12-05 15:52:35 -05:00
parent 2666b815a3
commit 4feafeeea0
4 changed files with 230 additions and 0 deletions

View File

@ -31,6 +31,7 @@ GOFILES=\
signal.go\
sorthelpers.go\
sortslice.go\
strconv.go\
stringssplit.go\
template.go\
timefileinfo.go\

View 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
}

127
src/cmd/gofix/strconv.go Normal file
View File

@ -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}}
}

View File

@ -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)
}
`,
},
}