mirror of
https://github.com/golang/go
synced 2024-11-22 05:14:40 -07:00
gofix: fixes for os/signal changes
Fixes #1971. R=adg, rsc CC=golang-dev https://golang.org/cl/4630056
This commit is contained in:
parent
d6f80e1a4c
commit
83550f0728
@ -18,6 +18,7 @@ GOFILES=\
|
|||||||
osopen.go\
|
osopen.go\
|
||||||
procattr.go\
|
procattr.go\
|
||||||
reflect.go\
|
reflect.go\
|
||||||
|
signal.go\
|
||||||
sortslice.go\
|
sortslice.go\
|
||||||
stringssplit.go\
|
stringssplit.go\
|
||||||
typecheck.go\
|
typecheck.go\
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"go/token"
|
"go/token"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fix struct {
|
type fix struct {
|
||||||
@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
|
|||||||
|
|
||||||
// imports returns true if f imports path.
|
// imports returns true if f imports path.
|
||||||
func imports(f *ast.File, path string) bool {
|
func imports(f *ast.File, path string) bool {
|
||||||
|
return importSpec(f, path) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// importSpec returns the import spec if f imports path,
|
||||||
|
// or nil otherwise.
|
||||||
|
func importSpec(f *ast.File, path string) *ast.ImportSpec {
|
||||||
for _, s := range f.Imports {
|
for _, s := range f.Imports {
|
||||||
|
if importPath(s) == path {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// importPath returns the unquoted import path of s,
|
||||||
|
// or "" if the path is not properly quoted.
|
||||||
|
func importPath(s *ast.ImportSpec) string {
|
||||||
t, err := strconv.Unquote(s.Path.Value)
|
t, err := strconv.Unquote(s.Path.Value)
|
||||||
if err == nil && t == path {
|
if err == nil {
|
||||||
return true
|
return t
|
||||||
}
|
}
|
||||||
}
|
return ""
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPkgDot returns true if t is the expression "pkg.name"
|
// isPkgDot returns true if t is the expression "pkg.name"
|
||||||
@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addImport adds the import path to the file f, if absent.
|
||||||
|
func addImport(f *ast.File, path string) {
|
||||||
|
if imports(f, path) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newImport := &ast.ImportSpec{
|
||||||
|
Path: &ast.BasicLit{
|
||||||
|
Kind: token.STRING,
|
||||||
|
Value: strconv.Quote(path),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var impdecl *ast.GenDecl
|
||||||
|
|
||||||
|
// Find an import decl to add to.
|
||||||
|
for _, decl := range f.Decls {
|
||||||
|
gen, ok := decl.(*ast.GenDecl)
|
||||||
|
|
||||||
|
if ok && gen.Tok == token.IMPORT {
|
||||||
|
impdecl = gen
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No import decl found. Add one.
|
||||||
|
if impdecl == nil {
|
||||||
|
impdecl = &ast.GenDecl{
|
||||||
|
Tok: token.IMPORT,
|
||||||
|
}
|
||||||
|
f.Decls = append(f.Decls, nil)
|
||||||
|
copy(f.Decls[1:], f.Decls)
|
||||||
|
f.Decls[0] = impdecl
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the import decl has parentheses, if needed.
|
||||||
|
if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
|
||||||
|
impdecl.Lparen = impdecl.Pos()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the import paths are alphabetically ordered.
|
||||||
|
// If they are not, the result is ugly, but legal.
|
||||||
|
insertAt := len(impdecl.Specs) // default to end of specs
|
||||||
|
for i, spec := range impdecl.Specs {
|
||||||
|
impspec := spec.(*ast.ImportSpec)
|
||||||
|
if importPath(impspec) > path {
|
||||||
|
insertAt = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impdecl.Specs = append(impdecl.Specs, nil)
|
||||||
|
copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
|
||||||
|
impdecl.Specs[insertAt] = newImport
|
||||||
|
|
||||||
|
f.Imports = append(f.Imports, newImport)
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteImport deletes the import path from the file f, if present.
|
||||||
|
func deleteImport(f *ast.File, path string) {
|
||||||
|
oldImport := importSpec(f, path)
|
||||||
|
|
||||||
|
// Find the import node that imports path, if any.
|
||||||
|
for i, decl := range f.Decls {
|
||||||
|
gen, ok := decl.(*ast.GenDecl)
|
||||||
|
if !ok || gen.Tok != token.IMPORT {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j, spec := range gen.Specs {
|
||||||
|
impspec := spec.(*ast.ImportSpec)
|
||||||
|
|
||||||
|
if oldImport != impspec {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found an import spec that imports path.
|
||||||
|
// Delete it.
|
||||||
|
copy(gen.Specs[j:], gen.Specs[j+1:])
|
||||||
|
gen.Specs = gen.Specs[:len(gen.Specs)-1]
|
||||||
|
|
||||||
|
// If this was the last import spec in this decl,
|
||||||
|
// delete the decl, too.
|
||||||
|
if len(gen.Specs) == 0 {
|
||||||
|
copy(f.Decls[i:], f.Decls[i+1:])
|
||||||
|
f.Decls = f.Decls[:len(f.Decls)-1]
|
||||||
|
} else if len(gen.Specs) == 1 {
|
||||||
|
gen.Lparen = token.NoPos // drop parens
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete it from f.Imports.
|
||||||
|
for i, imp := range f.Imports {
|
||||||
|
if imp == oldImport {
|
||||||
|
copy(f.Imports[i:], f.Imports[i+1:])
|
||||||
|
f.Imports = f.Imports[:len(f.Imports)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func usesImport(f *ast.File, path string) (used bool) {
|
||||||
|
spec := importSpec(f, path)
|
||||||
|
if spec == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := spec.Name.String()
|
||||||
|
switch name {
|
||||||
|
case "<nil>":
|
||||||
|
// If the package name is not explicitly specified,
|
||||||
|
// make an educated guess. This is not guaranteed to be correct.
|
||||||
|
lastSlash := strings.LastIndex(path, "/")
|
||||||
|
if lastSlash == -1 {
|
||||||
|
name = path
|
||||||
|
} else {
|
||||||
|
name = path[lastSlash+1:]
|
||||||
|
}
|
||||||
|
case "_", ".":
|
||||||
|
// Not sure if this import is used - err on the side of caution.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
walk(f, func(n interface{}) {
|
||||||
|
sel, ok := n.(*ast.SelectorExpr)
|
||||||
|
if ok && isTopName(sel.X, name) {
|
||||||
|
used = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
49
src/cmd/gofix/signal.go
Normal file
49
src/cmd/gofix/signal.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// 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"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register(fix{
|
||||||
|
"signal",
|
||||||
|
signal,
|
||||||
|
`Adapt code to types moved from os/signal to signal.
|
||||||
|
|
||||||
|
http://codereview.appspot.com/4437091
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func signal(f *ast.File) (fixed bool) {
|
||||||
|
if !imports(f, "os/signal") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
walk(f, func(n interface{}) {
|
||||||
|
s, ok := n.(*ast.SelectorExpr)
|
||||||
|
|
||||||
|
if !ok || !isTopName(s.X, "signal") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sel := s.Sel.String()
|
||||||
|
if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
|
||||||
|
s.X = &ast.Ident{Name: "os"}
|
||||||
|
fixed = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if fixed {
|
||||||
|
addImport(f, "os")
|
||||||
|
if !usesImport(f, "os/signal") {
|
||||||
|
deleteImport(f, "os/signal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
96
src/cmd/gofix/signal_test.go
Normal file
96
src/cmd/gofix/signal_test.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// 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(signalTests)
|
||||||
|
}
|
||||||
|
|
||||||
|
var signalTests = []testCase{
|
||||||
|
{
|
||||||
|
Name: "signal.0",
|
||||||
|
In: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "a"
|
||||||
|
"os/signal"
|
||||||
|
_ "z"
|
||||||
|
)
|
||||||
|
|
||||||
|
type T1 signal.UnixSignal
|
||||||
|
type T2 signal.Signal
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
_ = signal.SIGHUP
|
||||||
|
_ = signal.Incoming
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
Out: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "a"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
_ "z"
|
||||||
|
)
|
||||||
|
|
||||||
|
type T1 os.UnixSignal
|
||||||
|
type T2 os.Signal
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
_ = os.SIGHUP
|
||||||
|
_ = signal.Incoming
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "signal.1",
|
||||||
|
In: `package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
var _ os.Error
|
||||||
|
_ = signal.SIGHUP
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
Out: `package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
var _ os.Error
|
||||||
|
_ = os.SIGHUP
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "signal.2",
|
||||||
|
In: `package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
import "os/signal"
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
var _ os.Error
|
||||||
|
_ = signal.SIGHUP
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
Out: `package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
|
||||||
|
func f() {
|
||||||
|
var _ os.Error
|
||||||
|
_ = os.SIGHUP
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user