summaryrefslogtreecommitdiff
path: root/src/cmd/fix/osopen.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fix/osopen.go')
-rw-r--r--src/cmd/fix/osopen.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/cmd/fix/osopen.go b/src/cmd/fix/osopen.go
new file mode 100644
index 000000000..af2796ac2
--- /dev/null
+++ b/src/cmd/fix/osopen.go
@@ -0,0 +1,124 @@
+// 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(osopenFix)
+}
+
+var osopenFix = fix{
+ "osopen",
+ "2011-04-04",
+ osopen,
+ `Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
+
+http://codereview.appspot.com/4357052
+`,
+}
+
+func osopen(f *ast.File) bool {
+ if !imports(f, "os") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // Rename O_CREAT to O_CREATE.
+ if expr, ok := n.(ast.Expr); ok && isPkgDot(expr, "os", "O_CREAT") {
+ expr.(*ast.SelectorExpr).Sel.Name = "O_CREATE"
+ fixed = true
+ return
+ }
+
+ // Fix up calls to Open.
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) != 3 {
+ return
+ }
+ if !isPkgDot(call.Fun, "os", "Open") {
+ return
+ }
+ sel := call.Fun.(*ast.SelectorExpr)
+ args := call.Args
+ // os.Open(a, os.O_RDONLY, c) -> os.Open(a)
+ if isPkgDot(args[1], "os", "O_RDONLY") || isPkgDot(args[1], "syscall", "O_RDONLY") {
+ call.Args = call.Args[0:1]
+ fixed = true
+ return
+ }
+ // os.Open(a, createlike_flags, c) -> os.Create(a, c)
+ if isCreateFlag(args[1]) {
+ sel.Sel.Name = "Create"
+ if !isSimplePerm(args[2]) {
+ warn(sel.Pos(), "rewrote os.Open to os.Create with permission not 0666")
+ }
+ call.Args = args[0:1]
+ fixed = true
+ return
+ }
+ // Fallback: os.Open(a, b, c) -> os.OpenFile(a, b, c)
+ sel.Sel.Name = "OpenFile"
+ fixed = true
+ })
+ return fixed
+}
+
+func isCreateFlag(flag ast.Expr) bool {
+ foundCreate := false
+ foundTrunc := false
+ // OR'ing of flags: is O_CREATE on? + or | would be fine; we just look for os.O_CREATE
+ // and don't worry about the actual operator.
+ p := flag.Pos()
+ for {
+ lhs := flag
+ expr, isBinary := flag.(*ast.BinaryExpr)
+ if isBinary {
+ lhs = expr.Y
+ }
+ sel, ok := lhs.(*ast.SelectorExpr)
+ if !ok || !isTopName(sel.X, "os") {
+ return false
+ }
+ switch sel.Sel.Name {
+ case "O_CREATE":
+ foundCreate = true
+ case "O_TRUNC":
+ foundTrunc = true
+ case "O_RDONLY", "O_WRONLY", "O_RDWR":
+ // okay
+ default:
+ // Unexpected flag, like O_APPEND or O_EXCL.
+ // Be conservative and do not rewrite.
+ return false
+ }
+ if !isBinary {
+ break
+ }
+ flag = expr.X
+ }
+ if !foundCreate {
+ return false
+ }
+ if !foundTrunc {
+ warn(p, "rewrote os.Open with O_CREATE but not O_TRUNC to os.Create")
+ }
+ return foundCreate
+}
+
+func isSimplePerm(perm ast.Expr) bool {
+ basicLit, ok := perm.(*ast.BasicLit)
+ if !ok {
+ return false
+ }
+ switch basicLit.Value {
+ case "0666":
+ return true
+ }
+ return false
+}