summaryrefslogtreecommitdiff
path: root/src/cmd/gofix
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gofix')
-rw-r--r--src/cmd/gofix/Makefile13
-rw-r--r--src/cmd/gofix/filepath.go53
-rw-r--r--src/cmd/gofix/filepath_test.go33
-rw-r--r--src/cmd/gofix/httpfinalurl.go2
-rw-r--r--src/cmd/gofix/httpfs.go63
-rw-r--r--src/cmd/gofix/httpfs_test.go47
-rw-r--r--src/cmd/gofix/httpheaders.go66
-rw-r--r--src/cmd/gofix/httpheaders_test.go73
-rw-r--r--src/cmd/gofix/main.go4
-rw-r--r--src/cmd/gofix/oserrorstring.go75
-rw-r--r--src/cmd/gofix/oserrorstring_test.go57
-rw-r--r--src/cmd/gofix/osopen.go2
-rw-r--r--src/cmd/gofix/sorthelpers.go47
-rw-r--r--src/cmd/gofix/sorthelpers_test.go45
-rw-r--r--src/cmd/gofix/sortslice.go50
-rw-r--r--src/cmd/gofix/sortslice_test.go35
-rw-r--r--src/cmd/gofix/stringssplit.go71
-rw-r--r--src/cmd/gofix/stringssplit_test.go51
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.out6
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.out2
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.out12
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.out2
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.out4
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.out8
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.in4
-rw-r--r--src/cmd/gofix/testdata/reflect.template.go.out4
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.out4
27 files changed, 803 insertions, 30 deletions
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index c4127d93e..7ce21e8aa 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -6,15 +6,22 @@ include ../../Make.inc
TARG=gofix
GOFILES=\
+ filepath.go\
fix.go\
- netdial.go\
- main.go\
- osopen.go\
httpfinalurl.go\
+ httpfs.go\
+ httpheaders.go\
httpserver.go\
+ main.go\
+ netdial.go\
+ oserrorstring.go\
+ osopen.go\
procattr.go\
reflect.go\
signal.go\
+ sorthelpers.go\
+ sortslice.go\
+ stringssplit.go\
typecheck.go\
include ../../Make.cmd
diff --git a/src/cmd/gofix/filepath.go b/src/cmd/gofix/filepath.go
new file mode 100644
index 000000000..1d0ad6879
--- /dev/null
+++ b/src/cmd/gofix/filepath.go
@@ -0,0 +1,53 @@
+// 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(fix{
+ "filepath",
+ filepathFunc,
+ `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
+
+http://codereview.appspot.com/4527090
+`,
+ })
+}
+
+func filepathFunc(f *ast.File) (fixed bool) {
+ if !imports(f, "path/filepath") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ e, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+
+ var ident string
+ switch {
+ case isPkgDot(*e, "filepath", "SeparatorString"):
+ ident = "filepath.Separator"
+ case isPkgDot(*e, "filepath", "ListSeparatorString"):
+ ident = "filepath.ListSeparator"
+ default:
+ return
+ }
+
+ // string(filepath.[List]Separator)
+ *e = &ast.CallExpr{
+ Fun: ast.NewIdent("string"),
+ Args: []ast.Expr{ast.NewIdent(ident)},
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/gofix/filepath_test.go
new file mode 100644
index 000000000..d170c3ae3
--- /dev/null
+++ b/src/cmd/gofix/filepath_test.go
@@ -0,0 +1,33 @@
+// 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(filepathTests)
+}
+
+var filepathTests = []testCase{
+ {
+ Name: "filepath.0",
+ In: `package main
+
+import (
+ "path/filepath"
+)
+
+var _ = filepath.SeparatorString
+var _ = filepath.ListSeparatorString
+`,
+ Out: `package main
+
+import (
+ "path/filepath"
+)
+
+var _ = string(filepath.Separator)
+var _ = string(filepath.ListSeparator)
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/gofix/httpfinalurl.go
index 53642b22f..9e6cbf6bc 100644
--- a/src/cmd/gofix/httpfinalurl.go
+++ b/src/cmd/gofix/httpfinalurl.go
@@ -13,7 +13,7 @@ var httpFinalURLFix = fix{
httpfinalurl,
`Adapt http Get calls to not have a finalURL result parameter.
- http://codereview.appspot.com/4535056/
+http://codereview.appspot.com/4535056/
`,
}
diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/gofix/httpfs.go
new file mode 100644
index 000000000..7f2765680
--- /dev/null
+++ b/src/cmd/gofix/httpfs.go
@@ -0,0 +1,63 @@
+// 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"
+ "go/token"
+)
+
+var httpFileSystemFix = fix{
+ "httpfs",
+ httpfs,
+ `Adapt http FileServer to take a FileSystem.
+
+http://codereview.appspot.com/4629047 http FileSystem interface
+`,
+}
+
+func init() {
+ register(httpFileSystemFix)
+}
+
+func httpfs(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || !isPkgDot(call.Fun, "http", "FileServer") {
+ return
+ }
+ if len(call.Args) != 2 {
+ return
+ }
+ dir, prefix := call.Args[0], call.Args[1]
+ call.Args = []ast.Expr{&ast.CallExpr{
+ Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")},
+ Args: []ast.Expr{dir},
+ }}
+ wrapInStripHandler := true
+ if prefixLit, ok := prefix.(*ast.BasicLit); ok {
+ if prefixLit.Kind == token.STRING && (prefixLit.Value == `"/"` || prefixLit.Value == `""`) {
+ wrapInStripHandler = false
+ }
+ }
+ if wrapInStripHandler {
+ call.Fun.(*ast.SelectorExpr).Sel = ast.NewIdent("StripPrefix")
+ call.Args = []ast.Expr{
+ prefix,
+ &ast.CallExpr{
+ Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")},
+ Args: call.Args,
+ },
+ }
+ }
+ fixed = true
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/gofix/httpfs_test.go
new file mode 100644
index 000000000..d1804e93b
--- /dev/null
+++ b/src/cmd/gofix/httpfs_test.go
@@ -0,0 +1,47 @@
+// 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(httpFileSystemTests)
+}
+
+var httpFileSystemTests = []testCase{
+ {
+ Name: "httpfs.0",
+ In: `package httpfs
+
+import (
+ "http"
+)
+
+func f() {
+ _ = http.FileServer("/var/www/foo", "/")
+ _ = http.FileServer("/var/www/foo", "")
+ _ = http.FileServer("/var/www/foo/bar", "/bar")
+ s := "/foo"
+ _ = http.FileServer(s, "/")
+ prefix := "/p"
+ _ = http.FileServer(s, prefix)
+}
+`,
+ Out: `package httpfs
+
+import (
+ "http"
+)
+
+func f() {
+ _ = http.FileServer(http.Dir("/var/www/foo"))
+ _ = http.FileServer(http.Dir("/var/www/foo"))
+ _ = http.StripPrefix("/bar", http.FileServer(http.Dir("/var/www/foo/bar")))
+ s := "/foo"
+ _ = http.FileServer(http.Dir(s))
+ prefix := "/p"
+ _ = http.StripPrefix(prefix, http.FileServer(http.Dir(s)))
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpheaders.go b/src/cmd/gofix/httpheaders.go
new file mode 100644
index 000000000..8a9080e8e
--- /dev/null
+++ b/src/cmd/gofix/httpheaders.go
@@ -0,0 +1,66 @@
+// 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"
+)
+
+var httpHeadersFix = fix{
+ "httpheaders",
+ httpheaders,
+ `Rename http Referer, UserAgent, Cookie, SetCookie, which are now methods.
+
+http://codereview.appspot.com/4620049/
+`,
+}
+
+func init() {
+ register(httpHeadersFix)
+}
+
+func httpheaders(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ called := make(map[ast.Node]bool)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.CallExpr:
+ called[n.Fun] = true
+ }
+ })
+
+ fixed := false
+ typeof := typecheck(headerTypeConfig, f)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.SelectorExpr:
+ if called[n] {
+ break
+ }
+ if t := typeof[n.X]; t != "*http.Request" && t != "*http.Response" {
+ break
+ }
+ switch n.Sel.Name {
+ case "Referer", "UserAgent":
+ n.Sel.Name += "()"
+ fixed = true
+ case "Cookie":
+ n.Sel.Name = "Cookies()"
+ fixed = true
+ }
+ }
+ })
+ return fixed
+}
+
+var headerTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "*http.Request": &Type{},
+ "*http.Response": &Type{},
+ },
+}
diff --git a/src/cmd/gofix/httpheaders_test.go b/src/cmd/gofix/httpheaders_test.go
new file mode 100644
index 000000000..cc82b5893
--- /dev/null
+++ b/src/cmd/gofix/httpheaders_test.go
@@ -0,0 +1,73 @@
+// 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(httpHeadersTests)
+}
+
+var httpHeadersTests = []testCase{
+ {
+ Name: "httpheaders.0",
+ In: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer
+ _ = req.UserAgent
+ _ = req.Cookie
+
+ _ = res.Cookie
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ Out: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+
+ _ = res.Cookies()
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
index 1b091c18a..e7e7013c5 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/gofix/main.go
@@ -53,7 +53,7 @@ func main() {
if *allowedRewrites != "" {
allowed = make(map[string]bool)
- for _, f := range strings.Split(*allowedRewrites, ",", -1) {
+ for _, f := range strings.Split(*allowedRewrites, ",") {
allowed[f] = true
}
}
@@ -123,7 +123,7 @@ func processFile(filename string, useStdin bool) os.Error {
newFile := file
fixed := false
for _, fix := range fixes {
- if allowed != nil && !allowed[fix.desc] {
+ if allowed != nil && !allowed[fix.name] {
continue
}
if fix.f(newFile) {
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/gofix/oserrorstring.go
new file mode 100644
index 000000000..5e61ab952
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring.go
@@ -0,0 +1,75 @@
+// 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"
+)
+
+var oserrorstringFix = fix{
+ "oserrorstring",
+ oserrorstring,
+ `Replace os.ErrorString() conversions with calls to os.NewError().
+
+http://codereview.appspot.com/4607052
+`,
+}
+
+func init() {
+ register(oserrorstringFix)
+}
+
+func oserrorstring(f *ast.File) bool {
+ if !imports(f, "os") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // The conversion os.ErrorString(x) looks like a call
+ // of os.ErrorString with one argument.
+ if call := callExpr(n, "os", "ErrorString"); call != nil {
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ fixed = true
+ return
+ }
+
+ // Remove os.Error type from variable declarations initialized
+ // with an os.NewError.
+ // (An *ast.ValueSpec may also be used in a const declaration
+ // but those won't be initialized with a call to os.NewError.)
+ if spec, ok := n.(*ast.ValueSpec); ok &&
+ len(spec.Names) == 1 &&
+ isPkgDot(spec.Type, "os", "Error") &&
+ len(spec.Values) == 1 &&
+ callExpr(spec.Values[0], "os", "NewError") != nil {
+ // var name os.Error = os.NewError(x) ->
+ // var name = os.NewError(x)
+ spec.Type = nil
+ fixed = true
+ return
+ }
+
+ // Other occurrences of os.ErrorString are not fixed
+ // but they are rare.
+
+ })
+ return fixed
+}
+
+
+// callExpr returns the call expression if x is a call to pkg.name with one argument;
+// otherwise it returns nil.
+func callExpr(x interface{}, pkg, name string) *ast.CallExpr {
+ if call, ok := x.(*ast.CallExpr); ok &&
+ len(call.Args) == 1 &&
+ isPkgDot(call.Fun, pkg, name) {
+ return call
+ }
+ return nil
+}
diff --git a/src/cmd/gofix/oserrorstring_test.go b/src/cmd/gofix/oserrorstring_test.go
new file mode 100644
index 000000000..070d9222b
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring_test.go
@@ -0,0 +1,57 @@
+// 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(oserrorstringTests)
+}
+
+var oserrorstringTests = []testCase{
+ {
+ Name: "oserrorstring.0",
+ In: `package main
+
+import "os"
+
+var _ = os.ErrorString("foo")
+var _ os.Error = os.ErrorString("bar1")
+var _ os.Error = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.ErrorString("foo")
+ _ os.Error = os.ErrorString("bar1")
+ _ os.Error = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.ErrorString("foo")
+ return os.ErrorString("foo")
+}
+`,
+ Out: `package main
+
+import "os"
+
+var _ = os.NewError("foo")
+var _ = os.NewError("bar1")
+var _ = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.NewError("foo")
+ _ = os.NewError("bar1")
+ _ = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.NewError("foo")
+ return os.NewError("foo")
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/osopen.go b/src/cmd/gofix/osopen.go
index 8eb5d0655..56147c390 100644
--- a/src/cmd/gofix/osopen.go
+++ b/src/cmd/gofix/osopen.go
@@ -13,7 +13,7 @@ var osopenFix = fix{
osopen,
`Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
- http://codereview.appspot.com/4357052
+http://codereview.appspot.com/4357052
`,
}
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/gofix/sorthelpers.go
new file mode 100644
index 000000000..4d0bee6e7
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers.go
@@ -0,0 +1,47 @@
+// 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(fix{
+ "sorthelpers",
+ sorthelpers,
+ `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
+`,
+ })
+}
+
+
+func sorthelpers(f *ast.File) (fixed bool) {
+ if !imports(f, "sort") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if !ok || !isTopName(s.X, "sort") {
+ return
+ }
+
+ switch s.Sel.String() {
+ case "SortFloat64s":
+ s.Sel.Name = "Float64s"
+ case "SortInts":
+ s.Sel.Name = "Ints"
+ case "SortStrings":
+ s.Sel.Name = "Strings"
+ default:
+ return
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/gofix/sorthelpers_test.go
new file mode 100644
index 000000000..6c37858fd
--- /dev/null
+++ b/src/cmd/gofix/sorthelpers_test.go
@@ -0,0 +1,45 @@
+// 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(sorthelpersTests)
+}
+
+var sorthelpersTests = []testCase{
+ {
+ Name: "sortslice.0",
+ In: `package main
+
+import (
+ "sort"
+)
+
+func main() {
+ var s []string
+ sort.SortStrings(s)
+ var i []ints
+ sort.SortInts(i)
+ var f []float64
+ sort.SortFloat64s(f)
+}
+`,
+ Out: `package main
+
+import (
+ "sort"
+)
+
+func main() {
+ var s []string
+ sort.Strings(s)
+ var i []ints
+ sort.Ints(i)
+ var f []float64
+ sort.Float64s(f)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/gofix/sortslice.go
new file mode 100644
index 000000000..b9c108b5a
--- /dev/null
+++ b/src/cmd/gofix/sortslice.go
@@ -0,0 +1,50 @@
+// 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(fix{
+ "sortslice",
+ sortslice,
+ `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice.
+
+http://codereview.appspot.com/4602054
+http://codereview.appspot.com/4639041
+`,
+ })
+}
+
+
+func sortslice(f *ast.File) (fixed bool) {
+ if !imports(f, "sort") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if !ok || !isTopName(s.X, "sort") {
+ return
+ }
+
+ switch s.Sel.String() {
+ case "Float64Array":
+ s.Sel.Name = "Float64Slice"
+ case "IntArray":
+ s.Sel.Name = "IntSlice"
+ case "StringArray":
+ s.Sel.Name = "StringSlice"
+ default:
+ return
+ }
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/gofix/sortslice_test.go
new file mode 100644
index 000000000..404feb26f
--- /dev/null
+++ b/src/cmd/gofix/sortslice_test.go
@@ -0,0 +1,35 @@
+// 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(sortsliceTests)
+}
+
+var sortsliceTests = []testCase{
+ {
+ Name: "sortslice.0",
+ In: `package main
+
+import (
+ "sort"
+)
+
+var _ = sort.Float64Array
+var _ = sort.IntArray
+var _ = sort.StringArray
+`,
+ Out: `package main
+
+import (
+ "sort"
+)
+
+var _ = sort.Float64Slice
+var _ = sort.IntSlice
+var _ = sort.StringSlice
+`,
+ },
+}
diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/gofix/stringssplit.go
new file mode 100644
index 000000000..4a1fe93d3
--- /dev/null
+++ b/src/cmd/gofix/stringssplit.go
@@ -0,0 +1,71 @@
+// 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"
+ "go/token"
+)
+
+var stringssplitFix = fix{
+ "stringssplit",
+ stringssplit,
+ `Restore strings.Split to its original meaning and add strings.SplitN. Bytes too.
+
+http://codereview.appspot.com/4661051
+`,
+}
+
+func init() {
+ register(stringssplitFix)
+}
+
+func stringssplit(f *ast.File) bool {
+ if !imports(f, "bytes") && !imports(f, "strings") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ // func Split(s, sep string, n int) []string
+ // func SplitAfter(s, sep string, n int) []string
+ if !ok || len(call.Args) != 3 {
+ return
+ }
+ // Is this our function?
+ switch {
+ case isPkgDot(call.Fun, "bytes", "Split"):
+ case isPkgDot(call.Fun, "bytes", "SplitAfter"):
+ case isPkgDot(call.Fun, "strings", "Split"):
+ case isPkgDot(call.Fun, "strings", "SplitAfter"):
+ default:
+ return
+ }
+
+ sel := call.Fun.(*ast.SelectorExpr)
+ args := call.Args
+ fixed = true // We're committed.
+
+ // Is the last argument -1? If so, drop the arg.
+ // (Actually we just look for a negative integer literal.)
+ // Otherwise, Split->SplitN and keep the arg.
+ final := args[2]
+ if unary, ok := final.(*ast.UnaryExpr); ok && unary.Op == token.SUB {
+ if lit, ok := unary.X.(*ast.BasicLit); ok {
+ // Is it an integer? If so, it's a negative integer and that's what we're after.
+ if lit.Kind == token.INT {
+ // drop the last arg.
+ call.Args = args[0:2]
+ return
+ }
+ }
+ }
+
+ // If not, rename and keep the argument list.
+ sel.Sel.Name += "N"
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/gofix/stringssplit_test.go
new file mode 100644
index 000000000..b925722af
--- /dev/null
+++ b/src/cmd/gofix/stringssplit_test.go
@@ -0,0 +1,51 @@
+// 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(stringssplitTests)
+}
+
+var stringssplitTests = []testCase{
+ {
+ Name: "stringssplit.0",
+ In: `package main
+
+import (
+ "bytes"
+ "strings"
+)
+
+func f() {
+ bytes.Split(a, b, c)
+ bytes.Split(a, b, -1)
+ bytes.SplitAfter(a, b, c)
+ bytes.SplitAfter(a, b, -1)
+ strings.Split(a, b, c)
+ strings.Split(a, b, -1)
+ strings.SplitAfter(a, b, c)
+ strings.SplitAfter(a, b, -1)
+}
+`,
+ Out: `package main
+
+import (
+ "bytes"
+ "strings"
+)
+
+func f() {
+ bytes.SplitN(a, b, c)
+ bytes.Split(a, b)
+ bytes.SplitAfterN(a, b, c)
+ bytes.SplitAfter(a, b)
+ strings.SplitN(a, b, c)
+ strings.Split(a, b)
+ strings.SplitAfterN(a, b, c)
+ strings.SplitAfter(a, b)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.out b/src/cmd/gofix/testdata/reflect.decoder.go.out
index 170eedb05..ece88ecbe 100644
--- a/src/cmd/gofix/testdata/reflect.decoder.go.out
+++ b/src/cmd/gofix/testdata/reflect.decoder.go.out
@@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder {
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
@@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
@@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.out b/src/cmd/gofix/testdata/reflect.encoder.go.out
index 781ef6504..925d39301 100644
--- a/src/cmd/gofix/testdata/reflect.encoder.go.out
+++ b/src/cmd/gofix/testdata/reflect.encoder.go.out
@@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
diff --git a/src/cmd/gofix/testdata/reflect.export.go.out b/src/cmd/gofix/testdata/reflect.export.go.out
index 486a812e2..460edb40b 100644
--- a/src/cmd/gofix/testdata/reflect.export.go.out
+++ b/src/cmd/gofix/testdata/reflect.export.go.out
@@ -343,20 +343,20 @@ func (exp *Exporter) Sync(timeout int64) os.Error {
func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
chanType := reflect.TypeOf(chT)
if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.ErrorString("not a channel")
+ return reflect.Value{}, os.NewError("not a channel")
}
if dir != Send && dir != Recv {
- return reflect.Value{}, os.ErrorString("unknown channel direction")
+ return reflect.Value{}, os.NewError("unknown channel direction")
}
switch chanType.ChanDir() {
case reflect.BothDir:
case reflect.SendDir:
if dir != Recv {
- return reflect.Value{}, os.ErrorString("to import/export with Send, must provide <-chan")
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
}
case reflect.RecvDir:
if dir != Send {
- return reflect.Value{}, os.ErrorString("to import/export with Recv, must provide chan<-")
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
}
}
return reflect.ValueOf(chT), nil
@@ -376,7 +376,7 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
defer exp.mu.Unlock()
_, present := exp.names[name]
if present {
- return os.ErrorString("channel name already being exported:" + name)
+ return os.NewError("channel name already being exported:" + name)
}
exp.names[name] = &chanDir{ch, dir}
return nil
@@ -393,7 +393,7 @@ func (exp *Exporter) Hangup(name string) os.Error {
// TODO drop all instances of channel from client sets
exp.mu.Unlock()
if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ return os.NewError("netchan export: hangup: no such channel: " + name)
}
chDir.ch.Close()
return nil
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/gofix/testdata/reflect.print.go.out
index 079948cca..10379bd20 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.out
+++ b/src/cmd/gofix/testdata/reflect.print.go.out
@@ -185,7 +185,7 @@ func Sprintf(format string, a ...interface{}) string {
// Errorf formats according to a format specifier and returns the string
// converted to an os.ErrorString, which satisfies the os.Error interface.
func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
diff --git a/src/cmd/gofix/testdata/reflect.read.go.out b/src/cmd/gofix/testdata/reflect.read.go.out
index 554b2a61b..a6b126744 100644
--- a/src/cmd/gofix/testdata/reflect.read.go.out
+++ b/src/cmd/gofix/testdata/reflect.read.go.out
@@ -244,7 +244,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch v := val; v.Kind() {
default:
- return os.ErrorString("unknown type " + v.Type().String())
+ return os.NewError("unknown type " + v.Type().String())
case reflect.Slice:
typ := v.Type()
@@ -483,7 +483,7 @@ Loop:
case reflect.Invalid:
// Probably a comment, handled below
default:
- return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if !getInt64() {
return err
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/gofix/testdata/reflect.scan.go.out
index 42bc52c92..2b07115e9 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.out
+++ b/src/cmd/gofix/testdata/reflect.scan.go.out
@@ -167,7 +167,7 @@ type ssave struct {
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -240,7 +240,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -426,8 +426,8 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
}
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/gofix/testdata/reflect.template.go.in
index ba06de4e3..1f5a8128f 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.in
+++ b/src/cmd/gofix/testdata/reflect.template.go.in
@@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement {
bar := strings.IndexRune(lastWord, '|')
if bar >= 0 {
words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|", -1)
+ formatters = strings.Split(lastWord[bar+1:], "|")
}
// We could remember the function address here and avoid the lookup later,
@@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
if s == "@" {
return indirectPtr(data, numStars)
}
- for _, elem := range strings.Split(s, ".", -1) {
+ for _, elem := range strings.Split(s, ".") {
// Look up field; data must be a struct or map.
data = t.lookup(st, data, elem)
if data == nil {
diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/gofix/testdata/reflect.template.go.out
index c36288455..f2f56ef3c 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.out
+++ b/src/cmd/gofix/testdata/reflect.template.go.out
@@ -444,7 +444,7 @@ func (t *Template) newVariable(words []string) *variableElement {
bar := strings.IndexRune(lastWord, '|')
if bar >= 0 {
words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|", -1)
+ formatters = strings.Split(lastWord[bar+1:], "|")
}
// We could remember the function address here and avoid the lookup later,
@@ -705,7 +705,7 @@ func (t *Template) findVar(st *state, s string) reflect.Value {
if s == "@" {
return indirectPtr(data, numStars)
}
- for _, elem := range strings.Split(s, ".", -1) {
+ for _, elem := range strings.Split(s, ".") {
// Look up field; data must be a struct or map.
data = t.lookup(st, data, elem)
if !data.IsValid() {
diff --git a/src/cmd/gofix/testdata/reflect.type.go.out b/src/cmd/gofix/testdata/reflect.type.go.out
index a39b074fe..9cd78296d 100644
--- a/src/cmd/gofix/testdata/reflect.type.go.out
+++ b/src/cmd/gofix/testdata/reflect.type.go.out
@@ -67,7 +67,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
ut.base = pt.Elem()
if ut.base == slowpoke { // ut.base lapped slowpoke
// recursive pointer type.
- return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
}
if ut.indir%2 == 0 {
slowpoke = slowpoke.Elem()
@@ -524,7 +524,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
return st, nil
default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}