@@ -33,6 +33,7 @@ import (
33
33
"golang.org/x/tools/gopls/internal/file"
34
34
"golang.org/x/tools/gopls/internal/protocol"
35
35
"golang.org/x/tools/gopls/internal/settings"
36
+ gastutil "golang.org/x/tools/gopls/internal/util/astutil"
36
37
"golang.org/x/tools/gopls/internal/util/bug"
37
38
"golang.org/x/tools/gopls/internal/util/safetoken"
38
39
"golang.org/x/tools/gopls/internal/util/slices"
@@ -134,52 +135,77 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
134
135
return protocol.Range {}, nil , err
135
136
}
136
137
137
- // Handle hovering over import paths, which do not have an associated
138
- // identifier.
139
- for _ , spec := range pgf .File .Imports {
140
- // We are inclusive of the end point here to allow hovering when the cursor
141
- // is just after the import path.
142
- if spec .Path .Pos () <= pos && pos <= spec .Path .End () {
143
- return hoverImport (ctx , snapshot , pkg , pgf , spec )
144
- }
145
- }
146
-
147
138
// Handle hovering over the package name, which does not have an associated
148
139
// object.
149
140
// As with import paths, we allow hovering just after the package name.
150
- if pgf .File .Name != nil && pgf . File . Name . Pos () <= pos && pos <= pgf .File .Name . Pos ( ) {
141
+ if pgf .File .Name != nil && gastutil . NodeContains ( pgf .File .Name , pos ) {
151
142
return hoverPackageName (pkg , pgf )
152
143
}
153
144
154
- // Handle hovering over (non-import-path) literals.
155
- if path , _ := astutil .PathEnclosingInterval (pgf .File , pos , pos ); len (path ) > 0 {
156
- if lit , _ := path [0 ].(* ast.BasicLit ); lit != nil {
157
- return hoverLit (pgf , lit , pos )
158
- }
159
- }
160
-
161
145
// Handle hovering over embed directive argument.
162
146
pattern , embedRng := parseEmbedDirective (pgf .Mapper , pp )
163
147
if pattern != "" {
164
148
return hoverEmbed (fh , embedRng , pattern )
165
149
}
166
150
151
+ // hoverRange is the range reported to the client (e.g. for highlighting).
152
+ // It may be an expansion around the selected identifier,
153
+ // for instance when hovering over a linkname directive or doc link.
154
+ var hoverRange * protocol.Range
167
155
// Handle linkname directive by overriding what to look for.
168
- var linkedRange * protocol.Range // range referenced by linkname directive, or nil
169
156
if pkgPath , name , offset := parseLinkname (pgf .Mapper , pp ); pkgPath != "" && name != "" {
170
157
// rng covering 2nd linkname argument: pkgPath.name.
171
158
rng , err := pgf .PosRange (pgf .Tok .Pos (offset ), pgf .Tok .Pos (offset + len (pkgPath )+ len ("." )+ len (name )))
172
159
if err != nil {
173
160
return protocol.Range {}, nil , fmt .Errorf ("range over linkname arg: %w" , err )
174
161
}
175
- linkedRange = & rng
162
+ hoverRange = & rng
176
163
177
164
pkg , pgf , pos , err = findLinkname (ctx , snapshot , PackagePath (pkgPath ), name )
178
165
if err != nil {
179
166
return protocol.Range {}, nil , fmt .Errorf ("find linkname: %w" , err )
180
167
}
181
168
}
182
169
170
+ // Handle hovering over a doc link
171
+ if obj , rng , _ := parseDocLink (pkg , pgf , pos ); obj != nil {
172
+ hoverRange = & rng
173
+ // Handle builtins, which don't have a package or position.
174
+ if ! obj .Pos ().IsValid () {
175
+ h , err := hoverBuiltin (ctx , snapshot , obj )
176
+ return * hoverRange , h , err
177
+ }
178
+ objURI := safetoken .StartPosition (pkg .FileSet (), obj .Pos ())
179
+ pkg , pgf , err = NarrowestPackageForFile (ctx , snapshot , protocol .URIFromPath (objURI .Filename ))
180
+ if err != nil {
181
+ return protocol.Range {}, nil , err
182
+ }
183
+ pos = pgf .Tok .Pos (objURI .Offset )
184
+ }
185
+
186
+ // Handle hovering over import paths, which do not have an associated
187
+ // identifier.
188
+ for _ , spec := range pgf .File .Imports {
189
+ if gastutil .NodeContains (spec , pos ) {
190
+ rng , hoverJSON , err := hoverImport (ctx , snapshot , pkg , pgf , spec )
191
+ if err != nil {
192
+ return protocol.Range {}, nil , err
193
+ }
194
+ if hoverRange == nil {
195
+ hoverRange = & rng
196
+ }
197
+ return * hoverRange , hoverJSON , nil
198
+ }
199
+ }
200
+ // Handle hovering over (non-import-path) literals.
201
+ if path , _ := astutil .PathEnclosingInterval (pgf .File , pos , pos ); len (path ) > 0 {
202
+ if lit , _ := path [0 ].(* ast.BasicLit ); lit != nil {
203
+ return hoverLit (pgf , lit , pos )
204
+ }
205
+ }
206
+
207
+ // Handle hover over identifier.
208
+
183
209
// The general case: compute hover information for the object referenced by
184
210
// the identifier at pos.
185
211
ident , obj , selectedType := referencedObject (pkg , pgf , pos )
@@ -188,14 +214,12 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
188
214
}
189
215
190
216
// Unless otherwise specified, rng covers the ident being hovered.
191
- var rng protocol.Range
192
- if linkedRange != nil {
193
- rng = * linkedRange
194
- } else {
195
- rng , err = pgf .NodeRange (ident )
217
+ if hoverRange == nil {
218
+ rng , err := pgf .NodeRange (ident )
196
219
if err != nil {
197
220
return protocol.Range {}, nil , err
198
221
}
222
+ hoverRange = & rng
199
223
}
200
224
201
225
// By convention, we qualify hover information relative to the package
@@ -209,7 +233,7 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
209
233
if selectedType != nil {
210
234
fakeObj := types .NewVar (obj .Pos (), obj .Pkg (), obj .Name (), selectedType )
211
235
signature := types .ObjectString (fakeObj , qf )
212
- return rng , & hoverJSON {
236
+ return * hoverRange , & hoverJSON {
213
237
Signature : signature ,
214
238
SingleLine : signature ,
215
239
SymbolName : fakeObj .Name (),
@@ -219,7 +243,7 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
219
243
// Handle builtins, which don't have a package or position.
220
244
if ! obj .Pos ().IsValid () {
221
245
h , err := hoverBuiltin (ctx , snapshot , obj )
222
- return rng , h , err
246
+ return * hoverRange , h , err
223
247
}
224
248
225
249
// For all other objects, consider the full syntax of their declaration in
@@ -523,7 +547,7 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
523
547
linkPath = strings .Replace (linkPath , mod .Path , mod .Path + "@" + mod .Version , 1 )
524
548
}
525
549
526
- return rng , & hoverJSON {
550
+ return * hoverRange , & hoverJSON {
527
551
Synopsis : doc .Synopsis (docText ),
528
552
FullDocumentation : docText ,
529
553
SingleLine : singleLineSignature ,
0 commit comments