2011-03-15 12:15:41 -06:00
|
|
|
// 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 (
|
|
|
|
"fmt"
|
|
|
|
"go/ast"
|
|
|
|
"go/token"
|
|
|
|
"os"
|
2011-04-08 10:27:08 -06:00
|
|
|
"strconv"
|
2011-03-15 12:15:41 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type fix struct {
|
|
|
|
name string
|
|
|
|
f func(*ast.File) bool
|
|
|
|
desc string
|
|
|
|
}
|
|
|
|
|
|
|
|
// main runs sort.Sort(fixes) after init process is done.
|
|
|
|
type fixlist []fix
|
|
|
|
|
|
|
|
func (f fixlist) Len() int { return len(f) }
|
|
|
|
func (f fixlist) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
|
|
|
func (f fixlist) Less(i, j int) bool { return f[i].name < f[j].name }
|
|
|
|
|
|
|
|
var fixes fixlist
|
|
|
|
|
|
|
|
func register(f fix) {
|
|
|
|
fixes = append(fixes, f)
|
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// walk traverses the AST x, calling visit(y) for each node y in the tree but
|
|
|
|
// also with a pointer to each ast.Expr, ast.Stmt, and *ast.BlockStmt,
|
|
|
|
// in a bottom-up traversal.
|
|
|
|
func walk(x interface{}, visit func(interface{})) {
|
|
|
|
walkBeforeAfter(x, nop, visit)
|
|
|
|
}
|
|
|
|
|
|
|
|
func nop(interface{}) {}
|
2011-03-15 12:15:41 -06:00
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// walkBeforeAfter is like walk but calls before(x) before traversing
|
|
|
|
// x's children and after(x) afterward.
|
|
|
|
func walkBeforeAfter(x interface{}, before, after func(interface{})) {
|
|
|
|
before(x)
|
|
|
|
|
|
|
|
switch n := x.(type) {
|
2011-03-15 12:15:41 -06:00
|
|
|
default:
|
2011-04-08 10:27:08 -06:00
|
|
|
panic(fmt.Errorf("unexpected type %T in walkBeforeAfter", x))
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case nil:
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// pointers to interfaces
|
|
|
|
case *ast.Decl:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *ast.Expr:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *ast.Spec:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *ast.Stmt:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
|
|
|
|
// pointers to struct pointers
|
|
|
|
case **ast.BlockStmt:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case **ast.CallExpr:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case **ast.FieldList:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case **ast.FuncType:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
|
|
|
|
// pointers to slices
|
|
|
|
case *[]ast.Stmt:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *[]ast.Expr:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *[]ast.Decl:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *[]ast.Spec:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
case *[]*ast.File:
|
|
|
|
walkBeforeAfter(*n, before, after)
|
|
|
|
|
2011-03-15 12:15:41 -06:00
|
|
|
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
|
|
|
|
case *ast.Field:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.FieldList:
|
|
|
|
for _, field := range n.List {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(field, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case *ast.BadExpr:
|
|
|
|
case *ast.Ident:
|
|
|
|
case *ast.Ellipsis:
|
|
|
|
case *ast.BasicLit:
|
|
|
|
case *ast.FuncLit:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.CompositeLit:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
|
|
|
walkBeforeAfter(&n.Elts, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.ParenExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.SelectorExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.IndexExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
|
|
|
walkBeforeAfter(&n.Index, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.SliceExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
if n.Low != nil {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Low, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
if n.High != nil {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.High, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case *ast.TypeAssertExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.CallExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Fun, before, after)
|
|
|
|
walkBeforeAfter(&n.Args, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.StarExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.UnaryExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.BinaryExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
|
|
|
walkBeforeAfter(&n.Y, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.KeyValueExpr:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Key, before, after)
|
|
|
|
walkBeforeAfter(&n.Value, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case *ast.ArrayType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Len, before, after)
|
|
|
|
walkBeforeAfter(&n.Elt, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.StructType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Fields, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.FuncType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Params, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
if n.Results != nil {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Results, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case *ast.InterfaceType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Methods, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.MapType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Key, before, after)
|
|
|
|
walkBeforeAfter(&n.Value, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.ChanType:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Value, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case *ast.BadStmt:
|
|
|
|
case *ast.DeclStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Decl, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.EmptyStmt:
|
|
|
|
case *ast.LabeledStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Stmt, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.ExprStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.SendStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Chan, before, after)
|
|
|
|
walkBeforeAfter(&n.Value, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.IncDecStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.X, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.AssignStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Lhs, before, after)
|
|
|
|
walkBeforeAfter(&n.Rhs, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.GoStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Call, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.DeferStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Call, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.ReturnStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Results, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.BranchStmt:
|
|
|
|
case *ast.BlockStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.List, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.IfStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Init, before, after)
|
|
|
|
walkBeforeAfter(&n.Cond, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
|
|
|
walkBeforeAfter(&n.Else, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.CaseClause:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.List, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.SwitchStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Init, before, after)
|
|
|
|
walkBeforeAfter(&n.Tag, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.TypeSwitchStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Init, before, after)
|
|
|
|
walkBeforeAfter(&n.Assign, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.CommClause:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Comm, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.SelectStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.ForStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Init, before, after)
|
|
|
|
walkBeforeAfter(&n.Cond, before, after)
|
|
|
|
walkBeforeAfter(&n.Post, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.RangeStmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Key, before, after)
|
|
|
|
walkBeforeAfter(&n.Value, before, after)
|
|
|
|
walkBeforeAfter(&n.X, before, after)
|
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case *ast.ImportSpec:
|
|
|
|
case *ast.ValueSpec:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
|
|
|
walkBeforeAfter(&n.Values, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.TypeSpec:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case *ast.BadDecl:
|
|
|
|
case *ast.GenDecl:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Specs, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
case *ast.FuncDecl:
|
|
|
|
if n.Recv != nil {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Recv, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Type, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
if n.Body != nil {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Body, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
case *ast.File:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Decls, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
|
|
|
case *ast.Package:
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n.Files, before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
case []*ast.File:
|
|
|
|
for i := range n {
|
|
|
|
walkBeforeAfter(&n[i], before, after)
|
|
|
|
}
|
2011-03-15 12:15:41 -06:00
|
|
|
case []ast.Decl:
|
2011-04-08 10:27:08 -06:00
|
|
|
for i := range n {
|
|
|
|
walkBeforeAfter(&n[i], before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case []ast.Expr:
|
|
|
|
for i := range n {
|
2011-04-08 10:27:08 -06:00
|
|
|
walkBeforeAfter(&n[i], before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case []ast.Stmt:
|
2011-04-08 10:27:08 -06:00
|
|
|
for i := range n {
|
|
|
|
walkBeforeAfter(&n[i], before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
case []ast.Spec:
|
2011-04-08 10:27:08 -06:00
|
|
|
for i := range n {
|
|
|
|
walkBeforeAfter(&n[i], before, after)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
}
|
2011-04-08 10:27:08 -06:00
|
|
|
after(x)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// imports returns true if f imports path.
|
2011-03-15 12:15:41 -06:00
|
|
|
func imports(f *ast.File, path string) bool {
|
2011-04-08 10:27:08 -06:00
|
|
|
for _, s := range f.Imports {
|
|
|
|
t, err := strconv.Unquote(s.Path.Value)
|
|
|
|
if err == nil && t == path {
|
|
|
|
return true
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isPkgDot returns true if t is the expression "pkg.name"
|
|
|
|
// where pkg is an imported identifier.
|
2011-03-15 12:15:41 -06:00
|
|
|
func isPkgDot(t ast.Expr, pkg, name string) bool {
|
|
|
|
sel, ok := t.(*ast.SelectorExpr)
|
2011-04-08 10:27:08 -06:00
|
|
|
return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isPtrPkgDot returns true if f is the expression "*pkg.name"
|
|
|
|
// where pkg is an imported identifier.
|
2011-03-15 12:15:41 -06:00
|
|
|
func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
|
|
|
|
ptr, ok := t.(*ast.StarExpr)
|
2011-04-08 10:27:08 -06:00
|
|
|
return ok && isPkgDot(ptr.X, pkg, name)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isTopName returns true if n is a top-level unresolved identifier with the given name.
|
2011-03-28 21:29:00 -06:00
|
|
|
func isTopName(n ast.Expr, name string) bool {
|
|
|
|
id, ok := n.(*ast.Ident)
|
2011-04-08 10:27:08 -06:00
|
|
|
return ok && id.Name == name && id.Obj == nil
|
2011-03-28 21:29:00 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isName returns true if n is an identifier with the given name.
|
2011-03-15 12:15:41 -06:00
|
|
|
func isName(n ast.Expr, name string) bool {
|
|
|
|
id, ok := n.(*ast.Ident)
|
2011-04-08 10:27:08 -06:00
|
|
|
return ok && id.String() == name
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isCall returns true if t is a call to pkg.name.
|
2011-03-15 20:33:57 -06:00
|
|
|
func isCall(t ast.Expr, pkg, name string) bool {
|
|
|
|
call, ok := t.(*ast.CallExpr)
|
|
|
|
return ok && isPkgDot(call.Fun, pkg, name)
|
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil.
|
|
|
|
func isIdent(n interface{}) *ast.Ident {
|
|
|
|
id, _ := n.(*ast.Ident)
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
|
|
|
// refersTo returns true if n is a reference to the same object as x.
|
2011-03-15 12:15:41 -06:00
|
|
|
func refersTo(n ast.Node, x *ast.Ident) bool {
|
|
|
|
id, ok := n.(*ast.Ident)
|
2011-04-08 10:27:08 -06:00
|
|
|
// The test of id.Name == x.Name handles top-level unresolved
|
|
|
|
// identifiers, which all have Obj == nil.
|
|
|
|
return ok && id.Obj == x.Obj && id.Name == x.Name
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isBlank returns true if n is the blank identifier.
|
2011-03-15 12:15:41 -06:00
|
|
|
func isBlank(n ast.Expr) bool {
|
|
|
|
return isName(n, "_")
|
|
|
|
}
|
|
|
|
|
2011-04-08 10:27:08 -06:00
|
|
|
// isEmptyString returns true if n is an empty string literal.
|
2011-03-15 12:15:41 -06:00
|
|
|
func isEmptyString(n ast.Expr) bool {
|
|
|
|
lit, ok := n.(*ast.BasicLit)
|
2011-04-08 10:27:08 -06:00
|
|
|
return ok && lit.Kind == token.STRING && len(lit.Value) == 2
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func warn(pos token.Pos, msg string, args ...interface{}) {
|
|
|
|
if pos.IsValid() {
|
2011-03-28 21:29:00 -06:00
|
|
|
msg = "%s: " + msg
|
|
|
|
arg1 := []interface{}{fset.Position(pos).String()}
|
|
|
|
args = append(arg1, args...)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
2011-03-28 21:29:00 -06:00
|
|
|
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
2011-03-15 12:15:41 -06:00
|
|
|
}
|
2011-04-08 10:27:08 -06:00
|
|
|
|
|
|
|
// countUses returns the number of uses of the identifier x in scope.
|
|
|
|
func countUses(x *ast.Ident, scope []ast.Stmt) int {
|
|
|
|
count := 0
|
|
|
|
ff := func(n interface{}) {
|
|
|
|
if n, ok := n.(ast.Node); ok && refersTo(n, x) {
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, n := range scope {
|
|
|
|
walk(n, ff)
|
|
|
|
}
|
|
|
|
return count
|
|
|
|
}
|
|
|
|
|
|
|
|
// rewriteUses replaces all uses of the identifier x and !x in scope
|
|
|
|
// with f(x.Pos()) and fnot(x.Pos()).
|
|
|
|
func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) {
|
|
|
|
var lastF ast.Expr
|
|
|
|
ff := func(n interface{}) {
|
|
|
|
ptr, ok := n.(*ast.Expr)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
nn := *ptr
|
|
|
|
|
|
|
|
// The child node was just walked and possibly replaced.
|
|
|
|
// If it was replaced and this is a negation, replace with fnot(p).
|
|
|
|
not, ok := nn.(*ast.UnaryExpr)
|
|
|
|
if ok && not.Op == token.NOT && not.X == lastF {
|
|
|
|
*ptr = fnot(nn.Pos())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if refersTo(nn, x) {
|
|
|
|
lastF = f(nn.Pos())
|
|
|
|
*ptr = lastF
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, n := range scope {
|
|
|
|
walk(n, ff)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// assignsTo returns true if any of the code in scope assigns to or takes the address of x.
|
|
|
|
func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
|
|
|
|
assigned := false
|
|
|
|
ff := func(n interface{}) {
|
|
|
|
if assigned {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch n := n.(type) {
|
|
|
|
case *ast.UnaryExpr:
|
|
|
|
// use of &x
|
|
|
|
if n.Op == token.AND && refersTo(n.X, x) {
|
|
|
|
assigned = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case *ast.AssignStmt:
|
|
|
|
for _, l := range n.Lhs {
|
|
|
|
if refersTo(l, x) {
|
|
|
|
assigned = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, n := range scope {
|
|
|
|
if assigned {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
walk(n, ff)
|
|
|
|
}
|
|
|
|
return assigned
|
|
|
|
}
|
|
|
|
|
|
|
|
// newPkgDot returns an ast.Expr referring to "pkg.name" at position pos.
|
|
|
|
func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
|
|
|
|
return &ast.SelectorExpr{
|
|
|
|
X: &ast.Ident{
|
|
|
|
NamePos: pos,
|
|
|
|
Name: pkg,
|
|
|
|
},
|
|
|
|
Sel: &ast.Ident{
|
|
|
|
NamePos: pos,
|
|
|
|
Name: name,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|