.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / source / rename_check.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/rename_check.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/source/rename_check.go
new file mode 100644 (file)
index 0000000..a46254c
--- /dev/null
@@ -0,0 +1,957 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Taken from golang.org/x/tools/refactor/rename.
+
+package source
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+       "go/types"
+       "reflect"
+       "strconv"
+       "strings"
+       "unicode"
+
+       "golang.org/x/tools/go/ast/astutil"
+       "golang.org/x/tools/refactor/satisfy"
+)
+
+// errorf reports an error (e.g. conflict) and prevents file modification.
+func (r *renamer) errorf(pos token.Pos, format string, args ...interface{}) {
+       r.hadConflicts = true
+       r.errors += fmt.Sprintf(format, args...)
+}
+
+// check performs safety checks of the renaming of the 'from' object to r.to.
+func (r *renamer) check(from types.Object) {
+       if r.objsToUpdate[from] {
+               return
+       }
+       r.objsToUpdate[from] = true
+
+       // NB: order of conditions is important.
+       if from_, ok := from.(*types.PkgName); ok {
+               r.checkInFileBlock(from_)
+       } else if from_, ok := from.(*types.Label); ok {
+               r.checkLabel(from_)
+       } else if isPackageLevel(from) {
+               r.checkInPackageBlock(from)
+       } else if v, ok := from.(*types.Var); ok && v.IsField() {
+               r.checkStructField(v)
+       } else if f, ok := from.(*types.Func); ok && recv(f) != nil {
+               r.checkMethod(f)
+       } else if isLocal(from) {
+               r.checkInLocalScope(from)
+       } else {
+               r.errorf(from.Pos(), "unexpected %s object %q (please report a bug)\n",
+                       objectKind(from), from)
+       }
+}
+
+// checkInFileBlock performs safety checks for renames of objects in the file block,
+// i.e. imported package names.
+func (r *renamer) checkInFileBlock(from *types.PkgName) {
+       // Check import name is not "init".
+       if r.to == "init" {
+               r.errorf(from.Pos(), "%q is not a valid imported package name", r.to)
+       }
+
+       // Check for conflicts between file and package block.
+       if prev := from.Pkg().Scope().Lookup(r.to); prev != nil {
+               r.errorf(from.Pos(), "renaming this %s %q to %q would conflict",
+                       objectKind(from), from.Name(), r.to)
+               r.errorf(prev.Pos(), "\twith this package member %s",
+                       objectKind(prev))
+               return // since checkInPackageBlock would report redundant errors
+       }
+
+       // Check for conflicts in lexical scope.
+       r.checkInLexicalScope(from, r.packages[from.Pkg()])
+}
+
+// checkInPackageBlock performs safety checks for renames of
+// func/var/const/type objects in the package block.
+func (r *renamer) checkInPackageBlock(from types.Object) {
+       // Check that there are no references to the name from another
+       // package if the renaming would make it unexported.
+       if ast.IsExported(from.Name()) && !ast.IsExported(r.to) {
+               for typ, pkg := range r.packages {
+                       if typ == from.Pkg() {
+                               continue
+                       }
+                       if id := someUse(pkg.GetTypesInfo(), from); id != nil &&
+                               !r.checkExport(id, typ, from) {
+                               break
+                       }
+               }
+       }
+
+       pkg := r.packages[from.Pkg()]
+       if pkg == nil {
+               return
+       }
+
+       // Check that in the package block, "init" is a function, and never referenced.
+       if r.to == "init" {
+               kind := objectKind(from)
+               if kind == "func" {
+                       // Reject if intra-package references to it exist.
+                       for id, obj := range pkg.GetTypesInfo().Uses {
+                               if obj == from {
+                                       r.errorf(from.Pos(),
+                                               "renaming this func %q to %q would make it a package initializer",
+                                               from.Name(), r.to)
+                                       r.errorf(id.Pos(), "\tbut references to it exist")
+                                       break
+                               }
+                       }
+               } else {
+                       r.errorf(from.Pos(), "you cannot have a %s at package level named %q",
+                               kind, r.to)
+               }
+       }
+
+       // Check for conflicts between package block and all file blocks.
+       for _, f := range pkg.GetSyntax() {
+               fileScope := pkg.GetTypesInfo().Scopes[f]
+               b, prev := fileScope.LookupParent(r.to, token.NoPos)
+               if b == fileScope {
+                       r.errorf(from.Pos(), "renaming this %s %q to %q would conflict", objectKind(from), from.Name(), r.to)
+                       var prevPos token.Pos
+                       if prev != nil {
+                               prevPos = prev.Pos()
+                       }
+                       r.errorf(prevPos, "\twith this %s", objectKind(prev))
+                       return // since checkInPackageBlock would report redundant errors
+               }
+       }
+
+       // Check for conflicts in lexical scope.
+       if from.Exported() {
+               for _, pkg := range r.packages {
+                       r.checkInLexicalScope(from, pkg)
+               }
+       } else {
+               r.checkInLexicalScope(from, pkg)
+       }
+}
+
+func (r *renamer) checkInLocalScope(from types.Object) {
+       pkg := r.packages[from.Pkg()]
+       r.checkInLexicalScope(from, pkg)
+}
+
+// checkInLexicalScope performs safety checks that a renaming does not
+// change the lexical reference structure of the specified package.
+//
+// For objects in lexical scope, there are three kinds of conflicts:
+// same-, sub-, and super-block conflicts.  We will illustrate all three
+// using this example:
+//
+//     var x int
+//     var z int
+//
+//     func f(y int) {
+//             print(x)
+//             print(y)
+//     }
+//
+// Renaming x to z encounters a SAME-BLOCK CONFLICT, because an object
+// with the new name already exists, defined in the same lexical block
+// as the old object.
+//
+// Renaming x to y encounters a SUB-BLOCK CONFLICT, because there exists
+// a reference to x from within (what would become) a hole in its scope.
+// The definition of y in an (inner) sub-block would cast a shadow in
+// the scope of the renamed variable.
+//
+// Renaming y to x encounters a SUPER-BLOCK CONFLICT.  This is the
+// converse situation: there is an existing definition of the new name
+// (x) in an (enclosing) super-block, and the renaming would create a
+// hole in its scope, within which there exist references to it.  The
+// new name casts a shadow in scope of the existing definition of x in
+// the super-block.
+//
+// Removing the old name (and all references to it) is always safe, and
+// requires no checks.
+//
+func (r *renamer) checkInLexicalScope(from types.Object, pkg Package) {
+       b := from.Parent() // the block defining the 'from' object
+       if b != nil {
+               toBlock, to := b.LookupParent(r.to, from.Parent().End())
+               if toBlock == b {
+                       // same-block conflict
+                       r.errorf(from.Pos(), "renaming this %s %q to %q",
+                               objectKind(from), from.Name(), r.to)
+                       r.errorf(to.Pos(), "\tconflicts with %s in same block",
+                               objectKind(to))
+                       return
+               } else if toBlock != nil {
+                       // Check for super-block conflict.
+                       // The name r.to is defined in a superblock.
+                       // Is that name referenced from within this block?
+                       forEachLexicalRef(pkg, to, func(id *ast.Ident, block *types.Scope) bool {
+                               _, obj := lexicalLookup(block, from.Name(), id.Pos())
+                               if obj == from {
+                                       // super-block conflict
+                                       r.errorf(from.Pos(), "renaming this %s %q to %q",
+                                               objectKind(from), from.Name(), r.to)
+                                       r.errorf(id.Pos(), "\twould shadow this reference")
+                                       r.errorf(to.Pos(), "\tto the %s declared here",
+                                               objectKind(to))
+                                       return false // stop
+                               }
+                               return true
+                       })
+               }
+       }
+       // Check for sub-block conflict.
+       // Is there an intervening definition of r.to between
+       // the block defining 'from' and some reference to it?
+       forEachLexicalRef(pkg, from, func(id *ast.Ident, block *types.Scope) bool {
+               // Find the block that defines the found reference.
+               // It may be an ancestor.
+               fromBlock, _ := lexicalLookup(block, from.Name(), id.Pos())
+
+               // See what r.to would resolve to in the same scope.
+               toBlock, to := lexicalLookup(block, r.to, id.Pos())
+               if to != nil {
+                       // sub-block conflict
+                       if deeper(toBlock, fromBlock) {
+                               r.errorf(from.Pos(), "renaming this %s %q to %q",
+                                       objectKind(from), from.Name(), r.to)
+                               r.errorf(id.Pos(), "\twould cause this reference to become shadowed")
+                               r.errorf(to.Pos(), "\tby this intervening %s definition",
+                                       objectKind(to))
+                               return false // stop
+                       }
+               }
+               return true
+       })
+
+       // Renaming a type that is used as an embedded field
+       // requires renaming the field too. e.g.
+       //      type T int // if we rename this to U..
+       //      var s struct {T}
+       //      print(s.T) // ...this must change too
+       if _, ok := from.(*types.TypeName); ok {
+               for id, obj := range pkg.GetTypesInfo().Uses {
+                       if obj == from {
+                               if field := pkg.GetTypesInfo().Defs[id]; field != nil {
+                                       r.check(field)
+                               }
+                       }
+               }
+       }
+}
+
+// lexicalLookup is like (*types.Scope).LookupParent but respects the
+// environment visible at pos.  It assumes the relative position
+// information is correct with each file.
+func lexicalLookup(block *types.Scope, name string, pos token.Pos) (*types.Scope, types.Object) {
+       for b := block; b != nil; b = b.Parent() {
+               obj := b.Lookup(name)
+               // The scope of a package-level object is the entire package,
+               // so ignore pos in that case.
+               // No analogous clause is needed for file-level objects
+               // since no reference can appear before an import decl.
+               if obj == nil || obj.Pkg() == nil {
+                       continue
+               }
+               if b == obj.Pkg().Scope() || obj.Pos() < pos {
+                       return b, obj
+               }
+       }
+       return nil, nil
+}
+
+// deeper reports whether block x is lexically deeper than y.
+func deeper(x, y *types.Scope) bool {
+       if x == y || x == nil {
+               return false
+       } else if y == nil {
+               return true
+       } else {
+               return deeper(x.Parent(), y.Parent())
+       }
+}
+
+// forEachLexicalRef calls fn(id, block) for each identifier id in package
+// pkg that is a reference to obj in lexical scope.  block is the
+// lexical block enclosing the reference.  If fn returns false the
+// iteration is terminated and findLexicalRefs returns false.
+func forEachLexicalRef(pkg Package, obj types.Object, fn func(id *ast.Ident, block *types.Scope) bool) bool {
+       ok := true
+       var stack []ast.Node
+
+       var visit func(n ast.Node) bool
+       visit = func(n ast.Node) bool {
+               if n == nil {
+                       stack = stack[:len(stack)-1] // pop
+                       return false
+               }
+               if !ok {
+                       return false // bail out
+               }
+
+               stack = append(stack, n) // push
+               switch n := n.(type) {
+               case *ast.Ident:
+                       if pkg.GetTypesInfo().Uses[n] == obj {
+                               block := enclosingBlock(pkg.GetTypesInfo(), stack)
+                               if !fn(n, block) {
+                                       ok = false
+                               }
+                       }
+                       return visit(nil) // pop stack
+
+               case *ast.SelectorExpr:
+                       // don't visit n.Sel
+                       ast.Inspect(n.X, visit)
+                       return visit(nil) // pop stack, don't descend
+
+               case *ast.CompositeLit:
+                       // Handle recursion ourselves for struct literals
+                       // so we don't visit field identifiers.
+                       tv, ok := pkg.GetTypesInfo().Types[n]
+                       if !ok {
+                               return visit(nil) // pop stack, don't descend
+                       }
+                       if _, ok := Deref(tv.Type).Underlying().(*types.Struct); ok {
+                               if n.Type != nil {
+                                       ast.Inspect(n.Type, visit)
+                               }
+                               for _, elt := range n.Elts {
+                                       if kv, ok := elt.(*ast.KeyValueExpr); ok {
+                                               ast.Inspect(kv.Value, visit)
+                                       } else {
+                                               ast.Inspect(elt, visit)
+                                       }
+                               }
+                               return visit(nil) // pop stack, don't descend
+                       }
+               }
+               return true
+       }
+
+       for _, f := range pkg.GetSyntax() {
+               ast.Inspect(f, visit)
+               if len(stack) != 0 {
+                       panic(stack)
+               }
+               if !ok {
+                       break
+               }
+       }
+       return ok
+}
+
+// enclosingBlock returns the innermost block enclosing the specified
+// AST node, specified in the form of a path from the root of the file,
+// [file...n].
+func enclosingBlock(info *types.Info, stack []ast.Node) *types.Scope {
+       for i := range stack {
+               n := stack[len(stack)-1-i]
+               // For some reason, go/types always associates a
+               // function's scope with its FuncType.
+               // TODO(adonovan): feature or a bug?
+               switch f := n.(type) {
+               case *ast.FuncDecl:
+                       n = f.Type
+               case *ast.FuncLit:
+                       n = f.Type
+               }
+               if b := info.Scopes[n]; b != nil {
+                       return b
+               }
+       }
+       panic("no Scope for *ast.File")
+}
+
+func (r *renamer) checkLabel(label *types.Label) {
+       // Check there are no identical labels in the function's label block.
+       // (Label blocks don't nest, so this is easy.)
+       if prev := label.Parent().Lookup(r.to); prev != nil {
+               r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name())
+               r.errorf(prev.Pos(), "\twould conflict with this one")
+       }
+}
+
+// checkStructField checks that the field renaming will not cause
+// conflicts at its declaration, or ambiguity or changes to any selection.
+func (r *renamer) checkStructField(from *types.Var) {
+       // Check that the struct declaration is free of field conflicts,
+       // and field/method conflicts.
+
+       // go/types offers no easy way to get from a field (or interface
+       // method) to its declaring struct (or interface), so we must
+       // ascend the AST.
+       fromPkg, ok := r.packages[from.Pkg()]
+       if !ok {
+               return
+       }
+       pkg, path, _ := pathEnclosingInterval(r.fset, fromPkg, from.Pos(), from.Pos())
+       if pkg == nil || path == nil {
+               return
+       }
+       // path matches this pattern:
+       // [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
+
+       // Ascend to FieldList.
+       var i int
+       for {
+               if _, ok := path[i].(*ast.FieldList); ok {
+                       break
+               }
+               i++
+       }
+       i++
+       tStruct := path[i].(*ast.StructType)
+       i++
+       // Ascend past parens (unlikely).
+       for {
+               _, ok := path[i].(*ast.ParenExpr)
+               if !ok {
+                       break
+               }
+               i++
+       }
+       if spec, ok := path[i].(*ast.TypeSpec); ok {
+               // This struct is also a named type.
+               // We must check for direct (non-promoted) field/field
+               // and method/field conflicts.
+               named := pkg.GetTypesInfo().Defs[spec.Name].Type()
+               prev, indices, _ := types.LookupFieldOrMethod(named, true, pkg.GetTypes(), r.to)
+               if len(indices) == 1 {
+                       r.errorf(from.Pos(), "renaming this field %q to %q",
+                               from.Name(), r.to)
+                       r.errorf(prev.Pos(), "\twould conflict with this %s",
+                               objectKind(prev))
+                       return // skip checkSelections to avoid redundant errors
+               }
+       } else {
+               // This struct is not a named type.
+               // We need only check for direct (non-promoted) field/field conflicts.
+               T := pkg.GetTypesInfo().Types[tStruct].Type.Underlying().(*types.Struct)
+               for i := 0; i < T.NumFields(); i++ {
+                       if prev := T.Field(i); prev.Name() == r.to {
+                               r.errorf(from.Pos(), "renaming this field %q to %q",
+                                       from.Name(), r.to)
+                               r.errorf(prev.Pos(), "\twould conflict with this field")
+                               return // skip checkSelections to avoid redundant errors
+                       }
+               }
+       }
+
+       // Renaming an anonymous field requires renaming the type too. e.g.
+       //      print(s.T)       // if we rename T to U,
+       //      type T int       // this and
+       //      var s struct {T} // this must change too.
+       if from.Anonymous() {
+               if named, ok := from.Type().(*types.Named); ok {
+                       r.check(named.Obj())
+               } else if named, ok := Deref(from.Type()).(*types.Named); ok {
+                       r.check(named.Obj())
+               }
+       }
+
+       // Check integrity of existing (field and method) selections.
+       r.checkSelections(from)
+}
+
+// checkSelection checks that all uses and selections that resolve to
+// the specified object would continue to do so after the renaming.
+func (r *renamer) checkSelections(from types.Object) {
+       for typ, pkg := range r.packages {
+               if id := someUse(pkg.GetTypesInfo(), from); id != nil {
+                       if !r.checkExport(id, typ, from) {
+                               return
+                       }
+               }
+
+               for syntax, sel := range pkg.GetTypesInfo().Selections {
+                       // There may be extant selections of only the old
+                       // name or only the new name, so we must check both.
+                       // (If neither, the renaming is sound.)
+                       //
+                       // In both cases, we wish to compare the lengths
+                       // of the implicit field path (Selection.Index)
+                       // to see if the renaming would change it.
+                       //
+                       // If a selection that resolves to 'from', when renamed,
+                       // would yield a path of the same or shorter length,
+                       // this indicates ambiguity or a changed referent,
+                       // analogous to same- or sub-block lexical conflict.
+                       //
+                       // If a selection using the name 'to' would
+                       // yield a path of the same or shorter length,
+                       // this indicates ambiguity or shadowing,
+                       // analogous to same- or super-block lexical conflict.
+
+                       // TODO(adonovan): fix: derive from Types[syntax.X].Mode
+                       // TODO(adonovan): test with pointer, value, addressable value.
+                       isAddressable := true
+
+                       if sel.Obj() == from {
+                               if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), r.to); obj != nil {
+                                       // Renaming this existing selection of
+                                       // 'from' may block access to an existing
+                                       // type member named 'to'.
+                                       delta := len(indices) - len(sel.Index())
+                                       if delta > 0 {
+                                               continue // no ambiguity
+                                       }
+                                       r.selectionConflict(from, delta, syntax, obj)
+                                       return
+                               }
+                       } else if sel.Obj().Name() == r.to {
+                               if obj, indices, _ := types.LookupFieldOrMethod(sel.Recv(), isAddressable, from.Pkg(), from.Name()); obj == from {
+                                       // Renaming 'from' may cause this existing
+                                       // selection of the name 'to' to change
+                                       // its meaning.
+                                       delta := len(indices) - len(sel.Index())
+                                       if delta > 0 {
+                                               continue //  no ambiguity
+                                       }
+                                       r.selectionConflict(from, -delta, syntax, sel.Obj())
+                                       return
+                               }
+                       }
+               }
+       }
+}
+
+func (r *renamer) selectionConflict(from types.Object, delta int, syntax *ast.SelectorExpr, obj types.Object) {
+       r.errorf(from.Pos(), "renaming this %s %q to %q",
+               objectKind(from), from.Name(), r.to)
+
+       switch {
+       case delta < 0:
+               // analogous to sub-block conflict
+               r.errorf(syntax.Sel.Pos(),
+                       "\twould change the referent of this selection")
+               r.errorf(obj.Pos(), "\tof this %s", objectKind(obj))
+       case delta == 0:
+               // analogous to same-block conflict
+               r.errorf(syntax.Sel.Pos(),
+                       "\twould make this reference ambiguous")
+               r.errorf(obj.Pos(), "\twith this %s", objectKind(obj))
+       case delta > 0:
+               // analogous to super-block conflict
+               r.errorf(syntax.Sel.Pos(),
+                       "\twould shadow this selection")
+               r.errorf(obj.Pos(), "\tof the %s declared here",
+                       objectKind(obj))
+       }
+}
+
+// checkMethod performs safety checks for renaming a method.
+// There are three hazards:
+// - declaration conflicts
+// - selection ambiguity/changes
+// - entailed renamings of assignable concrete/interface types.
+//   We reject renamings initiated at concrete methods if it would
+//   change the assignability relation.  For renamings of abstract
+//   methods, we rename all methods transitively coupled to it via
+//   assignability.
+func (r *renamer) checkMethod(from *types.Func) {
+       // e.g. error.Error
+       if from.Pkg() == nil {
+               r.errorf(from.Pos(), "you cannot rename built-in method %s", from)
+               return
+       }
+
+       // ASSIGNABILITY: We reject renamings of concrete methods that
+       // would break a 'satisfy' constraint; but renamings of abstract
+       // methods are allowed to proceed, and we rename affected
+       // concrete and abstract methods as necessary.  It is the
+       // initial method that determines the policy.
+
+       // Check for conflict at point of declaration.
+       // Check to ensure preservation of assignability requirements.
+       R := recv(from).Type()
+       if IsInterface(R) {
+               // Abstract method
+
+               // declaration
+               prev, _, _ := types.LookupFieldOrMethod(R, false, from.Pkg(), r.to)
+               if prev != nil {
+                       r.errorf(from.Pos(), "renaming this interface method %q to %q",
+                               from.Name(), r.to)
+                       r.errorf(prev.Pos(), "\twould conflict with this method")
+                       return
+               }
+
+               // Check all interfaces that embed this one for
+               // declaration conflicts too.
+               for _, pkg := range r.packages {
+                       // Start with named interface types (better errors)
+                       for _, obj := range pkg.GetTypesInfo().Defs {
+                               if obj, ok := obj.(*types.TypeName); ok && IsInterface(obj.Type()) {
+                                       f, _, _ := types.LookupFieldOrMethod(
+                                               obj.Type(), false, from.Pkg(), from.Name())
+                                       if f == nil {
+                                               continue
+                                       }
+                                       t, _, _ := types.LookupFieldOrMethod(
+                                               obj.Type(), false, from.Pkg(), r.to)
+                                       if t == nil {
+                                               continue
+                                       }
+                                       r.errorf(from.Pos(), "renaming this interface method %q to %q",
+                                               from.Name(), r.to)
+                                       r.errorf(t.Pos(), "\twould conflict with this method")
+                                       r.errorf(obj.Pos(), "\tin named interface type %q", obj.Name())
+                               }
+                       }
+
+                       // Now look at all literal interface types (includes named ones again).
+                       for e, tv := range pkg.GetTypesInfo().Types {
+                               if e, ok := e.(*ast.InterfaceType); ok {
+                                       _ = e
+                                       _ = tv.Type.(*types.Interface)
+                                       // TODO(adonovan): implement same check as above.
+                               }
+                       }
+               }
+
+               // assignability
+               //
+               // Find the set of concrete or abstract methods directly
+               // coupled to abstract method 'from' by some
+               // satisfy.Constraint, and rename them too.
+               for key := range r.satisfy() {
+                       // key = (lhs, rhs) where lhs is always an interface.
+
+                       lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
+                       if lsel == nil {
+                               continue
+                       }
+                       rmethods := r.msets.MethodSet(key.RHS)
+                       rsel := rmethods.Lookup(from.Pkg(), from.Name())
+                       if rsel == nil {
+                               continue
+                       }
+
+                       // If both sides have a method of this name,
+                       // and one of them is m, the other must be coupled.
+                       var coupled *types.Func
+                       switch from {
+                       case lsel.Obj():
+                               coupled = rsel.Obj().(*types.Func)
+                       case rsel.Obj():
+                               coupled = lsel.Obj().(*types.Func)
+                       default:
+                               continue
+                       }
+
+                       // We must treat concrete-to-interface
+                       // constraints like an implicit selection C.f of
+                       // each interface method I.f, and check that the
+                       // renaming leaves the selection unchanged and
+                       // unambiguous.
+                       //
+                       // Fun fact: the implicit selection of C.f
+                       //      type I interface{f()}
+                       //      type C struct{I}
+                       //      func (C) g()
+                       //      var _ I = C{} // here
+                       // yields abstract method I.f.  This can make error
+                       // messages less than obvious.
+                       //
+                       if !IsInterface(key.RHS) {
+                               // The logic below was derived from checkSelections.
+
+                               rtosel := rmethods.Lookup(from.Pkg(), r.to)
+                               if rtosel != nil {
+                                       rto := rtosel.Obj().(*types.Func)
+                                       delta := len(rsel.Index()) - len(rtosel.Index())
+                                       if delta < 0 {
+                                               continue // no ambiguity
+                                       }
+
+                                       // TODO(adonovan): record the constraint's position.
+                                       keyPos := token.NoPos
+
+                                       r.errorf(from.Pos(), "renaming this method %q to %q",
+                                               from.Name(), r.to)
+                                       if delta == 0 {
+                                               // analogous to same-block conflict
+                                               r.errorf(keyPos, "\twould make the %s method of %s invoked via interface %s ambiguous",
+                                                       r.to, key.RHS, key.LHS)
+                                               r.errorf(rto.Pos(), "\twith (%s).%s",
+                                                       recv(rto).Type(), r.to)
+                                       } else {
+                                               // analogous to super-block conflict
+                                               r.errorf(keyPos, "\twould change the %s method of %s invoked via interface %s",
+                                                       r.to, key.RHS, key.LHS)
+                                               r.errorf(coupled.Pos(), "\tfrom (%s).%s",
+                                                       recv(coupled).Type(), r.to)
+                                               r.errorf(rto.Pos(), "\tto (%s).%s",
+                                                       recv(rto).Type(), r.to)
+                                       }
+                                       return // one error is enough
+                               }
+                       }
+
+                       if !r.changeMethods {
+                               // This should be unreachable.
+                               r.errorf(from.Pos(), "internal error: during renaming of abstract method %s", from)
+                               r.errorf(coupled.Pos(), "\tchangedMethods=false, coupled method=%s", coupled)
+                               r.errorf(from.Pos(), "\tPlease file a bug report")
+                               return
+                       }
+
+                       // Rename the coupled method to preserve assignability.
+                       r.check(coupled)
+               }
+       } else {
+               // Concrete method
+
+               // declaration
+               prev, indices, _ := types.LookupFieldOrMethod(R, true, from.Pkg(), r.to)
+               if prev != nil && len(indices) == 1 {
+                       r.errorf(from.Pos(), "renaming this method %q to %q",
+                               from.Name(), r.to)
+                       r.errorf(prev.Pos(), "\twould conflict with this %s",
+                               objectKind(prev))
+                       return
+               }
+
+               // assignability
+               //
+               // Find the set of abstract methods coupled to concrete
+               // method 'from' by some satisfy.Constraint, and rename
+               // them too.
+               //
+               // Coupling may be indirect, e.g. I.f <-> C.f via type D.
+               //
+               //      type I interface {f()}
+               //      type C int
+               //      type (C) f()
+               //      type D struct{C}
+               //      var _ I = D{}
+               //
+               for key := range r.satisfy() {
+                       // key = (lhs, rhs) where lhs is always an interface.
+                       if IsInterface(key.RHS) {
+                               continue
+                       }
+                       rsel := r.msets.MethodSet(key.RHS).Lookup(from.Pkg(), from.Name())
+                       if rsel == nil || rsel.Obj() != from {
+                               continue // rhs does not have the method
+                       }
+                       lsel := r.msets.MethodSet(key.LHS).Lookup(from.Pkg(), from.Name())
+                       if lsel == nil {
+                               continue
+                       }
+                       imeth := lsel.Obj().(*types.Func)
+
+                       // imeth is the abstract method (e.g. I.f)
+                       // and key.RHS is the concrete coupling type (e.g. D).
+                       if !r.changeMethods {
+                               r.errorf(from.Pos(), "renaming this method %q to %q",
+                                       from.Name(), r.to)
+                               var pos token.Pos
+                               var iface string
+
+                               I := recv(imeth).Type()
+                               if named, ok := I.(*types.Named); ok {
+                                       pos = named.Obj().Pos()
+                                       iface = "interface " + named.Obj().Name()
+                               } else {
+                                       pos = from.Pos()
+                                       iface = I.String()
+                               }
+                               r.errorf(pos, "\twould make %s no longer assignable to %s",
+                                       key.RHS, iface)
+                               r.errorf(imeth.Pos(), "\t(rename %s.%s if you intend to change both types)",
+                                       I, from.Name())
+                               return // one error is enough
+                       }
+
+                       // Rename the coupled interface method to preserve assignability.
+                       r.check(imeth)
+               }
+       }
+
+       // Check integrity of existing (field and method) selections.
+       // We skip this if there were errors above, to avoid redundant errors.
+       r.checkSelections(from)
+}
+
+func (r *renamer) checkExport(id *ast.Ident, pkg *types.Package, from types.Object) bool {
+       // Reject cross-package references if r.to is unexported.
+       // (Such references may be qualified identifiers or field/method
+       // selections.)
+       if !ast.IsExported(r.to) && pkg != from.Pkg() {
+               r.errorf(from.Pos(),
+                       "renaming %q to %q would make it unexported",
+                       from.Name(), r.to)
+               r.errorf(id.Pos(), "\tbreaking references from packages such as %q",
+                       pkg.Path())
+               return false
+       }
+       return true
+}
+
+// satisfy returns the set of interface satisfaction constraints.
+func (r *renamer) satisfy() map[satisfy.Constraint]bool {
+       if r.satisfyConstraints == nil {
+               // Compute on demand: it's expensive.
+               var f satisfy.Finder
+               for _, pkg := range r.packages {
+                       // From satisfy.Finder documentation:
+                       //
+                       // The package must be free of type errors, and
+                       // info.{Defs,Uses,Selections,Types} must have been populated by the
+                       // type-checker.
+                       //
+                       // Only proceed if all packages have no errors.
+                       if pkg.HasListOrParseErrors() || pkg.HasTypeErrors() {
+                               r.errorf(token.NoPos, // we don't have a position for this error.
+                                       "renaming %q to %q not possible because %q has errors",
+                                       r.from, r.to, pkg.PkgPath())
+                               return nil
+                       }
+                       f.Find(pkg.GetTypesInfo(), pkg.GetSyntax())
+               }
+               r.satisfyConstraints = f.Result
+       }
+       return r.satisfyConstraints
+}
+
+// -- helpers ----------------------------------------------------------
+
+// recv returns the method's receiver.
+func recv(meth *types.Func) *types.Var {
+       return meth.Type().(*types.Signature).Recv()
+}
+
+// someUse returns an arbitrary use of obj within info.
+func someUse(info *types.Info, obj types.Object) *ast.Ident {
+       for id, o := range info.Uses {
+               if o == obj {
+                       return id
+               }
+       }
+       return nil
+}
+
+// pathEnclosingInterval returns the Package and ast.Node that
+// contain source interval [start, end), and all the node's ancestors
+// up to the AST root.  It searches all ast.Files of all packages.
+// exact is defined as for astutil.PathEnclosingInterval.
+//
+// The zero value is returned if not found.
+//
+func pathEnclosingInterval(fset *token.FileSet, pkg Package, start, end token.Pos) (resPkg Package, path []ast.Node, exact bool) {
+       pkgs := []Package{pkg}
+       for _, f := range pkg.GetSyntax() {
+               for _, imp := range f.Imports {
+                       if imp == nil {
+                               continue
+                       }
+                       importPath, err := strconv.Unquote(imp.Path.Value)
+                       if err != nil {
+                               continue
+                       }
+                       importPkg, err := pkg.GetImport(importPath)
+                       if err != nil {
+                               return nil, nil, false
+                       }
+                       pkgs = append(pkgs, importPkg)
+               }
+       }
+       for _, p := range pkgs {
+               for _, f := range p.GetSyntax() {
+                       if f.Pos() == token.NoPos {
+                               // This can happen if the parser saw
+                               // too many errors and bailed out.
+                               // (Use parser.AllErrors to prevent that.)
+                               continue
+                       }
+                       if !tokenFileContainsPos(fset.File(f.Pos()), start) {
+                               continue
+                       }
+                       if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
+                               return pkg, path, exact
+                       }
+               }
+       }
+       return nil, nil, false
+}
+
+// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
+func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
+       p := int(pos)
+       base := f.Base()
+       return base <= p && p < base+f.Size()
+}
+
+func objectKind(obj types.Object) string {
+       if obj == nil {
+               return "nil object"
+       }
+       switch obj := obj.(type) {
+       case *types.PkgName:
+               return "imported package name"
+       case *types.TypeName:
+               return "type"
+       case *types.Var:
+               if obj.IsField() {
+                       return "field"
+               }
+       case *types.Func:
+               if obj.Type().(*types.Signature).Recv() != nil {
+                       return "method"
+               }
+       }
+       // label, func, var, const
+       return strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
+}
+
+// NB: for renamings, blank is not considered valid.
+func isValidIdentifier(id string) bool {
+       if id == "" || id == "_" {
+               return false
+       }
+       for i, r := range id {
+               if !isLetter(r) && (i == 0 || !isDigit(r)) {
+                       return false
+               }
+       }
+       return token.Lookup(id) == token.IDENT
+}
+
+// isLocal reports whether obj is local to some function.
+// Precondition: not a struct field or interface method.
+func isLocal(obj types.Object) bool {
+       // [... 5=stmt 4=func 3=file 2=pkg 1=universe]
+       var depth int
+       for scope := obj.Parent(); scope != nil; scope = scope.Parent() {
+               depth++
+       }
+       return depth >= 4
+}
+
+func isPackageLevel(obj types.Object) bool {
+       if obj == nil {
+               return false
+       }
+       return obj.Pkg().Scope().Lookup(obj.Name()) == obj
+}
+
+// -- Plundered from go/scanner: ---------------------------------------
+
+func isLetter(ch rune) bool {
+       return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+}
+
+func isDigit(ch rune) bool {
+       return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+}