summaryrefslogtreecommitdiff
path: root/src/cmd/fix/error.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fix/error.go')
-rw-r--r--src/cmd/fix/error.go353
1 files changed, 0 insertions, 353 deletions
diff --git a/src/cmd/fix/error.go b/src/cmd/fix/error.go
deleted file mode 100644
index 55613210a..000000000
--- a/src/cmd/fix/error.go
+++ /dev/null
@@ -1,353 +0,0 @@
-// 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"
- "regexp"
- "strings"
-)
-
-func init() {
- register(errorFix)
-}
-
-var errorFix = fix{
- "error",
- "2011-11-02",
- errorFn,
- `Use error instead of os.Error.
-
-This fix rewrites code using os.Error to use error:
-
- os.Error -> error
- os.NewError -> errors.New
- os.EOF -> io.EOF
-
-Seeing the old names above (os.Error and so on) triggers the following
-heuristic rewrites. The heuristics can be forced using the -force=error flag.
-
-A top-level function, variable, or constant named error is renamed error_.
-
-Error implementations—those types used as os.Error or named
-XxxError—have their String methods renamed to Error. Any existing
-Error field or method is renamed to Err.
-
-Error values—those with type os.Error or named e, err, error, err1,
-and so on—have method calls and field references rewritten just
-as the types do (String to Error, Error to Err). Also, a type assertion
-of the form err.(*os.Waitmsg) becomes err.(*exec.ExitError).
-
-http://codereview.appspot.com/5305066
-`,
-}
-
-// At minimum, this fix applies the following rewrites:
-//
-// os.Error -> error
-// os.NewError -> errors.New
-// os.EOF -> io.EOF
-//
-// However, if can apply any of those rewrites, it assumes that the
-// file predates the error type and tries to update the code to use
-// the new definition for error - an Error method, not a String method.
-// This more heuristic procedure may not be 100% accurate, so it is
-// only run when the file needs updating anyway. The heuristic can
-// be forced to run using -force=error.
-//
-// First, we must identify the implementations of os.Error.
-// These include the type of any value returned as or assigned to an os.Error.
-// To that set we add any type whose name contains "Error" or "error".
-// The heuristic helps for implementations that are not used as os.Error
-// in the file in which they are defined.
-//
-// In any implementation of os.Error, we rename an existing struct field
-// or method named Error to Err and rename the String method to Error.
-//
-// Second, we must identify the values of type os.Error.
-// These include any value that obviously has type os.Error.
-// To that set we add any variable whose name is e or err or error
-// possibly followed by _ or a numeric or capitalized suffix.
-// The heuristic helps for variables that are initialized using calls
-// to functions in other packages. The type checker does not have
-// information about those packages available, and in general cannot
-// (because the packages may themselves not compile).
-//
-// For any value of type os.Error, we replace a call to String with a call to Error.
-// We also replace type assertion err.(*os.Waitmsg) with err.(*exec.ExitError).
-
-// Variables matching this regexp are assumed to have type os.Error.
-var errVar = regexp.MustCompile(`^(e|err|error)_?([A-Z0-9].*)?$`)
-
-// Types matching this regexp are assumed to be implementations of os.Error.
-var errType = regexp.MustCompile(`^\*?([Ee]rror|.*Error)$`)
-
-// Type-checking configuration: tell the type-checker this basic
-// information about types, functions, and variables in external packages.
-var errorTypeConfig = &TypeConfig{
- Type: map[string]*Type{
- "os.Error": {},
- },
- Func: map[string]string{
- "fmt.Errorf": "os.Error",
- "os.NewError": "os.Error",
- },
- Var: map[string]string{
- "os.EPERM": "os.Error",
- "os.ENOENT": "os.Error",
- "os.ESRCH": "os.Error",
- "os.EINTR": "os.Error",
- "os.EIO": "os.Error",
- "os.ENXIO": "os.Error",
- "os.E2BIG": "os.Error",
- "os.ENOEXEC": "os.Error",
- "os.EBADF": "os.Error",
- "os.ECHILD": "os.Error",
- "os.EDEADLK": "os.Error",
- "os.ENOMEM": "os.Error",
- "os.EACCES": "os.Error",
- "os.EFAULT": "os.Error",
- "os.EBUSY": "os.Error",
- "os.EEXIST": "os.Error",
- "os.EXDEV": "os.Error",
- "os.ENODEV": "os.Error",
- "os.ENOTDIR": "os.Error",
- "os.EISDIR": "os.Error",
- "os.EINVAL": "os.Error",
- "os.ENFILE": "os.Error",
- "os.EMFILE": "os.Error",
- "os.ENOTTY": "os.Error",
- "os.EFBIG": "os.Error",
- "os.ENOSPC": "os.Error",
- "os.ESPIPE": "os.Error",
- "os.EROFS": "os.Error",
- "os.EMLINK": "os.Error",
- "os.EPIPE": "os.Error",
- "os.EAGAIN": "os.Error",
- "os.EDOM": "os.Error",
- "os.ERANGE": "os.Error",
- "os.EADDRINUSE": "os.Error",
- "os.ECONNREFUSED": "os.Error",
- "os.ENAMETOOLONG": "os.Error",
- "os.EAFNOSUPPORT": "os.Error",
- "os.ETIMEDOUT": "os.Error",
- "os.ENOTCONN": "os.Error",
- },
-}
-
-func errorFn(f *ast.File) bool {
- if !imports(f, "os") && !force["error"] {
- return false
- }
-
- // Fix gets called once to run the heuristics described above
- // when we notice that this file definitely needs fixing
- // (it mentions os.Error or something similar).
- var fixed bool
- var didHeuristic bool
- heuristic := func() {
- if didHeuristic {
- return
- }
- didHeuristic = true
-
- // We have identified a necessary fix (like os.Error -> error)
- // but have not applied it or any others yet. Prepare the file
- // for fixing and apply heuristic fixes.
-
- // Rename error to error_ to make room for error.
- fixed = renameTop(f, "error", "error_") || fixed
-
- // Use type checker to build list of error implementations.
- typeof, assign := typecheck(errorTypeConfig, f)
-
- isError := map[string]bool{}
- for _, val := range assign["os.Error"] {
- t := typeof[val]
- if strings.HasPrefix(t, "*") {
- t = t[1:]
- }
- if t != "" && !strings.HasPrefix(t, "func(") {
- isError[t] = true
- }
- }
-
- // We use both the type check results and the "Error" name heuristic
- // to identify implementations of os.Error.
- isErrorImpl := func(typ string) bool {
- return isError[typ] || errType.MatchString(typ)
- }
-
- isErrorVar := func(x ast.Expr) bool {
- if typ := typeof[x]; typ != "" {
- return isErrorImpl(typ) || typ == "os.Error"
- }
- if sel, ok := x.(*ast.SelectorExpr); ok {
- return sel.Sel.Name == "Error" || sel.Sel.Name == "Err"
- }
- if id, ok := x.(*ast.Ident); ok {
- return errVar.MatchString(id.Name)
- }
- return false
- }
-
- walk(f, func(n interface{}) {
- // In method declaration on error implementation type,
- // rename String() to Error() and Error() to Err().
- fn, ok := n.(*ast.FuncDecl)
- if ok &&
- fn.Recv != nil &&
- len(fn.Recv.List) == 1 &&
- isErrorImpl(typeName(fn.Recv.List[0].Type)) {
- // Rename.
- switch fn.Name.Name {
- case "String":
- fn.Name.Name = "Error"
- fixed = true
- case "Error":
- fn.Name.Name = "Err"
- fixed = true
- }
- return
- }
-
- // In type definition of an error implementation type,
- // rename Error field to Err to make room for method.
- // Given type XxxError struct { ... Error T } rename field to Err.
- d, ok := n.(*ast.GenDecl)
- if ok {
- for _, s := range d.Specs {
- switch s := s.(type) {
- case *ast.TypeSpec:
- if isErrorImpl(typeName(s.Name)) {
- st, ok := s.Type.(*ast.StructType)
- if ok {
- for _, f := range st.Fields.List {
- for _, n := range f.Names {
- if n.Name == "Error" {
- n.Name = "Err"
- fixed = true
- }
- }
- }
- }
- }
- }
- }
- }
-
- // For values that are an error implementation type,
- // rename .Error to .Err and .String to .Error
- sel, selok := n.(*ast.SelectorExpr)
- if selok && isErrorImpl(typeof[sel.X]) {
- switch sel.Sel.Name {
- case "Error":
- sel.Sel.Name = "Err"
- fixed = true
- case "String":
- sel.Sel.Name = "Error"
- fixed = true
- }
- }
-
- // Assume x.Err is an error value and rename .String to .Error
- // Children have been processed so the rewrite from Error to Err
- // has already happened there.
- if selok {
- if subsel, ok := sel.X.(*ast.SelectorExpr); ok && subsel.Sel.Name == "Err" && sel.Sel.Name == "String" {
- sel.Sel.Name = "Error"
- fixed = true
- }
- }
-
- // For values that are an error variable, rename .String to .Error.
- if selok && isErrorVar(sel.X) && sel.Sel.Name == "String" {
- sel.Sel.Name = "Error"
- fixed = true
- }
-
- // Rewrite composite literal of error type to turn Error: into Err:.
- lit, ok := n.(*ast.CompositeLit)
- if ok && isErrorImpl(typeof[lit]) {
- for _, e := range lit.Elts {
- if kv, ok := e.(*ast.KeyValueExpr); ok && isName(kv.Key, "Error") {
- kv.Key.(*ast.Ident).Name = "Err"
- fixed = true
- }
- }
- }
-
- // Rename os.Waitmsg to exec.ExitError
- // when used in a type assertion on an error.
- ta, ok := n.(*ast.TypeAssertExpr)
- if ok && isErrorVar(ta.X) && isPtrPkgDot(ta.Type, "os", "Waitmsg") {
- addImport(f, "exec")
- sel := ta.Type.(*ast.StarExpr).X.(*ast.SelectorExpr)
- sel.X.(*ast.Ident).Name = "exec"
- sel.Sel.Name = "ExitError"
- fixed = true
- }
-
- })
- }
-
- fix := func() {
- if fixed {
- return
- }
- fixed = true
- heuristic()
- }
-
- if force["error"] {
- heuristic()
- }
-
- walk(f, func(n interface{}) {
- p, ok := n.(*ast.Expr)
- if !ok {
- return
- }
- sel, ok := (*p).(*ast.SelectorExpr)
- if !ok {
- return
- }
- switch {
- case isPkgDot(sel, "os", "Error"):
- fix()
- *p = &ast.Ident{NamePos: sel.Pos(), Name: "error"}
- case isPkgDot(sel, "os", "NewError"):
- fix()
- addImport(f, "errors")
- sel.X.(*ast.Ident).Name = "errors"
- sel.Sel.Name = "New"
- case isPkgDot(sel, "os", "EOF"):
- fix()
- addImport(f, "io")
- sel.X.(*ast.Ident).Name = "io"
- }
- })
-
- if fixed && !usesImport(f, "os") {
- deleteImport(f, "os")
- }
-
- return fixed
-}
-
-func typeName(typ ast.Expr) string {
- if p, ok := typ.(*ast.StarExpr); ok {
- typ = p.X
- }
- id, ok := typ.(*ast.Ident)
- if ok {
- return id.Name
- }
- sel, ok := typ.(*ast.SelectorExpr)
- if ok {
- return typeName(sel.X) + "." + sel.Sel.Name
- }
- return ""
-}