@@ -40,6 +40,7 @@ import (
40
40
"golang.org/x/tools/gopls/internal/util/typesutil"
41
41
"golang.org/x/tools/internal/aliases"
42
42
"golang.org/x/tools/internal/event"
43
+ "golang.org/x/tools/internal/stdlib"
43
44
"golang.org/x/tools/internal/tokeninternal"
44
45
"golang.org/x/tools/internal/typeparams"
45
46
"golang.org/x/tools/internal/typesinternal"
@@ -77,6 +78,10 @@ type hoverJSON struct {
77
78
// For example, the "Node" part of "pkg.go.dev/go/ast#Node".
78
79
LinkAnchor string `json:"linkAnchor"`
79
80
81
+ // stdVersion is the Go release version at which this symbol became available.
82
+ // It is nil for non-std library.
83
+ stdVersion * stdlib.Version
84
+
80
85
// New fields go below, and are unexported. The existing
81
86
// exported fields are underspecified and have already
82
87
// constrained our movements too much. A detailed JSON
@@ -595,6 +600,11 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
595
600
linkPath = strings .Replace (linkPath , mod .Path , mod .Path + "@" + mod .Version , 1 )
596
601
}
597
602
603
+ var version * stdlib.Version
604
+ if symbol := StdSymbolOf (obj ); symbol != nil {
605
+ version = & symbol .Version
606
+ }
607
+
598
608
return * hoverRange , & hoverJSON {
599
609
Synopsis : doc .Synopsis (docText ),
600
610
FullDocumentation : docText ,
@@ -606,6 +616,7 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
606
616
typeDecl : typeDecl ,
607
617
methods : methods ,
608
618
promotedFields : fields ,
619
+ stdVersion : version ,
609
620
}, nil
610
621
}
611
622
@@ -1166,11 +1177,15 @@ func formatHover(h *hoverJSON, options *settings.Options, pkgURL func(path Packa
1166
1177
formatDoc (h , options ),
1167
1178
maybeMarkdown (h .promotedFields ),
1168
1179
maybeMarkdown (h .methods ),
1180
+ fmt .Sprintf ("Added in %v" , h .stdVersion ),
1169
1181
formatLink (h , options , pkgURL ),
1170
1182
}
1171
1183
if h .typeDecl != "" {
1172
1184
parts [0 ] = "" // type: suppress redundant Signature
1173
1185
}
1186
+ if h .stdVersion == nil || * h .stdVersion == stdlib .Version (0 ) {
1187
+ parts [5 ] = "" // suppress stdlib version if not applicable or initial version 1.0
1188
+ }
1174
1189
parts = slices .Remove (parts , "" )
1175
1190
1176
1191
var b strings.Builder
@@ -1191,6 +1206,29 @@ func formatHover(h *hoverJSON, options *settings.Options, pkgURL func(path Packa
1191
1206
}
1192
1207
}
1193
1208
1209
+ // StdSymbolOf returns the std lib symbol information of the given obj.
1210
+ // It returns nil if the input obj is not an exported standard library symbol.
1211
+ func StdSymbolOf (obj types.Object ) * stdlib.Symbol {
1212
+ if ! obj .Exported () {
1213
+ return nil
1214
+ }
1215
+
1216
+ if isPackageLevel (obj ) {
1217
+ // TODO(hxjiang): This is binary searchable.
1218
+ for _ , s := range stdlib .PackageSymbols [obj .Pkg ().Path ()] {
1219
+ if s .Kind == stdlib .Method || s .Kind == stdlib .Field {
1220
+ continue
1221
+ }
1222
+ if s .Name == obj .Name () {
1223
+ return & s
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ // TODO(hxjiang): handle exported fields and methods of package level types.
1229
+ return nil
1230
+ }
1231
+
1194
1232
// If pkgURL is non-nil, it should be used to generate doc links.
1195
1233
func formatLink (h * hoverJSON , options * settings.Options , pkgURL func (path PackagePath , fragment string ) protocol.URI ) string {
1196
1234
if options .LinksInHover == false || h .LinkPath == "" {
0 commit comments