gopls/internal/lsp/source: fix renaming instantiated fields
Correctly associate instantiated functions and fields with their origin
during renaming.
Fixes golang/go#61640
Change-Id: I819ffe303a2b1c35810d5b3c2d71fa5f4231a0c4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/518897
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/gopls/internal/lsp/source/origin.go b/gopls/internal/lsp/source/origin.go
new file mode 100644
index 0000000..8ee467e
--- /dev/null
+++ b/gopls/internal/lsp/source/origin.go
@@ -0,0 +1,26 @@
+// Copyright 2023 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.
+
+//go:build !go1.19
+// +build !go1.19
+
+package source
+
+import "go/types"
+
+// containsOrigin reports whether the provided object set contains an object
+// with the same origin as the provided obj (which may be a synthetic object
+// created during instantiation).
+func containsOrigin(objSet map[types.Object]bool, obj types.Object) bool {
+ if obj == nil {
+ return objSet[obj]
+ }
+ // In Go 1.18, we can't use the types.Var.Origin and types.Func.Origin methods.
+ for target := range objSet {
+ if target.Pkg() == obj.Pkg() && target.Pos() == obj.Pos() && target.Name() == obj.Name() {
+ return true
+ }
+ }
+ return false
+}
diff --git a/gopls/internal/lsp/source/origin_119.go b/gopls/internal/lsp/source/origin_119.go
new file mode 100644
index 0000000..a249ce4
--- /dev/null
+++ b/gopls/internal/lsp/source/origin_119.go
@@ -0,0 +1,33 @@
+// Copyright 2023 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.
+
+//go:build go1.19
+// +build go1.19
+
+package source
+
+import "go/types"
+
+// containsOrigin reports whether the provided object set contains an object
+// with the same origin as the provided obj (which may be a synthetic object
+// created during instantiation).
+func containsOrigin(objSet map[types.Object]bool, obj types.Object) bool {
+ objOrigin := origin(obj)
+ for target := range objSet {
+ if origin(target) == objOrigin {
+ return true
+ }
+ }
+ return false
+}
+
+func origin(obj types.Object) types.Object {
+ switch obj := obj.(type) {
+ case *types.Var:
+ return obj.Origin()
+ case *types.Func:
+ return obj.Origin()
+ }
+ return obj
+}
diff --git a/gopls/internal/lsp/source/references.go b/gopls/internal/lsp/source/references.go
index 3d923e4..46459dc 100644
--- a/gopls/internal/lsp/source/references.go
+++ b/gopls/internal/lsp/source/references.go
@@ -580,10 +580,8 @@
// matches reports whether obj either is or corresponds to a target.
// (Correspondence is defined as usual for interface methods.)
matches := func(obj types.Object) bool {
- for target := range targets {
- if equalOrigin(obj, target) {
- return true
- }
+ if containsOrigin(targets, obj) {
+ return true
}
if methodRecvs != nil && obj.Name() == methodName {
if orecv := effectiveReceiver(obj); orecv != nil {
@@ -611,13 +609,6 @@
return 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()
-}
-
// effectiveReceiver returns the effective receiver type for method-set
// comparisons for obj, if it is a method, or nil otherwise.
func effectiveReceiver(obj types.Object) types.Type {
diff --git a/gopls/internal/lsp/source/rename.go b/gopls/internal/lsp/source/rename.go
index c1db0e5..eb1fdce 100644
--- a/gopls/internal/lsp/source/rename.go
+++ b/gopls/internal/lsp/source/rename.go
@@ -1054,13 +1054,7 @@
// shouldUpdate reports whether obj is one of (or an
// instantiation of one of) the target objects.
shouldUpdate := func(obj types.Object) bool {
- if r.objsToUpdate[obj] {
- return true
- }
- if fn, ok := obj.(*types.Func); ok && r.objsToUpdate[funcOrigin(fn)] {
- return true
- }
- return false
+ return containsOrigin(r.objsToUpdate, obj)
}
// Find all identifiers in the package that define or use a