github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/cmd/fix/fix.go (about)

     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  }