summaryrefslogtreecommitdiff
path: root/src/cmd/gofix/oserrorstring.go
blob: db39ee9dc6a288c4cd42022a1f3fde60dfada9e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 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
}