Skip to content

Commit c117dde

Browse files
cuishuangmadelinekalil
authored andcommitted
gopls/internal/golang: normalize instantiated fields before rename
When a rename is initiated at a field selection on an instantiated generic type, go/types reports a synthetic *types.Var. The rename operation consequently updates other instantiated uses but misses the original field declaration. Normalize field targets to their origin before performing the rename. This ensures that the declaration, selector uses, and keyed composite literals are updated together. Add a marker test for a rename initiated at an instantiated field selection. Fixes golang/go#80542 Change-Id: I8cdd107e6f4de584879f896ebf27d3c823b87473 Reviewed-on: https://go-review.googlesource.com/c/tools/+/804901 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Madeline Kalil <mkalil@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent b5b860c commit c117dde

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

gopls/internal/golang/rename.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,15 @@ func renameOrdinary(ctx context.Context, snapshot *cache.Snapshot, uri protocol.
611611
targets = []objectAt{{obj, cur}}
612612
}
613613

614+
// A field selected from an instantiated generic type is represented by a
615+
// synthetic *types.Var. Normalize it to the declared field so that a rename
616+
// initiated at the selection updates the declaration too (golang/go#80542).
617+
for i := range targets {
618+
if field, ok := targets[i].obj.(*types.Var); ok && field.IsField() {
619+
targets[i].obj = field.Origin()
620+
}
621+
}
622+
614623
// Pick a representative object arbitrarily.
615624
// (All share the same name, pos, and kind.)
616625
obj, node := targets[0].obj, targets[0].cur.Node()
@@ -654,8 +663,6 @@ func renameOrdinary(ctx context.Context, snapshot *cache.Snapshot, uri protocol.
654663
case *types.Func:
655664
obj = obj0.Origin()
656665
case *types.Var:
657-
// TODO(adonovan): do vars need the origin treatment too? (issue #58462)
658-
659666
// Function parameter and result vars that are (unusually)
660667
// capitalized are technically exported, even though they
661668
// cannot be referenced, because they may affect downstream
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
This test verifies that a rename of a field selected from an instantiated
2+
generic type updates the field declaration, including across packages.
3+
4+
-- flags --
5+
-ignore_extra_diags
6+
7+
-- go.mod --
8+
module example.com
9+
10+
go 1.18
11+
12+
-- a.go --
13+
package a
14+
15+
type box[T any] struct {
16+
value T
17+
}
18+
19+
func (b box[T]) use() {
20+
_ = b.value //@rename("value", "renamed", valueToRenamed)
21+
}
22+
23+
var _ = box[int]{value: 1}
24+
25+
-- lib/lib.go --
26+
package lib
27+
28+
type Box[T any] struct {
29+
Value T
30+
}
31+
32+
-- use/use.go --
33+
package use
34+
35+
import "example.com/lib"
36+
37+
func use(b lib.Box[int]) {
38+
_ = b.Value //@rename("Value", "Renamed", crossPackage)
39+
}
40+
41+
var _ = lib.Box[int]{Value: 1}
42+
43+
-- @valueToRenamed/a.go --
44+
@@ -4 +4 @@
45+
- value T
46+
+ renamed T
47+
@@ -8 +8 @@
48+
- _ = b.value //@rename("value", "renamed", valueToRenamed)
49+
+ _ = b.renamed //@rename("value", "renamed", valueToRenamed)
50+
@@ -11 +11 @@
51+
-var _ = box[int]{value: 1}
52+
+var _ = box[int]{renamed: 1}
53+
-- @crossPackage/lib/lib.go --
54+
@@ -4 +4 @@
55+
- Value T
56+
+ Renamed T
57+
-- @crossPackage/use/use.go --
58+
@@ -6 +6 @@
59+
- _ = b.Value //@rename("Value", "Renamed", crossPackage)
60+
+ _ = b.Renamed //@rename("Value", "Renamed", crossPackage)
61+
@@ -9 +9 @@
62+
-var _ = lib.Box[int]{Value: 1}
63+
+var _ = lib.Box[int]{Renamed: 1}

0 commit comments

Comments
 (0)