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