Skip to content

Commit

Permalink
internal/lsp/source: canonicalize objects in reference/rename requests
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
findleyr committed Mar 15, 2022
1 parent 54a569a commit 6799a7a
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 5 deletions.
18 changes: 14 additions & 4 deletions internal/lsp/source/references.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,13 @@ func references(ctx context.Context, snapshot Snapshot, qos []qualifiedObject, i
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
}
Expand Down Expand Up @@ -167,6 +170,13 @@ func references(ctx context.Context, snapshot Snapshot, qos []qualifiedObject, i
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) {
Expand Down
10 changes: 10 additions & 0 deletions internal/lsp/testdata/rename/generics/embedded.go
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions internal/lsp/testdata/rename/generics/embedded.go.golden
Original file line number Diff line number Diff line change
@@ -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

25 changes: 25 additions & 0 deletions internal/lsp/testdata/rename/generics/generics.go
Original file line number Diff line number Diff line change
@@ -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()
}
108 changes: 108 additions & 0 deletions internal/lsp/testdata/rename/generics/generics.go.golden
Original file line number Diff line number Diff line change
@@ -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()
}

10 changes: 10 additions & 0 deletions internal/lsp/testdata/rename/generics/unions.go
Original file line number Diff line number Diff line change
@@ -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")
}
24 changes: 24 additions & 0 deletions internal/lsp/testdata/rename/generics/unions.go.golden
Original file line number Diff line number Diff line change
@@ -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")
}

2 changes: 1 addition & 1 deletion internal/lsp/testdata/summary_go1.18.txt.golden
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ DefinitionsCount = 108
TypeDefinitionsCount = 18
HighlightsCount = 69
ReferencesCount = 27
RenamesCount = 41
RenamesCount = 48
PrepareRenamesCount = 7
SymbolsCount = 5
WorkspaceSymbolsCount = 20
Expand Down

0 comments on commit 6799a7a

Please sign in to comment.