internal/lsp/source: canonicalize objects in reference/rename requests

With generics, instantiated object may have differing pointer
identities. Fix references/rename requests for instantiated
methods/fields by using a canonical object identity of (pos, pkg, name).

Fixes golang/go#51672

Change-Id: I0021ca562b8a74dadb616cf6864cb0bdd0165cc3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/392480
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/lsp/source/references.go b/internal/lsp/source/references.go
index 993b9f8..5d3eac3 100644
--- a/internal/lsp/source/references.go
+++ b/internal/lsp/source/references.go
@@ -109,10 +109,13 @@
 		searchPkgs = append(searchPkgs, qo.pkg)
 		for _, pkg := range searchPkgs {
 			for ident, obj := range pkg.GetTypesInfo().Uses {
-				if obj != qo.obj {
-					// If ident is not a use of qo.obj, skip it, with one exception: uses
-					// of an embedded field can be considered references of the embedded
-					// type name.
+				// For instantiated objects (as in methods or fields on instantiated
+				// types), we may not have pointer-identical objects but still want to
+				// consider them references.
+				if !equalOrigin(obj, qo.obj) {
+					// If ident is not a use of qo.obj, skip it, with one exception:
+					// uses of an embedded field can be considered references of the
+					// embedded type name
 					if !includeEmbeddedRefs {
 						continue
 					}
@@ -167,6 +170,13 @@
 	return references, nil
 }
 
+// equalOrigin reports whether obj1 and obj2 have equivalent origin object.
+// This may be the case even if obj1 != obj2, if one or both of them is
+// instantiated.
+func equalOrigin(obj1, obj2 types.Object) bool {
+	return obj1.Pkg() == obj2.Pkg() && obj1.Pos() == obj2.Pos() && obj1.Name() == obj2.Name()
+}
+
 // interfaceReferences returns the references to the interfaces implemented by
 // the type or method at the given position.
 func interfaceReferences(ctx context.Context, s Snapshot, f FileHandle, pp protocol.Position) ([]*ReferenceInfo, error) {
diff --git a/internal/lsp/testdata/rename/generics/embedded.go b/internal/lsp/testdata/rename/generics/embedded.go
new file mode 100644
index 0000000..b44bab8
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/embedded.go
@@ -0,0 +1,10 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type foo[P any] int //@rename("foo","bar")
+
+var x struct{ foo[int] }
+
+var _ = x.foo
diff --git a/internal/lsp/testdata/rename/generics/embedded.go.golden b/internal/lsp/testdata/rename/generics/embedded.go.golden
new file mode 100644
index 0000000..faa9afb
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/embedded.go.golden
@@ -0,0 +1,12 @@
+-- bar-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type bar[P any] int //@rename("foo","bar")
+
+var x struct{ bar[int] }
+
+var _ = x.bar
+
diff --git a/internal/lsp/testdata/rename/generics/generics.go b/internal/lsp/testdata/rename/generics/generics.go
new file mode 100644
index 0000000..977589c
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/generics.go
@@ -0,0 +1,25 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+	F int
+}
+
+func (G[_]) M() {}
+
+func F[P any](P) {
+	var p P //@rename("P", "Q")
+	_ = p
+}
+
+func _() {
+	var x G[int] //@rename("G", "H")
+	_ = x.F      //@rename("F", "K")
+	x.M()        //@rename("M", "N")
+
+	var y G[string]
+	_ = y.F
+	y.M()
+}
diff --git a/internal/lsp/testdata/rename/generics/generics.go.golden b/internal/lsp/testdata/rename/generics/generics.go.golden
new file mode 100644
index 0000000..b46a083
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/generics.go.golden
@@ -0,0 +1,108 @@
+-- Q-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+	F int
+}
+
+func (G[_]) M() {}
+
+func F[Q any](Q) {
+	var p Q //@rename("P", "Q")
+	_ = p
+}
+
+func _() {
+	var x G[int] //@rename("G", "H")
+	_ = x.F      //@rename("F", "K")
+	x.M()        //@rename("M", "N")
+
+	var y G[string]
+	_ = y.F
+	y.M()
+}
+
+-- H-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type H[P any] struct {
+	F int
+}
+
+func (H[_]) M() {}
+
+func F[P any](P) {
+	var p P //@rename("P", "Q")
+	_ = p
+}
+
+func _() {
+	var x H[int] //@rename("G", "H")
+	_ = x.F      //@rename("F", "K")
+	x.M()        //@rename("M", "N")
+
+	var y H[string]
+	_ = y.F
+	y.M()
+}
+
+-- K-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+	K int
+}
+
+func (G[_]) M() {}
+
+func F[P any](P) {
+	var p P //@rename("P", "Q")
+	_ = p
+}
+
+func _() {
+	var x G[int] //@rename("G", "H")
+	_ = x.K      //@rename("F", "K")
+	x.M()        //@rename("M", "N")
+
+	var y G[string]
+	_ = y.K
+	y.M()
+}
+
+-- N-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type G[P any] struct {
+	F int
+}
+
+func (G[_]) N() {}
+
+func F[P any](P) {
+	var p P //@rename("P", "Q")
+	_ = p
+}
+
+func _() {
+	var x G[int] //@rename("G", "H")
+	_ = x.F      //@rename("F", "K")
+	x.N()        //@rename("M", "N")
+
+	var y G[string]
+	_ = y.F
+	y.N()
+}
+
diff --git a/internal/lsp/testdata/rename/generics/unions.go b/internal/lsp/testdata/rename/generics/unions.go
new file mode 100644
index 0000000..c737b5c
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/unions.go
@@ -0,0 +1,10 @@
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type T string //@rename("T", "R")
+
+type C interface {
+	T | ~int //@rename("T", "S")
+}
diff --git a/internal/lsp/testdata/rename/generics/unions.go.golden b/internal/lsp/testdata/rename/generics/unions.go.golden
new file mode 100644
index 0000000..4632896
--- /dev/null
+++ b/internal/lsp/testdata/rename/generics/unions.go.golden
@@ -0,0 +1,24 @@
+-- R-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type R string //@rename("T", "R")
+
+type C interface {
+	R | ~int //@rename("T", "S")
+}
+
+-- S-rename --
+//go:build go1.18
+// +build go1.18
+
+package generics
+
+type S string //@rename("T", "R")
+
+type C interface {
+	S | ~int //@rename("T", "S")
+}
+
diff --git a/internal/lsp/testdata/summary_go1.18.txt.golden b/internal/lsp/testdata/summary_go1.18.txt.golden
index 6bb0671..284ef64 100644
--- a/internal/lsp/testdata/summary_go1.18.txt.golden
+++ b/internal/lsp/testdata/summary_go1.18.txt.golden
@@ -20,7 +20,7 @@
 TypeDefinitionsCount = 18
 HighlightsCount = 69
 ReferencesCount = 27
-RenamesCount = 41
+RenamesCount = 48
 PrepareRenamesCount = 7
 SymbolsCount = 5
 WorkspaceSymbolsCount = 20