github.com/robhaswell/grandperspective-scan@v0.1.0/test/go-go1.7.1/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 }