]> Cypherpunks repositories - gostls13.git/commitdiff
gofix: procattr
authorRuss Cox <rsc@golang.org>
Wed, 16 Mar 2011 02:33:57 +0000 (22:33 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 16 Mar 2011 02:33:57 +0000 (22:33 -0400)
R=adg
CC=golang-dev
https://golang.org/cl/4274059

src/cmd/gofix/Makefile
src/cmd/gofix/fix.go
src/cmd/gofix/httpserver_test.go
src/cmd/gofix/main.go
src/cmd/gofix/main_test.go
src/cmd/gofix/procattr.go [new file with mode: 0644]
src/cmd/gofix/procattr_test.go [new file with mode: 0644]

index 020a6a2920f012ad78c62154e939bf36cc0a22f1..9383f5ac641d01fac68d0fc96261e9d60abda2cd 100644 (file)
@@ -9,6 +9,7 @@ GOFILES=\
        fix.go\
        main.go\
        httpserver.go\
+       procattr.go\
 
 include ../../Make.cmd
 
index eadddbadc8215ad2fbefa74f8f529357f8cf2cfa..69af99179ac5a8e3aa954d975815613456bdfed3 100644 (file)
@@ -264,6 +264,11 @@ func isName(n ast.Expr, name string) bool {
        return id.String() == name
 }
 
+func isCall(t ast.Expr, pkg, name string) bool {
+       call, ok := t.(*ast.CallExpr)
+       return ok && isPkgDot(call.Fun, pkg, name)
+}
+
 func refersTo(n ast.Node, x *ast.Ident) bool {
        id, ok := n.(*ast.Ident)
        if !ok {
index 7e79056c50ddf9a0bcb455054a276fa1fb93ec93..eca2a769344025e25bd58bc0863c7569270b2d39 100644 (file)
@@ -1,3 +1,7 @@
+// 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
 
 func init() {
index 40c86e8f21d15adda994c2a7c425bc98f96a6b8a..9ca2ddb461cb68ef34c685adc962c5603f2737f1 100644 (file)
@@ -82,7 +82,7 @@ func main() {
 const (
        tabWidth    = 8
        parserMode  = parser.ParseComments
-       printerMode = printer.TabIndent
+       printerMode = printer.TabIndent | printer.UseSpaces
 )
 
 
index 597bff22ac6b0bf161409f6d043dcf2ffc0fbceb..e4d0f60cce6c10c293057330adc2abd82c29a79b 100644 (file)
@@ -6,9 +6,12 @@ package main
 
 import (
        "bytes"
+       "exec"
        "go/ast"
        "go/parser"
        "go/printer"
+       "io/ioutil"
+       "os"
        "testing"
 )
 
@@ -42,6 +45,7 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out
        if s := buf.String(); in != s {
                t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
                        desc, desc, in, desc, s)
+               tdiff(t, in, s)
                return
        }
 
@@ -75,6 +79,7 @@ func TestRewrite(t *testing.T) {
 
                if out != tt.Out {
                        t.Errorf("%s: incorrect output.\n--- have\n%s\n--- want\n%s", tt.Name, out, tt.Out)
+                       tdiff(t, out, tt.Out)
                        continue
                }
 
@@ -97,6 +102,50 @@ func TestRewrite(t *testing.T) {
                if out2 != out {
                        t.Errorf("%s: changed output after second round of fixes.\n--- output after first round\n%s\n--- output after second round\n%s",
                                tt.Name, out, out2)
+                       tdiff(t, out, out2)
                }
        }
 }
+
+func tdiff(t *testing.T, a, b string) {
+       f1, err := ioutil.TempFile("", "gofix")
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       defer os.Remove(f1.Name())
+       defer f1.Close()
+
+       f2, err := ioutil.TempFile("", "gofix")
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       defer os.Remove(f2.Name())
+       defer f2.Close()
+
+       f1.Write([]byte(a))
+       f2.Write([]byte(b))
+
+       diffcmd, err := exec.LookPath("diff")
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       c, err := exec.Run(diffcmd, []string{"diff", f1.Name(), f2.Name()}, nil, "",
+               exec.DevNull, exec.Pipe, exec.MergeWithStdout)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       defer c.Close()
+
+       data, err := ioutil.ReadAll(c.Stdout)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       t.Error(string(data))
+}
diff --git a/src/cmd/gofix/procattr.go b/src/cmd/gofix/procattr.go
new file mode 100644 (file)
index 0000000..3409776
--- /dev/null
@@ -0,0 +1,61 @@
+// 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"
+       "go/token"
+)
+
+var procattrFix = fix{
+       "procattr",
+       procattr,
+`Adapt calls to os.StartProcess to use new ProcAttr type.
+
+http://codereview.appspot.com/4253052
+`,
+}
+
+func init() {
+       register(httpserverFix)
+}
+
+func procattr(f *ast.File) bool {
+       if !imports(f, "os") && !imports(f, "syscall") {
+               return false
+       }
+
+       fixed := false
+       rewrite(f, func(n interface{}) {
+               call, ok := n.(*ast.CallExpr)
+               if !ok || len(call.Args) != 5 {
+                       return
+               }
+               var pkg string
+               if isPkgDot(call.Fun, "os", "StartProcess") {
+                       pkg = "os"
+               } else if isPkgDot(call.Fun, "syscall", "StartProcess") {
+                       pkg = "syscall"
+               } else {
+                       return
+               }
+               // os.StartProcess(a, b, c, d, e) -> os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
+               lit := &ast.CompositeLit{Type: ast.NewIdent(pkg + ".ProcAttr")}
+               env, dir, files := call.Args[2], call.Args[3], call.Args[4]
+               if !isName(env, "nil") && !isCall(env, "os", "Environ") {
+                       lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Env"), Value: env})
+               }
+               if !isEmptyString(dir) {
+                       lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Dir"), Value: dir})
+               }
+               if !isName(files, "nil") {
+                       lit.Elts = append(lit.Elts, &ast.KeyValueExpr{Key: ast.NewIdent("Files"), Value: files})
+               }
+               call.Args[2] = &ast.UnaryExpr{Op: token.AND, X: lit}
+               call.Args = call.Args[:3]
+               fixed = true
+       })
+       return fixed
+}
diff --git a/src/cmd/gofix/procattr_test.go b/src/cmd/gofix/procattr_test.go
new file mode 100644 (file)
index 0000000..1a8eb86
--- /dev/null
@@ -0,0 +1,75 @@
+// 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
+
+func init() {
+       addTestCases(procattrTests)
+}
+
+var procattrTests = []testCase{
+       {
+               Name: "procattr.0",
+               Fn:   procattr,
+               In: `package main
+
+import (
+       "os"
+       "syscall"
+)
+
+func f() {
+       os.StartProcess(a, b, c, d, e)
+       os.StartProcess(a, b, os.Environ(), d, e)
+       os.StartProcess(a, b, nil, d, e)
+       os.StartProcess(a, b, c, "", e)
+       os.StartProcess(a, b, c, d, nil)
+       os.StartProcess(a, b, nil, "", nil)
+
+       os.StartProcess(
+               a,
+               b,
+               c,
+               d,
+               e,
+       )
+
+       syscall.StartProcess(a, b, c, d, e)
+       syscall.StartProcess(a, b, os.Environ(), d, e)
+       syscall.StartProcess(a, b, nil, d, e)
+       syscall.StartProcess(a, b, c, "", e)
+       syscall.StartProcess(a, b, c, d, nil)
+       syscall.StartProcess(a, b, nil, "", nil)
+}
+`,
+               Out: `package main
+
+import (
+       "os"
+       "syscall"
+)
+
+func f() {
+       os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d, Files: e})
+       os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
+       os.StartProcess(a, b, &os.ProcAttr{Dir: d, Files: e})
+       os.StartProcess(a, b, &os.ProcAttr{Env: c, Files: e})
+       os.StartProcess(a, b, &os.ProcAttr{Env: c, Dir: d})
+       os.StartProcess(a, b, &os.ProcAttr{})
+
+       os.StartProcess(
+               a,
+               b, &os.ProcAttr{Env: c, Dir: d, Files: e},
+       )
+
+       syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d, Files: e})
+       syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
+       syscall.StartProcess(a, b, &syscall.ProcAttr{Dir: d, Files: e})
+       syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Files: e})
+       syscall.StartProcess(a, b, &syscall.ProcAttr{Env: c, Dir: d})
+       syscall.StartProcess(a, b, &syscall.ProcAttr{})
+}
+`,
+       },
+}