@@ -103,42 +103,72 @@ func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, p
103
103
// builtinDefinition returns the location of the fake source
104
104
// declaration of a built-in in {builtin,unsafe}.go.
105
105
func builtinDefinition (ctx context.Context , snapshot * cache.Snapshot , obj types.Object ) ([]protocol.Location , error ) {
106
- pgf , decl , err := builtinDecl (ctx , snapshot , obj )
106
+ pgf , ident , err := builtinDecl (ctx , snapshot , obj )
107
107
if err != nil {
108
108
return nil , err
109
109
}
110
110
111
- loc , err := pgf .PosLocation ( decl . Pos (), decl . Pos () + token . Pos ( len ( obj . Name ())) )
111
+ loc , err := pgf .NodeLocation ( ident )
112
112
if err != nil {
113
113
return nil , err
114
114
}
115
115
return []protocol.Location {loc }, nil
116
116
}
117
117
118
118
// builtinDecl returns the parsed Go file and node corresponding to a builtin
119
- // object, which may be a universe object or part of types.Unsafe.
120
- func builtinDecl (ctx context.Context , snapshot * cache.Snapshot , obj types.Object ) (* parsego.File , ast.Node , error ) {
121
- // getDecl returns the file-level declaration of name
122
- // using legacy (go/ast) object resolution.
123
- getDecl := func (file * ast.File , name string ) (ast.Node , error ) {
119
+ // object, which may be a universe object or part of types.Unsafe, as well as
120
+ // its declaring identifier.
121
+ func builtinDecl (ctx context.Context , snapshot * cache.Snapshot , obj types.Object ) (* parsego.File , * ast.Ident , error ) {
122
+ // declaringIdent returns the file-level declaration node (as reported by
123
+ // ast.Object) and declaring identifier of name using legacy (go/ast) object
124
+ // resolution.
125
+ declaringIdent := func (file * ast.File , name string ) (ast.Node , * ast.Ident , error ) {
124
126
astObj := file .Scope .Lookup (name )
125
127
if astObj == nil {
126
128
// Every built-in should have documentation syntax.
127
129
// However, it is possible to reach this statement by
128
130
// commenting out declarations in {builtin,unsafe}.go.
129
- return nil , fmt .Errorf ("internal error: no object for %s" , name )
131
+ return nil , nil , fmt .Errorf ("internal error: no object for %s" , name )
130
132
}
131
133
decl , ok := astObj .Decl .(ast.Node )
132
134
if ! ok {
133
- return nil , bug .Errorf ("internal error: no declaration for %s" , obj .Name ())
135
+ return nil , nil , bug .Errorf ("internal error: no declaration for %s" , obj .Name ())
134
136
}
135
- return decl , nil
137
+ var ident * ast.Ident
138
+ switch node := decl .(type ) {
139
+ case * ast.Field :
140
+ for _ , id := range node .Names {
141
+ if id .Name == name {
142
+ ident = id
143
+ }
144
+ }
145
+ case * ast.ValueSpec :
146
+ for _ , id := range node .Names {
147
+ if id .Name == name {
148
+ ident = id
149
+ }
150
+ }
151
+ case * ast.TypeSpec :
152
+ ident = node .Name
153
+ case * ast.Ident :
154
+ ident = node
155
+ case * ast.FuncDecl :
156
+ ident = node .Name
157
+ case * ast.ImportSpec , * ast.LabeledStmt , * ast.AssignStmt :
158
+ // Not reachable for imported objects.
159
+ default :
160
+ return nil , nil , bug .Errorf ("internal error: unexpected decl type %T" , decl )
161
+ }
162
+ if ident == nil {
163
+ return nil , nil , bug .Errorf ("internal error: no declaring identifier for %s" , obj .Name ())
164
+ }
165
+ return decl , ident , nil
136
166
}
137
167
138
168
var (
139
- pgf * parsego.File
140
- decl ast.Node
141
- err error
169
+ pgf * parsego.File
170
+ ident * ast.Ident
171
+ err error
142
172
)
143
173
if obj .Pkg () == types .Unsafe {
144
174
// package "unsafe":
@@ -154,11 +184,13 @@ func builtinDecl(ctx context.Context, snapshot *cache.Snapshot, obj types.Object
154
184
if err != nil {
155
185
return nil , nil , err
156
186
}
187
+ // TODO(rfindley): treat unsafe symmetrically with the builtin file. Either
188
+ // pre-parse them both, or look up metadata for both.
157
189
pgf , err = snapshot .ParseGo (ctx , fh , parsego .Full &^parser .SkipObjectResolution )
158
190
if err != nil {
159
191
return nil , nil , err
160
192
}
161
- decl , err = getDecl (pgf .File , obj .Name ())
193
+ _ , ident , err = declaringIdent (pgf .File , obj .Name ())
162
194
if err != nil {
163
195
return nil , nil , err
164
196
}
@@ -172,23 +204,24 @@ func builtinDecl(ctx context.Context, snapshot *cache.Snapshot, obj types.Object
172
204
173
205
if obj .Parent () == types .Universe {
174
206
// built-in function or type
175
- decl , err = getDecl (pgf .File , obj .Name ())
207
+ _ , ident , err = declaringIdent (pgf .File , obj .Name ())
176
208
if err != nil {
177
209
return nil , nil , err
178
210
}
179
211
} else if obj .Name () == "Error" {
180
212
// error.Error method
181
- decl , err = getDecl (pgf .File , "error" )
213
+ decl , _ , err := declaringIdent (pgf .File , "error" )
182
214
if err != nil {
183
215
return nil , nil , err
184
216
}
185
- decl = decl .(* ast.TypeSpec ).Type .(* ast.InterfaceType ).Methods .List [0 ]
186
-
217
+ field : = decl .(* ast.TypeSpec ).Type .(* ast.InterfaceType ).Methods .List [0 ]
218
+ ident = field . Names [ 0 ]
187
219
} else {
188
220
return nil , nil , bug .Errorf ("unknown built-in %v" , obj )
189
221
}
190
222
}
191
- return pgf , decl , nil
223
+
224
+ return pgf , ident , nil
192
225
}
193
226
194
227
// referencedObject returns the identifier and object referenced at the
0 commit comments