gopls/internal/golang: provide version info for stdlib in pkgdoc

The available versions are provided for functions and methods.
Same as https://pkg.go.dev/

1. The std lib version is only available for FUNC, METHOD, TYPE. Not
   available for CONST, VAR & FIELD. Because those types do not have
   dedicated HTML element, declarations are shown only as source code.
2. Introduce css element stdlibVersion which contains the styles needed.

For golang/go#67159

Change-Id: I4b4f469a858a1aca6598f2abed6f990ab1931b00
Reviewed-on: https://go-review.googlesource.com/c/tools/+/595855
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/gopls/internal/golang/pkgdoc.go b/gopls/internal/golang/pkgdoc.go
index d0e9ffc..8f6b636 100644
--- a/gopls/internal/golang/pkgdoc.go
+++ b/gopls/internal/golang/pkgdoc.go
@@ -51,6 +51,7 @@
 	"golang.org/x/tools/gopls/internal/util/safetoken"
 	"golang.org/x/tools/gopls/internal/util/slices"
 	"golang.org/x/tools/gopls/internal/util/typesutil"
+	"golang.org/x/tools/internal/stdlib"
 	"golang.org/x/tools/internal/typesinternal"
 )
 
@@ -415,6 +416,12 @@
   padding: 0.3em;
 }
 
+.Documentation-sinceVersion {
+  font-weight: normal;
+  color: #808080;
+  float: right;
+}
+
 #pkgsite { height: 1.5em; }
 
 #hdr-Selector {
@@ -782,6 +789,15 @@
 		values(docpkg.Vars)
 	}
 
+	// addedInHTML returns an HTML division containing the Go release version at
+	// which this obj became available.
+	addedInHTML := func(obj types.Object) string {
+		if sym := StdSymbolOf(obj); sym != nil && sym.Version != stdlib.Version(0) {
+			return fmt.Sprintf("<span class='Documentation-sinceVersion'>added in %v</span>", sym.Version)
+		}
+		return ""
+	}
+
 	// package-level functions
 	fmt.Fprintf(&buf, "<h2 id='hdr-Functions'>Functions</h2>\n")
 	// funcs emits a list of package-level functions,
@@ -789,8 +805,9 @@
 	funcs := func(funcs []*doc.Func) {
 		for _, docfn := range funcs {
 			obj := scope.Lookup(docfn.Name).(*types.Func)
-			fmt.Fprintf(&buf, "<h3 id='%s'>func %s</h3>\n",
-				docfn.Name, objHTML(pkg.FileSet(), web, obj))
+
+			fmt.Fprintf(&buf, "<h3 id='%s'>func %s %s</h3>\n",
+				docfn.Name, objHTML(pkg.FileSet(), web, obj), addedInHTML(obj))
 
 			// decl: func F(params) results
 			fmt.Fprintf(&buf, "<pre class='code'>%s</pre>\n",
@@ -808,8 +825,8 @@
 		tname := scope.Lookup(doctype.Name).(*types.TypeName)
 
 		// title and source link
-		fmt.Fprintf(&buf, "<h3 id='%s'>type %s</a></h3>\n",
-			doctype.Name, objHTML(pkg.FileSet(), web, tname))
+		fmt.Fprintf(&buf, "<h3 id='%s'>type %s %s</h3>\n",
+			doctype.Name, objHTML(pkg.FileSet(), web, tname), addedInHTML(tname))
 
 		// declaration
 		// TODO(adonovan): excise non-exported struct fields somehow.
@@ -828,10 +845,10 @@
 		// methods on T
 		for _, docmethod := range doctype.Methods {
 			method, _, _ := types.LookupFieldOrMethod(tname.Type(), true, tname.Pkg(), docmethod.Name)
-			fmt.Fprintf(&buf, "<h4 id='%s.%s'>func (%s) %s</h4>\n",
+			fmt.Fprintf(&buf, "<h4 id='%s.%s'>func (%s) %s %s</h4>\n",
 				doctype.Name, docmethod.Name,
 				docmethod.Orig, // T or *T
-				objHTML(pkg.FileSet(), web, method))
+				objHTML(pkg.FileSet(), web, method), addedInHTML(method))
 
 			// decl: func (x T) M(params) results
 			fmt.Fprintf(&buf, "<pre class='code'>%s</pre>\n",