Home | History | Annotate | Download | only in fix
      1 // Copyright 2011 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package main
      6 
      7 import (
      8 	"fmt"
      9 	"go/ast"
     10 	"go/parser"
     11 	"go/token"
     12 	"os"
     13 	"path"
     14 	"reflect"
     15 	"strconv"
     16 	"strings"
     17 )
     18 
     19 type fix struct {
     20 	name string
     21 	date string // date that fix was introduced, in YYYY-MM-DD format
     22 	f    func(*ast.File) bool
     23 	desc string
     24 }
     25 
     26 // main runs sort.Sort(byName(fixes)) before printing list of fixes.
     27 type byName []fix
     28 
     29 func (f byName) Len() int           { return len(f) }
     30 func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
     31 func (f byName) Less(i, j int) bool { return f[i].name < f[j].name }
     32 
     33 // main runs sort.Sort(byDate(fixes)) before applying fixes.
     34 type byDate []fix
     35 
     36 func (f byDate) Len() int           { return len(f) }
     37 func (f byDate) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
     38 func (f byDate) Less(i, j int) bool { return f[i].date < f[j].date }
     39 
     40 var fixes []fix
     41 
     42 func register(f fix) {
     43 	fixes = append(fixes, f)
     44 }
     45 
     46 // walk traverses the AST x, calling visit(y) for each node y in the tree but
     47 // also with a pointer to each ast.Expr, ast.Stmt, and *ast.BlockStmt,
     48 // in a bottom-up traversal.
     49 func walk(x interface{}, visit func(interface{})) {
     50 	walkBeforeAfter(x, nop, visit)
     51 }
     52 
     53 func nop(interface{}) {}
     54 
     55 // walkBeforeAfter is like walk but calls before(x) before traversing
     56 // x's children and after(x) afterward.
     57 func walkBeforeAfter(x interface{}, before, after func(interface{})) {
     58 	before(x)
     59 
     60 	switch n := x.(type) {
     61 	default:
     62 		panic(fmt.Errorf("unexpected type %T in walkBeforeAfter", x))
     63 
     64 	case nil:
     65 
     66 	// pointers to interfaces
     67 	case *ast.Decl:
     68 		walkBeforeAfter(*n, before, after)
     69 	case *ast.Expr:
     70 		walkBeforeAfter(*n, before, after)
     71 	case *ast.Spec:
     72 		walkBeforeAfter(*n, before, after)
     73 	case *ast.Stmt:
     74 		walkBeforeAfter(*n, before, after)
     75 
     76 	// pointers to struct pointers
     77 	case **ast.BlockStmt:
     78 		walkBeforeAfter(*n, before, after)
     79 	case **ast.CallExpr:
     80 		walkBeforeAfter(*n, before, after)
     81 	case **ast.FieldList:
     82 		walkBeforeAfter(*n, before, after)
     83 	case **ast.FuncType:
     84 		walkBeforeAfter(*n, before, after)
     85 	case **ast.Ident:
     86 		walkBeforeAfter(*n, before, after)
     87 	case **ast.BasicLit:
     88 		walkBeforeAfter(*n, before, after)
     89 
     90 	// pointers to slices
     91 	case *[]ast.Decl:
     92 		walkBeforeAfter(*n, before, after)
     93 	case *[]ast.Expr:
     94 		walkBeforeAfter(*n, before, after)
     95 	case *[]*ast.File:
     96 		walkBeforeAfter(*n, before, after)
     97 	case *[]*ast.Ident:
     98 		walkBeforeAfter(*n, before, after)
     99 	case *[]ast.Spec:
    100 		walkBeforeAfter(*n, before, after)
    101 	case *[]ast.Stmt:
    102 		walkBeforeAfter(*n, before, after)
    103 
    104 	// These are ordered and grouped to match ../../go/ast/ast.go
    105 	case *ast.Field:
    106 		walkBeforeAfter(&n.Names, before, after)
    107 		walkBeforeAfter(&n.Type, before, after)
    108 		walkBeforeAfter(&n.Tag, before, after)
    109 	case *ast.FieldList:
    110 		for _, field := range n.List {
    111 			walkBeforeAfter(field, before, after)
    112 		}
    113 	case *ast.BadExpr:
    114 	case *ast.Ident:
    115 	case *ast.Ellipsis:
    116 		walkBeforeAfter(&n.Elt, before, after)
    117 	case *ast.BasicLit:
    118 	case *ast.FuncLit:
    119 		walkBeforeAfter(&n.Type, before, after)
    120 		walkBeforeAfter(&n.Body, before, after)
    121 	case *ast.CompositeLit:
    122 		walkBeforeAfter(&n.Type, before, after)
    123 		walkBeforeAfter(&n.Elts, before, after)
    124 	case *ast.ParenExpr:
    125 		walkBeforeAfter(&n.X, before, after)
    126 	case *ast.SelectorExpr:
    127 		walkBeforeAfter(&n.X, before, after)
    128 	case *ast.IndexExpr:
    129 		walkBeforeAfter(&n.X, before, after)
    130 		walkBeforeAfter(&n.Index, before, after)
    131 	case *ast.SliceExpr:
    132 		walkBeforeAfter(&n.X, before, after)
    133 		if n.Low != nil {
    134 			walkBeforeAfter(&n.Low, before, after)
    135 		}
    136 		if n.High != nil {
    137 			walkBeforeAfter(&n.High, before, after)
    138 		}
    139 	case *ast.TypeAssertExpr:
    140 		walkBeforeAfter(&n.X, before, after)
    141 		walkBeforeAfter(&n.Type, before, after)
    142 	case *ast.CallExpr:
    143 		walkBeforeAfter(&n.Fun, before, after)
    144 		walkBeforeAfter(&n.Args, before, after)
    145 	case *ast.StarExpr:
    146 		walkBeforeAfter(&n.X, before, after)
    147 	case *ast.UnaryExpr:
    148 		walkBeforeAfter(&n.X, before, after)
    149 	case *ast.BinaryExpr:
    150 		walkBeforeAfter(&n.X, before, after)
    151 		walkBeforeAfter(&n.Y, before, after)
    152 	case *ast.KeyValueExpr:
    153 		walkBeforeAfter(&n.Key, before, after)
    154 		walkBeforeAfter(&n.Value, before, after)
    155 
    156 	case *ast.ArrayType:
    157 		walkBeforeAfter(&n.Len, before, after)
    158 		walkBeforeAfter(&n.Elt, before, after)
    159 	case *ast.StructType:
    160 		walkBeforeAfter(&n.Fields, before, after)
    161 	case *ast.FuncType:
    162 		walkBeforeAfter(&n.Params, before, after)
    163 		if n.Results != nil {
    164 			walkBeforeAfter(&n.Results, before, after)
    165 		}
    166 	case *ast.InterfaceType:
    167 		walkBeforeAfter(&n.Methods, before, after)
    168 	case *ast.MapType:
    169 		walkBeforeAfter(&n.Key, before, after)
    170 		walkBeforeAfter(&n.Value, before, after)
    171 	case *ast.ChanType:
    172 		walkBeforeAfter(&n.Value, before, after)
    173 
    174 	case *ast.BadStmt:
    175 	case *ast.DeclStmt:
    176 		walkBeforeAfter(&n.Decl, before, after)
    177 	case *ast.EmptyStmt:
    178 	case *ast.LabeledStmt:
    179 		walkBeforeAfter(&n.Stmt, before, after)
    180 	case *ast.ExprStmt:
    181 		walkBeforeAfter(&n.X, before, after)
    182 	case *ast.SendStmt:
    183 		walkBeforeAfter(&n.Chan, before, after)
    184 		walkBeforeAfter(&n.Value, before, after)
    185 	case *ast.IncDecStmt:
    186 		walkBeforeAfter(&n.X, before, after)
    187 	case *ast.AssignStmt:
    188 		walkBeforeAfter(&n.Lhs, before, after)
    189 		walkBeforeAfter(&n.Rhs, before, after)
    190 	case *ast.GoStmt:
    191 		walkBeforeAfter(&n.Call, before, after)
    192 	case *ast.DeferStmt:
    193 		walkBeforeAfter(&n.Call, before, after)
    194 	case *ast.ReturnStmt:
    195 		walkBeforeAfter(&n.Results, before, after)
    196 	case *ast.BranchStmt:
    197 	case *ast.BlockStmt:
    198 		walkBeforeAfter(&n.List, before, after)
    199 	case *ast.IfStmt:
    200 		walkBeforeAfter(&n.Init, before, after)
    201 		walkBeforeAfter(&n.Cond, before, after)
    202 		walkBeforeAfter(&n.Body, before, after)
    203 		walkBeforeAfter(&n.Else, before, after)
    204 	case *ast.CaseClause:
    205 		walkBeforeAfter(&n.List, before, after)
    206 		walkBeforeAfter(&n.Body, before, after)
    207 	case *ast.SwitchStmt:
    208 		walkBeforeAfter(&n.Init, before, after)
    209 		walkBeforeAfter(&n.Tag, before, after)
    210 		walkBeforeAfter(&n.Body, before, after)
    211 	case *ast.TypeSwitchStmt:
    212 		walkBeforeAfter(&n.Init, before, after)
    213 		walkBeforeAfter(&n.Assign, before, after)
    214 		walkBeforeAfter(&n.Body, before, after)
    215 	case *ast.CommClause:
    216 		walkBeforeAfter(&n.Comm, before, after)
    217 		walkBeforeAfter(&n.Body, before, after)
    218 	case *ast.SelectStmt:
    219 		walkBeforeAfter(&n.Body, before, after)
    220 	case *ast.ForStmt:
    221 		walkBeforeAfter(&n.Init, before, after)
    222 		walkBeforeAfter(&n.Cond, before, after)
    223 		walkBeforeAfter(&n.Post, before, after)
    224 		walkBeforeAfter(&n.Body, before, after)
    225 	case *ast.RangeStmt:
    226 		walkBeforeAfter(&n.Key, before, after)
    227 		walkBeforeAfter(&n.Value, before, after)
    228 		walkBeforeAfter(&n.X, before, after)
    229 		walkBeforeAfter(&n.Body, before, after)
    230 
    231 	case *ast.ImportSpec:
    232 	case *ast.ValueSpec:
    233 		walkBeforeAfter(&n.Type, before, after)
    234 		walkBeforeAfter(&n.Values, before, after)
    235 		walkBeforeAfter(&n.Names, before, after)
    236 	case *ast.TypeSpec:
    237 		walkBeforeAfter(&n.Type, before, after)
    238 
    239 	case *ast.BadDecl:
    240 	case *ast.GenDecl:
    241 		walkBeforeAfter(&n.Specs, before, after)
    242 	case *ast.FuncDecl:
    243 		if n.Recv != nil {
    244 			walkBeforeAfter(&n.Recv, before, after)
    245 		}
    246 		walkBeforeAfter(&n.Type, before, after)
    247 		if n.Body != nil {
    248 			walkBeforeAfter(&n.Body, before, after)
    249 		}
    250 
    251 	case *ast.File:
    252 		walkBeforeAfter(&n.Decls, before, after)
    253 
    254 	case *ast.Package:
    255 		walkBeforeAfter(&n.Files, before, after)
    256 
    257 	case []*ast.File:
    258 		for i := range n {
    259 			walkBeforeAfter(&n[i], before, after)
    260 		}
    261 	case []ast.Decl:
    262 		for i := range n {
    263 			walkBeforeAfter(&n[i], before, after)
    264 		}
    265 	case []ast.Expr:
    266 		for i := range n {
    267 			walkBeforeAfter(&n[i], before, after)
    268 		}
    269 	case []*ast.Ident:
    270 		for i := range n {
    271 			walkBeforeAfter(&n[i], before, after)
    272 		}
    273 	case []ast.Stmt:
    274 		for i := range n {
    275 			walkBeforeAfter(&n[i], before, after)
    276 		}
    277 	case []ast.Spec:
    278 		for i := range n {
    279 			walkBeforeAfter(&n[i], before, after)
    280 		}
    281 	}
    282 	after(x)
    283 }
    284 
    285 // imports reports whether f imports path.
    286 func imports(f *ast.File, path string) bool {
    287 	return importSpec(f, path) != nil
    288 }
    289 
    290 // importSpec returns the import spec if f imports path,
    291 // or nil otherwise.
    292 func importSpec(f *ast.File, path string) *ast.ImportSpec {
    293 	for _, s := range f.Imports {
    294 		if importPath(s) == path {
    295 			return s
    296 		}
    297 	}
    298 	return nil
    299 }
    300 
    301 // importPath returns the unquoted import path of s,
    302 // or "" if the path is not properly quoted.
    303 func importPath(s *ast.ImportSpec) string {
    304 	t, err := strconv.Unquote(s.Path.Value)
    305 	if err == nil {
    306 		return t
    307 	}
    308 	return ""
    309 }
    310 
    311 // declImports reports whether gen contains an import of path.
    312 func declImports(gen *ast.GenDecl, path string) bool {
    313 	if gen.Tok != token.IMPORT {
    314 		return false
    315 	}
    316 	for _, spec := range gen.Specs {
    317 		impspec := spec.(*ast.ImportSpec)
    318 		if importPath(impspec) == path {
    319 			return true
    320 		}
    321 	}
    322 	return false
    323 }
    324 
    325 // isPkgDot reports whether t is the expression "pkg.name"
    326 // where pkg is an imported identifier.
    327 func isPkgDot(t ast.Expr, pkg, name string) bool {
    328 	sel, ok := t.(*ast.SelectorExpr)
    329 	return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
    330 }
    331 
    332 // isPtrPkgDot reports whether f is the expression "*pkg.name"
    333 // where pkg is an imported identifier.
    334 func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
    335 	ptr, ok := t.(*ast.StarExpr)
    336 	return ok && isPkgDot(ptr.X, pkg, name)
    337 }
    338 
    339 // isTopName reports whether n is a top-level unresolved identifier with the given name.
    340 func isTopName(n ast.Expr, name string) bool {
    341 	id, ok := n.(*ast.Ident)
    342 	return ok && id.Name == name && id.Obj == nil
    343 }
    344 
    345 // isName reports whether n is an identifier with the given name.
    346 func isName(n ast.Expr, name string) bool {
    347 	id, ok := n.(*ast.Ident)
    348 	return ok && id.String() == name
    349 }
    350 
    351 // isCall reports whether t is a call to pkg.name.
    352 func isCall(t ast.Expr, pkg, name string) bool {
    353 	call, ok := t.(*ast.CallExpr)
    354 	return ok && isPkgDot(call.Fun, pkg, name)
    355 }
    356 
    357 // If n is an *ast.Ident, isIdent returns it; otherwise isIdent returns nil.
    358 func isIdent(n interface{}) *ast.Ident {
    359 	id, _ := n.(*ast.Ident)
    360 	return id
    361 }
    362 
    363 // refersTo reports whether n is a reference to the same object as x.
    364 func refersTo(n ast.Node, x *ast.Ident) bool {
    365 	id, ok := n.(*ast.Ident)
    366 	// The test of id.Name == x.Name handles top-level unresolved
    367 	// identifiers, which all have Obj == nil.
    368 	return ok && id.Obj == x.Obj && id.Name == x.Name
    369 }
    370 
    371 // isBlank reports whether n is the blank identifier.
    372 func isBlank(n ast.Expr) bool {
    373 	return isName(n, "_")
    374 }
    375 
    376 // isEmptyString reports whether n is an empty string literal.
    377 func isEmptyString(n ast.Expr) bool {
    378 	lit, ok := n.(*ast.BasicLit)
    379 	return ok && lit.Kind == token.STRING && len(lit.Value) == 2
    380 }
    381 
    382 func warn(pos token.Pos, msg string, args ...interface{}) {
    383 	if pos.IsValid() {
    384 		msg = "%s: " + msg
    385 		arg1 := []interface{}{fset.Position(pos).String()}
    386 		args = append(arg1, args...)
    387 	}
    388 	fmt.Fprintf(os.Stderr, msg+"\n", args...)
    389 }
    390 
    391 // countUses returns the number of uses of the identifier x in scope.
    392 func countUses(x *ast.Ident, scope []ast.Stmt) int {
    393 	count := 0
    394 	ff := func(n interface{}) {
    395 		if n, ok := n.(ast.Node); ok && refersTo(n, x) {
    396 			count++
    397 		}
    398 	}
    399 	for _, n := range scope {
    400 		walk(n, ff)
    401 	}
    402 	return count
    403 }
    404 
    405 // rewriteUses replaces all uses of the identifier x and !x in scope
    406 // with f(x.Pos()) and fnot(x.Pos()).
    407 func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stmt) {
    408 	var lastF ast.Expr
    409 	ff := func(n interface{}) {
    410 		ptr, ok := n.(*ast.Expr)
    411 		if !ok {
    412 			return
    413 		}
    414 		nn := *ptr
    415 
    416 		// The child node was just walked and possibly replaced.
    417 		// If it was replaced and this is a negation, replace with fnot(p).
    418 		not, ok := nn.(*ast.UnaryExpr)
    419 		if ok && not.Op == token.NOT && not.X == lastF {
    420 			*ptr = fnot(nn.Pos())
    421 			return
    422 		}
    423 		if refersTo(nn, x) {
    424 			lastF = f(nn.Pos())
    425 			*ptr = lastF
    426 		}
    427 	}
    428 	for _, n := range scope {
    429 		walk(n, ff)
    430 	}
    431 }
    432 
    433 // assignsTo reports whether any of the code in scope assigns to or takes the address of x.
    434 func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
    435 	assigned := false
    436 	ff := func(n interface{}) {
    437 		if assigned {
    438 			return
    439 		}
    440 		switch n := n.(type) {
    441 		case *ast.UnaryExpr:
    442 			// use of &x
    443 			if n.Op == token.AND && refersTo(n.X, x) {
    444 				assigned = true
    445 				return
    446 			}
    447 		case *ast.AssignStmt:
    448 			for _, l := range n.Lhs {
    449 				if refersTo(l, x) {
    450 					assigned = true
    451 					return
    452 				}
    453 			}
    454 		}
    455 	}
    456 	for _, n := range scope {
    457 		if assigned {
    458 			break
    459 		}
    460 		walk(n, ff)
    461 	}
    462 	return assigned
    463 }
    464 
    465 // newPkgDot returns an ast.Expr referring to "pkg.name" at position pos.
    466 func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
    467 	return &ast.SelectorExpr{
    468 		X: &ast.Ident{
    469 			NamePos: pos,
    470 			Name:    pkg,
    471 		},
    472 		Sel: &ast.Ident{
    473 			NamePos: pos,
    474 			Name:    name,
    475 		},
    476 	}
    477 }
    478 
    479 // renameTop renames all references to the top-level name old.
    480 // It returns true if it makes any changes.
    481 func renameTop(f *ast.File, old, new string) bool {
    482 	var fixed bool
    483 
    484 	// Rename any conflicting imports
    485 	// (assuming package name is last element of path).
    486 	for _, s := range f.Imports {
    487 		if s.Name != nil {
    488 			if s.Name.Name == old {
    489 				s.Name.Name = new
    490 				fixed = true
    491 			}
    492 		} else {
    493 			_, thisName := path.Split(importPath(s))
    494 			if thisName == old {
    495 				s.Name = ast.NewIdent(new)
    496 				fixed = true
    497 			}
    498 		}
    499 	}
    500 
    501 	// Rename any top-level declarations.
    502 	for _, d := range f.Decls {
    503 		switch d := d.(type) {
    504 		case *ast.FuncDecl:
    505 			if d.Recv == nil && d.Name.Name == old {
    506 				d.Name.Name = new
    507 				d.Name.Obj.Name = new
    508 				fixed = true
    509 			}
    510 		case *ast.GenDecl:
    511 			for _, s := range d.Specs {
    512 				switch s := s.(type) {
    513 				case *ast.TypeSpec:
    514 					if s.Name.Name == old {
    515 						s.Name.Name = new
    516 						s.Name.Obj.Name = new
    517 						fixed = true
    518 					}
    519 				case *ast.ValueSpec:
    520 					for _, n := range s.Names {
    521 						if n.Name == old {
    522 							n.Name = new
    523 							n.Obj.Name = new
    524 							fixed = true
    525 						}
    526 					}
    527 				}
    528 			}
    529 		}
    530 	}
    531 
    532 	// Rename top-level old to new, both unresolved names
    533 	// (probably defined in another file) and names that resolve
    534 	// to a declaration we renamed.
    535 	walk(f, func(n interface{}) {
    536 		id, ok := n.(*ast.Ident)
    537 		if ok && isTopName(id, old) {
    538 			id.Name = new
    539 			fixed = true
    540 		}
    541 		if ok && id.Obj != nil && id.Name == old && id.Obj.Name == new {
    542 			id.Name = id.Obj.Name
    543 			fixed = true
    544 		}
    545 	})
    546 
    547 	return fixed
    548 }
    549 
    550 // matchLen returns the length of the longest prefix shared by x and y.
    551 func matchLen(x, y string) int {
    552 	i := 0
    553 	for i < len(x) && i < len(y) && x[i] == y[i] {
    554 		i++
    555 	}
    556 	return i
    557 }
    558 
    559 // addImport adds the import path to the file f, if absent.
    560 func addImport(f *ast.File, ipath string) (added bool) {
    561 	if imports(f, ipath) {
    562 		return false
    563 	}
    564 
    565 	// Determine name of import.
    566 	// Assume added imports follow convention of using last element.
    567 	_, name := path.Split(ipath)
    568 
    569 	// Rename any conflicting top-level references from name to name_.
    570 	renameTop(f, name, name+"_")
    571 
    572 	newImport := &ast.ImportSpec{
    573 		Path: &ast.BasicLit{
    574 			Kind:  token.STRING,
    575 			Value: strconv.Quote(ipath),
    576 		},
    577 	}
    578 
    579 	// Find an import decl to add to.
    580 	var (
    581 		bestMatch  = -1
    582 		lastImport = -1
    583 		impDecl    *ast.GenDecl
    584 		impIndex   = -1
    585 	)
    586 	for i, decl := range f.Decls {
    587 		gen, ok := decl.(*ast.GenDecl)
    588 		if ok && gen.Tok == token.IMPORT {
    589 			lastImport = i
    590 			// Do not add to import "C", to avoid disrupting the
    591 			// association with its doc comment, breaking cgo.
    592 			if declImports(gen, "C") {
    593 				continue
    594 			}
    595 
    596 			// Compute longest shared prefix with imports in this block.
    597 			for j, spec := range gen.Specs {
    598 				impspec := spec.(*ast.ImportSpec)
    599 				n := matchLen(importPath(impspec), ipath)
    600 				if n > bestMatch {
    601 					bestMatch = n
    602 					impDecl = gen
    603 					impIndex = j
    604 				}
    605 			}
    606 		}
    607 	}
    608 
    609 	// If no import decl found, add one after the last import.
    610 	if impDecl == nil {
    611 		impDecl = &ast.GenDecl{
    612 			Tok: token.IMPORT,
    613 		}
    614 		f.Decls = append(f.Decls, nil)
    615 		copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
    616 		f.Decls[lastImport+1] = impDecl
    617 	}
    618 
    619 	// Ensure the import decl has parentheses, if needed.
    620 	if len(impDecl.Specs) > 0 && !impDecl.Lparen.IsValid() {
    621 		impDecl.Lparen = impDecl.Pos()
    622 	}
    623 
    624 	insertAt := impIndex + 1
    625 	if insertAt == 0 {
    626 		insertAt = len(impDecl.Specs)
    627 	}
    628 	impDecl.Specs = append(impDecl.Specs, nil)
    629 	copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
    630 	impDecl.Specs[insertAt] = newImport
    631 	if insertAt > 0 {
    632 		// Assign same position as the previous import,
    633 		// so that the sorter sees it as being in the same block.
    634 		prev := impDecl.Specs[insertAt-1]
    635 		newImport.Path.ValuePos = prev.Pos()
    636 		newImport.EndPos = prev.Pos()
    637 	}
    638 
    639 	f.Imports = append(f.Imports, newImport)
    640 	return true
    641 }
    642 
    643 // deleteImport deletes the import path from the file f, if present.
    644 func deleteImport(f *ast.File, path string) (deleted bool) {
    645 	oldImport := importSpec(f, path)
    646 
    647 	// Find the import node that imports path, if any.
    648 	for i, decl := range f.Decls {
    649 		gen, ok := decl.(*ast.GenDecl)
    650 		if !ok || gen.Tok != token.IMPORT {
    651 			continue
    652 		}
    653 		for j, spec := range gen.Specs {
    654 			impspec := spec.(*ast.ImportSpec)
    655 			if oldImport != impspec {
    656 				continue
    657 			}
    658 
    659 			// We found an import spec that imports path.
    660 			// Delete it.
    661 			deleted = true
    662 			copy(gen.Specs[j:], gen.Specs[j+1:])
    663 			gen.Specs = gen.Specs[:len(gen.Specs)-1]
    664 
    665 			// If this was the last import spec in this decl,
    666 			// delete the decl, too.
    667 			if len(gen.Specs) == 0 {
    668 				copy(f.Decls[i:], f.Decls[i+1:])
    669 				f.Decls = f.Decls[:len(f.Decls)-1]
    670 			} else if len(gen.Specs) == 1 {
    671 				gen.Lparen = token.NoPos // drop parens
    672 			}
    673 			if j > 0 {
    674 				// We deleted an entry but now there will be
    675 				// a blank line-sized hole where the import was.
    676 				// Close the hole by making the previous
    677 				// import appear to "end" where this one did.
    678 				gen.Specs[j-1].(*ast.ImportSpec).EndPos = impspec.End()
    679 			}
    680 			break
    681 		}
    682 	}
    683 
    684 	// Delete it from f.Imports.
    685 	for i, imp := range f.Imports {
    686 		if imp == oldImport {
    687 			copy(f.Imports[i:], f.Imports[i+1:])
    688 			f.Imports = f.Imports[:len(f.Imports)-1]
    689 			break
    690 		}
    691 	}
    692 
    693 	return
    694 }
    695 
    696 // rewriteImport rewrites any import of path oldPath to path newPath.
    697 func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) {
    698 	for _, imp := range f.Imports {
    699 		if importPath(imp) == oldPath {
    700 			rewrote = true
    701 			// record old End, because the default is to compute
    702 			// it using the length of imp.Path.Value.
    703 			imp.EndPos = imp.End()
    704 			imp.Path.Value = strconv.Quote(newPath)
    705 		}
    706 	}
    707 	return
    708 }
    709 
    710 func usesImport(f *ast.File, path string) (used bool) {
    711 	spec := importSpec(f, path)
    712 	if spec == nil {
    713 		return
    714 	}
    715 
    716 	name := spec.Name.String()
    717 	switch name {
    718 	case "<nil>":
    719 		// If the package name is not explicitly specified,
    720 		// make an educated guess. This is not guaranteed to be correct.
    721 		lastSlash := strings.LastIndex(path, "/")
    722 		if lastSlash == -1 {
    723 			name = path
    724 		} else {
    725 			name = path[lastSlash+1:]
    726 		}
    727 	case "_", ".":
    728 		// Not sure if this import is used - err on the side of caution.
    729 		return true
    730 	}
    731 
    732 	walk(f, func(n interface{}) {
    733 		sel, ok := n.(*ast.SelectorExpr)
    734 		if ok && isTopName(sel.X, name) {
    735 			used = true
    736 		}
    737 	})
    738 
    739 	return
    740 }
    741 
    742 func expr(s string) ast.Expr {
    743 	x, err := parser.ParseExpr(s)
    744 	if err != nil {
    745 		panic("parsing " + s + ": " + err.Error())
    746 	}
    747 	// Remove position information to avoid spurious newlines.
    748 	killPos(reflect.ValueOf(x))
    749 	return x
    750 }
    751 
    752 var posType = reflect.TypeOf(token.Pos(0))
    753 
    754 func killPos(v reflect.Value) {
    755 	switch v.Kind() {
    756 	case reflect.Ptr, reflect.Interface:
    757 		if !v.IsNil() {
    758 			killPos(v.Elem())
    759 		}
    760 	case reflect.Slice:
    761 		n := v.Len()
    762 		for i := 0; i < n; i++ {
    763 			killPos(v.Index(i))
    764 		}
    765 	case reflect.Struct:
    766 		n := v.NumField()
    767 		for i := 0; i < n; i++ {
    768 			f := v.Field(i)
    769 			if f.Type() == posType {
    770 				f.SetInt(0)
    771 				continue
    772 			}
    773 			killPos(f)
    774 		}
    775 	}
    776 }
    777 
    778 // A Rename describes a single renaming.
    779 type rename struct {
    780 	OldImport string // only apply rename if this import is present
    781 	NewImport string // add this import during rewrite
    782 	Old       string // old name: p.T or *p.T
    783 	New       string // new name: p.T or *p.T
    784 }
    785 
    786 func renameFix(tab []rename) func(*ast.File) bool {
    787 	return func(f *ast.File) bool {
    788 		return renameFixTab(f, tab)
    789 	}
    790 }
    791 
    792 func parseName(s string) (ptr bool, pkg, nam string) {
    793 	i := strings.Index(s, ".")
    794 	if i < 0 {
    795 		panic("parseName: invalid name " + s)
    796 	}
    797 	if strings.HasPrefix(s, "*") {
    798 		ptr = true
    799 		s = s[1:]
    800 		i--
    801 	}
    802 	pkg = s[:i]
    803 	nam = s[i+1:]
    804 	return
    805 }
    806 
    807 func renameFixTab(f *ast.File, tab []rename) bool {
    808 	fixed := false
    809 	added := map[string]bool{}
    810 	check := map[string]bool{}
    811 	for _, t := range tab {
    812 		if !imports(f, t.OldImport) {
    813 			continue
    814 		}
    815 		optr, opkg, onam := parseName(t.Old)
    816 		walk(f, func(n interface{}) {
    817 			np, ok := n.(*ast.Expr)
    818 			if !ok {
    819 				return
    820 			}
    821 			x := *np
    822 			if optr {
    823 				p, ok := x.(*ast.StarExpr)
    824 				if !ok {
    825 					return
    826 				}
    827 				x = p.X
    828 			}
    829 			if !isPkgDot(x, opkg, onam) {
    830 				return
    831 			}
    832 			if t.NewImport != "" && !added[t.NewImport] {
    833 				addImport(f, t.NewImport)
    834 				added[t.NewImport] = true
    835 			}
    836 			*np = expr(t.New)
    837 			check[t.OldImport] = true
    838 			fixed = true
    839 		})
    840 	}
    841 
    842 	for ipath := range check {
    843 		if !usesImport(f, ipath) {
    844 			deleteImport(f, ipath)
    845 		}
    846 	}
    847 	return fixed
    848 }
    849