github.com/v2fly/tools@v0.100.0/internal/lsp/source/rename_check.go (about) 1 // Copyright 2019 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 // Taken from github.com/v2fly/tools/refactor/rename. 6 7 package source 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "go/types" 14 "reflect" 15 "strconv" 16 "strings" 17 "unicode" 18 19 "github.com/v2fly/tools/go/ast/astutil" 20 "github.com/v2fly/tools/refactor/satisfy" 21 ) 22 23 // errorf reports an error (e.g. conflict) and prevents file modification. 24 func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) { 25 r.hadConflicts = true 26 r.errors += fmt.Sprintf(format, args...) 27 } 28 29 // check performs safety checks of the renaming of the 'from' object to r.to. 30 func (r *renamer) check(from types.Object) { 31 if r.objsToUpdate[from] { 32 return 33 } 34 r.objsToUpdate[from] = true 35 36 // NB: order of conditions is important. 37 if from_, ok := from.(*types.PkgName); ok { 38 r.checkInFileBlock(from_) 39 } else if from_, ok := from.(*types.Label); ok { 40 r.checkLabel(from_) 41 } else if isPackageLevel(from) { 42 r.checkInPackageBlock(from) 43 } else if v, ok := from.(*types.Var); ok && v.IsField() { 44 r.checkStructField(v) 45 } else if f, ok := from.(*types.Func); ok && recv(f) != nil { 46 r.checkMethod(f) 47 } else if isLocal(from) { 48 r.checkInLocalScope(from) 49 } else { 50 r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n", 51 objectKind(from), from) 52 } 53 } 54 55 // checkInFileBlock performs safety checks for renames of objects in the file block, 56 // i.e. imported package names. 57 func (r *renamer) checkInFileBlock(from *types.PkgName) { 58 // Check import name is not "init". 59 if r.to == "init" { 60 r.errorf(from.Pos(), "%q is not a valid imported package name", r.to) 61 } 62 63 // Check for conflicts between file and package block. 64 if prev := from.Pkg().Scope().Lookup(r.to); prev != nil { 65 r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", 66 objectKind(from), from.Name(), r.to) 67 r.errorf(prev.Pos(), "\twith this package member %s", 68 objectKind(prev)) 69 return // since checkInPackageBlock would report redundant errors 70 } 71 72 // Check for conflicts in lexical scope. 73 r.checkInLexicalScope(from, r.packages[from.Pkg()]) 74 } 75 76 // checkInPackageBlock performs safety checks for renames of 77 // func/var/const/type objects in the package block. 78 func (r *renamer) checkInPackageBlock(from types.Object) { 79 // Check that there are no references to the name from another 80 // package if the renaming would make it unexported. 81 if ast.IsExported(from.Name()) && !ast.IsExported(r.to) { 82 for typ, pkg := range r.packages { 83 if typ == from.Pkg() { 84 continue 85 } 86 if id := someUse(pkg.GetTypesInfo(), from); id != nil && 87 !r.checkExport(id, typ, from) { 88 break 89 } 90 } 91 } 92 93 pkg := r.packages[from.Pkg()] 94 if pkg == nil { 95 return 96 } 97 98 // Check that in the package block, "init" is a function, and never referenced. 99 if r.to == "init" { 100 kind := objectKind(from) 101 if kind == "func" { 102 // Reject if intra-package references to it exist. 103 for id, obj := range pkg.GetTypesInfo().Uses { 104 if obj == from { 105 r.errorf(from.Pos(), 106 "renaming this func %q to %q would make it a package initializer", 107 from.Name(), r.to) 108 r.errorf(id.Pos(), "\tbut references to it exist") 109 break 110 } 111 } 112 } else { 113 r.errorf(from.Pos(), "you cannot have a %s at package level named %q", 114 kind, r.to) 115 } 116 } 117 118 // Check for conflicts between package block and all file blocks. 119 for _, f := range pkg.GetSyntax() { 120 fileScope := pkg.GetTypesInfo().Scopes[f] 121 b, prev := fileScope.LookupParent(r.to, token.NoPos) 122 if b == fileScope { 123 r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", objectKind(from), from.Name(), r.to) 124 var prevPos token.Pos 125 if prev != nil { 126 prevPos = prev.Pos() 127 } 128 r.errorf(prevPos, "\twith this %s", objectKind(prev)) 129 return // since checkInPackageBlock would report redundant errors 130 } 131 } 132 133 // Check for conflicts in lexical scope. 134 if from.Exported() { 135 for _, pkg := range r.packages { 136 r.checkInLexicalScope(from, pkg) 137 } 138 } else { 139 r.checkInLexicalScope(from, pkg) 140 } 141 } 142 143 func (r *renamer) checkInLocalScope(from types.Object) { 144 pkg := r.packages[from.Pkg()] 145 r.checkInLexicalScope(from, pkg) 146 } 147 148 // checkInLexicalScope performs safety checks that a renaming does not 149 // change the lexical reference structure of the specified package. 150 // 151 // For objects in lexical scope, there are three kinds of conflicts: 152 // same-, sub-, and super-block conflicts. We will illustrate all three 153 // using this example: 154 // 155 // var x int 156 // var z int 157 // 158 // func f(y int) { 159 // print(x) 160 // print(y) 161 // } 162 // 163 // Renaming x to z encounters a SAME-BLOCK CONFLICT, because an object 164 // with the new name already exists, defined in the same lexical block 165 // as the old object. 166 // 167 // Renaming x to y encounters a SUB-BLOCK CONFLICT, because there exists 168 // a reference to x from within (what would become) a hole in its scope. 169 // The definition of y in an (inner) sub-block would cast a shadow in 170 // the scope of the renamed variable. 171 // 172 // Renaming y to x encounters a SUPER-BLOCK CONFLICT. This is the 173 // converse situation: there is an existing definition of the new name 174 // (x) in an (enclosing) super-block, and the renaming would create a 175 // hole in its scope, within which there exist references to it. The 176 // new name casts a shadow in scope of the existing definition of x in 177 // the super-block. 178 // 179 // Removing the old name (and all references to it) is always safe, and 180 // requires no checks. 181 // 182 func (r *renamer) checkInLexicalScope(from types.Object, pkg Package) { 183 b := from.Parent() // the block defining the 'from' object 184 if b != nil { 185 toBlock, to := b.LookupParent(r.to, from.Parent().End()) 186 if toBlock == b { 187 // same-block conflict 188 r.errorf(from.Pos(), "renaming this %s %q to %q", 189 objectKind(from), from.Name(), r.to) 190 r.errorf(to.Pos(), "\tconflicts with %s in same block", 191 objectKind(to)) 192 return 193 } else if toBlock != nil { 194 // Check for super-block conflict. 195 // The name r.to is defined in a superblock. 196 // Is that name referenced from within this block? 197 forEachLexicalRef(pkg, to, func(id *ast.Ident, block *types.Scope) bool { 198 _, obj := lexicalLookup(block, from.Name(), id.Pos()) 199 if obj == from { 200 // super-block conflict 201 r.errorf(from.Pos(), "renaming this %s %q to %q", 202 objectKind(from), from.Name(), r.to) 203 r.errorf(id.Pos(), "\twould shadow this reference") 204 r.errorf(to.Pos(), "\tto the %s declared here", 205 objectKind(to)) 206 return false // stop 207 } 208 return true 209 }) 210 } 211 } 212 // Check for sub-block conflict. 213 // Is there an intervening definition of r.to between 214 // the block defining 'from' and some reference to it? 215 forEachLexicalRef(pkg, from, func(id *ast.Ident, block *types.Scope) bool { 216 // Find the block that defines the found reference. 217 // It may be an ancestor. 218 fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos()) 219 220 // See what r.to would resolve to in the same scope. 221 toBlock, to := lexicalLookup(block, r.to, id.Pos()) 222 if to != nil { 223 // sub-block conflict 224 if deeper(toBlock, fromBlock) { 225 r.errorf(from.Pos(), "renaming this %s %q to %q", 226 objectKind(from), from.Name(), r.to) 227 r.errorf(id.Pos(), "\twould cause this reference to become shadowed") 228 r.errorf(to.Pos(), "\tby this intervening %s definition", 229 objectKind(to)) 230 return false // stop 231 } 232 } 233 return true 234 }) 235 236 // Renaming a type that is used as an embedded field 237 // requires renaming the field too. e.g. 238 // type T int // if we rename this to U.. 239 // var s struct {T} 240 // print(s.T) // ...this must change too 241 if _, ok := from.(*types.TypeName); ok { 242 for id, obj := range pkg.GetTypesInfo().Uses { 243 if obj == from { 244 if field := pkg.GetTypesInfo().Defs[id]; field != nil { 245 r.check(field) 246 } 247 } 248 } 249 } 250 } 251 252 // lexicalLookup is like (*types.Scope).LookupParent but respects the 253 // environment visible at pos. It assumes the relative position 254 // information is correct with each file. 255 func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) { 256 for b := block; b != nil; b = b.Parent() { 257 obj := b.Lookup(name) 258 // The scope of a package-level object is the entire package, 259 // so ignore pos in that case. 260 // No analogous clause is needed for file-level objects 261 // since no reference can appear before an import decl. 262 if obj == nil || obj.Pkg() == nil { 263 continue 264 } 265 if b == obj.Pkg().Scope() || obj.Pos() < pos { 266 return b, obj 267 } 268 } 269 return nil, nil 270 } 271 272 // deeper reports whether block x is lexically deeper than y. 273 func deeper(x, y *types.Scope) bool { 274 if x == y || x == nil { 275 return false 276 } else if y == nil { 277 return true 278 } else { 279 return deeper(x.Parent(), y.Parent()) 280 } 281 } 282 283 // forEachLexicalRef calls fn(id, block) for each identifier id in package 284 // pkg that is a reference to obj in lexical scope. block is the 285 // lexical block enclosing the reference. If fn returns false the 286 // iteration is terminated and findLexicalRefs returns false. 287 func forEachLexicalRef(pkg Package, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool { 288 ok := true 289 var stack []ast.Node 290 291 var visit func(n ast.Node) bool 292 visit = func(n ast.Node) bool { 293 if n == nil { 294 stack = stack[:len(stack)-1] // pop 295 return false 296 } 297 if !ok { 298 return false // bail out 299 } 300 301 stack = append(stack, n) // push 302 switch n := n.(type) { 303 case *ast.Ident: 304 if pkg.GetTypesInfo().Uses[n] == obj { 305 block := enclosingBlock(pkg.GetTypesInfo(), stack) 306 if !fn(n, block) { 307 ok = false 308 } 309 } 310 return visit(nil) // pop stack 311 312 case *ast.SelectorExpr: 313 // don't visit n.Sel 314 ast.Inspect(n.X, visit) 315 return visit(nil) // pop stack, don't descend 316 317 case *ast.CompositeLit: 318 // Handle recursion ourselves for struct literals 319 // so we don't visit field identifiers. 320 tv, ok := pkg.GetTypesInfo().Types[n] 321 if !ok { 322 return visit(nil) // pop stack, don't descend 323 } 324 if _, ok := Deref(tv.Type).Underlying().(*types.Struct); ok { 325 if n.Type != nil { 326 ast.Inspect(n.Type, visit) 327 } 328 for _, elt := range n.Elts { 329 if kv, ok := elt.(*ast.KeyValueExpr); ok { 330 ast.Inspect(kv.Value, visit) 331 } else { 332 ast.Inspect(elt, visit) 333 } 334 } 335 return visit(nil) // pop stack, don't descend 336 } 337 } 338 return true 339 } 340 341 for _, f := range pkg.GetSyntax() { 342 ast.Inspect(f, visit) 343 if len(stack) != 0 { 344 panic(stack) 345 } 346 if !ok { 347 break 348 } 349 } 350 return ok 351 } 352 353 // enclosingBlock returns the innermost block enclosing the specified 354 // AST node, specified in the form of a path from the root of the file, 355 // [file...n]. 356 func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope { 357 for i := range stack { 358 n := stack[len(stack)-1-i] 359 // For some reason, go/types always associates a 360 // function's scope with its FuncType. 361 // TODO(adonovan): feature or a bug? 362 switch f := n.(type) { 363 case *ast.FuncDecl: 364 n = f.Type 365 case *ast.FuncLit: 366 n = f.Type 367 } 368 if b := info.Scopes[n]; b != nil { 369 return b 370 } 371 } 372 panic("no Scope for *ast.File") 373 } 374 375 func (r *renamer) checkLabel(label *types.Label) { 376 // Check there are no identical labels in the function's label block. 377 // (Label blocks don't nest, so this is easy.) 378 if prev := label.Parent().Lookup(r.to); prev != nil { 379 r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name()) 380 r.errorf(prev.Pos(), "\twould conflict with this one") 381 } 382 } 383 384 // checkStructField checks that the field renaming will not cause 385 // conflicts at its declaration, or ambiguity or changes to any selection. 386 func (r *renamer) checkStructField(from *types.Var) { 387 // Check that the struct declaration is free of field conflicts, 388 // and field/method conflicts. 389 390 // go/types offers no easy way to get from a field (or interface 391 // method) to its declaring struct (or interface), so we must 392 // ascend the AST. 393 fromPkg, ok := r.packages[from.Pkg()] 394 if !ok { 395 return 396 } 397 pkg, path, _ := pathEnclosingInterval(r.fset, fromPkg, from.Pos(), from.Pos()) 398 if pkg == nil || path == nil { 399 return 400 } 401 // path matches this pattern: 402 // [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File] 403 404 // Ascend to FieldList. 405 var i int 406 for { 407 if _, ok := path[i].(*ast.FieldList); ok { 408 break 409 } 410 i++ 411 } 412 i++ 413 tStruct := path[i].(*ast.StructType) 414 i++ 415 // Ascend past parens (unlikely). 416 for { 417 _, ok := path[i].(*ast.ParenExpr) 418 if !ok { 419 break 420 } 421 i++ 422 } 423 if spec, ok := path[i].(*ast.TypeSpec); ok { 424 // This struct is also a named type. 425 // We must check for direct (non-promoted) field/field 426 // and method/field conflicts. 427 named := pkg.GetTypesInfo().Defs[spec.Name].Type() 428 prev, indices, _ := types.LookupFieldOrMethod(named, true, pkg.GetTypes(), r.to) 429 if len(indices) == 1 { 430 r.errorf(from.Pos(), "renaming this field %q to %q", 431 from.Name(), r.to) 432 r.errorf(prev.Pos(), "\twould conflict with this %s", 433 objectKind(prev)) 434 return // skip checkSelections to avoid redundant errors 435 } 436 } else { 437 // This struct is not a named type. 438 // We need only check for direct (non-promoted) field/field conflicts. 439 T := pkg.GetTypesInfo().Types[tStruct].Type.Underlying().(*types.Struct) 440 for i := 0; i < T.NumFields(); i++ { 441 if prev := T.Field(i); prev.Name() == r.to { 442 r.errorf(from.Pos(), "renaming this field %q to %q", 443 from.Name(), r.to) 444 r.errorf(prev.Pos(), "\twould conflict with this field") 445 return // skip checkSelections to avoid redundant errors 446 } 447 } 448 } 449 450 // Renaming an anonymous field requires renaming the type too. e.g. 451 // print(s.T) // if we rename T to U, 452 // type T int // this and 453 // var s struct {T} // this must change too. 454 if from.Anonymous() { 455 if named, ok := from.Type().(*types.Named); ok { 456 r.check(named.Obj()) 457 } else if named, ok := Deref(from.Type()).(*types.Named); ok { 458 r.check(named.Obj()) 459 } 460 } 461 462 // Check integrity of existing (field and method) selections. 463 r.checkSelections(from) 464 } 465 466 // checkSelection checks that all uses and selections that resolve to 467 // the specified object would continue to do so after the renaming. 468 func (r *renamer) checkSelections(from types.Object) { 469 for typ, pkg := range r.packages { 470 if id := someUse(pkg.GetTypesInfo(), from); id != nil { 471 if !r.checkExport(id, typ, from) { 472 return 473 } 474 } 475 476 for syntax, sel := range pkg.GetTypesInfo().Selections { 477 // There may be extant selections of only the old 478 // name or only the new name, so we must check both. 479 // (If neither, the renaming is sound.) 480 // 481 // In both cases, we wish to compare the lengths 482 // of the implicit field path (Selection.Index) 483 // to see if the renaming would change it. 484 // 485 // If a selection that resolves to 'from', when renamed, 486 // would yield a path of the same or shorter length, 487 // this indicates ambiguity or a changed referent, 488 // analogous to same- or sub-block lexical conflict. 489 // 490 // If a selection using the name 'to' would 491 // yield a path of the same or shorter length, 492 // this indicates ambiguity or shadowing, 493 // analogous to same- or super-block lexical conflict. 494 495 // TODO(adonovan): fix: derive from Types[syntax.X].Mode 496 // TODO(adonovan): test with pointer, value, addressable value. 497 isAddressable := true 498 499 if sel.Obj() == from { 500 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil { 501 // Renaming this existing selection of 502 // 'from' may block access to an existing 503 // type member named 'to'. 504 delta := len(indices) - len(sel.Index()) 505 if delta > 0 { 506 continue // no ambiguity 507 } 508 r.selectionConflict(from, delta, syntax, obj) 509 return 510 } 511 } else if sel.Obj().Name() == r.to { 512 if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from { 513 // Renaming 'from' may cause this existing 514 // selection of the name 'to' to change 515 // its meaning. 516 delta := len(indices) - len(sel.Index()) 517 if delta > 0 { 518 continue // no ambiguity 519 } 520 r.selectionConflict(from, -delta, syntax, sel.Obj()) 521 return 522 } 523 } 524 } 525 } 526 } 527 528 func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) { 529 r.errorf(from.Pos(), "renaming this %s %q to %q", 530 objectKind(from), from.Name(), r.to) 531 532 switch { 533 case delta < 0: 534 // analogous to sub-block conflict 535 r.errorf(syntax.Sel.Pos(), 536 "\twould change the referent of this selection") 537 r.errorf(obj.Pos(), "\tof this %s", objectKind(obj)) 538 case delta == 0: 539 // analogous to same-block conflict 540 r.errorf(syntax.Sel.Pos(), 541 "\twould make this reference ambiguous") 542 r.errorf(obj.Pos(), "\twith this %s", objectKind(obj)) 543 case delta > 0: 544 // analogous to super-block conflict 545 r.errorf(syntax.Sel.Pos(), 546 "\twould shadow this selection") 547 r.errorf(obj.Pos(), "\tof the %s declared here", 548 objectKind(obj)) 549 } 550 } 551 552 // checkMethod performs safety checks for renaming a method. 553 // There are three hazards: 554 // - declaration conflicts 555 // - selection ambiguity/changes 556 // - entailed renamings of assignable concrete/interface types. 557 // We reject renamings initiated at concrete methods if it would 558 // change the assignability relation. For renamings of abstract 559 // methods, we rename all methods transitively coupled to it via 560 // assignability. 561 func (r *renamer) checkMethod(from *types.Func) { 562 // e.g. error.Error 563 if from.Pkg() == nil { 564 r.errorf(from.Pos(), "you cannot rename built-in method %s", from) 565 return 566 } 567 568 // ASSIGNABILITY: We reject renamings of concrete methods that 569 // would break a 'satisfy' constraint; but renamings of abstract 570 // methods are allowed to proceed, and we rename affected 571 // concrete and abstract methods as necessary. It is the 572 // initial method that determines the policy. 573 574 // Check for conflict at point of declaration. 575 // Check to ensure preservation of assignability requirements. 576 R := recv(from).Type() 577 if IsInterface(R) { 578 // Abstract method 579 580 // declaration 581 prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to) 582 if prev != nil { 583 r.errorf(from.Pos(), "renaming this interface method %q to %q", 584 from.Name(), r.to) 585 r.errorf(prev.Pos(), "\twould conflict with this method") 586 return 587 } 588 589 // Check all interfaces that embed this one for 590 // declaration conflicts too. 591 for _, pkg := range r.packages { 592 // Start with named interface types (better errors) 593 for _, obj := range pkg.GetTypesInfo().Defs { 594 if obj, ok := obj.(*types.TypeName); ok && IsInterface(obj.Type()) { 595 f, _, _ := types.LookupFieldOrMethod( 596 obj.Type(), false, from.Pkg(), from.Name()) 597 if f == nil { 598 continue 599 } 600 t, _, _ := types.LookupFieldOrMethod( 601 obj.Type(), false, from.Pkg(), r.to) 602 if t == nil { 603 continue 604 } 605 r.errorf(from.Pos(), "renaming this interface method %q to %q", 606 from.Name(), r.to) 607 r.errorf(t.Pos(), "\twould conflict with this method") 608 r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name()) 609 } 610 } 611 612 // Now look at all literal interface types (includes named ones again). 613 for e, tv := range pkg.GetTypesInfo().Types { 614 if e, ok := e.(*ast.InterfaceType); ok { 615 _ = e 616 _ = tv.Type.(*types.Interface) 617 // TODO(adonovan): implement same check as above. 618 } 619 } 620 } 621 622 // assignability 623 // 624 // Find the set of concrete or abstract methods directly 625 // coupled to abstract method 'from' by some 626 // satisfy.Constraint, and rename them too. 627 for key := range r.satisfy() { 628 // key = (lhs, rhs) where lhs is always an interface. 629 630 lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name()) 631 if lsel == nil { 632 continue 633 } 634 rmethods := r.msets.MethodSet(key.RHS) 635 rsel := rmethods.Lookup(from.Pkg(), from.Name()) 636 if rsel == nil { 637 continue 638 } 639 640 // If both sides have a method of this name, 641 // and one of them is m, the other must be coupled. 642 var coupled *types.Func 643 switch from { 644 case lsel.Obj(): 645 coupled = rsel.Obj().(*types.Func) 646 case rsel.Obj(): 647 coupled = lsel.Obj().(*types.Func) 648 default: 649 continue 650 } 651 652 // We must treat concrete-to-interface 653 // constraints like an implicit selection C.f of 654 // each interface method I.f, and check that the 655 // renaming leaves the selection unchanged and 656 // unambiguous. 657 // 658 // Fun fact: the implicit selection of C.f 659 // type I interface{f()} 660 // type C struct{I} 661 // func (C) g() 662 // var _ I = C{} // here 663 // yields abstract method I.f. This can make error 664 // messages less than obvious. 665 // 666 if !IsInterface(key.RHS) { 667 // The logic below was derived from checkSelections. 668 669 rtosel := rmethods.Lookup(from.Pkg(), r.to) 670 if rtosel != nil { 671 rto := rtosel.Obj().(*types.Func) 672 delta := len(rsel.Index()) - len(rtosel.Index()) 673 if delta < 0 { 674 continue // no ambiguity 675 } 676 677 // TODO(adonovan): record the constraint's position. 678 keyPos := token.NoPos 679 680 r.errorf(from.Pos(), "renaming this method %q to %q", 681 from.Name(), r.to) 682 if delta == 0 { 683 // analogous to same-block conflict 684 r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous", 685 r.to, key.RHS, key.LHS) 686 r.errorf(rto.Pos(), "\twith (%s).%s", 687 recv(rto).Type(), r.to) 688 } else { 689 // analogous to super-block conflict 690 r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s", 691 r.to, key.RHS, key.LHS) 692 r.errorf(coupled.Pos(), "\tfrom (%s).%s", 693 recv(coupled).Type(), r.to) 694 r.errorf(rto.Pos(), "\tto (%s).%s", 695 recv(rto).Type(), r.to) 696 } 697 return // one error is enough 698 } 699 } 700 701 if !r.changeMethods { 702 // This should be unreachable. 703 r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from) 704 r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled) 705 r.errorf(from.Pos(), "\tPlease file a bug report") 706 return 707 } 708 709 // Rename the coupled method to preserve assignability. 710 r.check(coupled) 711 } 712 } else { 713 // Concrete method 714 715 // declaration 716 prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to) 717 if prev != nil && len(indices) == 1 { 718 r.errorf(from.Pos(), "renaming this method %q to %q", 719 from.Name(), r.to) 720 r.errorf(prev.Pos(), "\twould conflict with this %s", 721 objectKind(prev)) 722 return 723 } 724 725 // assignability 726 // 727 // Find the set of abstract methods coupled to concrete 728 // method 'from' by some satisfy.Constraint, and rename 729 // them too. 730 // 731 // Coupling may be indirect, e.g. I.f <-> C.f via type D. 732 // 733 // type I interface {f()} 734 // type C int 735 // type (C) f() 736 // type D struct{C} 737 // var _ I = D{} 738 // 739 for key := range r.satisfy() { 740 // key = (lhs, rhs) where lhs is always an interface. 741 if IsInterface(key.RHS) { 742 continue 743 } 744 rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name()) 745 if rsel == nil || rsel.Obj() != from { 746 continue // rhs does not have the method 747 } 748 lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name()) 749 if lsel == nil { 750 continue 751 } 752 imeth := lsel.Obj().(*types.Func) 753 754 // imeth is the abstract method (e.g. I.f) 755 // and key.RHS is the concrete coupling type (e.g. D). 756 if !r.changeMethods { 757 r.errorf(from.Pos(), "renaming this method %q to %q", 758 from.Name(), r.to) 759 var pos token.Pos 760 var iface string 761 762 I := recv(imeth).Type() 763 if named, ok := I.(*types.Named); ok { 764 pos = named.Obj().Pos() 765 iface = "interface " + named.Obj().Name() 766 } else { 767 pos = from.Pos() 768 iface = I.String() 769 } 770 r.errorf(pos, "\twould make %s no longer assignable to %s", 771 key.RHS, iface) 772 r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)", 773 I, from.Name()) 774 return // one error is enough 775 } 776 777 // Rename the coupled interface method to preserve assignability. 778 r.check(imeth) 779 } 780 } 781 782 // Check integrity of existing (field and method) selections. 783 // We skip this if there were errors above, to avoid redundant errors. 784 r.checkSelections(from) 785 } 786 787 func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool { 788 // Reject cross-package references if r.to is unexported. 789 // (Such references may be qualified identifiers or field/method 790 // selections.) 791 if !ast.IsExported(r.to) && pkg != from.Pkg() { 792 r.errorf(from.Pos(), 793 "renaming %q to %q would make it unexported", 794 from.Name(), r.to) 795 r.errorf(id.Pos(), "\tbreaking references from packages such as %q", 796 pkg.Path()) 797 return false 798 } 799 return true 800 } 801 802 // satisfy returns the set of interface satisfaction constraints. 803 func (r *renamer) satisfy() map[satisfy.Constraint]bool { 804 if r.satisfyConstraints == nil { 805 // Compute on demand: it's expensive. 806 var f satisfy.Finder 807 for _, pkg := range r.packages { 808 // From satisfy.Finder documentation: 809 // 810 // The package must be free of type errors, and 811 // info.{Defs,Uses,Selections,Types} must have been populated by the 812 // type-checker. 813 // 814 // Only proceed if all packages have no errors. 815 if pkg.HasListOrParseErrors() || pkg.HasTypeErrors() { 816 r.errorf(token.NoPos, // we don't have a position for this error. 817 "renaming %q to %q not possible because %q has errors", 818 r.from, r.to, pkg.PkgPath()) 819 return nil 820 } 821 f.Find(pkg.GetTypesInfo(), pkg.GetSyntax()) 822 } 823 r.satisfyConstraints = f.Result 824 } 825 return r.satisfyConstraints 826 } 827 828 // -- helpers ---------------------------------------------------------- 829 830 // recv returns the method's receiver. 831 func recv(meth *types.Func) *types.Var { 832 return meth.Type().(*types.Signature).Recv() 833 } 834 835 // someUse returns an arbitrary use of obj within info. 836 func someUse(info *types.Info, obj types.Object) *ast.Ident { 837 for id, o := range info.Uses { 838 if o == obj { 839 return id 840 } 841 } 842 return nil 843 } 844 845 // pathEnclosingInterval returns the Package and ast.Node that 846 // contain source interval [start, end), and all the node's ancestors 847 // up to the AST root. It searches all ast.Files of all packages. 848 // exact is defined as for astutil.PathEnclosingInterval. 849 // 850 // The zero value is returned if not found. 851 // 852 func pathEnclosingInterval(fset *token.FileSet, pkg Package, start, end token.Pos) (resPkg Package, path []ast.Node, exact bool) { 853 pkgs := []Package{pkg} 854 for _, f := range pkg.GetSyntax() { 855 for _, imp := range f.Imports { 856 if imp == nil { 857 continue 858 } 859 importPath, err := strconv.Unquote(imp.Path.Value) 860 if err != nil { 861 continue 862 } 863 importPkg, err := pkg.GetImport(importPath) 864 if err != nil { 865 return nil, nil, false 866 } 867 pkgs = append(pkgs, importPkg) 868 } 869 } 870 for _, p := range pkgs { 871 for _, f := range p.GetSyntax() { 872 if f.Pos() == token.NoPos { 873 // This can happen if the parser saw 874 // too many errors and bailed out. 875 // (Use parser.AllErrors to prevent that.) 876 continue 877 } 878 if !tokenFileContainsPos(fset.File(f.Pos()), start) { 879 continue 880 } 881 if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil { 882 return pkg, path, exact 883 } 884 } 885 } 886 return nil, nil, false 887 } 888 889 // TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos) 890 func tokenFileContainsPos(f *token.File, pos token.Pos) bool { 891 p := int(pos) 892 base := f.Base() 893 return base <= p && p < base+f.Size() 894 } 895 896 func objectKind(obj types.Object) string { 897 if obj == nil { 898 return "nil object" 899 } 900 switch obj := obj.(type) { 901 case *types.PkgName: 902 return "imported package name" 903 case *types.TypeName: 904 return "type" 905 case *types.Var: 906 if obj.IsField() { 907 return "field" 908 } 909 case *types.Func: 910 if obj.Type().(*types.Signature).Recv() != nil { 911 return "method" 912 } 913 } 914 // label, func, var, const 915 return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) 916 } 917 918 // NB: for renamings, blank is not considered valid. 919 func isValidIdentifier(id string) bool { 920 if id == "" || id == "_" { 921 return false 922 } 923 for i, r := range id { 924 if !isLetter(r) && (i == 0 || !isDigit(r)) { 925 return false 926 } 927 } 928 return token.Lookup(id) == token.IDENT 929 } 930 931 // isLocal reports whether obj is local to some function. 932 // Precondition: not a struct field or interface method. 933 func isLocal(obj types.Object) bool { 934 // [... 5=stmt 4=func 3=file 2=pkg 1=universe] 935 var depth int 936 for scope := obj.Parent(); scope != nil; scope = scope.Parent() { 937 depth++ 938 } 939 return depth >= 4 940 } 941 942 func isPackageLevel(obj types.Object) bool { 943 if obj == nil { 944 return false 945 } 946 return obj.Pkg().Scope().Lookup(obj.Name()) == obj 947 } 948 949 // -- Plundered from go/scanner: --------------------------------------- 950 951 func isLetter(ch rune) bool { 952 return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) 953 } 954 955 func isDigit(ch rune) bool { 956 return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) 957 }