| // 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 | |
| } |