| // 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 osopenFix = fix{ |
| "osopen", |
| osopen, |
| `Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE. |
| |
| http://codereview.appspot.com/4357052 |
| `, |
| } |
| |
| func init() { |
| register(osopenFix) |
| } |
| |
| 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" |
| 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 |
| } |