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