internal/lsp: add changeMethods logic to rename check

This logic is directly copied from the refactor/rename package. See
https://github.com/golang/tools/blob/master/refactor/rename/rename.go#L321.

Fixes golang/go#39269

Change-Id: Ibe335aab37c495d2a960cb9da254b24b6fbac8e8
Reviewed-on: https://go-review.googlesource.com/c/tools/+/242158
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index 0e7114b..bbc7c7b 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -615,6 +615,7 @@
 	scope, ok := s.workspacePackages[id]
 	return scope, ok
 }
+
 func (s *snapshot) FindFile(uri span.URI) source.FileHandle {
 	f, err := s.view.getFile(uri)
 	if err != nil {
diff --git a/internal/lsp/source/rename.go b/internal/lsp/source/rename.go
index 2c1cd57..ef2bc0b 100644
--- a/internal/lsp/source/rename.go
+++ b/internal/lsp/source/rename.go
@@ -104,6 +104,19 @@
 		to:           newName,
 		packages:     make(map[*types.Package]Package),
 	}
+
+	// A renaming initiated at an interface method indicates the
+	// intention to rename abstract and concrete methods as needed
+	// to preserve assignability.
+	for _, ref := range refs {
+		if obj, ok := ref.obj.(*types.Func); ok {
+			recv := obj.Type().(*types.Signature).Recv()
+			if recv != nil && isInterface(recv.Type().Underlying()) {
+				r.changeMethods = true
+				break
+			}
+		}
+	}
 	for _, from := range refs {
 		r.packages[from.pkg.GetTypes()] = from.pkg
 	}
diff --git a/internal/lsp/source/rename_check.go b/internal/lsp/source/rename_check.go
index 1541f0e..8823951 100644
--- a/internal/lsp/source/rename_check.go
+++ b/internal/lsp/source/rename_check.go
@@ -502,7 +502,6 @@
 					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
@@ -845,7 +844,7 @@
 // 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) {
-	var pkgs = []Package{pkg}
+	pkgs := []Package{pkg}
 	for _, f := range pkg.GetSyntax() {
 		for _, imp := range f.Imports {
 			if imp == nil {
diff --git a/internal/lsp/testdata/lsp/primarymod/rename/b/b.go.golden b/internal/lsp/testdata/lsp/primarymod/rename/b/b.go.golden
index c8691ef..3a0e3f1 100644
--- a/internal/lsp/testdata/lsp/primarymod/rename/b/b.go.golden
+++ b/internal/lsp/testdata/lsp/primarymod/rename/b/b.go.golden
@@ -1,27 +1,3 @@
--- error-rename --
-package b
-
-var c int //@rename("int", "uint")
-
-func _() {
-	error := 1 //@rename("a", "error")
-	error = 2
-	_ = error
-}
-
-var (
-	// Hello there.
-	// Foo does the thing.
-	Foo int //@rename("Foo", "Bob")
-)
-
-/*
-Hello description
-*/
-func Hello() {} //@rename("Hello", "Goodbye")
-
--- uint-rename --
-builtin object "int"
 -- Bob-rename --
 package b
 
@@ -66,3 +42,27 @@
 */
 func Goodbye() {} //@rename("Hello", "Goodbye")
 
+-- error-rename --
+package b
+
+var c int //@rename("int", "uint")
+
+func _() {
+	error := 1 //@rename("a", "error")
+	error = 2
+	_ = error
+}
+
+var (
+	// Hello there.
+	// Foo does the thing.
+	Foo int //@rename("Foo", "Bob")
+)
+
+/*
+Hello description
+*/
+func Hello() {} //@rename("Hello", "Goodbye")
+
+-- uint-rename --
+builtin object "int"
diff --git a/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go b/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go
new file mode 100644
index 0000000..9b50af2
--- /dev/null
+++ b/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go
@@ -0,0 +1,13 @@
+package another
+
+type (
+	I interface{ F() }
+	C struct{ I }
+)
+
+func (C) g()
+
+func _() {
+	var x I = C{}
+	x.F() //@rename("F", "G")
+}
diff --git a/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go.golden b/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go.golden
new file mode 100644
index 0000000..d3fccda
--- /dev/null
+++ b/internal/lsp/testdata/lsp/primarymod/rename/crosspkg/another/another.go.golden
@@ -0,0 +1,15 @@
+-- G-rename --
+package another
+
+type (
+	I interface{ G() }
+	C struct{ I }
+)
+
+func (C) g()
+
+func _() {
+	var x I = C{}
+	x.G() //@rename("F", "G")
+}
+
diff --git a/internal/lsp/testdata/lsp/summary.txt.golden b/internal/lsp/testdata/lsp/summary.txt.golden
index bf5762f..31f7f43 100644
--- a/internal/lsp/testdata/lsp/summary.txt.golden
+++ b/internal/lsp/testdata/lsp/summary.txt.golden
@@ -16,7 +16,7 @@
 TypeDefinitionsCount = 2
 HighlightsCount = 69
 ReferencesCount = 11
-RenamesCount = 27
+RenamesCount = 28
 PrepareRenamesCount = 7
 SymbolsCount = 3
 WorkspaceSymbolsCount = 2