Commit d7106f28 authored by Russ Cox's avatar Russ Cox

gofix: procattr

R=adg
CC=golang-dev
https://golang.org/cl/4274059
parent bcd6c733
...@@ -9,6 +9,7 @@ GOFILES=\ ...@@ -9,6 +9,7 @@ GOFILES=\
fix.go\ fix.go\
main.go\ main.go\
httpserver.go\ httpserver.go\
procattr.go\
include ../../Make.cmd include ../../Make.cmd
......
...@@ -264,6 +264,11 @@ func isName(n ast.Expr, name string) bool { ...@@ -264,6 +264,11 @@ func isName(n ast.Expr, name string) bool {
return id.String() == name 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 { func refersTo(n ast.Node, x *ast.Ident) bool {
id, ok := n.(*ast.Ident) id, ok := n.(*ast.Ident)
if !ok { if !ok {
......
// 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 package main
func init() { func init() {
......
...@@ -82,7 +82,7 @@ func main() { ...@@ -82,7 +82,7 @@ func main() {
const ( const (
tabWidth = 8 tabWidth = 8
parserMode = parser.ParseComments parserMode = parser.ParseComments
printerMode = printer.TabIndent printerMode = printer.TabIndent | printer.UseSpaces
) )
......
...@@ -6,9 +6,12 @@ package main ...@@ -6,9 +6,12 @@ package main
import ( import (
"bytes" "bytes"
"exec"
"go/ast" "go/ast"
"go/parser" "go/parser"
"go/printer" "go/printer"
"io/ioutil"
"os"
"testing" "testing"
) )
...@@ -42,6 +45,7 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out ...@@ -42,6 +45,7 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out
if s := buf.String(); in != s { if s := buf.String(); in != s {
t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s", t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
desc, desc, in, desc, s) desc, desc, in, desc, s)
tdiff(t, in, s)
return return
} }
...@@ -75,6 +79,7 @@ func TestRewrite(t *testing.T) { ...@@ -75,6 +79,7 @@ func TestRewrite(t *testing.T) {
if out != tt.Out { if out != tt.Out {
t.Errorf("%s: incorrect output.\n--- have\n%s\n--- want\n%s", tt.Name, 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 continue
} }
...@@ -97,6 +102,50 @@ func TestRewrite(t *testing.T) { ...@@ -97,6 +102,50 @@ func TestRewrite(t *testing.T) {
if out2 != out { 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", 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) 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))
}
// 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
}
// 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{})
}
`,
},
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment