@@ -15,6 +15,7 @@ import (
15
15
16
16
"golang.org/x/tools/go/types/typeutil"
17
17
"golang.org/x/tools/internal/lsp/diff"
18
+ "golang.org/x/tools/internal/lsp/protocol"
18
19
"golang.org/x/tools/internal/span"
19
20
"golang.org/x/tools/internal/telemetry/trace"
20
21
"golang.org/x/tools/refactor/satisfy"
@@ -35,6 +36,39 @@ type renamer struct {
35
36
changeMethods bool
36
37
}
37
38
39
+ type PrepareItem struct {
40
+ Range span.Range
41
+ Text string
42
+ }
43
+
44
+ func PrepareRename (ctx context.Context , view View , f GoFile , pos protocol.Position ) (* PrepareItem , error ) {
45
+ ctx , done := trace .StartSpan (ctx , "source.PrepareRename" )
46
+ defer done ()
47
+
48
+ i , err := Identifier (ctx , view , f , pos )
49
+ if err != nil {
50
+ return nil , err
51
+ }
52
+ // If the object declaration is nil, assume it is an import spec.
53
+ if i .Declaration .obj == nil {
54
+ // Find the corresponding package name for this import spec
55
+ // and rename that instead.
56
+ i , err = i .getPkgName (ctx )
57
+ if err != nil {
58
+ return nil , err
59
+ }
60
+ }
61
+
62
+ // Do not rename builtin identifiers.
63
+ if i .Declaration .obj .Parent () == types .Universe {
64
+ return nil , errors .Errorf ("cannot rename builtin %q" , i .Name )
65
+ }
66
+ return & PrepareItem {
67
+ Range : i .spanRange ,
68
+ Text : i .Name ,
69
+ }, nil
70
+ }
71
+
38
72
// Rename returns a map of TextEdits for each file modified when renaming a given identifier within a package.
39
73
func (i * IdentifierInfo ) Rename (ctx context.Context , view View , newName string ) (map [span.URI ][]diff.TextEdit , error ) {
40
74
ctx , done := trace .StartSpan (ctx , "source.Rename" )
@@ -53,7 +87,7 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
53
87
if i .Name == newName {
54
88
return nil , errors .Errorf ("old and new names are the same: %s" , newName )
55
89
}
56
- if ! isValidIdentifier (i . Name ) {
90
+ if ! isValidIdentifier (newName ) {
57
91
return nil , errors .Errorf ("invalid identifier to rename: %q" , i .Name )
58
92
}
59
93
// Do not rename builtin identifiers.
@@ -112,18 +146,31 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
112
146
// getPkgName gets the pkg name associated with an identifer representing
113
147
// the import path in an import spec.
114
148
func (i * IdentifierInfo ) getPkgName (ctx context.Context ) (* IdentifierInfo , error ) {
115
- file := i .File .FileSet ().File (i .mappedRange .spanRange .Start )
116
- pkgLine := file .Line (i .mappedRange .spanRange .Start )
149
+ file , err := i .File .GetAST (ctx , ParseHeader )
150
+ if err != nil {
151
+ return nil , err
152
+ }
153
+ var namePos token.Pos
154
+ for _ , spec := range file .Imports {
155
+ if spec .Path .Pos () == i .spanRange .Start {
156
+ namePos = spec .Pos ()
157
+ break
158
+ }
159
+ }
160
+ if ! namePos .IsValid () {
161
+ return nil , errors .Errorf ("import spec not found for %q" , i .Name )
162
+ }
117
163
164
+ // Look for the object defined at NamePos.
118
165
for _ , obj := range i .pkg .GetTypesInfo ().Defs {
119
166
pkgName , ok := obj .(* types.PkgName )
120
- if ok && file . Line ( pkgName .Pos ()) == pkgLine {
167
+ if ok && pkgName .Pos () == namePos {
121
168
return getPkgNameIdentifier (ctx , i , pkgName )
122
169
}
123
170
}
124
171
for _ , obj := range i .pkg .GetTypesInfo ().Implicits {
125
172
pkgName , ok := obj .(* types.PkgName )
126
- if ok && file . Line ( pkgName .Pos ()) == pkgLine {
173
+ if ok && pkgName .Pos () == namePos {
127
174
return getPkgNameIdentifier (ctx , i , pkgName )
128
175
}
129
176
}
0 commit comments