upgrade dependencies (#3730)

upgrade x/tools v0.14.0
upgrade x/sys   v0.13.0

Signed-off-by: Weizhen Wang <wangweizhen@pingcap.com>
diff --git a/go.mod b/go.mod
index 8b81c68..9e65dea 100644
--- a/go.mod
+++ b/go.mod
@@ -9,9 +9,10 @@
 )
 
 require (
-	golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
-	golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
-	golang.org/x/text v0.3.3 // indirect
+	golang.org/x/net v0.16.0 // indirect
+	golang.org/x/sys v0.13.0 // indirect
+	golang.org/x/text v0.13.0 // indirect
+	golang.org/x/tools v0.14.0 // indirect
 	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
 	google.golang.org/grpc v1.50.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 56a11be..5631d83 100644
--- a/go.sum
+++ b/go.sum
@@ -50,6 +50,8 @@
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos=
+golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -65,10 +67,14 @@
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -78,6 +84,8 @@
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl
index 2c702e9..8ee2fb9 100644
--- a/go/private/repositories.bzl
+++ b/go/private/repositories.bzl
@@ -64,13 +64,13 @@
     wrapper(
         http_archive,
         name = "org_golang_x_tools",
-        # v0.7.0, latest as of 2023-03-27
+        # v0.14.0, latest as of 2023-10-29
         urls = [
-            "https://mirror.bazel.build/github.com/golang/tools/archive/refs/tags/v0.7.0.zip",
-            "https://github.com/golang/tools/archive/refs/tags/v0.7.0.zip",
+            "https://mirror.bazel.build/github.com/golang/tools/archive/refs/tags/v0.14.0.zip",
+            "https://github.com/golang/tools/archive/refs/tags/v0.14.0.zip",
         ],
-        sha256 = "9f20a20f29f4008d797a8be882ef82b69cf8f7f2b96dbdfe3814c57d8280fa4b",
-        strip_prefix = "tools-0.7.0",
+        sha256 = "9c71911c61a791d8b13368ffbc409a0b38859cac80a4b5039487d2a27399e8b9",
+        strip_prefix = "tools-0.14.0",
         patches = [
             # deletegopls removes the gopls subdirectory. It contains a nested
             # module with additional dependencies. It's not needed by rules_go.
@@ -105,13 +105,13 @@
     wrapper(
         http_archive,
         name = "org_golang_x_sys",
-        # v0.12.0, latest as of 2023-09-18
+        # v0.13.0, latest as of 2023-10-29
         urls = [
-            "https://mirror.bazel.build/github.com/golang/sys/archive/refs/tags/v0.12.0.zip",
-            "https://github.com/golang/sys/archive/refs/tags/v0.12.0.zip",
+            "https://mirror.bazel.build/github.com/golang/sys/archive/refs/tags/v0.13.0.zip",
+            "https://github.com/golang/sys/archive/refs/tags/v0.13.0.zip",
         ],
-        sha256 = "229b079d23d18f5b1a0c46335020cddc6e5d543da2dae6e45b59d84b5d074e3a",
-        strip_prefix = "sys-0.12.0",
+        sha256 = "24abdcbecddb288fb1007f8cb814b1592531d5bb62817bc30925e3175f3f5749",
+        strip_prefix = "sys-0.13.0",
         patches = [
             # releaser:patch-cmd gazelle -repo_root . -go_prefix golang.org/x/sys -go_naming_convention import_alias
             Label("//third_party:org_golang_x_sys-gazelle.patch"),
diff --git a/go/tools/builders/nogo_main.go b/go/tools/builders/nogo_main.go
index c6156e1..4f65f11 100644
--- a/go/tools/builders/nogo_main.go
+++ b/go/tools/builders/nogo_main.go
@@ -234,7 +234,7 @@
 
 	// Process diagnostics and encode facts for importers of this package.
 	diagnostics := checkAnalysisResults(roots, pkg)
-	facts := pkg.facts.Encode()
+	facts := pkg.facts.Encode(true/* skipMethodSorting */)
 	return diagnostics, facts, nil
 }
 
@@ -396,7 +396,7 @@
 	}
 	pkg.types, pkg.typesInfo = types, info
 
-	pkg.facts, err = facts.NewDecoder(pkg.types).Decode(imp.readFacts)
+	pkg.facts, err = facts.NewDecoder(pkg.types).Decode(true/* skipMethodSorting */, imp.readFacts)
 	if err != nil {
 		return nil, fmt.Errorf("internal error decoding facts: %v", err)
 	}
@@ -609,8 +609,8 @@
 	return gcexportdata.Read(r, i.fset, i.packageCache, path)
 }
 
-func (i *importer) readFacts(pkg *types.Package) ([]byte, error) {
-	archive := i.factMap[pkg.Path()]
+func (i *importer) readFacts(pkgPath string) ([]byte, error) {
+	archive := i.factMap[pkgPath]
 	if archive == "" {
 		// Packages that were not built with the nogo toolchain will not be
 		// analyzed, so there's no opportunity to store facts. This includes
diff --git a/tests/integration/popular_repos/BUILD.bazel b/tests/integration/popular_repos/BUILD.bazel
index b528656..79c1d68 100644
--- a/tests/integration/popular_repos/BUILD.bazel
+++ b/tests/integration/popular_repos/BUILD.bazel
@@ -102,7 +102,6 @@
     tests = [
         "@org_golang_x_sys//cpu:cpu_test",
         "@org_golang_x_sys//execabs:execabs_test",
-        "@org_golang_x_sys//internal/unsafeheader:unsafeheader_test",
         "@org_golang_x_sys//plan9:plan9_test",
         "@org_golang_x_sys//unix/internal/mkmerge:mkmerge_test",
         "@org_golang_x_sys//windows/mkwinsyscall:mkwinsyscall_test",
@@ -193,8 +192,6 @@
         "@org_golang_x_tools//internal/jsonrpc2:jsonrpc2_test",
         "@org_golang_x_tools//internal/jsonrpc2/servertest:servertest_test",
         "@org_golang_x_tools//internal/jsonrpc2_v2:jsonrpc2_v2_test",
-        "@org_golang_x_tools//internal/lockedfile:lockedfile_test",
-        "@org_golang_x_tools//internal/lockedfile/internal/filelock:filelock_test",
         "@org_golang_x_tools//internal/memoize:memoize_test",
         "@org_golang_x_tools//internal/persistent:persistent_test",
         "@org_golang_x_tools//internal/proxydir:proxydir_test",
diff --git a/tests/integration/popular_repos/README.rst b/tests/integration/popular_repos/README.rst
index 66f85a8..446f121 100644
--- a/tests/integration/popular_repos/README.rst
+++ b/tests/integration/popular_repos/README.rst
@@ -96,7 +96,6 @@
 
 * @org_golang_x_sys//cpu:cpu_test
 * @org_golang_x_sys//execabs:execabs_test
-* @org_golang_x_sys//internal/unsafeheader:unsafeheader_test
 * @org_golang_x_sys//plan9:plan9_test
 * @org_golang_x_sys//unix/internal/mkmerge:mkmerge_test
 * @org_golang_x_sys//windows/mkwinsyscall:mkwinsyscall_test
@@ -191,8 +190,6 @@
 * @org_golang_x_tools//internal/jsonrpc2:jsonrpc2_test
 * @org_golang_x_tools//internal/jsonrpc2/servertest:servertest_test
 * @org_golang_x_tools//internal/jsonrpc2_v2:jsonrpc2_v2_test
-* @org_golang_x_tools//internal/lockedfile:lockedfile_test
-* @org_golang_x_tools//internal/lockedfile/internal/filelock:filelock_test
 * @org_golang_x_tools//internal/memoize:memoize_test
 * @org_golang_x_tools//internal/persistent:persistent_test
 * @org_golang_x_tools//internal/proxydir:proxydir_test
diff --git a/third_party/org_golang_x_sys-gazelle.patch b/third_party/org_golang_x_sys-gazelle.patch
index 389982d..b6ee36d 100644
--- a/third_party/org_golang_x_sys-gazelle.patch
+++ b/third_party/org_golang_x_sys-gazelle.patch
@@ -503,7 +503,7 @@
 diff -urN a/windows/BUILD.bazel b/windows/BUILD.bazel
 --- a/windows/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
 +++ b/windows/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,60 @@
+@@ -0,0 +1,53 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -535,12 +535,6 @@
 +    ],
 +    importpath = "golang.org/x/sys/windows",
 +    visibility = ["//visibility:public"],
-+    deps = select({
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            "//internal/unsafeheader",
-+        ],
-+        "//conditions:default": [],
-+    }),
 +)
 +
 +alias(
@@ -559,7 +553,6 @@
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:windows": [
 +            ":windows",
-+            "//internal/unsafeheader",
 +        ],
 +        "//conditions:default": [],
 +    }),
@@ -629,7 +622,7 @@
 diff -urN a/windows/svc/BUILD.bazel b/windows/svc/BUILD.bazel
 --- a/windows/svc/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
 +++ b/windows/svc/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,36 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -642,7 +635,6 @@
 +    visibility = ["//visibility:public"],
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:windows": [
-+            "//internal/unsafeheader",
 +            "//windows",
 +        ],
 +        "//conditions:default": [],
@@ -768,7 +760,7 @@
 diff -urN a/windows/svc/mgr/BUILD.bazel b/windows/svc/mgr/BUILD.bazel
 --- a/windows/svc/mgr/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
 +++ b/windows/svc/mgr/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,40 @@
+@@ -0,0 +1,39 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -783,7 +775,6 @@
 +    visibility = ["//visibility:public"],
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:windows": [
-+            "//internal/unsafeheader",
 +            "//windows",
 +            "//windows/svc",
 +        ],
diff --git a/third_party/org_golang_x_tools-deletegopls.patch b/third_party/org_golang_x_tools-deletegopls.patch
index 6011df5..e15c915 100644
--- a/third_party/org_golang_x_tools-deletegopls.patch
+++ b/third_party/org_golang_x_tools-deletegopls.patch
@@ -1,6 +1,142 @@
+diff -urN a/gopls/README.md b/gopls/README.md
+--- a/gopls/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/README.md	1970-01-01 08:00:00
+@@ -1,132 +0,0 @@
+-# `gopls`, the Go language server
+-
+-[![PkgGoDev](https://pkg.go.dev/badge/golang.org/x/tools/gopls)](https://pkg.go.dev/golang.org/x/tools/gopls)
+-
+-`gopls` (pronounced "Go please") is the official Go [language server] developed
+-by the Go team. It provides IDE features to any [LSP]-compatible editor.
+-
+-<!--TODO(rfindley): Add gifs here.-->
+-
+-You should not need to interact with `gopls` directly--it will be automatically
+-integrated into your editor. The specific features and settings vary slightly
+-by editor, so we recommend that you proceed to the
+-[documentation for your editor](#editors) below.
+-
+-## Editors
+-
+-To get started with `gopls`, install an LSP plugin in your editor of choice.
+-
+-* [VS Code](https://github.com/golang/vscode-go/blob/master/README.md)
+-* [Vim / Neovim](doc/vim.md)
+-* [Emacs](doc/emacs.md)
+-* [Atom](https://github.com/MordFustang21/ide-gopls)
+-* [Sublime Text](doc/subl.md)
+-* [Acme](https://github.com/fhs/acme-lsp)
+-* [Lapce](https://github.com/lapce-community/lapce-go)
+-
+-If you use `gopls` with an editor that is not on this list, please send us a CL
+-[updating this documentation](doc/contributing.md).
+-
+-## Installation
+-
+-For the most part, you should not need to install or update `gopls`. Your
+-editor should handle that step for you.
+-
+-If you do want to get the latest stable version of `gopls`, run the following
+-command:
+-
+-```sh
+-go install golang.org/x/tools/gopls@latest
+-```
+-
+-Learn more in the
+-[advanced installation instructions](doc/advanced.md#installing-unreleased-versions).
+-
+-Learn more about gopls releases in the [release policy](doc/releases.md).
+-
+-## Setting up your workspace
+-
+-`gopls` supports both Go module, multi-module and GOPATH modes. See the
+-[workspace documentation](doc/workspace.md) for information on supported
+-workspace layouts.
+-
+-## Configuration
+-
+-You can configure `gopls` to change your editor experience or view additional
+-debugging information. Configuration options will be made available by your
+-editor, so see your [editor's instructions](#editors) for specific details. A
+-full list of `gopls` settings can be found in the [settings documentation](doc/settings.md).
+-
+-### Environment variables
+-
+-`gopls` inherits your editor's environment, so be aware of any environment
+-variables you configure. Some editors, such as VS Code, allow users to
+-selectively override the values of some environment variables.
+-
+-## Support Policy
+-
+-Gopls is maintained by engineers on the
+-[Go tools team](https://github.com/orgs/golang/teams/tools-team/members),
+-who actively monitor the
+-[Go](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls)
+-and
+-[VS Code Go](https://github.com/golang/vscode-go/issues) issue trackers.
+-
+-### Supported Go versions
+-
+-`gopls` follows the
+-[Go Release Policy](https://golang.org/doc/devel/release.html#policy),
+-meaning that it officially supports the last 2 major Go releases. Per
+-[issue #39146](https://go.dev/issues/39146), we attempt to maintain best-effort
+-support for the last 4 major Go releases, but this support extends only to not
+-breaking the build and avoiding easily fixable regressions.
+-
+-In the context of this discussion, gopls "supports" a Go version if it supports
+-being built with that Go version as well as integrating with the `go` command
+-of that Go version.
+-
+-The following table shows the final gopls version that supports a given Go
+-version. Go releases more recent than any in the table can be used with any
+-version of gopls.
+-
+-| Go Version  | Final gopls version with support (without warnings) |
+-| ----------- | --------------------------------------------------- |
+-| Go 1.12     | [gopls@v0.7.5](https://github.com/golang/tools/releases/tag/gopls%2Fv0.7.5) |
+-| Go 1.15     | [gopls@v0.9.5](https://github.com/golang/tools/releases/tag/gopls%2Fv0.9.5) |
+-| Go 1.17     | [gopls@v0.11.0](https://github.com/golang/tools/releases/tag/gopls%2Fv0.11.0) |
+-
+-Our extended support is enforced via [continuous integration with older Go
+-versions](doc/contributing.md#ci). This legacy Go CI may not block releases:
+-test failures may be skipped rather than fixed. Furthermore, if a regression in
+-an older Go version causes irreconcilable CI failures, we may drop support for
+-that Go version in CI if it is 3 or 4 Go versions old.
+-
+-### Supported build systems
+-
+-`gopls` currently only supports the `go` command, so if you are using
+-a different build system, `gopls` will not work well. Bazel is not officially
+-supported, but may be made to work with an appropriately configured
+-`go/packages` driver. See
+-[bazelbuild/rules_go#512](https://github.com/bazelbuild/rules_go/issues/512)
+-for more information.
+-You can follow [these instructions](https://github.com/bazelbuild/rules_go/wiki/Editor-setup)
+-to configure your `gopls` to work with Bazel.
+-
+-### Troubleshooting
+-
+-If you are having issues with `gopls`, please follow the steps described in the
+-[troubleshooting guide](doc/troubleshooting.md).
+-
+-## Additional information
+-
+-* [Features](doc/features.md)
+-* [Command-line interface](doc/command-line.md)
+-* [Advanced topics](doc/advanced.md)
+-* [Contributing to `gopls`](doc/contributing.md)
+-* [Integrating `gopls` with an editor](doc/design/integrating.md)
+-* [Design requirements and decisions](doc/design/design.md)
+-* [Implementation details](doc/design/implementation.md)
+-* [Open issues](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls)
+-
+-[language server]: https://langserver.org
+-[LSP]: https://microsoft.github.io/language-server-protocol/
 diff -urN a/gopls/api-diff/api_diff.go b/gopls/api-diff/api_diff.go
 --- a/gopls/api-diff/api_diff.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/api-diff/api_diff.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/api-diff/api_diff.go	1970-01-01 08:00:00
 @@ -1,89 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -93,8 +229,8 @@
 -}
 diff -urN a/gopls/doc/advanced.md b/gopls/doc/advanced.md
 --- a/gopls/doc/advanced.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/advanced.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,69 +0,0 @@
++++ b/gopls/doc/advanced.md	1970-01-01 08:00:00
+@@ -1,80 +0,0 @@
 -# Advanced topics
 -
 -This documentation is for advanced `gopls` users, who may want to test
@@ -139,6 +275,18 @@
 -(`export PATH=$HOME/go/bin:$PATH` on Unix systems) or by configuring your
 -editor.
 -
+-To work on both `std` and `cmd` simultaneously, add a `go.work` file to
+-`GOROOT/src`:
+-
+-```
+-cd $(go env GOROOT)/src
+-go work init . cmd
+-```
+-
+-Note that you must work inside the `GOROOT/src` subdirectory, as the `go`
+-command does not recognize `go.work` files in a parent of `GOROOT/src`
+-(https://go.dev/issue/59429).
+-
 -## Working with generic code
 -
 -Gopls has support for editing generic Go code. To enable this support, you need
@@ -152,7 +300,6 @@
 -
 -It is strongly recommended that you install the latest version of `gopls`, or
 -the latest **unstable** version as [described above](#installing-unreleased-versions).
--We're still working on improving our generics support.
 -
 -The `gopls` built with these instructions understands generic code. See the
 -[generics tutorial](https://go.dev/doc/tutorial/generics) for more information
@@ -166,8 +313,8 @@
 -[Go project]: https://go.googlesource.com/go
 diff -urN a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md
 --- a/gopls/doc/analyzers.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/analyzers.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,762 +0,0 @@
++++ b/gopls/doc/analyzers.md	1970-01-01 08:00:00
+@@ -1,837 +0,0 @@
 -# Analyzers
 -
 -This document describes the analyzers that `gopls` uses inside the editor.
@@ -176,6 +323,21 @@
 -[here](settings.md#analyses).
 -
 -<!-- BEGIN Analyzers: DO NOT MANUALLY EDIT THIS SECTION -->
+-## **appends**
+-
+-check for missing values after append
+-
+-This checker reports calls to append that pass
+-no values to be appended to the slice.
+-
+-	s := []string{"a", "b", "c"}
+-	_ = append(s)
+-
+-Such calls are always no-ops and often indicate an
+-underlying mistake.
+-
+-**Enabled by default.**
+-
 -## **asmdecl**
 -
 -report mismatches between assembly files and Go declarations
@@ -278,6 +440,37 @@
 -
 -**Enabled by default.**
 -
+-## **defers**
+-
+-report common mistakes in defer statements
+-
+-The defers analyzer reports a diagnostic when a defer statement would
+-result in a non-deferred call to time.Since, as experience has shown
+-that this is nearly always a mistake.
+-
+-For example:
+-
+-	start := time.Now()
+-	...
+-	defer recordLatency(time.Since(start)) // error: call to time.Since is not deferred
+-
+-The correct code is:
+-
+-	defer func() { recordLatency(time.Since(start)) }()
+-
+-**Enabled by default.**
+-
+-## **deprecated**
+-
+-check for use of deprecated identifiers
+-
+-The deprecated analyzer looks for deprecated symbols and package imports.
+-
+-See https://go.dev/wiki/Deprecated to learn about Go's convention
+-for documenting and signaling deprecated identifiers.
+-
+-**Enabled by default.**
+-
 -## **directive**
 -
 -check Go toolchain directives such as //go:debug
@@ -300,10 +493,14 @@
 -
 -## **embed**
 -
--check for //go:embed directive import
+-check //go:embed directive usage
 -
--This analyzer checks that the embed package is imported when source code contains //go:embed comment directives.
--The embed package must be imported for //go:embed directives to function.import _ "embed".
+-This analyzer checks that the embed package is imported if //go:embed
+-directives are present, providing a suggested fix to add the import if
+-it is missing.
+-
+-This analyzer also checks that //go:embed directives precede the
+-declaration of a single variable.
 -
 -**Enabled by default.**
 -
@@ -385,23 +582,6 @@
 -The Read method in v has a different signature than the Read method in
 -io.Reader, so this assertion cannot succeed.
 -
--
--**Enabled by default.**
--
--## **infertypeargs**
--
--check for unnecessary type arguments in call expressions
--
--Explicit type arguments may be omitted from call expressions if they can be
--inferred from function arguments, or from other type arguments:
--
--	func f[T any](T) {}
--	
--	func _() {
--		f[string]("foo") // string could be inferred
--	}
--
--
 -**Enabled by default.**
 -
 -## **loopclosure**
@@ -416,43 +596,43 @@
 -In this example, all the deferred functions run after the loop has
 -completed, so all observe the final value of v.
 -
--    for _, v := range list {
--        defer func() {
--            use(v) // incorrect
--        }()
--    }
+-	for _, v := range list {
+-	    defer func() {
+-	        use(v) // incorrect
+-	    }()
+-	}
 -
 -One fix is to create a new variable for each iteration of the loop:
 -
--    for _, v := range list {
--        v := v // new var per iteration
--        defer func() {
--            use(v) // ok
--        }()
--    }
+-	for _, v := range list {
+-	    v := v // new var per iteration
+-	    defer func() {
+-	        use(v) // ok
+-	    }()
+-	}
 -
 -The next example uses a go statement and has a similar problem.
 -In addition, it has a data race because the loop updates v
 -concurrent with the goroutines accessing it.
 -
--    for _, v := range elem {
--        go func() {
--            use(v)  // incorrect, and a data race
--        }()
--    }
+-	for _, v := range elem {
+-	    go func() {
+-	        use(v)  // incorrect, and a data race
+-	    }()
+-	}
 -
 -A fix is the same as before. The checker also reports problems
 -in goroutines started by golang.org/x/sync/errgroup.Group.
 -A hard-to-spot variant of this form is common in parallel tests:
 -
--    func Test(t *testing.T) {
--        for _, test := range tests {
--            t.Run(test.name, func(t *testing.T) {
--                t.Parallel()
--                use(test) // incorrect, and a data race
--            })
--        }
--    }
+-	func Test(t *testing.T) {
+-	    for _, test := range tests {
+-	        t.Run(test.name, func(t *testing.T) {
+-	            t.Parallel()
+-	            use(test) // incorrect, and a data race
+-	        })
+-	    }
+-	}
 -
 -The t.Parallel() call causes the rest of the function to execute
 -concurrent with the loop.
@@ -523,22 +703,32 @@
 -		panic(p)
 -	}
 -
--
 -**Disabled by default. Enable it by setting `"analyses": {"nilness": true}`.**
 -
 -## **printf**
 -
 -check consistency of Printf format strings and arguments
 -
--The check applies to known functions (for example, those in package fmt)
--as well as any detected wrappers of known functions.
+-The check applies to calls of the formatting functions such as
+-[fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of
+-those functions.
 -
--A function that wants to avail itself of printf checking but is not
--found by this analyzer's heuristics (for example, due to use of
--dynamic calls) can insert a bogus call:
+-In this example, the %d format operator requires an integer operand:
 -
--	if false {
--		_ = fmt.Sprintf(format, args...) // enable printf checking
+-	fmt.Printf("%d", "hello") // fmt.Printf format %d has arg "hello" of wrong type string
+-
+-See the documentation of the fmt package for the complete set of
+-format operators and their operand types.
+-
+-To enable printf checking on a function that is not found by this
+-analyzer's heuristics (for example, because control is obscured by
+-dynamic method calls), insert a bogus call:
+-
+-	func MyPrintf(format string, args ...any) {
+-		if false {
+-			_ = fmt.Sprintf(format, args...) // enable printf checker
+-		}
+-		...
 -	}
 -
 -The -funcs flag specifies a comma-separated list of names of additional
@@ -555,7 +745,6 @@
 -argument list. Otherwise it is assumed to be Print-like, taking a list
 -of arguments with no format string.
 -
--
 -**Enabled by default.**
 -
 -## **shadow**
@@ -585,7 +774,6 @@
 -		return err
 -	}
 -
--
 -**Disabled by default. Enable it by setting `"analyses": {"shadow": true}`.**
 -
 -## **shift**
@@ -638,6 +826,24 @@
 -
 -**Enabled by default.**
 -
+-## **slog**
+-
+-check for invalid structured logging calls
+-
+-The slog checker looks for calls to functions from the log/slog
+-package that take alternating key-value pairs. It reports calls
+-where an argument in a key position is neither a string nor a
+-slog.Attr, and where a final key is missing its value.
+-For example,it would report
+-
+-	slog.Warn("message", 11, "k") // slog.Warn arg "11" should be a string or a slog.Attr
+-
+-and
+-
+-	slog.Info("message", "k1", v1, "k2") // call to slog.Info missing a final value
+-
+-**Enabled by default.**
+-
 -## **sortslice**
 -
 -check the argument type of sort.Slice
@@ -657,19 +863,19 @@
 -not error, to satisfy io.WriterTo:
 -
 -	type myWriterTo struct{...}
--        func (myWriterTo) WriteTo(w io.Writer) error { ... }
+-	func (myWriterTo) WriteTo(w io.Writer) error { ... }
 -
 -This check ensures that each method whose name matches one of several
 -well-known interface methods from the standard library has the correct
 -signature for that interface.
 -
 -Checked method names include:
+-
 -	Format GobEncode GobDecode MarshalJSON MarshalXML
 -	Peek ReadByte ReadFrom ReadRune Scan Seek
 -	UnmarshalJSON UnreadByte UnreadRune WriteByte
 -	WriteTo
 -
--
 -**Enabled by default.**
 -
 -## **stringintconv**
@@ -686,7 +892,6 @@
 -with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the
 -string representation of the value in the desired base.
 -
--
 -**Enabled by default.**
 -
 -## **structtag**
@@ -706,12 +911,11 @@
 -This checker detects calls to these functions that occur within a goroutine
 -started by the test. For example:
 -
--func TestFoo(t *testing.T) {
--    go func() {
--        t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine
--    }()
--}
--
+-	func TestFoo(t *testing.T) {
+-	    go func() {
+-	        t.Fatal("oops") // error: (*T).Fatal called from non-test goroutine
+-	    }()
+-	}
 -
 -**Enabled by default.**
 -
@@ -719,7 +923,7 @@
 -
 -check for common mistaken usages of tests and examples
 -
--The tests checker walks Test, Benchmark and Example functions checking
+-The tests checker walks Test, Benchmark, Fuzzing and Example functions checking
 -malformed names, wrong signatures and examples documenting non-existent
 -identifiers.
 -
@@ -736,7 +940,6 @@
 -format. Internationally, "yyyy-dd-mm" does not occur in common calendar date
 -standards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.
 -
--
 -**Enabled by default.**
 -
 -## **unmarshal**
@@ -779,7 +982,7 @@
 -
 -To reduce false positives it ignores:
 -- methods
--- parameters that do not have a name or are underscored
+-- parameters that do not have a name or have the name '_' (the blank identifier)
 -- functions in test files
 -- functions with empty bodies or those with just a return stmt
 -
@@ -789,9 +992,11 @@
 -
 -check for unused results of calls to some functions
 -
--Some functions like fmt.Errorf return a result and have no side effects,
--so it is always a mistake to discard the result. This analyzer reports
--calls to certain functions in which the result of the call is ignored.
+-Some functions like fmt.Errorf return a result and have no side
+-effects, so it is always a mistake to discard the result. Other
+-functions may return an error that must not be ignored, or a cleanup
+-operation that must be called. This analyzer reports calls to
+-functions like these when the result of the call is ignored.
 -
 -The set of functions may be controlled using flags.
 -
@@ -810,6 +1015,7 @@
 -For example:
 -
 -	type T struct { x int }
+-
 -	func f(input []T) {
 -		for i, v := range input {  // v is a copy
 -			v.x = i  // unused write to field x
@@ -819,11 +1025,11 @@
 -Another example is about non-pointer receiver:
 -
 -	type T struct { x int }
+-
 -	func (t T) f() {  // t is a copy
 -		t.x = i  // unused write to field x
 -	}
 -
--
 -**Disabled by default. Enable it by setting `"analyses": {"unusedwrite": true}`.**
 -
 -## **useany**
@@ -920,6 +1126,22 @@
 -
 -**Enabled by default.**
 -
+-## **infertypeargs**
+-
+-check for unnecessary type arguments in call expressions
+-
+-Explicit type arguments may be omitted from call expressions if they can be
+-inferred from function arguments, or from other type arguments:
+-
+-	func f[T any](T) {}
+-	
+-	func _() {
+-		f[string]("foo") // string could be inferred
+-	}
+-
+-
+-**Enabled by default.**
+-
 -## **stubmethods**
 -
 -stub methods analyzer
@@ -932,7 +1154,7 @@
 -<!-- END Analyzers: DO NOT MANUALLY EDIT THIS SECTION -->
 diff -urN a/gopls/doc/command-line.md b/gopls/doc/command-line.md
 --- a/gopls/doc/command-line.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/command-line.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/command-line.md	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -# Command line
 -
@@ -951,8 +1173,8 @@
 -It is not a goal of `gopls` to be a high performance command line tool. Its command line is intended for single file/package user interaction speeds, not bulk processing.
 diff -urN a/gopls/doc/commands.md b/gopls/doc/commands.md
 --- a/gopls/doc/commands.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/commands.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,467 +0,0 @@
++++ b/gopls/doc/commands.md	1970-01-01 08:00:00
+@@ -1,586 +0,0 @@
 -# Commands
 -
 -This document describes the LSP-level commands supported by `gopls`. They cannot be invoked directly by users, and all the details are subject to change, so nobody should rely on this information.
@@ -996,6 +1218,22 @@
 -}
 -```
 -
+-### **update the given telemetry counters.**
+-Identifier: `gopls.add_telemetry_counters`
+-
+-Gopls will prepend "fwd/" to all the counters updated using this command
+-to avoid conflicts with other counters gopls collects.
+-
+-Args:
+-
+-```
+-{
+-	// Names and Values must have the same length.
+-	"Names": []string,
+-	"Values": []int64,
+-}
+-```
+-
 -### **Apply a fix**
 -Identifier: `gopls.apply_fix`
 -
@@ -1072,7 +1310,7 @@
 -Result:
 -
 -```
--map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/govulncheck.Result
+-map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/vulncheck.Result
 -```
 -
 -### **Toggle gc_details**
@@ -1177,6 +1415,12 @@
 -}
 -```
 -
+-### **checks for the right conditions, and then prompts**
+-Identifier: `gopls.maybe_prompt_for_telemetry`
+-
+-the user to ask if they want to enable Go telemetry uploading. If the user
+-responds 'Yes', the telemetry mode is set to "on".
+-
 -### **fetch memory statistics**
 -Identifier: `gopls.mem_stats`
 -
@@ -1191,6 +1435,7 @@
 -{
 -	"HeapAlloc": uint64,
 -	"HeapInUse": uint64,
+-	"TotalAlloc": uint64,
 -}
 -```
 -
@@ -1221,6 +1466,9 @@
 -	"URI": string,
 -	// The module path to remove.
 -	"ModulePath": string,
+-	// If the module is tidied apart from the one unused diagnostic, we can
+-	// run `go get module@none`, and then run `go mod tidy`. Otherwise, we
+-	// must make textual edits.
 -	"OnlyDiagnostic": bool,
 -}
 -```
@@ -1243,7 +1491,22 @@
 -}
 -```
 -
--### **Run govulncheck.**
+-### **run `go work [args...]`, and apply the resulting go.work**
+-Identifier: `gopls.run_go_work_command`
+-
+-edits to the current go.work file.
+-
+-Args:
+-
+-```
+-{
+-	"ViewID": string,
+-	"InitFirst": bool,
+-	"Args": []string,
+-}
+-```
+-
+-### **Run vulncheck.**
 -Identifier: `gopls.run_govulncheck`
 -
 -Run vulnerability check (`govulncheck`).
@@ -1300,14 +1563,14 @@
 -	// Optional: the address (including port) for the debug server to listen on.
 -	// If not provided, the debug server will bind to "localhost:0", and the
 -	// full debug URL will be contained in the result.
--	// 
+-	//
 -	// If there is more than one gopls instance along the serving path (i.e. you
 -	// are using a daemon), each gopls instance will attempt to start debugging.
 -	// If Addr specifies a port, only the daemon will be able to bind to that
 -	// port, and each intermediate gopls instance will fail to start debugging.
 -	// For this reason it is recommended not to specify a port (or equivalently,
 -	// to specify ":0").
--	// 
+-	//
 -	// If the server was already debugging this field has no effect, and the
 -	// result will contain the previously configured debug URL(s).
 -	"Addr": string,
@@ -1321,7 +1584,7 @@
 -	// The URLs to use to access the debug servers, for all gopls instances in
 -	// the serving path. For the common case of a single gopls instance (i.e. no
 -	// daemon), this will be exactly one address.
--	// 
+-	//
 -	// In the case of one or more gopls instances forwarding the LSP to a daemon,
 -	// URLs will contain debug addresses for each server in the serving path, in
 -	// serving order. The daemon debug address will be the last entry in the
@@ -1332,6 +1595,48 @@
 -}
 -```
 -
+-### **start capturing a profile of gopls' execution.**
+-Identifier: `gopls.start_profile`
+-
+-Start a new pprof profile. Before using the resulting file, profiling must
+-be stopped with a corresponding call to StopProfile.
+-
+-This command is intended for internal use only, by the gopls benchmark
+-runner.
+-
+-Args:
+-
+-```
+-struct{}
+-```
+-
+-Result:
+-
+-```
+-struct{}
+-```
+-
+-### **stop an ongoing profile.**
+-Identifier: `gopls.stop_profile`
+-
+-This command is intended for internal use only, by the gopls benchmark
+-runner.
+-
+-Args:
+-
+-```
+-struct{}
+-```
+-
+-Result:
+-
+-```
+-{
+-	// File is the profile file name.
+-	"File": string,
+-}
+-```
+-
 -### **Run test(s) (legacy)**
 -Identifier: `gopls.test`
 -
@@ -1419,11 +1724,47 @@
 -}
 -```
 -
+-### **fetch workspace statistics**
+-Identifier: `gopls.workspace_stats`
+-
+-Query statistics about workspace builds, modules, packages, and files.
+-
+-This command is intended for internal use only, by the gopls stats
+-command.
+-
+-Result:
+-
+-```
+-{
+-	"Files": {
+-		"Total": int,
+-		"Largest": int,
+-		"Errs": int,
+-	},
+-	"Views": []{
+-		"GoCommandVersion": string,
+-		"AllPackages": {
+-			"Packages": int,
+-			"LargestPackage": int,
+-			"CompiledGoFiles": int,
+-			"Modules": int,
+-		},
+-		"WorkspacePackages": {
+-			"Packages": int,
+-			"LargestPackage": int,
+-			"CompiledGoFiles": int,
+-			"Modules": int,
+-		},
+-		"Diagnostics": int,
+-	},
+-}
+-```
+-
 -<!-- END Commands: DO NOT MANUALLY EDIT THIS SECTION -->
 diff -urN a/gopls/doc/contributing.md b/gopls/doc/contributing.md
 --- a/gopls/doc/contributing.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/contributing.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,119 +0,0 @@
++++ b/gopls/doc/contributing.md	1970-01-01 08:00:00
+@@ -1,165 +0,0 @@
 -# Documentation for contributors
 -
 -This documentation augments the general documentation for contributing to the
@@ -1472,6 +1813,52 @@
 -gophers slack. Please feel free to ask any questions about your contribution or
 -about contributing in general.
 -
+-
+-## Error handling
+-
+-It is important for the user experience that, whenever practical,
+-minor logic errors in a particular feature don't cause the server to
+-crash.
+-
+-The representation of a Go program is complex. The import graph of
+-package metadata, the syntax trees of parsed files, and their
+-associated type information together form a huge API surface area.
+-Even when the input is valid, there are many edge cases to consider,
+-and this grows by an order of magnitude when you consider missing
+-imports, parse errors, and type errors.
+-
+-What should you do when your logic must handle an error that you
+-believe "can't happen"?
+-
+-- If it's possible to return an error, then use the `bug.Errorf`
+-  function to return an error to the user, but also record the bug in
+-  gopls' cache so that it is less likely to be ignored.
+-
+-- If it's safe to proceed, you can call `bug.Reportf` to record the
+-  error and continue as normal.
+-
+-- If there's no way to proceed, call `bug.Fatalf` to record the error
+-  and then stop the program with `log.Fatalf`. You can also use
+-  `bug.Panicf` if there's a chance that a recover handler might save
+-  the situation.
+-
+-- Only if you can prove locally that an error is impossible should you
+-  call `log.Fatal`. If the error may happen for some input, however
+-  unlikely, then you should use one of the approaches above. Also, if
+-  the proof of safety depends on invariants broadly distributed across
+-  the code base, then you should instead use `bug.Panicf`.
+-
+-Note also that panicking is preferable to `log.Fatal` because it
+-allows VS Code's crash reporting to recognize and capture the stack.
+-
+-Bugs reported through `bug.Errorf` and friends are retrieved using the
+-`gopls bug` command, which opens a GitHub Issue template and populates
+-it with a summary of each bug and its frequency.
+-The text of the bug is rather fastidiously printed to stdout to avoid
+-sharing user names and error message strings (which could contain
+-project identifiers) with GitHub.
+-Users are invited to share it if they are willing.
+-
 -## Testing
 -
 -To run tests for just `gopls/`, run,
@@ -1545,7 +1932,7 @@
 -[issue-wanted]: https://github.com/golang/go/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Agopls+label%3A"help+wanted" "help wanted"
 diff -urN a/gopls/doc/daemon.md b/gopls/doc/daemon.md
 --- a/gopls/doc/daemon.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/daemon.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/daemon.md	1970-01-01 08:00:00
 @@ -1,183 +0,0 @@
 -# Running gopls as a daemon
 -
@@ -1732,7 +2119,7 @@
 -that actually starts the daemon.
 diff -urN a/gopls/doc/design/design.md b/gopls/doc/design/design.md
 --- a/gopls/doc/design/design.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/design/design.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/design/design.md	1970-01-01 08:00:00
 @@ -1,394 +0,0 @@
 -# `gopls` design documentation
 -
@@ -2130,7 +2517,7 @@
 -[`workspace/didChangeWatchedFiles`]: https://github.com/Microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md#workspace_didChangeWatchedFiles
 diff -urN a/gopls/doc/design/implementation.md b/gopls/doc/design/implementation.md
 --- a/gopls/doc/design/implementation.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/design/implementation.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/design/implementation.md	1970-01-01 08:00:00
 @@ -1,48 +0,0 @@
 -# gopls implementation documentation
 -
@@ -2171,18 +2558,18 @@
 -
 -[gopls]: https://github.com/golang/tools/tree/master/gopls
 -[internal/jsonrpc2]: https://github.com/golang/tools/tree/master/internal/jsonrpc2
--[internal/lsp]: https://github.com/golang/tools/tree/master/internal/lsp
--[internal/lsp/cache]: https://github.com/golang/tools/tree/master/internal/lsp/cache
--[internal/lsp/cmd]: https://github.com/golang/tools/tree/master/internal/lsp/cmd
--[internal/lsp/debug]: https://github.com/golang/tools/tree/master/internal/lsp/debug
--[internal/lsp/protocol]: https://github.com/golang/tools/tree/master/internal/lsp/protocol
--[internal/lsp/source]: https://github.com/golang/tools/tree/master/internal/lsp/source
+-[internal/lsp]: https://github.com/golang/tools/tree/master/gopls/internal/lsp
+-[internal/lsp/cache]: https://github.com/golang/tools/tree/master/gopls/internal/lsp/cache
+-[internal/lsp/cmd]: https://github.com/golang/tools/tree/master/gopls/internal/lsp/cmd
+-[internal/lsp/debug]: https://github.com/golang/tools/tree/master/gopls/internal/lsp/debug
+-[internal/lsp/protocol]: https://github.com/golang/tools/tree/master/gopls/internal/lsp/protocol
+-[internal/lsp/source]: https://github.com/golang/tools/tree/master/gopls/internal/lsp/source
 -[internal/memoize]: https://github.com/golang/tools/tree/master/internal/memoize
--[internal/span]: https://github.com/golang/tools/tree/master/internal/span
+-[internal/span]: https://github.com/golang/tools/tree/master/gopls/internal/span
 -[x/tools]: https://github.com/golang/tools
 diff -urN a/gopls/doc/design/integrating.md b/gopls/doc/design/integrating.md
 --- a/gopls/doc/design/integrating.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/design/integrating.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/design/integrating.md	1970-01-01 08:00:00
 @@ -1,91 +0,0 @@
 -# Documentation for plugin authors
 -
@@ -2277,7 +2664,7 @@
 -[#31526]: https://github.com/golang/go/issues/31526
 diff -urN a/gopls/doc/emacs.md b/gopls/doc/emacs.md
 --- a/gopls/doc/emacs.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/emacs.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/emacs.md	1970-01-01 08:00:00
 @@ -1,183 +0,0 @@
 -# Emacs
 -
@@ -2464,7 +2851,7 @@
 -[Gophers slack]: https://invite.slack.golangbridge.org/
 diff -urN a/gopls/doc/features.md b/gopls/doc/features.md
 --- a/gopls/doc/features.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/features.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/features.md	1970-01-01 08:00:00
 @@ -1,55 +0,0 @@
 -# Features
 -
@@ -2523,8 +2910,8 @@
 -
 diff -urN a/gopls/doc/generate.go b/gopls/doc/generate.go
 --- a/gopls/doc/generate.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/generate.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,778 +0,0 @@
++++ b/gopls/doc/generate.go	1970-01-01 08:00:00
+@@ -1,786 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -2545,7 +2932,6 @@
 -	"go/token"
 -	"go/types"
 -	"io"
--	"io/ioutil"
 -	"os"
 -	"os/exec"
 -	"path/filepath"
@@ -2612,9 +2998,13 @@
 -
 -// pkgDir returns the directory corresponding to the import path pkgPath.
 -func pkgDir(pkgPath string) (string, error) {
--	out, err := exec.Command("go", "list", "-f", "{{.Dir}}", pkgPath).Output()
+-	cmd := exec.Command("go", "list", "-f", "{{.Dir}}", pkgPath)
+-	out, err := cmd.Output()
 -	if err != nil {
--		return "", err
+-		if ee, _ := err.(*exec.ExitError); ee != nil && len(ee.Stderr) > 0 {
+-			return "", fmt.Errorf("%v: %w\n%s", cmd, err, ee.Stderr)
+-		}
+-		return "", fmt.Errorf("%v: %w", cmd, err)
 -	}
 -	return strings.TrimSpace(string(out)), nil
 -}
@@ -2992,7 +3382,11 @@
 -		if fld.Doc != "" && level == 0 {
 -			doclines := strings.Split(fld.Doc, "\n")
 -			for _, line := range doclines {
--				fmt.Fprintf(&b, "%s\t// %s\n", indent, line)
+-				text := ""
+-				if line != "" {
+-					text = " " + line
+-				}
+-				fmt.Fprintf(&b, "%s\t//%s\n", indent, text)
 -			}
 -		}
 -		tag := strings.Split(fld.JSONTag, ",")[0]
@@ -3043,6 +3437,7 @@
 -		json = append(json, &source.AnalyzerJSON{
 -			Name:    a.Analyzer.Name,
 -			Doc:     a.Analyzer.Doc,
+-			URL:     a.Analyzer.URL,
 -			Default: a.Enabled,
 -		})
 -	}
@@ -3091,7 +3486,7 @@
 -}
 -
 -func rewriteFile(file string, api *source.APIJSON, write bool, rewrite func([]byte, *source.APIJSON) ([]byte, error)) (bool, error) {
--	old, err := ioutil.ReadFile(file)
+-	old, err := os.ReadFile(file)
 -	if err != nil {
 -		return false, err
 -	}
@@ -3105,7 +3500,7 @@
 -		return bytes.Equal(old, new), nil
 -	}
 -
--	if err := ioutil.WriteFile(file, new, 0); err != nil {
+-	if err := os.WriteFile(file, new, 0); err != nil {
 -		return false, err
 -	}
 -
@@ -3305,8 +3700,8 @@
 -}
 diff -urN a/gopls/doc/generate_test.go b/gopls/doc/generate_test.go
 --- a/gopls/doc/generate_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/generate_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,26 +0,0 @@
++++ b/gopls/doc/generate_test.go	1970-01-01 08:00:00
+@@ -1,28 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -3320,22 +3715,24 @@
 -)
 -
 -func TestGenerated(t *testing.T) {
--	// This test fails on 1.18 Kokoro for unknown reasons; in any case, it
--	// suffices to run this test on any builder.
--	testenv.NeedsGo1Point(t, 19)
--	testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code.
+-	testenv.NeedsGoPackages(t)
+-	// This test fails on Kokoro, for unknown reasons, so must be run only on TryBots.
+-	// In any case, it suffices to run this test on any builder.
+-	testenv.NeedsGo1Point(t, 21)
+-
+-	testenv.NeedsLocalXTools(t)
 -
 -	ok, err := doMain(false)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
 -	if !ok {
--		t.Error("documentation needs updating. run: `go run doc/generate.go` from the gopls module.")
+-		t.Error("documentation needs updating. Run: cd gopls && go generate")
 -	}
 -}
 diff -urN a/gopls/doc/inlayHints.md b/gopls/doc/inlayHints.md
 --- a/gopls/doc/inlayHints.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/inlayHints.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/inlayHints.md	1970-01-01 08:00:00
 @@ -1,80 +0,0 @@
 -# Hints
 -
@@ -3419,7 +3816,7 @@
 -<!-- END Hints: DO NOT MANUALLY EDIT THIS SECTION -->
 diff -urN a/gopls/doc/releases.md b/gopls/doc/releases.md
 --- a/gopls/doc/releases.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/releases.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/releases.md	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -# Gopls release policy
 -
@@ -3448,7 +3845,7 @@
 -For more background on this policy, see https://go.dev/issue/55267.
 diff -urN a/gopls/doc/semantictokens.md b/gopls/doc/semantictokens.md
 --- a/gopls/doc/semantictokens.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/semantictokens.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/semantictokens.md	1970-01-01 08:00:00
 @@ -1,121 +0,0 @@
 -# Semantic Tokens
 -
@@ -3574,8 +3971,8 @@
 \ No newline at end of file
 diff -urN a/gopls/doc/settings.md b/gopls/doc/settings.md
 --- a/gopls/doc/settings.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/settings.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,527 +0,0 @@
++++ b/gopls/doc/settings.md	1970-01-01 08:00:00
+@@ -1,567 +0,0 @@
 -# Settings
 -
 -<!--TODO: Generate this file from the documentation in golang.org/x/tools/gopls/internal/lsp/source/options.go.-->
@@ -3847,6 +4244,16 @@
 -
 -Default: `true`.
 -
+-##### **completeFunctionCalls** *bool*
+-
+-completeFunctionCalls enables function call completion.
+-
+-When completing a statement, or when a function return type matches the
+-expected of the expression being completed, completion may suggest call
+-expressions (i.e. may include parentheses).
+-
+-Default: `true`.
+-
 -#### Diagnostic
 -
 -##### **analyses** *map[string]bool*
@@ -3920,7 +4327,21 @@
 -
 -This option must be set to a valid duration string, for example `"250ms"`.
 -
--Default: `"250ms"`.
+-Default: `"1s"`.
+-
+-##### **analysisProgressReporting** *bool*
+-
+-analysisProgressReporting controls whether gopls sends progress
+-notifications when construction of its index of analysis facts is taking a
+-long time. Cancelling these notifications will cancel the indexing task,
+-though it will restart after the next change in the workspace.
+-
+-When a package is opened for the first time and heavyweight analyses such as
+-staticcheck are enabled, it can take a while to construct the index of
+-analysis facts for all its dependencies. The index is cached in the
+-filesystem, so subsequent analysis should be faster.
+-
+-Default: `true`.
 -
 -#### Documentation
 -
@@ -4034,6 +4455,22 @@
 -
 -Default: `"Dynamic"`.
 -
+-##### **symbolScope** *enum*
+-
+-symbolScope controls which packages are searched for workspace/symbol
+-requests. The default value, "workspace", searches only workspace
+-packages. The legacy behavior, "all", causes all loaded packages to be
+-searched, including dependencies; this is more expensive and may return
+-unwanted results.
+-
+-Must be one of:
+-
+-* `"all"` matches symbols in any loaded package, including
+-dependencies.
+-* `"workspace"` matches symbols in workspace packages only.
+-
+-Default: `"all"`.
+-
 -#### **verboseOutput** *bool*
 -
 -**This setting is for debugging purposes only.**
@@ -4077,7 +4514,7 @@
 -Identifier: `regenerate_cgo`
 -
 -Regenerates cgo definitions.
--### **Run govulncheck.**
+-### **Run vulncheck.**
 -
 -Identifier: `run_govulncheck`
 -
@@ -4105,7 +4542,7 @@
 -<!-- END Lenses: DO NOT MANUALLY EDIT THIS SECTION -->
 diff -urN a/gopls/doc/subl.md b/gopls/doc/subl.md
 --- a/gopls/doc/subl.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/subl.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/subl.md	1970-01-01 08:00:00
 @@ -1,81 +0,0 @@
 -# Sublime Text
 -
@@ -4190,7 +4627,7 @@
 -[LSP]: https://packagecontrol.io/packages/LSP
 diff -urN a/gopls/doc/troubleshooting.md b/gopls/doc/troubleshooting.md
 --- a/gopls/doc/troubleshooting.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/troubleshooting.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/troubleshooting.md	1970-01-01 08:00:00
 @@ -1,48 +0,0 @@
 -# Troubleshooting
 -
@@ -4242,8 +4679,8 @@
 -`gopls` automatically writes out memory debug information when your usage exceeds 1GB. This information can be found in your temporary directory with names like `gopls.1234-5GiB-withnames.zip`. On Windows, your temporary directory will be located at `%TMP%`, and on Unixes, it will be `$TMPDIR`, which is usually `/tmp`. Please [file an issue](#file-an-issue) with this memory debug information attached. If you are uncomfortable sharing the package names of your code, you can share the `-nonames` zip instead, but it's much less useful.
 diff -urN a/gopls/doc/vim.md b/gopls/doc/vim.md
 --- a/gopls/doc/vim.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/vim.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,216 +0,0 @@
++++ b/gopls/doc/vim.md	1970-01-01 08:00:00
+@@ -1,234 +0,0 @@
 -# Vim / Neovim
 -
 -* [vim-go](#vimgo)
@@ -4337,7 +4774,7 @@
 -
 -```json
 -  "languageserver": {
--    "golang": {
+-    "go": {
 -      "command": "gopls",
 -      "rootPatterns": ["go.work", "go.mod", ".vim/", ".git/", ".hg/"],
 -      "filetypes": ["go"],
@@ -4386,42 +4823,60 @@
 -git clone 'https://github.com/neovim/nvim-lspconfig.git' .
 -```
 -
--### <a href="#neovim-config" id="neovim-config">Custom Configuration</a>
+-### <a href="#neovim-config" id="neovim-config">Configuration</a>
 -
--You can add custom configuration using Lua.  Here is an example of enabling the
--`unusedparams` check as well as `staticcheck`:
--
--```vim
--lua <<EOF
--  lspconfig = require "lspconfig"
--  util = require "lspconfig/util"
--
--  lspconfig.gopls.setup {
--    cmd = {"gopls", "serve"},
--    filetypes = {"go", "gomod"},
--    root_dir = util.root_pattern("go.work", "go.mod", ".git"),
--    settings = {
--      gopls = {
--        analyses = {
--          unusedparams = true,
--        },
--        staticcheck = true,
--      },
--    },
--  }
--EOF
--```
--
--### <a href="#neovim-imports" id="neovim-imports">Imports</a>
--
--Use the following configuration to have your imports organized on save using
--the logic of `goimports`. Note: this requires Neovim v0.7.0 or later.
+-nvim-lspconfig aims to provide reasonable defaults, so your setup can be very
+-brief.
 -
 -```lua
--vim.api.nvim_create_autocmd('BufWritePre', {
--  pattern = '*.go',
+-local lspconfig = require("lspconfig")
+-lspconfig.gopls.setup({})
+-```
+-
+-However, you can also configure `gopls` for your preferences. Here's an
+-example that enables `unusedparams`, `staticcheck`, and `gofumpt`.
+-
+-```lua
+-local lspconfig = require("lspconfig")
+-lspconfig.gopls.setup({
+-  settings = {
+-    gopls = {
+-      analyses = {
+-        unusedparams = true,
+-      },
+-      staticcheck = true,
+-      gofumpt = true,
+-    },
+-  },
+-})
+-```
+-
+-### <a href="#neovim-imports" id="neovim-imports">Imports and Formatting</a>
+-
+-Use the following configuration to have your imports organized on save using
+-the logic of `goimports` and your code formatted.
+-
+-```lua
+-autocmd("BufWritePre", {
+-  pattern = "*.go",
 -  callback = function()
--    vim.lsp.buf.code_action({ context = { only = { 'source.organizeImports' } }, apply = true })
+-    local params = vim.lsp.util.make_range_params()
+-    params.context = {only = {"source.organizeImports"}}
+-    -- buf_request_sync defaults to a 1000ms timeout. Depending on your
+-    -- machine and codebase, you may want longer. Add an additional
+-    -- argument after params if you find that you have to write the file
+-    -- twice for changes to be saved.
+-    -- E.g., vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, 3000)
+-    local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params)
+-    for cid, res in pairs(result or {}) do
+-      for _, r in pairs(res.result or {}) do
+-        if r.edit then
+-          local enc = (vim.lsp.get_client_by_id(cid) or {}).offset_encoding or "utf-16"
+-          vim.lsp.util.apply_workspace_edit(r.edit, enc)
+-        end
+-      end
+-    end
+-    vim.lsp.buf.format({async = false})
 -  end
 -})
 -```
@@ -4462,7 +4917,7 @@
 -[nvim-lspconfig-imports]: https://github.com/neovim/nvim-lspconfig/issues/115
 diff -urN a/gopls/doc/workspace.md b/gopls/doc/workspace.md
 --- a/gopls/doc/workspace.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/doc/workspace.md	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/doc/workspace.md	1970-01-01 08:00:00
 @@ -1,101 +0,0 @@
 -# Setting up your workspace
 -
@@ -4567,8 +5022,8 @@
 -[file a new issue](https://github.com/golang/go/issues/new).
 diff -urN a/gopls/go.mod b/gopls/go.mod
 --- a/gopls/go.mod	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/go.mod	1970-01-01 00:00:00.000000000 +0000
-@@ -1,29 +0,0 @@
++++ b/gopls/go.mod	1970-01-01 08:00:00
+@@ -1,30 +0,0 @@
 -module golang.org/x/tools/gopls
 -
 -go 1.18
@@ -4578,14 +5033,15 @@
 -	github.com/jba/printsrc v0.2.2
 -	github.com/jba/templatecheck v0.6.0
 -	github.com/sergi/go-diff v1.1.0
--	golang.org/x/mod v0.9.0
--	golang.org/x/sync v0.1.0
--	golang.org/x/sys v0.6.0
--	golang.org/x/text v0.8.0
--	golang.org/x/tools v0.6.0
--	golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815
+-	golang.org/x/mod v0.13.0
+-	golang.org/x/sync v0.4.0
+-	golang.org/x/sys v0.13.0
+-	golang.org/x/telemetry v0.0.0-20231003223302-0168ef4ebbd3
+-	golang.org/x/text v0.13.0
+-	golang.org/x/tools v0.13.1-0.20230920233436-f9b8da7b22be
+-	golang.org/x/vuln v1.0.1
 -	gopkg.in/yaml.v3 v3.0.1
--	honnef.co/go/tools v0.4.2
+-	honnef.co/go/tools v0.4.5
 -	mvdan.cc/gofumpt v0.4.0
 -	mvdan.cc/xurls/v2 v2.4.0
 -)
@@ -4593,33 +5049,23 @@
 -require (
 -	github.com/BurntSushi/toml v1.2.1 // indirect
 -	github.com/google/safehtml v0.1.0 // indirect
--	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
 -	golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 // indirect
+-
 -)
 -
 -replace golang.org/x/tools => ../
 diff -urN a/gopls/go.sum b/gopls/go.sum
 --- a/gopls/go.sum	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/go.sum	1970-01-01 00:00:00.000000000 +0000
-@@ -1,101 +0,0 @@
--github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
++++ b/gopls/go.sum	1970-01-01 08:00:00
+@@ -1,72 +0,0 @@
 -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
 -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
--github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
--github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
--github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
--github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
--github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
--github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
--github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
--github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
--github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 -github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
 -github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8=
 -github.com/google/safehtml v0.1.0/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
@@ -4629,61 +5075,45 @@
 -github.com/jba/templatecheck v0.6.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4=
 -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
--github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
--github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
--github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
 -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
--github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
--golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
--golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
--golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
--golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 -golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW6Y=
 -golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
--golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
--golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
--golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
--golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
--golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
--golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
--golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+-golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
+-golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+-golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
--golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
--golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
--golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
--golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
--golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+-golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
+-golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
--golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
--golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
--golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+-golang.org/x/telemetry v0.0.0-20231003223302-0168ef4ebbd3 h1:vxxQvncMbcRAtqHV5HsHGJkbya+BIOYIY+y6cdPZhzk=
+-golang.org/x/telemetry v0.0.0-20231003223302-0168ef4ebbd3/go.mod h1:ppZ76JTkRgJC2GQEgtVY3fiuJR+N8FU2MAlp+gfN1E4=
+-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+-golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
 -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
--golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
--golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
--golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815 h1:A9kONVi4+AnuOr1dopsibH6hLi1Huy54cbeJxnq4vmU=
--golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815/go.mod h1:XJiVExZgoZfrrxoTeVsFYrSSk1snhfpOEC95JL+A4T0=
--golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
--golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
--golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+-golang.org/x/vuln v1.0.1 h1:KUas02EjQK5LTuIx1OylBQdKKZ9jeugs+HiqO5HormU=
+-golang.org/x/vuln v1.0.1/go.mod h1:bb2hMwln/tqxg32BNY4CcxHWtHXuYa3SbIBmtsyjxtM=
 -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@@ -4694,18 +5124,86 @@
 -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
--honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
--honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc=
--honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
+-honnef.co/go/tools v0.4.5 h1:YGD4H+SuIOOqsyoLOpZDWcieM28W47/zRO7f+9V3nvo=
+-honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k=
 -mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
 -mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
--mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 h1:Jh3LAeMt1eGpxomyu3jVkmVZWW2MxZ1qIIV2TZ/nRio=
--mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY=
 -mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
 -mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=
+diff -urN a/gopls/integration/govim/Dockerfile b/gopls/integration/govim/Dockerfile
+--- a/gopls/integration/govim/Dockerfile	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/integration/govim/Dockerfile	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+-# Copyright 2019 The Go Authors. All rights reserved.
+-# Use of this source code is governed by a BSD-style
+-# license that can be found in the LICENSE file.
+-
+-# govim requires a more recent version of vim than is available in most
+-# distros, so we build from their base image.
+-FROM govim/govim:latest-vim
+-ARG GOVIM_REF
+-
+-ENV GOPROXY=https://proxy.golang.org GOPATH=/go VIM_FLAVOR=vim
+-WORKDIR /src
+-
+-# Clone govim. In order to use the go command for resolving latest, we download
+-# a redundant copy of govim to the build cache using `go mod download`.
+-RUN git clone https://github.com/govim/govim /src/govim && cd /src/govim && \
+-    git checkout $GOVIM_REF
+diff -urN a/gopls/integration/govim/README.md b/gopls/integration/govim/README.md
+--- a/gopls/integration/govim/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/integration/govim/README.md	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
+-# govim integration tests
+-
+-Files in this directory configure Cloud Build to run [govim] integration tests
+-against a gopls binary built from source.
+-
+-## Running on GCP
+-
+-To run these integration tests in Cloud Build, use the following steps.  Here
+-we assume that `$PROJECT_ID` is a valid GCP project and `$BUCKET` is a cloud
+-storage bucket owned by that project.
+-
+-- `cd` to the root directory of the tools project.
+-- (at least once per GCP project) Build the test harness:
+-```
+-$ gcloud builds submit \
+-	--project="${PROJECT_ID}" \
+-	--config=gopls/integration/govim/cloudbuild.harness.yaml
+-```
+-- Run the integration tests:
+-```
+-$ gcloud builds submit \
+-	--project="${PROJECT_ID}" \
+-	--config=gopls/integration/govim/cloudbuild.yaml \
+-	--substitutions=_RESULT_BUCKET="${BUCKET}"
+-```
+-
+-## Fetching Artifacts
+-
+-Assuming the artifacts bucket is world readable, you can fetch integration from
+-GCS. They are located at:
+-
+-- logs: `https://storage.googleapis.com/${BUCKET}/log-${EVALUATION_ID}.txt`
+-- artifact tarball: `https://storage.googleapis.com/${BUCKET}/govim/${EVALUATION_ID}/artifacts.tar.gz`
+-
+-The `artifacts.go` command can be used to fetch both artifacts using an
+-evaluation id.
+-
+-## Running locally
+-
+-Run `gopls/integration/govim/run_local.sh`. This may take a while the first
+-time it is run, as it will require building the test harness. This script
+-accepts two flags to modify its behavior:
+-
+-**--sudo**: run docker with `sudo`
+-**--short**: run `go test -short`
+-
+-[govim]: https://github.com/govim/govim
 diff -urN a/gopls/integration/govim/artifacts.go b/gopls/integration/govim/artifacts.go
 --- a/gopls/integration/govim/artifacts.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/artifacts.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/integration/govim/artifacts.go	1970-01-01 08:00:00
 @@ -1,67 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -4716,7 +5214,7 @@
 -import (
 -	"flag"
 -	"fmt"
--	"io/ioutil"
+-	"io"
 -	"net/http"
 -	"os"
 -	"path"
@@ -4765,18 +5263,18 @@
 -	if resp.StatusCode != http.StatusOK {
 -		return fmt.Errorf("got status code %d from GCS", resp.StatusCode)
 -	}
--	data, err := ioutil.ReadAll(resp.Body)
+-	data, err := io.ReadAll(resp.Body)
 -	if err != nil {
 -		return fmt.Errorf("reading result: %v", err)
 -	}
--	if err := ioutil.WriteFile(name, data, 0644); err != nil {
+-	if err := os.WriteFile(name, data, 0644); err != nil {
 -		return fmt.Errorf("writing artifact: %v", err)
 -	}
 -	return nil
 -}
 diff -urN a/gopls/integration/govim/cloudbuild.harness.yaml b/gopls/integration/govim/cloudbuild.harness.yaml
 --- a/gopls/integration/govim/cloudbuild.harness.yaml	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/cloudbuild.harness.yaml	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/integration/govim/cloudbuild.harness.yaml	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -# Copyright 2019 The Go Authors. All rights reserved.
 -# Use of this source code is governed by a BSD-style
@@ -4801,7 +5299,7 @@
 -  - gcr.io/$PROJECT_ID/govim-harness
 diff -urN a/gopls/integration/govim/cloudbuild.yaml b/gopls/integration/govim/cloudbuild.yaml
 --- a/gopls/integration/govim/cloudbuild.yaml	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/cloudbuild.yaml	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/integration/govim/cloudbuild.yaml	1970-01-01 08:00:00
 @@ -1,51 +0,0 @@
 -# Copyright 2019 The Go Authors. All rights reserved.
 -# Use of this source code is governed by a BSD-style
@@ -4854,80 +5352,9 @@
 -# Write build logs to the same bucket as artifacts, so they can be more easily
 -# shared.
 -logsBucket: 'gs://${_RESULT_BUCKET}'
-diff -urN a/gopls/integration/govim/Dockerfile b/gopls/integration/govim/Dockerfile
---- a/gopls/integration/govim/Dockerfile	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/Dockerfile	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--# Copyright 2019 The Go Authors. All rights reserved.
--# Use of this source code is governed by a BSD-style
--# license that can be found in the LICENSE file.
--
--# govim requires a more recent version of vim than is available in most
--# distros, so we build from their base image.
--FROM govim/govim:latest-vim
--ARG GOVIM_REF
--
--ENV GOPROXY=https://proxy.golang.org GOPATH=/go VIM_FLAVOR=vim
--WORKDIR /src
--
--# Clone govim. In order to use the go command for resolving latest, we download
--# a redundant copy of govim to the build cache using `go mod download`.
--RUN git clone https://github.com/govim/govim /src/govim && cd /src/govim && \
--    git checkout $GOVIM_REF
-diff -urN a/gopls/integration/govim/README.md b/gopls/integration/govim/README.md
---- a/gopls/integration/govim/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,47 +0,0 @@
--# govim integration tests
--
--Files in this directory configure Cloud Build to run [govim] integration tests
--against a gopls binary built from source.
--
--## Running on GCP
--
--To run these integration tests in Cloud Build, use the following steps.  Here
--we assume that `$PROJECT_ID` is a valid GCP project and `$BUCKET` is a cloud
--storage bucket owned by that project.
--
--- `cd` to the root directory of the tools project.
--- (at least once per GCP project) Build the test harness:
--```
--$ gcloud builds submit \
--	--project="${PROJECT_ID}" \
--	--config=gopls/integration/govim/cloudbuild.harness.yaml
--```
--- Run the integration tests:
--```
--$ gcloud builds submit \
--	--project="${PROJECT_ID}" \
--	--config=gopls/integration/govim/cloudbuild.yaml \
--	--substitutions=_RESULT_BUCKET="${BUCKET}"
--```
--
--## Fetching Artifacts
--
--Assuming the artifacts bucket is world readable, you can fetch integration from
--GCS. They are located at:
--
--- logs: `https://storage.googleapis.com/${BUCKET}/log-${EVALUATION_ID}.txt`
--- artifact tarball: `https://storage.googleapis.com/${BUCKET}/govim/${EVALUATION_ID}/artifacts.tar.gz`
--
--The `artifacts.go` command can be used to fetch both artifacts using an
--evaluation id.
--
--## Running locally
--
--Run `gopls/integration/govim/run_local.sh`. This may take a while the first
--time it is run, as it will require building the test harness. This script
--accepts two flags to modify its behavior:
--
--**--sudo**: run docker with `sudo`
--**--short**: run `go test -short`
--
--[govim]: https://github.com/govim/govim
 diff -urN a/gopls/integration/govim/run_local.sh b/gopls/integration/govim/run_local.sh
 --- a/gopls/integration/govim/run_local.sh	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/run_local.sh	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/integration/govim/run_local.sh	1970-01-01 08:00:00
 @@ -1,96 +0,0 @@
 -#!/bin/bash -e
 -
@@ -5027,7 +5454,7 @@
 -    -gopls "/src/tools/gopls/${temp_gopls_name}"
 diff -urN a/gopls/integration/govim/run_tests_for_cloudbuild.sh b/gopls/integration/govim/run_tests_for_cloudbuild.sh
 --- a/gopls/integration/govim/run_tests_for_cloudbuild.sh	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/integration/govim/run_tests_for_cloudbuild.sh	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/integration/govim/run_tests_for_cloudbuild.sh	1970-01-01 08:00:00
 @@ -1,28 +0,0 @@
 -#!/bin/bash
 -
@@ -5057,9 +5484,486 @@
 -  # Remove directories we don't care about.
 -  find "$GOVIM_TESTSCRIPT_WORKDIR_ROOT" -type d \( -name .vim -o -name gopath \) -prune -exec rm -rf '{}' \;
 -fi
+diff -urN a/gopls/internal/astutil/purge.go b/gopls/internal/astutil/purge.go
+--- a/gopls/internal/astutil/purge.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/astutil/purge.go	1970-01-01 08:00:00
+@@ -1,74 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Package astutil provides various AST utility functions for gopls.
+-package astutil
+-
+-import (
+-	"bytes"
+-	"go/scanner"
+-	"go/token"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
+-)
+-
+-// PurgeFuncBodies returns a copy of src in which the contents of each
+-// outermost {...} region except struct and interface types have been
+-// deleted. This reduces the amount of work required to parse the
+-// top-level declarations.
+-//
+-// PurgeFuncBodies does not preserve newlines or position information.
+-// Also, if the input is invalid, parsing the output of
+-// PurgeFuncBodies may result in a different tree due to its effects
+-// on parser error recovery.
+-func PurgeFuncBodies(src []byte) []byte {
+-	// Destroy the content of any {...}-bracketed regions that are
+-	// not immediately preceded by a "struct" or "interface"
+-	// token.  That includes function bodies, composite literals,
+-	// switch/select bodies, and all blocks of statements.
+-	// This will lead to non-void functions that don't have return
+-	// statements, which of course is a type error, but that's ok.
+-
+-	var out bytes.Buffer
+-	file := token.NewFileSet().AddFile("", -1, len(src))
+-	var sc scanner.Scanner
+-	sc.Init(file, src, nil, 0)
+-	var prev token.Token
+-	var cursor int         // last consumed src offset
+-	var braces []token.Pos // stack of unclosed braces or -1 for struct/interface type
+-	for {
+-		pos, tok, _ := sc.Scan()
+-		if tok == token.EOF {
+-			break
+-		}
+-		switch tok {
+-		case token.COMMENT:
+-			// TODO(adonovan): opt: skip, to save an estimated 20% of time.
+-
+-		case token.LBRACE:
+-			if prev == token.STRUCT || prev == token.INTERFACE {
+-				pos = -1
+-			}
+-			braces = append(braces, pos)
+-
+-		case token.RBRACE:
+-			if last := len(braces) - 1; last >= 0 {
+-				top := braces[last]
+-				braces = braces[:last]
+-				if top < 0 {
+-					// struct/interface type: leave alone
+-				} else if len(braces) == 0 { // toplevel only
+-					// Delete {...} body.
+-					start, _ := safetoken.Offset(file, top)
+-					end, _ := safetoken.Offset(file, pos)
+-					out.Write(src[cursor : start+len("{")])
+-					cursor = end
+-				}
+-			}
+-		}
+-		prev = tok
+-	}
+-	out.Write(src[cursor:])
+-	return out.Bytes()
+-}
+diff -urN a/gopls/internal/astutil/purge_test.go b/gopls/internal/astutil/purge_test.go
+--- a/gopls/internal/astutil/purge_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/astutil/purge_test.go	1970-01-01 08:00:00
+@@ -1,89 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package astutil_test
+-
+-import (
+-	"go/ast"
+-	"go/parser"
+-	"go/token"
+-	"os"
+-	"reflect"
+-	"testing"
+-
+-	"golang.org/x/tools/go/packages"
+-	"golang.org/x/tools/gopls/internal/astutil"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-// TestPurgeFuncBodies tests PurgeFuncBodies by comparing it against a
+-// (less efficient) reference implementation that purges after parsing.
+-func TestPurgeFuncBodies(t *testing.T) {
+-	testenv.NeedsGoBuild(t) // we need the source code for std
+-
+-	// Load a few standard packages.
+-	config := packages.Config{Mode: packages.NeedCompiledGoFiles}
+-	pkgs, err := packages.Load(&config, "encoding/...")
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	// preorder returns the nodes of tree f in preorder.
+-	preorder := func(f *ast.File) (nodes []ast.Node) {
+-		ast.Inspect(f, func(n ast.Node) bool {
+-			if n != nil {
+-				nodes = append(nodes, n)
+-			}
+-			return true
+-		})
+-		return nodes
+-	}
+-
+-	packages.Visit(pkgs, nil, func(p *packages.Package) {
+-		for _, filename := range p.CompiledGoFiles {
+-			content, err := os.ReadFile(filename)
+-			if err != nil {
+-				t.Fatal(err)
+-			}
+-
+-			fset := token.NewFileSet()
+-
+-			// Parse then purge (reference implementation).
+-			f1, _ := parser.ParseFile(fset, filename, content, 0)
+-			ast.Inspect(f1, func(n ast.Node) bool {
+-				switch n := n.(type) {
+-				case *ast.FuncDecl:
+-					if n.Body != nil {
+-						n.Body.List = nil
+-					}
+-				case *ast.FuncLit:
+-					n.Body.List = nil
+-				case *ast.CompositeLit:
+-					n.Elts = nil
+-				}
+-				return true
+-			})
+-
+-			// Purge before parse (logic under test).
+-			f2, _ := parser.ParseFile(fset, filename, astutil.PurgeFuncBodies(content), 0)
+-
+-			// Compare sequence of node types.
+-			nodes1 := preorder(f1)
+-			nodes2 := preorder(f2)
+-			if len(nodes2) < len(nodes1) {
+-				t.Errorf("purged file has fewer nodes: %d vs  %d",
+-					len(nodes2), len(nodes1))
+-				nodes1 = nodes1[:len(nodes2)] // truncate
+-			}
+-			for i := range nodes1 {
+-				x, y := nodes1[i], nodes2[i]
+-				if reflect.TypeOf(x) != reflect.TypeOf(y) {
+-					t.Errorf("%s: got %T, want %T",
+-						fset.Position(x.Pos()), y, x)
+-					break
+-				}
+-			}
+-		}
+-	})
+-}
+diff -urN a/gopls/internal/astutil/util.go b/gopls/internal/astutil/util.go
+--- a/gopls/internal/astutil/util.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/astutil/util.go	1970-01-01 08:00:00
+@@ -1,61 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package astutil
+-
+-import (
+-	"go/ast"
+-
+-	"golang.org/x/tools/internal/typeparams"
+-)
+-
+-// UnpackRecv unpacks a receiver type expression, reporting whether it is a
+-// pointer recever, along with the type name identifier and any receiver type
+-// parameter identifiers.
+-//
+-// Copied (with modifications) from go/types.
+-func UnpackRecv(rtyp ast.Expr) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
+-L: // unpack receiver type
+-	// This accepts invalid receivers such as ***T and does not
+-	// work for other invalid receivers, but we don't care. The
+-	// validity of receiver expressions is checked elsewhere.
+-	for {
+-		switch t := rtyp.(type) {
+-		case *ast.ParenExpr:
+-			rtyp = t.X
+-		case *ast.StarExpr:
+-			ptr = true
+-			rtyp = t.X
+-		default:
+-			break L
+-		}
+-	}
+-
+-	// unpack type parameters, if any
+-	switch rtyp.(type) {
+-	case *ast.IndexExpr, *typeparams.IndexListExpr:
+-		var indices []ast.Expr
+-		rtyp, _, indices, _ = typeparams.UnpackIndexExpr(rtyp)
+-		for _, arg := range indices {
+-			var par *ast.Ident
+-			switch arg := arg.(type) {
+-			case *ast.Ident:
+-				par = arg
+-			default:
+-				// ignore errors
+-			}
+-			if par == nil {
+-				par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
+-			}
+-			tparams = append(tparams, par)
+-		}
+-	}
+-
+-	// unpack receiver name
+-	if name, _ := rtyp.(*ast.Ident); name != nil {
+-		rname = name
+-	}
+-
+-	return
+-}
+diff -urN a/gopls/internal/bug/bug.go b/gopls/internal/bug/bug.go
+--- a/gopls/internal/bug/bug.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/bug/bug.go	1970-01-01 08:00:00
+@@ -1,142 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Package bug provides utilities for reporting internal bugs, and being
+-// notified when they occur.
+-//
+-// Philosophically, because gopls runs as a sidecar process that the user does
+-// not directly control, sometimes it keeps going on broken invariants rather
+-// than panicking. In those cases, bug reports provide a mechanism to alert
+-// developers and capture relevant metadata.
+-package bug
+-
+-import (
+-	"fmt"
+-	"runtime"
+-	"runtime/debug"
+-	"sort"
+-	"sync"
+-	"time"
+-
+-	"golang.org/x/telemetry/counter"
+-)
+-
+-// PanicOnBugs controls whether to panic when bugs are reported.
+-//
+-// It may be set to true during testing.
+-var PanicOnBugs = false
+-
+-var (
+-	mu        sync.Mutex
+-	exemplars map[string]Bug
+-	handlers  []func(Bug)
+-)
+-
+-// A Bug represents an unexpected event or broken invariant. They are used for
+-// capturing metadata that helps us understand the event.
+-//
+-// Bugs are JSON-serializable.
+-type Bug struct {
+-	File        string    // file containing the call to bug.Report
+-	Line        int       // line containing the call to bug.Report
+-	Description string    // description of the bug
+-	Key         string    // key identifying the bug (file:line if available)
+-	Stack       string    // call stack
+-	AtTime      time.Time // time the bug was reported
+-}
+-
+-// Reportf reports a formatted bug message.
+-func Reportf(format string, args ...interface{}) {
+-	report(fmt.Sprintf(format, args...))
+-}
+-
+-// Errorf calls fmt.Errorf for the given arguments, and reports the resulting
+-// error message as a bug.
+-func Errorf(format string, args ...interface{}) error {
+-	err := fmt.Errorf(format, args...)
+-	report(err.Error())
+-	return err
+-}
+-
+-// Report records a new bug encountered on the server.
+-// It uses reflection to report the position of the immediate caller.
+-func Report(description string) {
+-	report(description)
+-}
+-
+-// BugReportCount is a telemetry counter that tracks # of bug reports.
+-var BugReportCount = counter.NewStack("gopls/bug", 16)
+-
+-func report(description string) {
+-	_, file, line, ok := runtime.Caller(2) // all exported reporting functions call report directly
+-
+-	key := "<missing callsite>"
+-	if ok {
+-		key = fmt.Sprintf("%s:%d", file, line)
+-	}
+-
+-	if PanicOnBugs {
+-		panic(fmt.Sprintf("%s: %s", key, description))
+-	}
+-
+-	bug := Bug{
+-		File:        file,
+-		Line:        line,
+-		Description: description,
+-		Key:         key,
+-		Stack:       string(debug.Stack()),
+-		AtTime:      time.Now(),
+-	}
+-
+-	newBug := false
+-	mu.Lock()
+-	if _, ok := exemplars[key]; !ok {
+-		if exemplars == nil {
+-			exemplars = make(map[string]Bug)
+-		}
+-		exemplars[key] = bug // capture one exemplar per key
+-		newBug = true
+-	}
+-	hh := handlers
+-	handlers = nil
+-	mu.Unlock()
+-
+-	if newBug {
+-		BugReportCount.Inc()
+-	}
+-	// Call the handlers outside the critical section since a
+-	// handler may itself fail and call bug.Report. Since handlers
+-	// are one-shot, the inner call should be trivial.
+-	for _, handle := range hh {
+-		handle(bug)
+-	}
+-}
+-
+-// Handle adds a handler function that will be called with the next
+-// bug to occur on the server. The handler only ever receives one bug.
+-// It is called synchronously, and should return in a timely manner.
+-func Handle(h func(Bug)) {
+-	mu.Lock()
+-	defer mu.Unlock()
+-	handlers = append(handlers, h)
+-}
+-
+-// List returns a slice of bug exemplars -- the first bugs to occur at each
+-// callsite.
+-func List() []Bug {
+-	mu.Lock()
+-	defer mu.Unlock()
+-
+-	var bugs []Bug
+-
+-	for _, bug := range exemplars {
+-		bugs = append(bugs, bug)
+-	}
+-
+-	sort.Slice(bugs, func(i, j int) bool {
+-		return bugs[i].Key < bugs[j].Key
+-	})
+-
+-	return bugs
+-}
+diff -urN a/gopls/internal/bug/bug_test.go b/gopls/internal/bug/bug_test.go
+--- a/gopls/internal/bug/bug_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/bug/bug_test.go	1970-01-01 08:00:00
+@@ -1,91 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package bug
+-
+-import (
+-	"encoding/json"
+-	"fmt"
+-	"testing"
+-	"time"
+-
+-	"github.com/google/go-cmp/cmp"
+-)
+-
+-func resetForTesting() {
+-	exemplars = nil
+-	handlers = nil
+-}
+-
+-func TestListBugs(t *testing.T) {
+-	defer resetForTesting()
+-
+-	Report("bad")
+-
+-	wantBugs(t, "bad")
+-
+-	for i := 0; i < 3; i++ {
+-		Report(fmt.Sprintf("index:%d", i))
+-	}
+-
+-	wantBugs(t, "bad", "index:0")
+-}
+-
+-func wantBugs(t *testing.T, want ...string) {
+-	t.Helper()
+-
+-	bugs := List()
+-	if got, want := len(bugs), len(want); got != want {
+-		t.Errorf("List(): got %d bugs, want %d", got, want)
+-		return
+-	}
+-
+-	for i, b := range bugs {
+-		if got, want := b.Description, want[i]; got != want {
+-			t.Errorf("bug.List()[%d] = %q, want %q", i, got, want)
+-		}
+-	}
+-}
+-
+-func TestBugHandler(t *testing.T) {
+-	defer resetForTesting()
+-
+-	Report("unseen")
+-
+-	// Both handlers are called, in order of registration, only once.
+-	var got string
+-	Handle(func(b Bug) { got += "1:" + b.Description })
+-	Handle(func(b Bug) { got += "2:" + b.Description })
+-
+-	Report("seen")
+-
+-	Report("again")
+-
+-	if want := "1:seen2:seen"; got != want {
+-		t.Errorf("got %q, want %q", got, want)
+-	}
+-}
+-
+-func TestBugJSON(t *testing.T) {
+-	b1 := Bug{
+-		File:        "foo.go",
+-		Line:        1,
+-		Description: "a bug",
+-		Key:         "foo.go:1",
+-		Stack:       "<stack>",
+-		AtTime:      time.Now(),
+-	}
+-
+-	data, err := json.Marshal(b1)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	var b2 Bug
+-	if err := json.Unmarshal(data, &b2); err != nil {
+-		t.Fatal(err)
+-	}
+-	if diff := cmp.Diff(b1, b2); diff != "" {
+-		t.Errorf("bugs differ after JSON Marshal/Unmarshal (-b1 +b2):\n%s", diff)
+-	}
+-}
 diff -urN a/gopls/internal/coverage/coverage.go b/gopls/internal/coverage/coverage.go
 --- a/gopls/internal/coverage/coverage.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/coverage/coverage.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/coverage/coverage.go	1970-01-01 08:00:00
 @@ -1,266 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -5327,463 +6231,9 @@
 -	filepath.WalkDir(dir, f)
 -	return ans
 -}
-diff -urN a/gopls/internal/govulncheck/semver/semver.go b/gopls/internal/govulncheck/semver/semver.go
---- a/gopls/internal/govulncheck/semver/semver.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/semver/semver.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,51 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--// Package semver provides shared utilities for manipulating
--// Go semantic versions.
--package semver
--
--import (
--	"regexp"
--	"strings"
--)
--
--// addSemverPrefix adds a 'v' prefix to s if it isn't already prefixed
--// with 'v' or 'go'. This allows us to easily test go-style SEMVER
--// strings against normal SEMVER strings.
--func addSemverPrefix(s string) string {
--	if !strings.HasPrefix(s, "v") && !strings.HasPrefix(s, "go") {
--		return "v" + s
--	}
--	return s
--}
--
--// removeSemverPrefix removes the 'v' or 'go' prefixes from go-style
--// SEMVER strings, for usage in the public vulnerability format.
--func removeSemverPrefix(s string) string {
--	s = strings.TrimPrefix(s, "v")
--	s = strings.TrimPrefix(s, "go")
--	return s
--}
--
--// CanonicalizeSemverPrefix turns a SEMVER string into the canonical
--// representation using the 'v' prefix, as used by the OSV format.
--// Input may be a bare SEMVER ("1.2.3"), Go prefixed SEMVER ("go1.2.3"),
--// or already canonical SEMVER ("v1.2.3").
--func CanonicalizeSemverPrefix(s string) string {
--	return addSemverPrefix(removeSemverPrefix(s))
--}
--
--var (
--	// Regexp for matching go tags. The groups are:
--	// 1  the major.minor version
--	// 2  the patch version, or empty if none
--	// 3  the entire prerelease, if present
--	// 4  the prerelease type ("beta" or "rc")
--	// 5  the prerelease number
--	tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc|-pre)(\d+))?$`)
--)
-diff -urN a/gopls/internal/govulncheck/semver/semver_test.go b/gopls/internal/govulncheck/semver/semver_test.go
---- a/gopls/internal/govulncheck/semver/semver_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/semver/semver_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,28 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--package semver
--
--import (
--	"testing"
--)
--
--func TestCanonicalize(t *testing.T) {
--	for _, test := range []struct {
--		v    string
--		want string
--	}{
--		{"v1.2.3", "v1.2.3"},
--		{"1.2.3", "v1.2.3"},
--		{"go1.2.3", "v1.2.3"},
--	} {
--		got := CanonicalizeSemverPrefix(test.v)
--		if got != test.want {
--			t.Errorf("want %s; got %s", test.want, got)
--		}
--	}
--}
-diff -urN a/gopls/internal/govulncheck/types_118.go b/gopls/internal/govulncheck/types_118.go
---- a/gopls/internal/govulncheck/types_118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/types_118.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,43 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--// Package govulncheck provides an experimental govulncheck API.
--package govulncheck
--
--import (
--	"golang.org/x/vuln/exp/govulncheck"
--)
--
--var (
--	// Source reports vulnerabilities that affect the analyzed packages.
--	Source = govulncheck.Source
--
--	// DefaultCache constructs cache for a vulnerability database client.
--	DefaultCache = govulncheck.DefaultCache
--)
--
--type (
--	// Config is the configuration for Main.
--	Config = govulncheck.Config
--
--	// Vuln represents a single OSV entry.
--	Vuln = govulncheck.Vuln
--
--	// Module represents a specific vulnerability relevant to a
--	// single module or package.
--	Module = govulncheck.Module
--
--	// Package is a Go package with known vulnerable symbols.
--	Package = govulncheck.Package
--
--	// CallStacks contains a representative call stack for each
--	// vulnerable symbol that is called.
--	CallStack = govulncheck.CallStack
--
--	// StackFrame represents a call stack entry.
--	StackFrame = govulncheck.StackFrame
--)
-diff -urN a/gopls/internal/govulncheck/types.go b/gopls/internal/govulncheck/types.go
---- a/gopls/internal/govulncheck/types.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/types.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package govulncheck
--
--import "time"
--
--// Result is the result of vulnerability scanning.
--type Result struct {
--	// Vulns contains all vulnerabilities that are called or imported by
--	// the analyzed module.
--	Vulns []*Vuln `json:",omitempty"`
--
--	// Mode contains the source of the vulnerability info.
--	// Clients of the gopls.fetch_vulncheck_result command may need
--	// to interpret the vulnerabilities differently based on the
--	// analysis mode. For example, Vuln without callstack traces
--	// indicate a vulnerability that is not used if the result was
--	// from 'govulncheck' analysis mode. On the other hand, Vuln
--	// without callstack traces just implies the package with the
--	// vulnerability is known to the workspace and we do not know
--	// whether the vulnerable symbols are actually used or not.
--	Mode AnalysisMode `json:",omitempty"`
--
--	// AsOf describes when this Result was computed using govulncheck.
--	// It is valid only with the govulncheck analysis mode.
--	AsOf time.Time `json:",omitempty"`
--}
--
--type AnalysisMode string
--
--const (
--	ModeInvalid     AnalysisMode = "" // zero value
--	ModeGovulncheck AnalysisMode = "govulncheck"
--	ModeImports     AnalysisMode = "imports"
--)
-diff -urN a/gopls/internal/govulncheck/types_not118.go b/gopls/internal/govulncheck/types_not118.go
---- a/gopls/internal/govulncheck/types_not118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/types_not118.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,126 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build !go1.18
--// +build !go1.18
--
--package govulncheck
--
--import (
--	"go/token"
--
--	"golang.org/x/vuln/osv"
--)
--
--// Vuln represents a single OSV entry.
--type Vuln struct {
--	// OSV contains all data from the OSV entry for this vulnerability.
--	OSV *osv.Entry
--
--	// Modules contains all of the modules in the OSV entry where a
--	// vulnerable package is imported by the target source code or binary.
--	//
--	// For example, a module M with two packages M/p1 and M/p2, where only p1
--	// is vulnerable, will appear in this list if and only if p1 is imported by
--	// the target source code or binary.
--	Modules []*Module
--}
--
--func (v *Vuln) IsCalled() bool {
--	return false
--}
--
--// Module represents a specific vulnerability relevant to a single module.
--type Module struct {
--	// Path is the module path of the module containing the vulnerability.
--	//
--	// Importable packages in the standard library will have the path "stdlib".
--	Path string
--
--	// FoundVersion is the module version where the vulnerability was found.
--	FoundVersion string
--
--	// FixedVersion is the module version where the vulnerability was
--	// fixed. If there are multiple fixed versions in the OSV report, this will
--	// be the latest fixed version.
--	//
--	// This is empty if a fix is not available.
--	FixedVersion string
--
--	// Packages contains all the vulnerable packages in OSV entry that are
--	// imported by the target source code or binary.
--	//
--	// For example, given a module M with two packages M/p1 and M/p2, where
--	// both p1 and p2 are vulnerable, p1 and p2 will each only appear in this
--	// list they are individually imported by the target source code or binary.
--	Packages []*Package
--}
--
--// Package is a Go package with known vulnerable symbols.
--type Package struct {
--	// Path is the import path of the package containing the vulnerability.
--	Path string
--
--	// CallStacks contains a representative call stack for each
--	// vulnerable symbol that is called.
--	//
--	// For vulnerabilities found from binary analysis, only CallStack.Symbol
--	// will be provided.
--	//
--	// For non-affecting vulnerabilities reported from the source mode
--	// analysis, this will be empty.
--	CallStacks []CallStack
--}
--
--// CallStacks contains a representative call stack for a vulnerable
--// symbol.
--type CallStack struct {
--	// Symbol is the name of the detected vulnerable function
--	// or method.
--	//
--	// This follows the naming convention in the OSV report.
--	Symbol string
--
--	// Summary is a one-line description of the callstack, used by the
--	// default govulncheck mode.
--	//
--	// Example: module3.main calls github.com/shiyanhui/dht.DHT.Run
--	Summary string
--
--	// Frames contains an entry for each stack in the call stack.
--	//
--	// Frames are sorted starting from the entry point to the
--	// imported vulnerable symbol. The last frame in Frames should match
--	// Symbol.
--	Frames []*StackFrame
--}
--
--// StackFrame represents a call stack entry.
--type StackFrame struct {
--	// PackagePath is the import path.
--	PkgPath string
--
--	// FuncName is the function name.
--	FuncName string
--
--	// RecvType is the fully qualified receiver type,
--	// if the called symbol is a method.
--	//
--	// The client can create the final symbol name by
--	// prepending RecvType to FuncName.
--	RecvType string
--
--	// Position describes an arbitrary source position
--	// including the file, line, and column location.
--	// A Position is valid if the line number is > 0.
--	Position token.Position
--}
--
--func (sf *StackFrame) Name() string {
--	return ""
--}
--
--func (sf *StackFrame) Pos() string {
--	return ""
--}
-diff -urN a/gopls/internal/govulncheck/util.go b/gopls/internal/govulncheck/util.go
---- a/gopls/internal/govulncheck/util.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/util.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,36 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--package govulncheck
--
--import (
--	"golang.org/x/mod/semver"
--	isem "golang.org/x/tools/gopls/internal/govulncheck/semver"
--	"golang.org/x/vuln/osv"
--)
--
--// LatestFixed returns the latest fixed version in the list of affected ranges,
--// or the empty string if there are no fixed versions.
--func LatestFixed(modulePath string, as []osv.Affected) string {
--	v := ""
--	for _, a := range as {
--		if a.Package.Name != modulePath {
--			continue
--		}
--		for _, r := range a.Ranges {
--			if r.Type == osv.TypeSemver {
--				for _, e := range r.Events {
--					if e.Fixed != "" && (v == "" ||
--						semver.Compare(isem.CanonicalizeSemverPrefix(e.Fixed), isem.CanonicalizeSemverPrefix(v)) > 0) {
--						v = e.Fixed
--					}
--				}
--			}
--		}
--	}
--	return v
--}
-diff -urN a/gopls/internal/govulncheck/vulncache.go b/gopls/internal/govulncheck/vulncache.go
---- a/gopls/internal/govulncheck/vulncache.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/govulncheck/vulncache.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,105 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--package govulncheck
--
--import (
--	"sync"
--	"time"
--
--	vulnc "golang.org/x/vuln/client"
--	"golang.org/x/vuln/osv"
--)
--
--// inMemoryCache is an implementation of the [client.Cache] interface
--// that "decorates" another instance of that interface to provide
--// an additional layer of (memory-based) caching.
--type inMemoryCache struct {
--	mu         sync.Mutex
--	underlying vulnc.Cache
--	db         map[string]*db
--}
--
--var _ vulnc.Cache = &inMemoryCache{}
--
--type db struct {
--	retrieved time.Time
--	index     vulnc.DBIndex
--	entry     map[string][]*osv.Entry
--}
--
--// NewInMemoryCache returns a new memory-based cache that decorates
--// the provided cache (file-based, perhaps).
--func NewInMemoryCache(underlying vulnc.Cache) *inMemoryCache {
--	return &inMemoryCache{
--		underlying: underlying,
--		db:         make(map[string]*db),
--	}
--}
--
--func (c *inMemoryCache) lookupDBLocked(dbName string) *db {
--	cached := c.db[dbName]
--	if cached == nil {
--		cached = &db{entry: make(map[string][]*osv.Entry)}
--		c.db[dbName] = cached
--	}
--	return cached
--}
--
--// ReadIndex returns the index for dbName from the cache, or returns zero values
--// if it is not present.
--func (c *inMemoryCache) ReadIndex(dbName string) (vulnc.DBIndex, time.Time, error) {
--	c.mu.Lock()
--	defer c.mu.Unlock()
--	cached := c.lookupDBLocked(dbName)
--
--	if cached.retrieved.IsZero() {
--		// First time ReadIndex is called.
--		index, retrieved, err := c.underlying.ReadIndex(dbName)
--		if err != nil {
--			return index, retrieved, err
--		}
--		cached.index, cached.retrieved = index, retrieved
--	}
--	return cached.index, cached.retrieved, nil
--}
--
--// WriteIndex puts the index and retrieved time into the cache.
--func (c *inMemoryCache) WriteIndex(dbName string, index vulnc.DBIndex, retrieved time.Time) error {
--	c.mu.Lock()
--	defer c.mu.Unlock()
--	cached := c.lookupDBLocked(dbName)
--	cached.index, cached.retrieved = index, retrieved
--	// TODO(hyangah): shouldn't we invalidate all cached entries?
--	return c.underlying.WriteIndex(dbName, index, retrieved)
--}
--
--// ReadEntries returns the vulndb entries for path from the cache.
--func (c *inMemoryCache) ReadEntries(dbName, path string) ([]*osv.Entry, error) {
--	c.mu.Lock()
--	defer c.mu.Unlock()
--	cached := c.lookupDBLocked(dbName)
--	entries, ok := cached.entry[path]
--	if !ok {
--		// cache miss
--		entries, err := c.underlying.ReadEntries(dbName, path)
--		if err != nil {
--			return entries, err
--		}
--		cached.entry[path] = entries
--	}
--	return entries, nil
--}
--
--// WriteEntries puts the entries for path into the cache.
--func (c *inMemoryCache) WriteEntries(dbName, path string, entries []*osv.Entry) error {
--	c.mu.Lock()
--	defer c.mu.Unlock()
--	cached := c.lookupDBLocked(dbName)
--	cached.entry[path] = entries
--	return c.underlying.WriteEntries(dbName, path, entries)
--}
 diff -urN a/gopls/internal/hooks/analysis_116.go b/gopls/internal/hooks/analysis_116.go
 --- a/gopls/internal/hooks/analysis_116.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/analysis_116.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/analysis_116.go	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -5801,7 +6251,7 @@
 -}
 diff -urN a/gopls/internal/hooks/analysis_119.go b/gopls/internal/hooks/analysis_119.go
 --- a/gopls/internal/hooks/analysis_119.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/analysis_119.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/analysis_119.go	1970-01-01 08:00:00
 @@ -1,62 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -5867,8 +6317,8 @@
 -}
 diff -urN a/gopls/internal/hooks/diff.go b/gopls/internal/hooks/diff.go
 --- a/gopls/internal/hooks/diff.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/diff.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,169 +0,0 @@
++++ b/gopls/internal/hooks/diff.go	1970-01-01 08:00:00
+@@ -1,168 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -5878,7 +6328,6 @@
 -import (
 -	"encoding/json"
 -	"fmt"
--	"io/ioutil"
 -	"log"
 -	"os"
 -	"path/filepath"
@@ -5887,7 +6336,7 @@
 -	"time"
 -
 -	"github.com/sergi/go-diff/diffmatchpatch"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/internal/diff"
 -)
 -
@@ -5913,7 +6362,7 @@
 -// save writes a JSON record of statistics about diff requests to a temporary file.
 -func (s *diffstat) save() {
 -	diffStatsOnce.Do(func() {
--		f, err := ioutil.TempFile("", "gopls-diff-stats-*")
+-		f, err := os.CreateTemp("", "gopls-diff-stats-*")
 -		if err != nil {
 -			log.Printf("can't create diff stats temp file: %v", err) // e.g. disk full
 -			return
@@ -5962,7 +6411,7 @@
 -	// We use NUL as a separator: it should never appear in Go source.
 -	data := before + "\x00" + after
 -
--	if err := ioutil.WriteFile(filename, []byte(data), 0600); err != nil {
+-	if err := os.WriteFile(filename, []byte(data), 0600); err != nil {
 -		log.Printf("failed to write diff bug report: %v", err)
 -		return ""
 -	}
@@ -6040,8 +6489,8 @@
 -}
 diff -urN a/gopls/internal/hooks/diff_test.go b/gopls/internal/hooks/diff_test.go
 --- a/gopls/internal/hooks/diff_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/diff_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,33 +0,0 @@
++++ b/gopls/internal/hooks/diff_test.go	1970-01-01 08:00:00
+@@ -1,32 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -6049,7 +6498,6 @@
 -package hooks
 -
 -import (
--	"io/ioutil"
 -	"os"
 -	"testing"
 -
@@ -6064,7 +6512,7 @@
 -	a := "This is a string,(\u0995) just for basic\nfunctionality"
 -	b := "This is another string, (\u0996) to see if disaster will store stuff correctly"
 -	fname := disaster(a, b)
--	buf, err := ioutil.ReadFile(fname)
+-	buf, err := os.ReadFile(fname)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -6077,7 +6525,7 @@
 -}
 diff -urN a/gopls/internal/hooks/gen-licenses.sh b/gopls/internal/hooks/gen-licenses.sh
 --- a/gopls/internal/hooks/gen-licenses.sh	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/gen-licenses.sh	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/gen-licenses.sh	1970-01-01 08:00:00
 @@ -1,38 +0,0 @@
 -#!/bin/bash -eu
 -
@@ -6120,7 +6568,7 @@
 \ No newline at end of file
 diff -urN a/gopls/internal/hooks/gofumpt_117.go b/gopls/internal/hooks/gofumpt_117.go
 --- a/gopls/internal/hooks/gofumpt_117.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/gofumpt_117.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/gofumpt_117.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6137,8 +6585,8 @@
 -}
 diff -urN a/gopls/internal/hooks/gofumpt_118.go b/gopls/internal/hooks/gofumpt_118.go
 --- a/gopls/internal/hooks/gofumpt_118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/gofumpt_118.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
++++ b/gopls/internal/hooks/gofumpt_118.go	1970-01-01 08:00:00
+@@ -1,78 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -6150,6 +6598,7 @@
 -
 -import (
 -	"context"
+-	"fmt"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"mvdan.cc/gofumpt/format"
@@ -6157,15 +6606,125 @@
 -
 -func updateGofumpt(options *source.Options) {
 -	options.GofumptFormat = func(ctx context.Context, langVersion, modulePath string, src []byte) ([]byte, error) {
+-		fixedVersion, err := fixLangVersion(langVersion)
+-		if err != nil {
+-			return nil, err
+-		}
 -		return format.Source(src, format.Options{
--			LangVersion: langVersion,
+-			LangVersion: fixedVersion,
 -			ModulePath:  modulePath,
 -		})
 -	}
 -}
+-
+-// fixLangVersion function cleans the input so that gofumpt doesn't panic. It is
+-// rather permissive, and accepts version strings that aren't technically valid
+-// in a go.mod file.
+-//
+-// More specifically, it looks for an optional 'v' followed by 1-3
+-// '.'-separated numbers. The resulting string is stripped of any suffix beyond
+-// this expected version number pattern.
+-//
+-// See also golang/go#61692: gofumpt does not accept the new language versions
+-// appearing in go.mod files (e.g. go1.21rc3).
+-func fixLangVersion(input string) (string, error) {
+-	bad := func() (string, error) {
+-		return "", fmt.Errorf("invalid language version syntax %q", input)
+-	}
+-	if input == "" {
+-		return input, nil
+-	}
+-	i := 0
+-	if input[0] == 'v' { // be flexible about 'v'
+-		i++
+-	}
+-	// takeDigits consumes ascii numerals 0-9 and reports if at least one was
+-	// consumed.
+-	takeDigits := func() bool {
+-		found := false
+-		for ; i < len(input) && '0' <= input[i] && input[i] <= '9'; i++ {
+-			found = true
+-		}
+-		return found
+-	}
+-	if !takeDigits() { // versions must start with at least one number
+-		return bad()
+-	}
+-
+-	// Accept optional minor and patch versions.
+-	for n := 0; n < 2; n++ {
+-		if i < len(input) && input[i] == '.' {
+-			// Look for minor/patch version.
+-			i++
+-			if !takeDigits() {
+-				i--
+-				break
+-			}
+-		}
+-	}
+-	// Accept any suffix.
+-	return input[:i], nil
+-}
+diff -urN a/gopls/internal/hooks/gofumpt_118_test.go b/gopls/internal/hooks/gofumpt_118_test.go
+--- a/gopls/internal/hooks/gofumpt_118_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/hooks/gofumpt_118_test.go	1970-01-01 08:00:00
+@@ -1,53 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.18
+-// +build go1.18
+-
+-package hooks
+-
+-import "testing"
+-
+-func TestFixLangVersion(t *testing.T) {
+-	tests := []struct {
+-		input, want string
+-		wantErr     bool
+-	}{
+-		{"", "", false},
+-		{"1.18", "1.18", false},
+-		{"v1.18", "v1.18", false},
+-		{"1.21", "1.21", false},
+-		{"1.21rc3", "1.21", false},
+-		{"1.21.0", "1.21.0", false},
+-		{"1.21.1", "1.21.1", false},
+-		{"v1.21.1", "v1.21.1", false},
+-		{"v1.21.0rc1", "v1.21.0", false}, // not technically valid, but we're flexible
+-		{"v1.21.0.0", "v1.21.0", false},  // also technically invalid
+-		{"1.1", "1.1", false},
+-		{"v1", "v1", false},
+-		{"1", "1", false},
+-		{"v1.21.", "v1.21", false}, // also invalid
+-		{"1.21.", "1.21", false},
+-
+-		// Error cases.
+-		{"rc1", "", true},
+-		{"x1.2.3", "", true},
+-	}
+-
+-	for _, test := range tests {
+-		got, err := fixLangVersion(test.input)
+-		if test.wantErr {
+-			if err == nil {
+-				t.Errorf("fixLangVersion(%q) succeeded unexpectedly", test.input)
+-			}
+-			continue
+-		}
+-		if err != nil {
+-			t.Fatalf("fixLangVersion(%q) failed: %v", test.input, err)
+-		}
+-		if got != test.want {
+-			t.Errorf("fixLangVersion(%q) = %s, want %s", test.input, got, test.want)
+-		}
+-	}
+-}
 diff -urN a/gopls/internal/hooks/hooks.go b/gopls/internal/hooks/hooks.go
 --- a/gopls/internal/hooks/hooks.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/hooks.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/hooks.go	1970-01-01 08:00:00
 @@ -1,31 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6200,7 +6759,7 @@
 -}
 diff -urN a/gopls/internal/hooks/licenses.go b/gopls/internal/hooks/licenses.go
 --- a/gopls/internal/hooks/licenses.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/licenses.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/licenses.go	1970-01-01 08:00:00
 @@ -1,169 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6373,7 +6932,7 @@
 -`
 diff -urN a/gopls/internal/hooks/licenses_test.go b/gopls/internal/hooks/licenses_test.go
 --- a/gopls/internal/hooks/licenses_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/hooks/licenses_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/hooks/licenses_test.go	1970-01-01 08:00:00
 @@ -1,47 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6383,7 +6942,7 @@
 -
 -import (
 -	"bytes"
--	"io/ioutil"
+-	"os"
 -	"os/exec"
 -	"runtime"
 -	"testing"
@@ -6395,12 +6954,12 @@
 -	// License text differs for older Go versions because staticcheck or gofumpt
 -	// isn't supported for those versions, and this fails for unknown, unrelated
 -	// reasons on Kokoro legacy CI.
--	testenv.NeedsGo1Point(t, 19)
+-	testenv.NeedsGo1Point(t, 21)
 -
 -	if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
 -		t.Skip("generating licenses only works on Unixes")
 -	}
--	tmp, err := ioutil.TempFile("", "")
+-	tmp, err := os.CreateTemp("", "")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -6410,11 +6969,11 @@
 -		t.Fatalf("generating licenses failed: %q, %v", out, err)
 -	}
 -
--	got, err := ioutil.ReadFile(tmp.Name())
+-	got, err := os.ReadFile(tmp.Name())
 -	if err != nil {
 -		t.Fatal(err)
 -	}
--	want, err := ioutil.ReadFile("licenses.go")
+-	want, err := os.ReadFile("licenses.go")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -6422,28 +6981,378 @@
 -		t.Error("combined license text needs updating. Run: `go generate ./internal/hooks` from the gopls module.")
 -	}
 -}
+diff -urN a/gopls/internal/lsp/README.md b/gopls/internal/lsp/README.md
+--- a/gopls/internal/lsp/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/README.md	1970-01-01 08:00:00
+@@ -1,7 +0,0 @@
+-# lsp
+-
+-internal/lsp provides much of the Language Server Protocol (lsp) implementation
+-for gopls.
+-
+-Documentation for users and contributors can be found in the
+-[`gopls/doc`](../../gopls/doc) directory.
+diff -urN a/gopls/internal/lsp/analysis/deprecated/deprecated.go b/gopls/internal/lsp/analysis/deprecated/deprecated.go
+--- a/gopls/internal/lsp/analysis/deprecated/deprecated.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/deprecated/deprecated.go	1970-01-01 08:00:00
+@@ -1,270 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Package deprecated defines an Analyzer that marks deprecated symbols and package imports.
+-package deprecated
+-
+-import (
+-	"bytes"
+-	"go/ast"
+-	"go/format"
+-	"go/token"
+-	"go/types"
+-	"strconv"
+-	"strings"
+-
+-	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/go/analysis/passes/inspect"
+-	"golang.org/x/tools/go/ast/inspector"
+-	"golang.org/x/tools/internal/typeparams"
+-)
+-
+-// TODO(hyangah): use analysisutil.MustExtractDoc.
+-var doc = `check for use of deprecated identifiers
+-
+-The deprecated analyzer looks for deprecated symbols and package imports.
+-
+-See https://go.dev/wiki/Deprecated to learn about Go's convention
+-for documenting and signaling deprecated identifiers.`
+-
+-var Analyzer = &analysis.Analyzer{
+-	Name:             "deprecated",
+-	Doc:              doc,
+-	Requires:         []*analysis.Analyzer{inspect.Analyzer},
+-	Run:              checkDeprecated,
+-	FactTypes:        []analysis.Fact{(*deprecationFact)(nil)},
+-	RunDespiteErrors: true,
+-}
+-
+-// checkDeprecated is a simplified copy of staticcheck.CheckDeprecated.
+-func checkDeprecated(pass *analysis.Pass) (interface{}, error) {
+-	inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+-
+-	deprs, err := collectDeprecatedNames(pass, inspector)
+-	if err != nil || (len(deprs.packages) == 0 && len(deprs.objects) == 0) {
+-		return nil, err
+-	}
+-
+-	reportDeprecation := func(depr *deprecationFact, node ast.Node) {
+-		// TODO(hyangah): staticcheck.CheckDeprecated has more complex logic. Do we need it here?
+-		// TODO(hyangah): Scrub depr.Msg. depr.Msg may contain Go comments
+-		// markdown syntaxes but LSP diagnostics do not support markdown syntax.
+-
+-		buf := new(bytes.Buffer)
+-		if err := format.Node(buf, pass.Fset, node); err != nil {
+-			// This shouldn't happen but let's be conservative.
+-			buf.Reset()
+-			buf.WriteString("declaration")
+-		}
+-		pass.ReportRangef(node, "%s is deprecated: %s", buf, depr.Msg)
+-	}
+-
+-	nodeFilter := []ast.Node{(*ast.SelectorExpr)(nil)}
+-	inspector.Preorder(nodeFilter, func(node ast.Node) {
+-		// Caveat: this misses dot-imported objects
+-		sel, ok := node.(*ast.SelectorExpr)
+-		if !ok {
+-			return
+-		}
+-
+-		obj := pass.TypesInfo.ObjectOf(sel.Sel)
+-		if obj_, ok := obj.(*types.Func); ok {
+-			obj = typeparams.OriginMethod(obj_)
+-		}
+-		if obj == nil || obj.Pkg() == nil {
+-			// skip invalid sel.Sel.
+-			return
+-		}
+-
+-		if obj.Pkg() == pass.Pkg {
+-			// A package is allowed to use its own deprecated objects
+-			return
+-		}
+-
+-		// A package "foo" has two related packages "foo_test" and "foo.test", for external tests and the package main
+-		// generated by 'go test' respectively. "foo_test" can import and use "foo", "foo.test" imports and uses "foo"
+-		// and "foo_test".
+-
+-		if strings.TrimSuffix(pass.Pkg.Path(), "_test") == obj.Pkg().Path() {
+-			// foo_test (the external tests of foo) can use objects from foo.
+-			return
+-		}
+-		if strings.TrimSuffix(pass.Pkg.Path(), ".test") == obj.Pkg().Path() {
+-			// foo.test (the main package of foo's tests) can use objects from foo.
+-			return
+-		}
+-		if strings.TrimSuffix(pass.Pkg.Path(), ".test") == strings.TrimSuffix(obj.Pkg().Path(), "_test") {
+-			// foo.test (the main package of foo's tests) can use objects from foo's external tests.
+-			return
+-		}
+-
+-		if depr, ok := deprs.objects[obj]; ok {
+-			reportDeprecation(depr, sel)
+-		}
+-	})
+-
+-	for _, f := range pass.Files {
+-		for _, spec := range f.Imports {
+-			var imp *types.Package
+-			var obj types.Object
+-			if spec.Name != nil {
+-				obj = pass.TypesInfo.ObjectOf(spec.Name)
+-			} else {
+-				obj = pass.TypesInfo.Implicits[spec]
+-			}
+-			pkgName, ok := obj.(*types.PkgName)
+-			if !ok {
+-				continue
+-			}
+-			imp = pkgName.Imported()
+-
+-			path, err := strconv.Unquote(spec.Path.Value)
+-			if err != nil {
+-				continue
+-			}
+-			pkgPath := pass.Pkg.Path()
+-			if strings.TrimSuffix(pkgPath, "_test") == path {
+-				// foo_test can import foo
+-				continue
+-			}
+-			if strings.TrimSuffix(pkgPath, ".test") == path {
+-				// foo.test can import foo
+-				continue
+-			}
+-			if strings.TrimSuffix(pkgPath, ".test") == strings.TrimSuffix(path, "_test") {
+-				// foo.test can import foo_test
+-				continue
+-			}
+-			if depr, ok := deprs.packages[imp]; ok {
+-				reportDeprecation(depr, spec.Path)
+-			}
+-		}
+-	}
+-	return nil, nil
+-}
+-
+-type deprecationFact struct{ Msg string }
+-
+-func (*deprecationFact) AFact()           {}
+-func (d *deprecationFact) String() string { return "Deprecated: " + d.Msg }
+-
+-type deprecatedNames struct {
+-	objects  map[types.Object]*deprecationFact
+-	packages map[*types.Package]*deprecationFact
+-}
+-
+-// collectDeprecatedNames collects deprecated identifiers and publishes
+-// them both as Facts and the return value. This is a simplified copy
+-// of staticcheck's fact_deprecated analyzer.
+-func collectDeprecatedNames(pass *analysis.Pass, ins *inspector.Inspector) (deprecatedNames, error) {
+-	extractDeprecatedMessage := func(docs []*ast.CommentGroup) string {
+-		for _, doc := range docs {
+-			if doc == nil {
+-				continue
+-			}
+-			parts := strings.Split(doc.Text(), "\n\n")
+-			for _, part := range parts {
+-				if !strings.HasPrefix(part, "Deprecated: ") {
+-					continue
+-				}
+-				alt := part[len("Deprecated: "):]
+-				alt = strings.Replace(alt, "\n", " ", -1)
+-				return strings.TrimSpace(alt)
+-			}
+-		}
+-		return ""
+-	}
+-
+-	doDocs := func(names []*ast.Ident, docs *ast.CommentGroup) {
+-		alt := extractDeprecatedMessage([]*ast.CommentGroup{docs})
+-		if alt == "" {
+-			return
+-		}
+-
+-		for _, name := range names {
+-			obj := pass.TypesInfo.ObjectOf(name)
+-			pass.ExportObjectFact(obj, &deprecationFact{alt})
+-		}
+-	}
+-
+-	var docs []*ast.CommentGroup
+-	for _, f := range pass.Files {
+-		docs = append(docs, f.Doc)
+-	}
+-	if alt := extractDeprecatedMessage(docs); alt != "" {
+-		// Don't mark package syscall as deprecated, even though
+-		// it is. A lot of people still use it for simple
+-		// constants like SIGKILL, and I am not comfortable
+-		// telling them to use x/sys for that.
+-		if pass.Pkg.Path() != "syscall" {
+-			pass.ExportPackageFact(&deprecationFact{alt})
+-		}
+-	}
+-	nodeFilter := []ast.Node{
+-		(*ast.GenDecl)(nil),
+-		(*ast.FuncDecl)(nil),
+-		(*ast.TypeSpec)(nil),
+-		(*ast.ValueSpec)(nil),
+-		(*ast.File)(nil),
+-		(*ast.StructType)(nil),
+-		(*ast.InterfaceType)(nil),
+-	}
+-	ins.Preorder(nodeFilter, func(node ast.Node) {
+-		var names []*ast.Ident
+-		var docs *ast.CommentGroup
+-		switch node := node.(type) {
+-		case *ast.GenDecl:
+-			switch node.Tok {
+-			case token.TYPE, token.CONST, token.VAR:
+-				docs = node.Doc
+-				for i := range node.Specs {
+-					switch n := node.Specs[i].(type) {
+-					case *ast.ValueSpec:
+-						names = append(names, n.Names...)
+-					case *ast.TypeSpec:
+-						names = append(names, n.Name)
+-					}
+-				}
+-			default:
+-				return
+-			}
+-		case *ast.FuncDecl:
+-			docs = node.Doc
+-			names = []*ast.Ident{node.Name}
+-		case *ast.TypeSpec:
+-			docs = node.Doc
+-			names = []*ast.Ident{node.Name}
+-		case *ast.ValueSpec:
+-			docs = node.Doc
+-			names = node.Names
+-		case *ast.StructType:
+-			for _, field := range node.Fields.List {
+-				doDocs(field.Names, field.Doc)
+-			}
+-		case *ast.InterfaceType:
+-			for _, field := range node.Methods.List {
+-				doDocs(field.Names, field.Doc)
+-			}
+-		}
+-		if docs != nil && len(names) > 0 {
+-			doDocs(names, docs)
+-		}
+-	})
+-
+-	// Every identifier is potentially deprecated, so we will need
+-	// to look up facts a lot. Construct maps of all facts propagated
+-	// to this pass for fast lookup.
+-	out := deprecatedNames{
+-		objects:  map[types.Object]*deprecationFact{},
+-		packages: map[*types.Package]*deprecationFact{},
+-	}
+-	for _, fact := range pass.AllObjectFacts() {
+-		out.objects[fact.Object] = fact.Fact.(*deprecationFact)
+-	}
+-	for _, fact := range pass.AllPackageFacts() {
+-		out.packages[fact.Package] = fact.Fact.(*deprecationFact)
+-	}
+-
+-	return out, nil
+-}
+diff -urN a/gopls/internal/lsp/analysis/deprecated/deprecated_test.go b/gopls/internal/lsp/analysis/deprecated/deprecated_test.go
+--- a/gopls/internal/lsp/analysis/deprecated/deprecated_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/deprecated/deprecated_test.go	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package deprecated
+-
+-import (
+-	"testing"
+-
+-	"golang.org/x/tools/go/analysis/analysistest"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-func Test(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 19)
+-	testdata := analysistest.TestData()
+-	analysistest.Run(t, testdata, Analyzer, "a")
+-}
+diff -urN a/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a.go b/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a.go
+--- a/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a.go	1970-01-01 08:00:00
+@@ -1,17 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package usedeprecated
+-
+-import "io/ioutil" // want "\"io/ioutil\" is deprecated: .*"
+-
+-func x() {
+-	_, _ = ioutil.ReadFile("") // want "ioutil.ReadFile is deprecated: As of Go 1.16, .*"
+-	Legacy()                   // expect no deprecation notice.
+-}
+-
+-// Legacy is deprecated.
+-//
+-// Deprecated: use X instead.
+-func Legacy() {} // want Legacy:"Deprecated: use X instead."
+diff -urN a/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a_test.go b/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a_test.go
+--- a/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/deprecated/testdata/src/a/a_test.go	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package usedeprecated
+-
+-import "testing"
+-
+-func TestF(t *testing.T) {
+-	Legacy() // expect no deprecation notice.
+-	x()
+-}
 diff -urN a/gopls/internal/lsp/analysis/embeddirective/embeddirective.go b/gopls/internal/lsp/analysis/embeddirective/embeddirective.go
 --- a/gopls/internal/lsp/analysis/embeddirective/embeddirective.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,58 +0,0 @@
++++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective.go	1970-01-01 08:00:00
+@@ -1,134 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
--// Package embeddirective defines an Analyzer that validates import for //go:embed directive.
+-// Package embeddirective defines an Analyzer that validates //go:embed directives.
+-// The analyzer defers fixes to its parent source.Analyzer.
 -package embeddirective
 -
 -import (
 -	"go/ast"
+-	"go/token"
 -	"strings"
 -
 -	"golang.org/x/tools/go/analysis"
 -)
 -
--const Doc = `check for //go:embed directive import
+-const Doc = `check //go:embed directive usage
 -
--This analyzer checks that the embed package is imported when source code contains //go:embed comment directives.
--The embed package must be imported for //go:embed directives to function.import _ "embed".`
+-This analyzer checks that the embed package is imported if //go:embed
+-directives are present, providing a suggested fix to add the import if
+-it is missing.
+-
+-This analyzer also checks that //go:embed directives precede the
+-declaration of a single variable.`
 -
 -var Analyzer = &analysis.Analyzer{
 -	Name:             "embed",
@@ -6453,40 +7362,110 @@
 -	RunDespiteErrors: true,
 -}
 -
+-// source.fixedByImportingEmbed relies on this message to filter
+-// out fixable diagnostics from this Analyzer.
+-const MissingImportMessage = `must import "embed" when using go:embed directives`
+-
 -func run(pass *analysis.Pass) (interface{}, error) {
 -	for _, f := range pass.Files {
--		com := hasEmbedDirectiveComment(f)
--		if com != nil {
--			assertEmbedImport(pass, com, f)
+-		comments := embedDirectiveComments(f)
+-		if len(comments) == 0 {
+-			continue // nothing to check
+-		}
+-
+-		hasEmbedImport := false
+-		for _, imp := range f.Imports {
+-			if imp.Path.Value == `"embed"` {
+-				hasEmbedImport = true
+-				break
+-			}
+-		}
+-
+-		for _, c := range comments {
+-			report := func(msg string) {
+-				pass.Report(analysis.Diagnostic{
+-					Pos:     c.Pos(),
+-					End:     c.Pos() + token.Pos(len("//go:embed")),
+-					Message: msg,
+-				})
+-			}
+-
+-			if !hasEmbedImport {
+-				report(MissingImportMessage)
+-			}
+-
+-			spec := nextVarSpec(c, f)
+-			switch {
+-			case spec == nil:
+-				report(`go:embed directives must precede a "var" declaration`)
+-			case len(spec.Names) > 1:
+-				report("declarations following go:embed directives must define a single variable")
+-			case len(spec.Values) > 0:
+-				report("declarations following go:embed directives must not specify a value")
+-			}
 -		}
 -	}
 -	return nil, nil
 -}
 -
--// Check if the comment contains //go:embed directive.
--func hasEmbedDirectiveComment(f *ast.File) *ast.Comment {
+-// embedDirectiveComments returns all comments in f that contains a //go:embed directive.
+-func embedDirectiveComments(f *ast.File) []*ast.Comment {
+-	comments := []*ast.Comment{}
 -	for _, cg := range f.Comments {
 -		for _, c := range cg.List {
 -			if strings.HasPrefix(c.Text, "//go:embed ") {
--				return c
+-				comments = append(comments, c)
 -			}
 -		}
 -	}
--	return nil
+-	return comments
 -}
 -
--// Verifies that "embed" import exists for //go:embed directive.
--func assertEmbedImport(pass *analysis.Pass, com *ast.Comment, f *ast.File) {
--	for _, imp := range f.Imports {
--		if "\"embed\"" == imp.Path.Value {
--			return
+-// nextVarSpec returns the ValueSpec for the variable declaration immediately following
+-// the go:embed comment, or nil if the next declaration is not a variable declaration.
+-func nextVarSpec(com *ast.Comment, f *ast.File) *ast.ValueSpec {
+-	// Embed directives must be followed by a declaration of one variable with no value.
+-	// There may be comments and empty lines between the directive and the declaration.
+-	var nextDecl ast.Decl
+-	for _, d := range f.Decls {
+-		if com.End() < d.End() {
+-			nextDecl = d
+-			break
 -		}
 -	}
--	pass.Report(analysis.Diagnostic{Pos: com.Pos(), End: com.Pos() + 10, Message: "The \"embed\" package must be imported when using go:embed directives."})
+-	if nextDecl == nil || nextDecl.Pos() == token.NoPos {
+-		return nil
+-	}
+-	decl, ok := nextDecl.(*ast.GenDecl)
+-	if !ok {
+-		return nil
+-	}
+-	if decl.Tok != token.VAR {
+-		return nil
+-	}
+-
+-	// var declarations can be both freestanding and blocks (with parenthesis).
+-	// Only the first variable spec following the directive is interesting.
+-	var nextSpec ast.Spec
+-	for _, s := range decl.Specs {
+-		if com.End() < s.End() {
+-			nextSpec = s
+-			break
+-		}
+-	}
+-	if nextSpec == nil {
+-		return nil
+-	}
+-	spec, ok := nextSpec.(*ast.ValueSpec)
+-	if !ok {
+-		// Invalid AST, but keep going.
+-		return nil
+-	}
+-	return spec
 -}
 diff -urN a/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go b/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go
 --- a/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/embeddirective/embeddirective_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6510,50 +7489,143 @@
 -
 -	analysistest.RunWithSuggestedFixes(t, testdata, Analyzer, tests...)
 -}
-diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go
---- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
+diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText
+--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText	1970-01-01 08:00:00
+@@ -1 +0,0 @@
+-Hello World
+\ No newline at end of file
+diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_missing.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_missing.go
+--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_missing.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_missing.go	1970-01-01 08:00:00
+@@ -1,17 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
 -package a
 -
 -import (
 -	"fmt"
 -)
 -
--//go:embed embedText // want "The \"embed\" package must be imported when using go:embed directives"
+-//go:embed embedtext // want "must import \"embed\" when using go:embed directives"
 -var s string
 -
 -// This is main function
 -func main() {
 -	fmt.Println(s)
 -}
-diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go
---- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/b.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
+diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present.go
+--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present.go	1970-01-01 08:00:00
+@@ -1,73 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
 -package a
 -
+-// Misplaced, above imports.
+-//go:embed embedText // want "go:embed directives must precede a \"var\" declaration"
+-
 -import (
--	_ "embed"
 -	"fmt"
+-
+-	_ "embed"
 -)
 -
 -//go:embed embedText // ok
 -var s string
 -
+-// The analyzer does not check for many directives using the same var.
+-//
+-//go:embed embedText // ok
+-//go:embed embedText // ok
+-var s string
+-
+-// Comments and blank lines between are OK.
+-//
+-//go:embed embedText // ok
+-//
+-// foo
+-
+-var s string
+-
+-// Followed by wrong kind of decl.
+-//
+-//go:embed embedText // want "go:embed directives must precede a \"var\" declaration"
+-func foo()
+-
+-// Multiple variable specs.
+-//
+-//go:embed embedText // want "declarations following go:embed directives must define a single variable"
+-var foo, bar []byte
+-
+-// Specifying a value is not allowed.
+-//
+-//go:embed embedText // want "declarations following go:embed directives must not specify a value"
+-var s string = "foo"
+-
+-// TODO: This should not be OK, misplaced according to compiler.
+-//
+-//go:embed embedText // ok
+-var (
+-	s string
+-	x string
+-)
+-
+-// var blocks are OK as long as the variable following the directive is OK.
+-var (
+-	x, y, z string
+-	//go:embed embedText // ok
+-	s       string
+-	q, r, t string
+-)
+-
+-//go:embed embedText // want "go:embed directives must precede a \"var\" declaration"
+-var ()
+-
 -// This is main function
 -func main() {
 -	fmt.Println(s)
 -}
-diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText
---- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/embedText	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--Hello World
-\ No newline at end of file
+-
+-// No declaration following.
+-//go:embed embedText // want "go:embed directives must precede a \"var\" declaration"
+diff -urN a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present_go120.go b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present_go120.go
+--- a/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present_go120.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/analysis/embeddirective/testdata/src/a/import_present_go120.go	1970-01-01 08:00:00
+@@ -1,26 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.20
+-// +build go1.20
+-
+-package a
+-
+-var (
+-	// Okay directive wise but the compiler will complain that
+-	// imports must appear before other declarations.
+-	//go:embed embedText // ok
+-	"foo"
+-)
+-
+-import (
+-	"fmt"
+-
+-	_ "embed"
+-)
+-
+-// This is main function
+-func main() {
+-	fmt.Println(s)
+-}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/fillreturns.go b/gopls/internal/lsp/analysis/fillreturns/fillreturns.go
 --- a/gopls/internal/lsp/analysis/fillreturns/fillreturns.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns.go	1970-01-01 08:00:00
 @@ -1,279 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6836,7 +7908,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go b/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go
 --- a/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/fillreturns_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -6862,7 +7934,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,139 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7005,7 +8077,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,139 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7148,7 +8220,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go
 --- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go	1970-01-01 08:00:00
 @@ -1,5 +0,0 @@
 -package fillreturns
 -
@@ -7157,7 +8229,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden
 --- a/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillreturns/testdata/src/a/typeparams/a.go.golden	1970-01-01 08:00:00
 @@ -1,5 +0,0 @@
 -package fillreturns
 -
@@ -7166,8 +8238,8 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillstruct/fillstruct.go b/gopls/internal/lsp/analysis/fillstruct/fillstruct.go
 --- a/gopls/internal/lsp/analysis/fillstruct/fillstruct.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,506 +0,0 @@
++++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct.go	1970-01-01 08:00:00
+@@ -1,515 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -7218,26 +8290,34 @@
 -	RunDespiteErrors: true,
 -}
 -
+-// TODO(rfindley): remove this thin wrapper around the fillstruct refactoring,
+-// and eliminate the fillstruct analyzer.
+-//
+-// Previous iterations used the analysis framework for computing refactorings,
+-// which proved inefficient.
 -func run(pass *analysis.Pass) (interface{}, error) {
 -	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+-	for _, d := range DiagnoseFillableStructs(inspect, token.NoPos, token.NoPos, pass.Pkg, pass.TypesInfo) {
+-		pass.Report(d)
+-	}
+-	return nil, nil
+-}
+-
+-// DiagnoseFillableStructs computes diagnostics for fillable struct composite
+-// literals overlapping with the provided start and end position.
+-//
+-// If either start or end is invalid, it is considered an unbounded condition.
+-func DiagnoseFillableStructs(inspect *inspector.Inspector, start, end token.Pos, pkg *types.Package, info *types.Info) []analysis.Diagnostic {
+-	var diags []analysis.Diagnostic
 -	nodeFilter := []ast.Node{(*ast.CompositeLit)(nil)}
 -	inspect.Preorder(nodeFilter, func(n ast.Node) {
 -		expr := n.(*ast.CompositeLit)
 -
--		// Find enclosing file.
--		// TODO(adonovan): use inspect.WithStack?
--		var file *ast.File
--		for _, f := range pass.Files {
--			if f.Pos() <= expr.Pos() && expr.Pos() <= f.End() {
--				file = f
--				break
--			}
--		}
--		if file == nil {
--			return
+-		if (start.IsValid() && expr.End() < start) || (end.IsValid() && expr.Pos() > end) {
+-			return // non-overlapping
 -		}
 -
--		typ := pass.TypesInfo.TypeOf(expr)
+-		typ := info.TypeOf(expr)
 -		if typ == nil {
 -			return
 -		}
@@ -7262,7 +8342,7 @@
 -		for i := 0; i < fieldCount; i++ {
 -			field := tStruct.Field(i)
 -			// Ignore fields that are not accessible in the current package.
--			if field.Pkg() != nil && field.Pkg() != pass.Pkg && !field.Exported() {
+-			if field.Pkg() != nil && field.Pkg() != pkg && !field.Exported() {
 -				continue
 -			}
 -			fillableFields = append(fillableFields, fmt.Sprintf("%s: %s", field.Name(), field.Type().String()))
@@ -7275,7 +8355,7 @@
 -		var name string
 -		if typ != tStruct {
 -			// named struct type (e.g. pkg.S[T])
--			name = types.TypeString(typ, types.RelativeTo(pass.Pkg))
+-			name = types.TypeString(typ, types.RelativeTo(pkg))
 -		} else {
 -			// anonymous struct type
 -			totalFields := len(fillableFields)
@@ -7294,13 +8374,14 @@
 -			}
 -			name = fmt.Sprintf("anonymous struct { %s }", strings.Join(fillableFields, ", "))
 -		}
--		pass.Report(analysis.Diagnostic{
+-		diags = append(diags, analysis.Diagnostic{
 -			Message: fmt.Sprintf("Fill %s", name),
 -			Pos:     expr.Pos(),
 -			End:     expr.End(),
 -		})
 -	})
--	return nil, nil
+-
+-	return diags
 -}
 -
 -// SuggestedFix computes the suggested fix for the kinds of
@@ -7338,7 +8419,7 @@
 -		return nil, fmt.Errorf("%s is not a (pointer to) struct type",
 -			types.TypeString(typ, types.RelativeTo(pkg)))
 -	}
--	// Inv: typ is the the possibly-named struct type.
+-	// Inv: typ is the possibly-named struct type.
 -
 -	fieldCount := tStruct.NumFields()
 -
@@ -7676,7 +8757,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go b/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go
 --- a/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillstruct/fillstruct_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7702,7 +8783,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,113 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7819,7 +8900,7 @@
 -var _ = unsafeStruct{} // want `Fill unsafeStruct`
 diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go
 --- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/b/b.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package fillstruct
 -
@@ -7829,7 +8910,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go
 --- a/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/fillstruct/testdata/src/typeparams/typeparams.go	1970-01-01 08:00:00
 @@ -1,50 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7883,8 +8964,8 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
++++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs.go	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -7894,8 +8975,11 @@
 -package infertypeargs
 -
 -import (
+-	"go/token"
+-
 -	"golang.org/x/tools/go/analysis"
 -	"golang.org/x/tools/go/analysis/passes/inspect"
+-	"golang.org/x/tools/go/ast/inspector"
 -)
 -
 -const Doc = `check for unnecessary type arguments in call expressions
@@ -7916,9 +9000,22 @@
 -	Requires: []*analysis.Analyzer{inspect.Analyzer},
 -	Run:      run,
 -}
+-
+-// TODO(rfindley): remove this thin wrapper around the infertypeargs refactoring,
+-// and eliminate the infertypeargs analyzer.
+-//
+-// Previous iterations used the analysis framework for computing refactorings,
+-// which proved inefficient.
+-func run(pass *analysis.Pass) (interface{}, error) {
+-	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+-	for _, diag := range DiagnoseInferableTypeArgs(pass.Fset, inspect, token.NoPos, token.NoPos, pass.Pkg, pass.TypesInfo) {
+-		pass.Report(diag)
+-	}
+-	return nil, nil
+-}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/infertypeargs_test.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -7943,8 +9040,8 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/run_go117.go b/gopls/internal/lsp/analysis/infertypeargs/run_go117.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/run_go117.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/run_go117.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
++++ b/gopls/internal/lsp/analysis/infertypeargs/run_go117.go	1970-01-01 08:00:00
+@@ -1,22 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -7954,17 +9051,23 @@
 -
 -package infertypeargs
 -
--import "golang.org/x/tools/go/analysis"
+-import (
+-	"go/token"
+-	"go/types"
 -
--// This analyzer only relates to go1.18+, and uses the types.CheckExpr API that
--// was added in Go 1.13.
--func run(pass *analysis.Pass) (interface{}, error) {
--	return nil, nil
+-	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/go/ast/inspector"
+-)
+-
+-// DiagnoseInferableTypeArgs returns an empty slice, as generics are not supported at
+-// this go version.
+-func DiagnoseInferableTypeArgs(fset *token.FileSet, inspect *inspector.Inspector, start, end token.Pos, pkg *types.Package, info *types.Info) []analysis.Diagnostic {
+-	return nil
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/run_go118.go b/gopls/internal/lsp/analysis/infertypeargs/run_go118.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/run_go118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/run_go118.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,111 +0,0 @@
++++ b/gopls/internal/lsp/analysis/infertypeargs/run_go118.go	1970-01-01 08:00:00
+@@ -1,120 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -7980,18 +9083,19 @@
 -	"go/types"
 -
 -	"golang.org/x/tools/go/analysis"
--	"golang.org/x/tools/go/analysis/passes/inspect"
 -	"golang.org/x/tools/go/ast/inspector"
 -	"golang.org/x/tools/internal/typeparams"
 -)
 -
--func run(pass *analysis.Pass) (interface{}, error) {
--	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+-// DiagnoseInferableTypeArgs reports diagnostics describing simplifications to type
+-// arguments overlapping with the provided start and end position.
+-//
+-// If start or end is token.NoPos, the corresponding bound is not checked
+-// (i.e. if both start and end are NoPos, all call expressions are considered).
+-func DiagnoseInferableTypeArgs(fset *token.FileSet, inspect *inspector.Inspector, start, end token.Pos, pkg *types.Package, info *types.Info) []analysis.Diagnostic {
+-	var diags []analysis.Diagnostic
 -
--	nodeFilter := []ast.Node{
--		(*ast.CallExpr)(nil),
--	}
--
+-	nodeFilter := []ast.Node{(*ast.CallExpr)(nil)}
 -	inspect.Preorder(nodeFilter, func(node ast.Node) {
 -		call := node.(*ast.CallExpr)
 -		x, lbrack, indices, rbrack := typeparams.UnpackIndexExpr(call.Fun)
@@ -8000,8 +9104,12 @@
 -			return // no explicit args, nothing to do
 -		}
 -
+-		if (start.IsValid() && call.End() < start) || (end.IsValid() && call.Pos() > end) {
+-			return // non-overlapping
+-		}
+-
 -		// Confirm that instantiation actually occurred at this ident.
--		idata, ok := typeparams.GetInstances(pass.TypesInfo)[ident]
+-		idata, ok := typeparams.GetInstances(info)[ident]
 -		if !ok {
 -			return // something went wrong, but fail open
 -		}
@@ -8027,7 +9135,7 @@
 -			}
 -			info := new(types.Info)
 -			typeparams.InitInstanceInfo(info)
--			if err := types.CheckExpr(pass.Fset, pass.Pkg, call.Pos(), newCall, info); err != nil {
+-			if err := types.CheckExpr(fset, pkg, call.Pos(), newCall, info); err != nil {
 -				// Most likely inference failed.
 -				break
 -			}
@@ -8041,20 +9149,24 @@
 -			required = i
 -		}
 -		if required < len(indices) {
--			var start, end token.Pos
+-			var s, e token.Pos
 -			var edit analysis.TextEdit
 -			if required == 0 {
--				start, end = lbrack, rbrack+1 // erase the entire index
--				edit = analysis.TextEdit{Pos: start, End: end}
+-				s, e = lbrack, rbrack+1 // erase the entire index
+-				edit = analysis.TextEdit{Pos: s, End: e}
 -			} else {
--				start = indices[required].Pos()
--				end = rbrack
+-				s = indices[required].Pos()
+-				e = rbrack
 -				//  erase from end of last arg to include last comma & white-spaces
--				edit = analysis.TextEdit{Pos: indices[required-1].End(), End: end}
+-				edit = analysis.TextEdit{Pos: indices[required-1].End(), End: e}
 -			}
--			pass.Report(analysis.Diagnostic{
--				Pos:     start,
--				End:     end,
+-			// Recheck that our (narrower) fixes overlap with the requested range.
+-			if (start.IsValid() && e < start) || (end.IsValid() && s > end) {
+-				return // non-overlapping
+-			}
+-			diags = append(diags, analysis.Diagnostic{
+-				Pos:     s,
+-				End:     e,
 -				Message: "unnecessary type arguments",
 -				SuggestedFixes: []analysis.SuggestedFix{{
 -					Message:   "simplify type arguments",
@@ -8064,7 +9176,7 @@
 -		}
 -	})
 -
--	return nil, nil
+-	return diags
 -}
 -
 -func calledIdent(x ast.Expr) *ast.Ident {
@@ -8078,7 +9190,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8102,7 +9214,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/basic.go.golden	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8126,7 +9238,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported/imported.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8137,7 +9249,7 @@
 -func F[T any](T) {}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8153,7 +9265,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/imported.go.golden	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8169,7 +9281,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8199,7 +9311,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden
 --- a/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/infertypeargs/testdata/src/a/notypechange.go.golden	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8229,7 +9341,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/nonewvars.go b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go
 --- a/gopls/internal/lsp/analysis/nonewvars/nonewvars.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go	1970-01-01 08:00:00
 @@ -1,95 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8328,7 +9440,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go b/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go
 --- a/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8354,7 +9466,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8374,7 +9486,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8394,7 +9506,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go
 --- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package nonewvars
 -
@@ -8404,7 +9516,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden
 --- a/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/nonewvars/testdata/src/typeparams/a.go.golden	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package nonewvars
 -
@@ -8414,7 +9526,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go
 --- a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues.go	1970-01-01 08:00:00
 @@ -1,92 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8510,7 +9622,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go
 --- a/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/noresultvalues_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8536,7 +9648,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8549,7 +9661,7 @@
 -func y() { return nil, "hello" } // want `no result values expected|too many return values`
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8562,7 +9674,7 @@
 -func y() { return } // want `no result values expected|too many return values`
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go
 --- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package noresult
 -
@@ -8572,7 +9684,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden
 --- a/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/noresultvalues/testdata/src/typeparams/a.go.golden	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package noresult
 -
@@ -8582,7 +9694,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go
 --- a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit.go	1970-01-01 08:00:00
 @@ -1,196 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8782,7 +9894,7 @@
 -)
 diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go
 --- a/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifycompositelit/simplifycompositelit_test.go	1970-01-01 08:00:00
 @@ -1,17 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -8803,7 +9915,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,234 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9041,7 +10153,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifycompositelit/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,234 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9279,7 +10391,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go
 --- a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange.go	1970-01-01 08:00:00
 @@ -1,116 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9399,7 +10511,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go
 --- a/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyrange/simplifyrange_test.go	1970-01-01 08:00:00
 @@ -1,17 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9420,7 +10532,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9440,7 +10552,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyrange/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9460,7 +10572,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go
 --- a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice.go	1970-01-01 08:00:00
 @@ -1,94 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9558,7 +10670,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go
 --- a/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/simplifyslice_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9584,7 +10696,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,70 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9658,7 +10770,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,70 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9732,7 +10844,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go
 --- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go	1970-01-01 08:00:00
 @@ -1,39 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9775,7 +10887,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden
 --- a/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/simplifyslice/testdata/src/typeparams/typeparams.go.golden	1970-01-01 08:00:00
 @@ -1,39 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -9818,8 +10930,8 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/stubmethods/stubmethods.go b/gopls/internal/lsp/analysis/stubmethods/stubmethods.go
 --- a/gopls/internal/lsp/analysis/stubmethods/stubmethods.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/stubmethods/stubmethods.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,418 +0,0 @@
++++ b/gopls/internal/lsp/analysis/stubmethods/stubmethods.go	1970-01-01 08:00:00
+@@ -1,449 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -9837,7 +10949,6 @@
 -	"strings"
 -
 -	"golang.org/x/tools/go/analysis"
--	"golang.org/x/tools/go/analysis/passes/inspect"
 -	"golang.org/x/tools/go/ast/astutil"
 -	"golang.org/x/tools/internal/analysisinternal"
 -	"golang.org/x/tools/internal/typesinternal"
@@ -9851,17 +10962,17 @@
 -var Analyzer = &analysis.Analyzer{
 -	Name:             "stubmethods",
 -	Doc:              Doc,
--	Requires:         []*analysis.Analyzer{inspect.Analyzer},
 -	Run:              run,
 -	RunDespiteErrors: true,
 -}
 -
+-// TODO(rfindley): remove this thin wrapper around the stubmethods refactoring,
+-// and eliminate the stubmethods analyzer.
+-//
+-// Previous iterations used the analysis framework for computing refactorings,
+-// which proved inefficient.
 -func run(pass *analysis.Pass) (interface{}, error) {
 -	for _, err := range pass.TypeErrors {
--		ifaceErr := strings.Contains(err.Msg, "missing method") || strings.HasPrefix(err.Msg, "cannot convert")
--		if !ifaceErr {
--			continue
--		}
 -		var file *ast.File
 -		for _, f := range pass.Files {
 -			if f.Pos() <= err.Pos && err.Pos < f.End() {
@@ -9869,33 +10980,54 @@
 -				break
 -			}
 -		}
--		if file == nil {
--			continue
--		}
 -		// Get the end position of the error.
--		_, _, endPos, ok := typesinternal.ReadGo116ErrorData(err)
+-		_, _, end, ok := typesinternal.ReadGo116ErrorData(err)
 -		if !ok {
 -			var buf bytes.Buffer
 -			if err := format.Node(&buf, pass.Fset, file); err != nil {
 -				continue
 -			}
--			endPos = analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos)
+-			end = analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos)
 -		}
--		path, _ := astutil.PathEnclosingInterval(file, err.Pos, endPos)
--		si := GetStubInfo(pass.Fset, pass.TypesInfo, path, err.Pos)
--		if si == nil {
--			continue
+-		if diag, ok := DiagnosticForError(pass.Fset, file, err.Pos, end, err.Msg, pass.TypesInfo); ok {
+-			pass.Report(diag)
 -		}
--		qf := RelativeToFiles(si.Concrete.Obj().Pkg(), file, nil, nil)
--		pass.Report(analysis.Diagnostic{
--			Pos:     err.Pos,
--			End:     endPos,
--			Message: fmt.Sprintf("Implement %s", types.TypeString(si.Interface.Type(), qf)),
--		})
 -	}
+-
 -	return nil, nil
 -}
 -
+-// MatchesMessage reports whether msg matches the error message sought after by
+-// the stubmethods fix.
+-func MatchesMessage(msg string) bool {
+-	return strings.Contains(msg, "missing method") || strings.HasPrefix(msg, "cannot convert")
+-}
+-
+-// DiagnosticForError computes a diagnostic suggesting to implement an
+-// interface to fix the type checking error defined by (start, end, msg).
+-//
+-// If no such fix is possible, the second result is false.
+-//
+-// TODO(rfindley): simplify this signature once the stubmethods refactoring is
+-// no longer wedged into the analysis framework.
+-func DiagnosticForError(fset *token.FileSet, file *ast.File, start, end token.Pos, msg string, info *types.Info) (analysis.Diagnostic, bool) {
+-	if !MatchesMessage(msg) {
+-		return analysis.Diagnostic{}, false
+-	}
+-
+-	path, _ := astutil.PathEnclosingInterval(file, start, end)
+-	si := GetStubInfo(fset, info, path, start)
+-	if si == nil {
+-		return analysis.Diagnostic{}, false
+-	}
+-	qf := RelativeToFiles(si.Concrete.Obj().Pkg(), file, nil, nil)
+-	return analysis.Diagnostic{
+-		Pos:     start,
+-		End:     end,
+-		Message: fmt.Sprintf("Implement %s", types.TypeString(si.Interface.Type(), qf)),
+-	}, true
+-}
+-
 -// StubInfo represents a concrete type
 -// that wants to stub out an interface type
 -type StubInfo struct {
@@ -9917,7 +11049,7 @@
 -//
 -// TODO(adonovan): this function (and its following 5 helpers) tries
 -// to deduce a pair of (concrete, interface) types that are related by
--// an assignment, either explictly or through a return statement or
+-// an assignment, either explicitly or through a return statement or
 -// function call. This is essentially what the refactor/satisfy does,
 -// more generally. Refactor to share logic, after auditing 'satisfy'
 -// for safety on ill-typed code.
@@ -9976,8 +11108,19 @@
 -	if !ok {
 -		return nil
 -	}
--	sigVar := sig.Params().At(paramIdx)
--	iface := ifaceObjFromType(sigVar.Type())
+-	var paramType types.Type
+-	if sig.Variadic() && paramIdx >= sig.Params().Len()-1 {
+-		v := sig.Params().At(sig.Params().Len() - 1)
+-		if s, _ := v.Type().(*types.Slice); s != nil {
+-			paramType = s.Elem()
+-		}
+-	} else if paramIdx < sig.Params().Len() {
+-		paramType = sig.Params().At(paramIdx).Type()
+-	}
+-	if paramType == nil {
+-		return nil // A type error prevents us from determining the param type.
+-	}
+-	iface := ifaceObjFromType(paramType)
 -	if iface == nil {
 -		return nil
 -	}
@@ -10240,7 +11383,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,28 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10272,7 +11415,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/channels.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10289,7 +11432,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/consecutive_params.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10303,7 +11446,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/error_param.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10317,7 +11460,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/literals.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10332,7 +11475,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/operation.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10347,7 +11490,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/selector.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10361,7 +11504,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/slice.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10374,7 +11517,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/tuple.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10391,7 +11534,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/testdata/src/a/unique_params.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10406,7 +11549,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go	1970-01-01 08:00:00
 @@ -1,347 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10757,7 +11900,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go b/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go
 --- a/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared_test.go	1970-01-01 08:00:00
 @@ -1,17 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10778,7 +11921,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,55 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10837,7 +11980,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,55 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10896,7 +12039,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go
 --- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go	1970-01-01 08:00:00
 @@ -1,55 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -10955,7 +12098,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden
 --- a/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/testdata/src/typeparams/typeparams.go.golden	1970-01-01 08:00:00
 @@ -1,55 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11014,7 +12157,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/unusedparams.go b/gopls/internal/lsp/analysis/unusedparams/unusedparams.go
 --- a/gopls/internal/lsp/analysis/unusedparams/unusedparams.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams.go	1970-01-01 08:00:00
 @@ -1,152 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11042,7 +12185,7 @@
 -
 -To reduce false positives it ignores:
 -- methods
--- parameters that do not have a name or are underscored
+-- parameters that do not have a name or have the name '_' (the blank identifier)
 -- functions in test files
 -- functions with empty bodies or those with just a return stmt`
 -
@@ -11170,7 +12313,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go b/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go
 --- a/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedparams/unusedparams_test.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11196,7 +12339,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go
 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go	1970-01-01 08:00:00
 @@ -1,74 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11274,7 +12417,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden
 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden	1970-01-01 08:00:00
 @@ -1,59 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11337,7 +12480,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go
 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go	1970-01-01 08:00:00
 @@ -1,30 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11371,7 +12514,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden
 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11399,7 +12542,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go
 --- a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go	1970-01-01 08:00:00
 @@ -1,300 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11703,7 +12846,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go
 --- a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable_test.go	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11731,7 +12874,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go
 --- a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11760,7 +12903,7 @@
 -type _[T any] int
 diff -urN a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden
 --- a/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/useany/testdata/src/a/a.go.golden	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11789,7 +12932,7 @@
 -type _[T any] int
 diff -urN a/gopls/internal/lsp/analysis/useany/useany.go b/gopls/internal/lsp/analysis/useany/useany.go
 --- a/gopls/internal/lsp/analysis/useany/useany.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/useany/useany.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/useany/useany.go	1970-01-01 08:00:00
 @@ -1,102 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11895,7 +13038,7 @@
 -}
 diff -urN a/gopls/internal/lsp/analysis/useany/useany_test.go b/gopls/internal/lsp/analysis/useany/useany_test.go
 --- a/gopls/internal/lsp/analysis/useany/useany_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/analysis/useany/useany_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/analysis/useany/useany_test.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11918,9 +13061,15 @@
 -	testdata := analysistest.TestData()
 -	analysistest.RunWithSuggestedFixes(t, testdata, useany.Analyzer, "a")
 -}
+diff -urN a/gopls/internal/lsp/browser/README.md b/gopls/internal/lsp/browser/README.md
+--- a/gopls/internal/lsp/browser/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/browser/README.md	1970-01-01 08:00:00
+@@ -1 +0,0 @@
+-This package is a copy of cmd/internal/browser from the go distribution
+\ No newline at end of file
 diff -urN a/gopls/internal/lsp/browser/browser.go b/gopls/internal/lsp/browser/browser.go
 --- a/gopls/internal/lsp/browser/browser.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/browser/browser.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/browser/browser.go	1970-01-01 08:00:00
 @@ -1,67 +0,0 @@
 -// Copyright 2016 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -11989,16 +13138,10 @@
 -		return err == nil
 -	}
 -}
-diff -urN a/gopls/internal/lsp/browser/README.md b/gopls/internal/lsp/browser/README.md
---- a/gopls/internal/lsp/browser/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/browser/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--This package is a copy of cmd/internal/browser from the go distribution
-\ No newline at end of file
 diff -urN a/gopls/internal/lsp/cache/analysis.go b/gopls/internal/lsp/cache/analysis.go
 --- a/gopls/internal/lsp/cache/analysis.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/analysis.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1247 +0,0 @@
++++ b/gopls/internal/lsp/cache/analysis.go	1970-01-01 08:00:00
+@@ -1,1515 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -12019,22 +13162,28 @@
 -	"go/token"
 -	"go/types"
 -	"log"
+-	urlpkg "net/url"
 -	"reflect"
+-	"runtime"
 -	"runtime/debug"
 -	"sort"
 -	"strings"
 -	"sync"
+-	"sync/atomic"
 -	"time"
 -
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/filecache"
+-	"golang.org/x/tools/gopls/internal/lsp/frob"
+-	"golang.org/x/tools/gopls/internal/lsp/progress"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/facts"
 -	"golang.org/x/tools/internal/gcimporter"
--	"golang.org/x/tools/internal/memoize"
 -	"golang.org/x/tools/internal/typeparams"
 -	"golang.org/x/tools/internal/typesinternal"
 -)
@@ -12043,48 +13192,50 @@
 -
 -   DESIGN
 -
--   An analysis request is for a set of analyzers and an individual
--   package ID, notated (a*, p). The result is the set of diagnostics
--   for that package. It could easily be generalized to a set of
--   packages, (a*, p*), and perhaps should be, to improve performance
--   versus calling it in a loop.
+-   An analysis request (Snapshot.Analyze) is for a set of Analyzers and
+-   PackageIDs. The result is the set of diagnostics for those
+-   packages. Each request constructs a transitively closed DAG of
+-   nodes, each representing a package, then works bottom up in
+-   parallel postorder calling runCached to ensure that each node's
+-   analysis summary is up to date. The summary contains the analysis
+-   diagnostics as well as the intermediate results required by the
+-   recursion, such as serialized types and facts.
 -
--   The snapshot holds a cache (persistent.Map) of entries keyed by
--   (a*, p) pairs ("analysisKey") that have been requested so far. Some
--   of these entries may be invalidated during snapshot cloning after a
--   modification event.  The cache maps each (a*, p) to a promise of
--   the analysis result or "analysisSummary". The summary contains the
--   results of analysis (e.g. diagnostics) as well as the intermediate
--   results required by the recursion, such as serialized types and
--   facts.
+-   The entire DAG is ephemeral. Each node in the DAG records the set
+-   of analyzers to run: the complete set for the root packages, and
+-   the "facty" subset for dependencies. Each package is thus analyzed
+-   at most once. The entire DAG shares a single FileSet for parsing
+-   and importing.
 -
--   The promise represents the result of a call to analyzeImpl, which
--   type-checks a package and then applies a graph of analyzers to it
--   in parallel postorder. (These graph edges are "horizontal": within
--   the same package.) First, analyzeImpl reads the source files of
--   package p, and obtains (recursively) the results of the "vertical"
--   dependencies (i.e. analyzers applied to the packages imported by
--   p). Only the subset of analyzers that use facts need be executed
--   recursively, but even if this subset is empty, the step is still
--   necessary because it provides type information. It is possible that
--   a package may need to be type-checked and analyzed twice, for
--   different subsets of analyzers, but the overlap is typically
--   insignificant.
--
--   With the file contents and the results of vertical dependencies,
--   analyzeImpl is then in a position to produce a key representing the
--   unit of work (parsing, type-checking, and analysis) that it has to
--   do. The key is a cryptographic hash of the "recipe" for this step,
--   including the Metadata, the file contents, the set of analyzers,
--   and the type and fact information from the vertical dependencies.
+-   Each node is processed by runCached. It gets the source file
+-   content hashes for package p, and the summaries of its "vertical"
+-   dependencies (direct imports), and from them it computes a key
+-   representing the unit of work (parsing, type-checking, and
+-   analysis) that it has to do. The key is a cryptographic hash of the
+-   "recipe" for this step, including the Metadata, the file contents,
+-   the set of analyzers, and the type and fact information from the
+-   vertical dependencies.
 -
 -   The key is sought in a machine-global persistent file-system based
 -   cache. If this gopls process, or another gopls process on the same
--   machine, has already performed this analysis step, analyzeImpl will
+-   machine, has already performed this analysis step, runCached will
 -   make a cache hit and load the serialized summary of the results. If
--   not, it will have to proceed to type-checking and analysis, and
--   write a new cache entry. The entry contains serialized types
--   (export data) and analysis facts.
+-   not, it will have to proceed to run() to parse and type-check the
+-   package and then apply a set of analyzers to it. (The set of
+-   analyzers applied to a single package itself forms a graph of
+-   "actions", and it too is evaluated in parallel postorder; these
+-   dependency edges within the same package are called "horizontal".)
+-   Finally it writes a new cache entry. The entry contains serialized
+-   types (export data) and analysis facts.
+-
+-   Each node in the DAG acts like a go/types importer mapping,
+-   providing a consistent view of packages and their objects: the
+-   mapping for a node is a superset of its dependencies' mappings.
+-   Every node has an associated *types.Package, initially nil. A
+-   package is populated during run (cache miss) by type-checking its
+-   syntax; but for a cache hit, the package is populated lazily, i.e.
+-   not until it later becomes necessary because it is imported
+-   directly or referenced by export data higher up in the DAG.
 -
 -   For types, we use "shallow" export data. Historically, the Go
 -   compiler always produced a summary of the types for a given package
@@ -12103,11 +13254,8 @@
 -   "Shallow" export data means that the serialized types describe only
 -   a single package. If those types mention types from other packages,
 -   the type checker may need to request additional packages beyond
--   just the direct imports. This means type information for the entire
--   transitive closure of imports may need to be available just in
--   case. After a cache hit or a cache miss, the summary is
--   postprocessed so that it contains the union of export data payloads
--   of all its direct dependencies.
+-   just the direct imports. Type information for the entire transitive
+-   closure of imports is provided (lazily) by the DAG.
 -
 -   For correct dependency analysis, the digest used as a cache key
 -   must reflect the "deep" export data, so it is derived recursively
@@ -12119,8 +13267,9 @@
 -   but if its export data is unchanged as a result, then indirect
 -   consumers may not need to be re-executed.  This allows, for example,
 -   one to insert a print statement in a function and not "rebuild" the
--   whole application (though export data does record line numbers of
--   types which may be perturbed by otherwise insignificant changes.)
+-   whole application (though export data does record line numbers and
+-   offsets of types which may be perturbed by otherwise insignificant
+-   changes.)
 -
 -   The summary must record whether a package is transitively
 -   error-free (whether it would compile) because many analyzers are
@@ -12133,13 +13282,6 @@
 -*/
 -
 -// TODO(adonovan):
--// - Profile + optimize:
--//   - on a cold run, mostly type checking + export data, unsurprisingly.
--//   - on a hot-disk run, mostly type checking the IWL.
--//     Would be nice to have a benchmark that separates this out.
--//   - measure and record in the code the typical operation times
--//     and file sizes (export data + facts = cache entries).
--// - Do "port the old logic" tasks (see TODO in actuallyAnalyze).
 -// - Add a (white-box) test of pruning when a change doesn't affect export data.
 -// - Optimise pruning based on subset of packages mentioned in exportdata.
 -// - Better logging so that it is possible to deduce why an analyzer
@@ -12147,7 +13289,6 @@
 -//   Even if the ultimate consumer decides to ignore errors,
 -//   tests and other situations want to be assured of freedom from
 -//   errors, not just missing results. This should be recorded.
--// - Check that the event trace is intelligible.
 -// - Split this into a subpackage, gopls/internal/lsp/cache/driver,
 -//   consisting of this file and three helpers from errors.go.
 -//   The (*snapshot).Analyze method would stay behind and make calls
@@ -12155,35 +13296,47 @@
 -//   Steps:
 -//   - define a narrow driver.Snapshot interface with only these methods:
 -//        Metadata(PackageID) source.Metadata
--//        GetFile(Context, URI) (source.FileHandle, error)
+-//        ReadFile(Context, URI) (source.FileHandle, error)
 -//        View() *View // for Options
--//   - define a State type that encapsulates the persistent map
--//     (with its own mutex), and has methods:
--//        New() *State
--//        Clone(invalidate map[PackageID]bool) *State
--//        Destroy()
 -//   - share cache.{goVersionRx,parseGoImpl}
 -
--var born = time.Now()
+-// AnalysisProgressTitle is the title of the progress report for ongoing
+-// analysis. It is sought by regression tests for the progress reporting
+-// feature.
+-const AnalysisProgressTitle = "Analyzing Dependencies"
 -
 -// Analyze applies a set of analyzers to the package denoted by id,
 -// and returns their diagnostics for that package.
 -//
 -// The analyzers list must be duplicate free; order does not matter.
 -//
+-// Notifications of progress may be sent to the optional reporter.
+-//
 -// Precondition: all analyzers within the process have distinct names.
 -// (The names are relied on by the serialization logic.)
--func (s *snapshot) Analyze(ctx context.Context, id PackageID, analyzers []*source.Analyzer) ([]*source.Diagnostic, error) {
--	if false { // debugging
--		log.Println("Analyze@", time.Since(born)) // called after the 7s IWL in k8s
+-func (snapshot *snapshot) Analyze(ctx context.Context, pkgs map[PackageID]unit, analyzers []*source.Analyzer, reporter *progress.Tracker) ([]*source.Diagnostic, error) {
+-	start := time.Now() // for progress reporting
+-
+-	var tagStr string // sorted comma-separated list of PackageIDs
+-	{
+-		// TODO(adonovan): replace with a generic map[S]any -> string
+-		// function in the tag package, and use maps.Keys + slices.Sort.
+-		keys := make([]string, 0, len(pkgs))
+-		for id := range pkgs {
+-			keys = append(keys, string(id))
+-		}
+-		sort.Strings(keys)
+-		tagStr = strings.Join(keys, ",")
 -	}
+-	ctx, done := event.Start(ctx, "snapshot.Analyze", tag.Package.Of(tagStr))
+-	defer done()
 -
 -	// Filter and sort enabled root analyzers.
 -	// A disabled analyzer may still be run if required by another.
 -	toSrc := make(map[*analysis.Analyzer]*source.Analyzer)
--	var enabled []*analysis.Analyzer
+-	var enabled []*analysis.Analyzer // enabled subset + transitive requirements
 -	for _, a := range analyzers {
--		if a.IsEnabled(s.view.Options()) {
+-		if a.IsEnabled(snapshot.options) {
 -			toSrc[a.Analyzer] = a
 -			enabled = append(enabled, a.Analyzer)
 -		}
@@ -12191,26 +13344,216 @@
 -	sort.Slice(enabled, func(i, j int) bool {
 -		return enabled[i].Name < enabled[j].Name
 -	})
+-	analyzers = nil // prevent accidental use
 -
 -	// Register fact types of required analyzers.
--	for _, a := range requiredAnalyzers(enabled) {
--		for _, f := range a.FactTypes {
--			gob.Register(f)
+-	enabled = requiredAnalyzers(enabled)
+-	var facty []*analysis.Analyzer // facty subset of enabled + transitive requirements
+-	for _, a := range enabled {
+-		if len(a.FactTypes) > 0 {
+-			facty = append(facty, a)
+-			for _, f := range a.FactTypes {
+-				gob.Register(f) // <2us
+-			}
+-		}
+-	}
+-	facty = requiredAnalyzers(facty)
+-
+-	// File set for this batch (entire graph) of analysis.
+-	fset := token.NewFileSet()
+-
+-	// Starting from the root packages and following DepsByPkgPath,
+-	// build the DAG of packages we're going to analyze.
+-	//
+-	// Root nodes will run the enabled set of analyzers,
+-	// whereas dependencies will run only the facty set.
+-	// Because (by construction) enabled is a superset of facty,
+-	// we can analyze each node with exactly one set of analyzers.
+-	nodes := make(map[PackageID]*analysisNode)
+-	var leaves []*analysisNode // nodes with no unfinished successors
+-	var makeNode func(from *analysisNode, id PackageID) (*analysisNode, error)
+-	makeNode = func(from *analysisNode, id PackageID) (*analysisNode, error) {
+-		an, ok := nodes[id]
+-		if !ok {
+-			m := snapshot.Metadata(id)
+-			if m == nil {
+-				return nil, bug.Errorf("no metadata for %s", id)
+-			}
+-
+-			// -- preorder --
+-
+-			an = &analysisNode{
+-				fset:       fset,
+-				m:          m,
+-				analyzers:  facty, // all nodes run at least the facty analyzers
+-				allDeps:    make(map[PackagePath]*analysisNode),
+-				exportDeps: make(map[PackagePath]*analysisNode),
+-			}
+-			nodes[id] = an
+-
+-			// -- recursion --
+-
+-			// Build subgraphs for dependencies.
+-			an.succs = make(map[PackageID]*analysisNode, len(m.DepsByPkgPath))
+-			for _, depID := range m.DepsByPkgPath {
+-				dep, err := makeNode(an, depID)
+-				if err != nil {
+-					return nil, err
+-				}
+-				an.succs[depID] = dep
+-
+-				// Compute the union of all dependencies.
+-				// (This step has quadratic complexity.)
+-				for pkgPath, node := range dep.allDeps {
+-					an.allDeps[pkgPath] = node
+-				}
+-			}
+-
+-			// -- postorder --
+-
+-			an.allDeps[m.PkgPath] = an // add self entry (reflexive transitive closure)
+-
+-			// Add leaf nodes (no successors) directly to queue.
+-			if len(an.succs) == 0 {
+-				leaves = append(leaves, an)
+-			}
+-
+-			// Load the contents of each compiled Go file through
+-			// the snapshot's cache. (These are all cache hits as
+-			// files are pre-loaded following packages.Load)
+-			an.files = make([]source.FileHandle, len(m.CompiledGoFiles))
+-			for i, uri := range m.CompiledGoFiles {
+-				fh, err := snapshot.ReadFile(ctx, uri)
+-				if err != nil {
+-					return nil, err
+-				}
+-				an.files[i] = fh
+-			}
+-		}
+-		// Add edge from predecessor.
+-		if from != nil {
+-			atomic.AddInt32(&from.unfinishedSuccs, 1) // TODO(adonovan): use generics
+-			an.preds = append(an.preds, from)
+-		}
+-		atomic.AddInt32(&an.unfinishedPreds, 1)
+-		return an, nil
+-	}
+-
+-	// For root packages, we run the enabled set of analyzers.
+-	var roots []*analysisNode
+-	for id := range pkgs {
+-		root, err := makeNode(nil, id)
+-		if err != nil {
+-			return nil, err
+-		}
+-		root.analyzers = enabled
+-		roots = append(roots, root)
+-	}
+-
+-	// Now that we have read all files,
+-	// we no longer need the snapshot.
+-	// (but options are needed for progress reporting)
+-	options := snapshot.options
+-	snapshot = nil
+-
+-	// Progress reporting. If supported, gopls reports progress on analysis
+-	// passes that are taking a long time.
+-	maybeReport := func(completed int64) {}
+-
+-	// Enable progress reporting if enabled by the user
+-	// and we have a capable reporter.
+-	if reporter != nil && reporter.SupportsWorkDoneProgress() && options.AnalysisProgressReporting {
+-		var reportAfter = options.ReportAnalysisProgressAfter // tests may set this to 0
+-		const reportEvery = 1 * time.Second
+-
+-		ctx, cancel := context.WithCancel(ctx)
+-		defer cancel()
+-
+-		var (
+-			reportMu   sync.Mutex
+-			lastReport time.Time
+-			wd         *progress.WorkDone
+-		)
+-		defer func() {
+-			reportMu.Lock()
+-			defer reportMu.Unlock()
+-
+-			if wd != nil {
+-				wd.End(ctx, "Done.") // ensure that the progress report exits
+-			}
+-		}()
+-		maybeReport = func(completed int64) {
+-			now := time.Now()
+-			if now.Sub(start) < reportAfter {
+-				return
+-			}
+-
+-			reportMu.Lock()
+-			defer reportMu.Unlock()
+-
+-			if wd == nil {
+-				wd = reporter.Start(ctx, AnalysisProgressTitle, "", nil, cancel)
+-			}
+-
+-			if now.Sub(lastReport) > reportEvery {
+-				lastReport = now
+-				// Trailing space is intentional: some LSP clients strip newlines.
+-				msg := fmt.Sprintf(`Indexed %d/%d packages. (Set "analysisProgressReporting" to false to disable notifications.)`,
+-					completed, len(nodes))
+-				pct := 100 * float64(completed) / float64(len(nodes))
+-				wd.Report(ctx, msg, pct)
+-			}
 -		}
 -	}
 -
--	if false { // debugging
--		// TODO(adonovan): use proper tracing.
--		t0 := time.Now()
--		defer func() {
--			log.Printf("%v for analyze(%s, %s)", time.Since(t0), id, enabled)
--		}()
--	}
+-	// Execute phase: run leaves first, adding
+-	// new nodes to the queue as they become leaves.
+-	var g errgroup.Group
 -
--	// Run the analysis.
--	res, err := s.analyze(ctx, id, enabled)
--	if err != nil {
--		return nil, err
+-	// Analysis is CPU-bound.
+-	//
+-	// Note: avoid g.SetLimit here: it makes g.Go stop accepting work, which
+-	// prevents workers from enqeuing, and thus finishing, and thus allowing the
+-	// group to make progress: deadlock.
+-	limiter := make(chan unit, runtime.GOMAXPROCS(0))
+-	var completed int64
+-
+-	var enqueue func(*analysisNode)
+-	enqueue = func(an *analysisNode) {
+-		g.Go(func() error {
+-			limiter <- unit{}
+-			defer func() { <-limiter }()
+-
+-			summary, err := an.runCached(ctx)
+-			if err != nil {
+-				return err // cancelled, or failed to produce a package
+-			}
+-			maybeReport(atomic.AddInt64(&completed, 1))
+-			an.summary = summary
+-
+-			// Notify each waiting predecessor,
+-			// and enqueue it when it becomes a leaf.
+-			for _, pred := range an.preds {
+-				if atomic.AddInt32(&pred.unfinishedSuccs, -1) == 0 {
+-					enqueue(pred)
+-				}
+-			}
+-
+-			// Notify each successor that we no longer need
+-			// its action summaries, which hold Result values.
+-			// After the last one, delete it, so that we
+-			// free up large results such as SSA.
+-			for _, succ := range an.succs {
+-				succ.decrefPreds()
+-			}
+-			return nil
+-		})
+-	}
+-	for _, leaf := range leaves {
+-		enqueue(leaf)
+-	}
+-	if err := g.Wait(); err != nil {
+-		return nil, err // cancelled, or failed to produce a package
 -	}
 -
 -	// Report diagnostics only from enabled actions that succeeded.
@@ -12224,47 +13567,162 @@
 -	// Even if current callers choose to discard the
 -	// results, we should propagate the per-action errors.
 -	var results []*source.Diagnostic
--	for _, a := range enabled {
--		summary := res.Actions[a.Name]
--		if summary.Err != "" {
--			continue // action failed
--		}
--		for _, gobDiag := range summary.Diagnostics {
--			results = append(results, toSourceDiagnostic(toSrc[a], &gobDiag))
+-	for _, root := range roots {
+-		for _, a := range enabled {
+-			// Skip analyzers that were added only to
+-			// fulfil requirements of the original set.
+-			srcAnalyzer, ok := toSrc[a]
+-			if !ok {
+-				// Although this 'skip' operation is logically sound,
+-				// it is nonetheless surprising that its absence should
+-				// cause #60909 since none of the analyzers added for
+-				// requirements (e.g. ctrlflow, inspect, buildssa)
+-				// is capable of reporting diagnostics.
+-				if summary := root.summary.Actions[a.Name]; summary != nil {
+-					if n := len(summary.Diagnostics); n > 0 {
+-						bug.Reportf("Internal error: got %d unexpected diagnostics from analyzer %s. This analyzer was added only to fulfil the requirements of the requested set of analyzers, and it is not expected that such analyzers report diagnostics. Please report this in issue #60909.", n, a)
+-					}
+-				}
+-				continue
+-			}
+-
+-			// Inv: root.summary is the successful result of run (via runCached).
+-			summary, ok := root.summary.Actions[a.Name]
+-			if summary == nil {
+-				panic(fmt.Sprintf("analyzeSummary.Actions[%q] = (nil, %t); got %v (#60551)",
+-					a.Name, ok, root.summary.Actions))
+-			}
+-			if summary.Err != "" {
+-				continue // action failed
+-			}
+-			for _, gobDiag := range summary.Diagnostics {
+-				results = append(results, toSourceDiagnostic(srcAnalyzer, &gobDiag))
+-			}
 -		}
 -	}
 -	return results, nil
 -}
 -
--// analysisKey is the type of keys in the snapshot.analyses map.
--type analysisKey struct {
--	analyzerNames string
--	pkgid         PackageID
+-func (an *analysisNode) decrefPreds() {
+-	if atomic.AddInt32(&an.unfinishedPreds, -1) == 0 {
+-		an.summary.Actions = nil
+-	}
 -}
 -
--func (key analysisKey) String() string {
--	return fmt.Sprintf("%s@%s", key.analyzerNames, key.pkgid)
+-// An analysisNode is a node in a doubly-linked DAG isomorphic to the
+-// import graph. Each node represents a single package, and the DAG
+-// represents a batch of analysis work done at once using a single
+-// realm of token.Pos or types.Object values.
+-//
+-// A complete DAG is created anew for each batch of analysis;
+-// subgraphs are not reused over time. Each node's *types.Package
+-// field is initially nil and is populated on demand, either from
+-// type-checking syntax trees (typeCheck) or from importing export
+-// data (_import). When this occurs, the typesOnce event becomes
+-// "done".
+-//
+-// Each node's allDeps map is a "view" of all its dependencies keyed by
+-// package path, which defines the types.Importer mapping used when
+-// populating the node's types.Package. Different nodes have different
+-// views (e.g. due to variants), but two nodes that are related by
+-// graph ordering have views that are consistent in their overlap.
+-// exportDeps is the subset actually referenced by export data;
+-// this is the set for which we attempt to decode facts.
+-//
+-// Each node's run method is called in parallel postorder. On success,
+-// its summary field is populated, either from the cache (hit), or by
+-// type-checking and analyzing syntax (miss).
+-type analysisNode struct {
+-	fset            *token.FileSet              // file set shared by entire batch (DAG)
+-	m               *source.Metadata            // metadata for this package
+-	files           []source.FileHandle         // contents of CompiledGoFiles
+-	analyzers       []*analysis.Analyzer        // set of analyzers to run
+-	preds           []*analysisNode             // graph edges:
+-	succs           map[PackageID]*analysisNode //   (preds -> self -> succs)
+-	unfinishedSuccs int32
+-	unfinishedPreds int32                         // effectively a summary.Actions refcount
+-	allDeps         map[PackagePath]*analysisNode // all dependencies including self
+-	exportDeps      map[PackagePath]*analysisNode // subset of allDeps ref'd by export data (+self)
+-	summary         *analyzeSummary               // serializable result of analyzing this package
+-
+-	typesOnce sync.Once      // guards lazy population of types and typesErr fields
+-	types     *types.Package // type information lazily imported from summary
+-	typesErr  error          // an error producing type information
+-}
+-
+-func (an *analysisNode) String() string { return string(an.m.ID) }
+-
+-// _import imports this node's types.Package from export data, if not already done.
+-// Precondition: analysis was a success.
+-// Postcondition: an.types and an.exportDeps are populated.
+-func (an *analysisNode) _import() (*types.Package, error) {
+-	an.typesOnce.Do(func() {
+-		if an.m.PkgPath == "unsafe" {
+-			an.types = types.Unsafe
+-			return
+-		}
+-
+-		an.types = types.NewPackage(string(an.m.PkgPath), string(an.m.Name))
+-
+-		// getPackages recursively imports each dependency
+-		// referenced by the export data, in parallel.
+-		getPackages := func(items []gcimporter.GetPackagesItem) error {
+-			var g errgroup.Group
+-			for i, item := range items {
+-				path := PackagePath(item.Path)
+-				dep, ok := an.allDeps[path]
+-				if !ok {
+-					// This early return bypasses Wait; that's ok.
+-					return fmt.Errorf("%s: unknown dependency %q", an.m, path)
+-				}
+-				an.exportDeps[path] = dep // record, for later fact decoding
+-				if dep == an {
+-					if an.typesErr != nil {
+-						return an.typesErr
+-					} else {
+-						items[i].Pkg = an.types
+-					}
+-				} else {
+-					i := i
+-					g.Go(func() error {
+-						depPkg, err := dep._import()
+-						if err == nil {
+-							items[i].Pkg = depPkg
+-						}
+-						return err
+-					})
+-				}
+-			}
+-			return g.Wait()
+-		}
+-		pkg, err := gcimporter.IImportShallow(an.fset, getPackages, an.summary.Export, string(an.m.PkgPath), bug.Reportf)
+-		if err != nil {
+-			an.typesErr = bug.Errorf("%s: invalid export data: %v", an.m, err)
+-			an.types = nil
+-		} else if pkg != an.types {
+-			log.Fatalf("%s: inconsistent packages", an.m)
+-		}
+-	})
+-	return an.types, an.typesErr
 -}
 -
 -// analyzeSummary is a gob-serializable summary of successfully
 -// applying a list of analyzers to a package.
 -type analyzeSummary struct {
--	PkgPath        PackagePath // types.Package.Path() (needed to decode export data)
--	Export         []byte
+-	Export         []byte      // encoded types of package
 -	DeepExportHash source.Hash // hash of reflexive transitive closure of export data
 -	Compiles       bool        // transitively free of list/parse/type errors
 -	Actions        actionsMap  // map from analyzer name to analysis results (*actionSummary)
--
--	// Not serialized: populated after the summary is computed or deserialized.
--	allExport map[PackagePath][]byte // transitive export data
 -}
 -
 -// actionsMap defines a stable Gob encoding for a map.
 -// TODO(adonovan): generalize and move to a library when we can use generics.
 -type actionsMap map[string]*actionSummary
 -
--var _ gob.GobEncoder = (actionsMap)(nil)
--var _ gob.GobDecoder = (*actionsMap)(nil)
+-var (
+-	_ gob.GobEncoder = (actionsMap)(nil)
+-	_ gob.GobDecoder = (*actionsMap)(nil)
+-)
 -
 -type actionsMapEntry struct {
 -	K string
@@ -12305,133 +13763,16 @@
 -	Err         string // "" => success
 -}
 -
--// analyze is a memoization of analyzeImpl.
--func (s *snapshot) analyze(ctx context.Context, id PackageID, analyzers []*analysis.Analyzer) (*analyzeSummary, error) {
--	// Use the sorted list of names of analyzers in the key.
--	//
--	// TODO(adonovan): opt: account for analysis results at a
--	// finer grain to avoid duplicate work when a
--	// a proper subset of analyzers is requested?
--	// In particular, TypeErrorAnalyzers don't use facts
--	// but need to request vdeps just for type information.
--	names := make([]string, 0, len(analyzers))
--	for _, a := range analyzers {
--		names = append(names, a.Name)
--	}
--	// This key describes the result of applying a list of analyzers to a package.
--	key := analysisKey{strings.Join(names, ","), id}
--
--	// An analysisPromise represents the result of loading, parsing,
--	// type-checking and analyzing a single package.
--	type analysisPromise struct {
--		promise *memoize.Promise // [analyzeImplResult]
--	}
--
--	type analyzeImplResult struct {
--		summary *analyzeSummary
--		err     error
--	}
--
--	// Access the map once, briefly, and atomically.
--	s.mu.Lock()
--	entry, hit := s.analyses.Get(key)
--	if !hit {
--		entry = analysisPromise{
--			promise: memoize.NewPromise("analysis", func(ctx context.Context, arg interface{}) interface{} {
--				summary, err := analyzeImpl(ctx, arg.(*snapshot), analyzers, id)
--				return analyzeImplResult{summary, err}
--			}),
--		}
--		s.analyses.Set(key, entry, nil) // nothing needs releasing
--	}
--	s.mu.Unlock()
--
--	// Await result.
--	ap := entry.(analysisPromise)
--	v, err := s.awaitPromise(ctx, ap.promise)
--	if err != nil {
--		return nil, err // e.g. cancelled
--	}
--	res := v.(analyzeImplResult)
--	return res.summary, res.err
--}
--
--// analyzeImpl applies a list of analyzers (plus any others
+-// runCached applies a list of analyzers (plus any others
 -// transitively required by them) to a package.  It succeeds as long
 -// as it could produce a types.Package, even if there were direct or
 -// indirect list/parse/type errors, and even if all the analysis
 -// actions failed. It usually fails only if the package was unknown,
 -// a file was missing, or the operation was cancelled.
 -//
--// Postcondition: analyzeImpl must not continue to use the snapshot
+-// Postcondition: runCached must not continue to use the snapshot
 -// (in background goroutines) after it has returned; see memoize.RefCounted.
--func analyzeImpl(ctx context.Context, snapshot *snapshot, analyzers []*analysis.Analyzer, id PackageID) (*analyzeSummary, error) {
--	m := snapshot.Metadata(id)
--	if m == nil {
--		return nil, fmt.Errorf("no metadata for %s", id)
--	}
--
--	// Recursively analyze each "vertical" dependency
--	// for its types.Package and (perhaps) analysis.Facts.
--	// If any of them fails to produce a package, we cannot continue.
--	// We request only the analyzers that produce facts.
--	//
--	// Also, load the contents of each "compiled" Go file through
--	// the snapshot's cache.
--	//
--	// Both loops occur in parallel, and parallel with each other.
--	vdeps := make(map[PackageID]*analyzeSummary)
--	compiledGoFiles := make([]source.FileHandle, len(m.CompiledGoFiles))
--	{
--		var group errgroup.Group
--
--		// Analyze vertical dependencies.
--		// We request only the required analyzers that use facts.
--		var useFacts []*analysis.Analyzer
--		for _, a := range requiredAnalyzers(analyzers) {
--			if len(a.FactTypes) > 0 {
--				useFacts = append(useFacts, a)
--			}
--		}
--		var vdepsMu sync.Mutex
--		for _, id := range m.DepsByPkgPath {
--			id := id
--			group.Go(func() error {
--				res, err := snapshot.analyze(ctx, id, useFacts)
--				if err != nil {
--					return err // cancelled, or failed to produce a package
--				}
--
--				vdepsMu.Lock()
--				vdeps[id] = res
--				vdepsMu.Unlock()
--				return nil
--			})
--		}
--
--		// Read file contents.
--		// (In practice these will be cache hits
--		// on reads done by the initial workspace load
--		// or after a change modification event.)
--		for i, uri := range m.CompiledGoFiles {
--			i, uri := i, uri
--			group.Go(func() error {
--				fh, err := snapshot.GetFile(ctx, uri) // ~25us
--				compiledGoFiles[i] = fh
--				return err // e.g. cancelled
--			})
--		}
--
--		if err := group.Wait(); err != nil {
--			return nil, err
--		}
--	}
--
--	// Inv: analyze() of all vdeps succeeded (though some actions may have failed).
--
--	// We no longer depend on the snapshot.
--	snapshot = nil
--
+-func (an *analysisNode) runCached(ctx context.Context) (*analyzeSummary, error) {
 -	// At this point we have the action results (serialized
 -	// packages and facts) of our immediate dependencies,
 -	// and the metadata and content of this package.
@@ -12443,62 +13784,54 @@
 -	// The hash of our inputs is based on the serialized export
 -	// data and facts so that immaterial changes can be pruned
 -	// without decoding.
--	key := analysisCacheKey(analyzers, m, compiledGoFiles, vdeps)
+-	key := an.cacheKey()
 -
 -	// Access the cache.
 -	var summary *analyzeSummary
 -	const cacheKind = "analysis"
 -	if data, err := filecache.Get(cacheKind, key); err == nil {
 -		// cache hit
--		mustDecode(data, &summary)
--
+-		analyzeSummaryCodec.Decode(data, &summary)
 -	} else if err != filecache.ErrNotFound {
 -		return nil, bug.Errorf("internal error reading shared cache: %v", err)
--
 -	} else {
 -		// Cache miss: do the work.
 -		var err error
--		summary, err = actuallyAnalyze(ctx, analyzers, m, vdeps, compiledGoFiles)
+-		summary, err = an.run(ctx)
 -		if err != nil {
 -			return nil, err
 -		}
--		data := mustEncode(summary)
--		if false {
--			log.Printf("Set key=%d value=%d id=%s\n", len(key), len(data), id)
--		}
--		if err := filecache.Set(cacheKind, key, data); err != nil {
--			return nil, fmt.Errorf("internal error updating shared cache: %v", err)
--		}
--	}
 -
--	// Hit or miss, we need to merge the export data from
--	// dependencies so that it includes all the types
--	// that might be summoned by the type checker.
--	//
--	// TODO(adonovan): opt: reduce this set by recording
--	// which packages were actually summoned by insert().
--	// (Just makes map smaller; probably marginal?)
--	allExport := make(map[PackagePath][]byte)
--	for _, vdep := range vdeps {
--		for k, v := range vdep.allExport {
--			allExport[k] = v
--		}
+-		atomic.AddInt32(&an.unfinishedPreds, +1) // incref
+-		go func() {
+-			defer an.decrefPreds() //decref
+-
+-			cacheLimit <- unit{}            // acquire token
+-			defer func() { <-cacheLimit }() // release token
+-
+-			data := analyzeSummaryCodec.Encode(summary)
+-			if false {
+-				log.Printf("Set key=%d value=%d id=%s\n", len(key), len(data), an.m.ID)
+-			}
+-			if err := filecache.Set(cacheKind, key, data); err != nil {
+-				event.Error(ctx, "internal error updating analysis shared cache", err)
+-			}
+-		}()
 -	}
--	allExport[m.PkgPath] = summary.Export
--	summary.allExport = allExport
 -
 -	return summary, nil
 -}
 -
+-// cacheLimit reduces parallelism of cache updates.
+-// We allow more than typical GOMAXPROCS as it's a mix of CPU and I/O.
+-var cacheLimit = make(chan unit, 32)
+-
 -// analysisCacheKey returns a cache key that is a cryptographic digest
 -// of the all the values that might affect type checking and analysis:
 -// the analyzer names, package metadata, names and contents of
--// compiled Go files, and vdeps information (export data and facts).
--//
--// TODO(adonovan): safety: define our own flavor of Metadata
--// containing just the fields we need, and using it in the subsequent
--// logic, to keep us honest about hashing all parts that matter?
--func analysisCacheKey(analyzers []*analysis.Analyzer, m *source.Metadata, compiledGoFiles []source.FileHandle, vdeps map[PackageID]*analyzeSummary) [sha256.Size]byte {
+-// compiled Go files, and vdeps (successor) information
+-// (export data and facts).
+-func (an *analysisNode) cacheKey() [sha256.Size]byte {
 -	hasher := sha256.New()
 -
 -	// In principle, a key must be the hash of an
@@ -12506,21 +13839,21 @@
 -	// If it's ambiguous, we risk collisions.
 -
 -	// analyzers
--	fmt.Fprintf(hasher, "analyzers: %d\n", len(analyzers))
--	for _, a := range analyzers {
+-	fmt.Fprintf(hasher, "analyzers: %d\n", len(an.analyzers))
+-	for _, a := range an.analyzers {
 -		fmt.Fprintln(hasher, a.Name)
 -	}
 -
 -	// package metadata
+-	m := an.m
 -	fmt.Fprintf(hasher, "package: %s %s %s\n", m.ID, m.Name, m.PkgPath)
 -	// We can ignore m.DepsBy{Pkg,Import}Path: although the logic
 -	// uses those fields, we account for them by hashing vdeps.
 -
 -	// type sizes
--	// This assertion is safe, but if a black-box implementation
--	// is ever needed, record Sizeof(*int) and Alignof(int64).
--	sz := m.TypesSizes.(*types.StdSizes)
--	fmt.Fprintf(hasher, "sizes: %d %d\n", sz.WordSize, sz.MaxAlign)
+-	wordSize := an.m.TypesSizes.Sizeof(types.Typ[types.Int])
+-	maxAlign := an.m.TypesSizes.Alignof(types.NewPointer(types.Typ[types.Int64]))
+-	fmt.Fprintf(hasher, "sizes: %d %d\n", wordSize, maxAlign)
 -
 -	// metadata errors: used for 'compiles' field
 -	fmt.Fprintf(hasher, "errors: %d", len(m.Errors))
@@ -12531,30 +13864,31 @@
 -	}
 -
 -	// file names and contents
--	fmt.Fprintf(hasher, "files: %d\n", len(compiledGoFiles))
--	for _, fh := range compiledGoFiles {
+-	fmt.Fprintf(hasher, "files: %d\n", len(an.files))
+-	for _, fh := range an.files {
 -		fmt.Fprintln(hasher, fh.FileIdentity())
 -	}
 -
 -	// vdeps, in PackageID order
--	depIDs := make([]string, 0, len(vdeps))
--	for depID := range vdeps {
+-	depIDs := make([]string, 0, len(an.succs))
+-	for depID := range an.succs {
 -		depIDs = append(depIDs, string(depID))
 -	}
--	sort.Strings(depIDs)
+-	sort.Strings(depIDs) // TODO(adonovan): avoid conversions by using slices.Sort[PackageID]
 -	for _, depID := range depIDs {
--		vdep := vdeps[PackageID(depID)]
--		fmt.Fprintf(hasher, "dep: %s\n", vdep.PkgPath)
--		fmt.Fprintf(hasher, "export: %s\n", vdep.DeepExportHash)
+-		vdep := an.succs[PackageID(depID)]
+-		fmt.Fprintf(hasher, "dep: %s\n", vdep.m.PkgPath)
+-		fmt.Fprintf(hasher, "export: %s\n", vdep.summary.DeepExportHash)
 -
 -		// action results: errors and facts
--		names := make([]string, 0, len(vdep.Actions))
--		for name := range vdep.Actions {
+-		actions := vdep.summary.Actions
+-		names := make([]string, 0, len(actions))
+-		for name := range actions {
 -			names = append(names, name)
 -		}
 -		sort.Strings(names)
 -		for _, name := range names {
--			summary := vdep.Actions[name]
+-			summary := actions[name]
 -			fmt.Fprintf(hasher, "action %s\n", name)
 -			if summary.Err != "" {
 -				fmt.Fprintf(hasher, "error %s\n", summary.Err)
@@ -12571,24 +13905,26 @@
 -	return hash
 -}
 -
--// actuallyAnalyze implements the cache-miss case.
+-// run implements the cache-miss case.
 -// This function does not access the snapshot.
--func actuallyAnalyze(ctx context.Context, analyzers []*analysis.Analyzer, m *source.Metadata, vdeps map[PackageID]*analyzeSummary, compiledGoFiles []source.FileHandle) (*analyzeSummary, error) {
--
--	// Create a local FileSet for processing this package only.
--	fset := token.NewFileSet()
--
+-//
+-// Postcondition: on success, the analyzeSummary.Actions
+-// key set is {a.Name for a in analyzers}.
+-func (an *analysisNode) run(ctx context.Context) (*analyzeSummary, error) {
 -	// Parse only the "compiled" Go files.
 -	// Do the computation in parallel.
--	parsed := make([]*source.ParsedGoFile, len(compiledGoFiles))
+-	parsed := make([]*source.ParsedGoFile, len(an.files))
 -	{
 -		var group errgroup.Group
--		for i, fh := range compiledGoFiles {
+-		group.SetLimit(4) // not too much: run itself is already called in parallel
+-		for i, fh := range an.files {
 -			i, fh := i, fh
 -			group.Go(func() error {
 -				// Call parseGoImpl directly, not the caching wrapper,
 -				// as cached ASTs require the global FileSet.
--				pgf, err := parseGoImpl(ctx, fset, fh, source.ParseFull)
+-				// ast.Object resolution is unfortunately an implied part of the
+-				// go/analysis contract.
+-				pgf, err := parseGoImpl(ctx, an.fset, fh, source.ParseFull&^source.SkipObjectResolution, false)
 -				parsed[i] = pgf
 -				return err
 -			})
@@ -12598,23 +13934,52 @@
 -		}
 -	}
 -
--	// Type-check the package.
--	pkg := typeCheckForAnalysis(fset, parsed, m, vdeps)
+-	// Type-check the package syntax.
+-	pkg := an.typeCheck(parsed)
 -
--	// Build a map of PkgPath to *Package for all packages mentioned
--	// in exportdata for use by facts.
--	pkg.factsDecoder = facts.NewDecoder(pkg.types)
+-	// Publish the completed package.
+-	an.typesOnce.Do(func() { an.types = pkg.types })
+-	if an.types != pkg.types {
+-		log.Fatalf("typesOnce prematurely done")
+-	}
+-
+-	// Compute the union of exportDeps across our direct imports.
+-	// This is the set that will be needed by the fact decoder.
+-	allExportDeps := make(map[PackagePath]*analysisNode)
+-	for _, succ := range an.succs {
+-		for k, v := range succ.exportDeps {
+-			allExportDeps[k] = v
+-		}
+-	}
+-
+-	// The fact decoder needs a means to look up a Package by path.
+-	pkg.factsDecoder = facts.NewDecoderFunc(pkg.types, func(path string) *types.Package {
+-		// Note: Decode is called concurrently, and thus so is this function.
+-
+-		// Does the fact relate to a package referenced by export data?
+-		if dep, ok := allExportDeps[PackagePath(path)]; ok {
+-			dep.typesOnce.Do(func() { log.Fatal("dep.types not populated") })
+-			if dep.typesErr == nil {
+-				return dep.types
+-			}
+-			return nil
+-		}
+-
+-		// If the fact relates to a dependency not referenced
+-		// by export data, it is safe to ignore it.
+-		// (In that case dep.types exists but may be unpopulated
+-		// or in the process of being populated from export data.)
+-		if an.allDeps[PackagePath(path)] == nil {
+-			log.Fatalf("fact package %q is not a dependency", path)
+-		}
+-		return nil
+-	})
 -
 -	// Poll cancellation state.
 -	if err := ctx.Err(); err != nil {
 -		return nil, err
 -	}
 -
--	// TODO(adonovan): port the old logic to:
--	// - gather go/packages diagnostics from m.Errors? (port goPackagesErrorDiagnostics)
--	// - record unparseable file URIs so we can suppress type errors for these files.
--	// - gather diagnostics from expandErrors + typeErrorDiagnostics + depsErrors.
--
 -	// -- analysis --
 -
 -	// Build action graph for this package.
@@ -12628,7 +13993,7 @@
 -			for _, req := range a.Requires {
 -				hdeps = append(hdeps, mkAction(req))
 -			}
--			act = &action{a: a, pkg: pkg, vdeps: vdeps, hdeps: hdeps}
+-			act = &action{a: a, pkg: pkg, vdeps: an.succs, hdeps: hdeps}
 -			actions[a] = act
 -		}
 -		return act
@@ -12636,12 +14001,13 @@
 -
 -	// Build actions for initial package.
 -	var roots []*action
--	for _, a := range analyzers {
+-	for _, a := range an.analyzers {
 -		roots = append(roots, mkAction(a))
 -	}
 -
 -	// Execute the graph in parallel.
 -	execActions(roots)
+-	// Inv: each root's summary is set (whether success or error).
 -
 -	// Don't return (or cache) the result in case of cancellation.
 -	if err := ctx.Err(); err != nil {
@@ -12650,12 +14016,14 @@
 -
 -	// Return summaries only for the requested actions.
 -	summaries := make(map[string]*actionSummary)
--	for _, act := range roots {
--		summaries[act.a.Name] = act.summary
+-	for _, root := range roots {
+-		if root.summary == nil {
+-			panic("root has nil action.summary (#60551)")
+-		}
+-		summaries[root.a.Name] = root.summary
 -	}
 -
 -	return &analyzeSummary{
--		PkgPath:        PackagePath(pkg.types.Path()),
 -		Export:         pkg.export,
 -		DeepExportHash: pkg.deepExportHash,
 -		Compiles:       pkg.compiles,
@@ -12663,14 +14031,17 @@
 -	}, nil
 -}
 -
--func typeCheckForAnalysis(fset *token.FileSet, parsed []*source.ParsedGoFile, m *source.Metadata, vdeps map[PackageID]*analyzeSummary) *analysisPackage {
+-// Postcondition: analysisPackage.types and an.exportDeps are populated.
+-func (an *analysisNode) typeCheck(parsed []*source.ParsedGoFile) *analysisPackage {
+-	m := an.m
+-
 -	if false { // debugging
--		log.Println("typeCheckForAnalysis", m.PkgPath)
+-		log.Println("typeCheck", m.ID)
 -	}
 -
 -	pkg := &analysisPackage{
 -		m:        m,
--		fset:     fset,
+-		fset:     an.fset,
 -		parsed:   parsed,
 -		files:    make([]*ast.File, len(parsed)),
 -		compiles: len(m.Errors) == 0, // false => list error
@@ -12687,6 +14058,12 @@
 -	}
 -	typeparams.InitInstanceInfo(pkg.typesInfo)
 -
+-	// Unsafe has no syntax.
+-	if m.PkgPath == "unsafe" {
+-		pkg.types = types.Unsafe
+-		return pkg
+-	}
+-
 -	for i, p := range parsed {
 -		pkg.files[i] = p.File
 -		if p.ParseErr != nil {
@@ -12694,94 +14071,35 @@
 -		}
 -	}
 -
--	// Unsafe is special.
--	if m.PkgPath == "unsafe" {
--		pkg.types = types.Unsafe
--		return pkg
--	}
--
--	// Compute the union of transitive export data.
--	// (The actual values are shared, and not serialized.)
--	allExport := make(map[PackagePath][]byte)
--	for _, vdep := range vdeps {
--		for k, v := range vdep.allExport {
--			allExport[k] = v
--		}
--
--		if !vdep.Compiles {
+-	for _, vdep := range an.succs {
+-		if !vdep.summary.Compiles {
 -			pkg.compiles = false // transitive error
 -		}
 -	}
 -
--	// exportHasher computes a hash of the names and export data of
--	// each package that was actually loaded during type checking.
--	//
--	// Because we use shallow export data, the hash for dependency
--	// analysis must incorporate indirect dependencies. As an
--	// optimization, we include only those that were actually
--	// used, which may be a small subset of those available.
--	//
--	// TODO(adonovan): opt: even better would be to implement a
--	// traversal over the package API like facts.NewDecoder does
--	// and only mention that set of packages in the hash.
--	// Perhaps there's a way to do that more efficiently.
--	//
--	// TODO(adonovan): opt: record the shallow hash alongside the
--	// shallow export data in the allExport map to avoid repeatedly
--	// hashing the export data.
--	//
--	// The writes to hasher below assume that type checking imports
--	// packages in a deterministic order.
--	exportHasher := sha256.New()
--	hashExport := func(pkgPath PackagePath, export []byte) {
--		fmt.Fprintf(exportHasher, "%s %d ", pkgPath, len(export))
--		exportHasher.Write(export)
--	}
--
--	// importer state
--	var (
--		insert    func(p *types.Package, name string)
--		importMap = make(map[string]*types.Package) // keys are PackagePaths
--	)
--	loadFromExportData := func(pkgPath PackagePath) (*types.Package, error) {
--		export, ok := allExport[pkgPath]
--		if !ok {
--			return nil, bug.Errorf("missing export data for %q", pkgPath)
--		}
--		hashExport(pkgPath, export)
--		imported, err := gcimporter.IImportShallow(fset, importMap, export, string(pkgPath), insert)
--		if err != nil {
--			return nil, bug.Errorf("invalid export data for %q: %v", pkgPath, err)
--		}
--		return imported, nil
--	}
--	insert = func(p *types.Package, name string) {
--		imported, err := loadFromExportData(PackagePath(p.Path()))
--		if err != nil {
--			log.Fatalf("internal error: %v", err)
--		}
--		if imported != p {
--			log.Fatalf("internal error: inconsistent packages")
--		}
--	}
--
 -	cfg := &types.Config{
 -		Sizes: m.TypesSizes,
 -		Error: func(e error) {
 -			pkg.compiles = false // type error
--			pkg.typeErrors = append(pkg.typeErrors, e.(types.Error))
+-
+-			// Suppress type errors in files with parse errors
+-			// as parser recovery can be quite lossy (#59888).
+-			typeError := e.(types.Error)
+-			for _, p := range parsed {
+-				if p.ParseErr != nil && source.NodeContains(p.File, typeError.Pos) {
+-					return
+-				}
+-			}
+-			pkg.typeErrors = append(pkg.typeErrors, typeError)
 -		},
 -		Importer: importerFunc(func(importPath string) (*types.Package, error) {
--			if importPath == "unsafe" {
--				return types.Unsafe, nil // unsafe has no export data
--			}
--
 -			// Beware that returning an error from this function
 -			// will cause the type checker to synthesize a fake
 -			// package whose Path is importPath, potentially
 -			// losing a vendor/ prefix. If type-checking errors
 -			// are swallowed, these packages may be confusing.
 -
+-			// Map ImportPath to ID.
 -			id, ok := m.DepsByImpPath[ImportPath(importPath)]
 -			if !ok {
 -				// The import syntax is inconsistent with the metadata.
@@ -12792,22 +14110,23 @@
 -				return nil, fmt.Errorf("missing metadata for import of %q", importPath)
 -			}
 -
--			depResult, ok := vdeps[id] // id may be ""
--			if !ok {
+-			// Map ID to node. (id may be "")
+-			dep := an.succs[id]
+-			if dep == nil {
 -				// Analogous to (*snapshot).missingPkgError
 -				// in the logic for regular type-checking,
 -				// but without a snapshot we can't provide
 -				// such detail, and anyway most analysis
 -				// failures aren't surfaced in the UI.
--				return nil, fmt.Errorf("no required module provides package %q (id=%q)", importPath, id)
+-				return nil, fmt.Errorf("no required module provides analysis package %q (id=%q)", importPath, id)
 -			}
 -
 -			// (Duplicates logic from check.go.)
--			if !source.IsValidImport(m.PkgPath, depResult.PkgPath) {
+-			if !source.IsValidImport(an.m.PkgPath, dep.m.PkgPath) {
 -				return nil, fmt.Errorf("invalid use of internal package %s", importPath)
 -			}
 -
--			return loadFromExportData(depResult.PkgPath)
+-			return dep._import()
 -		}),
 -	}
 -
@@ -12827,7 +14146,7 @@
 -	// TODO(adonovan): do we actually need this??
 -	typesinternal.SetUsesCgo(cfg)
 -
--	check := types.NewChecker(cfg, fset, pkg.types, pkg.typesInfo)
+-	check := types.NewChecker(cfg, pkg.fset, pkg.types, pkg.typesInfo)
 -
 -	// Type checking errors are handled via the config, so ignore them here.
 -	_ = check.Files(pkg.files)
@@ -12839,8 +14158,8 @@
 -		}
 -	}
 -
--	// Emit the export data and compute the deep hash.
--	export, err := gcimporter.IExportShallow(pkg.fset, pkg.types)
+-	// Emit the export data and compute the recursive hash.
+-	export, err := gcimporter.IExportShallow(pkg.fset, pkg.types, bug.Reportf)
 -	if err != nil {
 -		// TODO(adonovan): in light of exporter bugs such as #57729,
 -		// consider using bug.Report here and retrying the IExportShallow
@@ -12848,12 +14167,56 @@
 -		log.Fatalf("internal error writing shallow export data: %v", err)
 -	}
 -	pkg.export = export
--	hashExport(m.PkgPath, export)
--	exportHasher.Sum(pkg.deepExportHash[:0])
+-
+-	// Compute a recursive hash to account for the export data of
+-	// this package and each dependency referenced by it.
+-	// Also, populate exportDeps.
+-	hash := sha256.New()
+-	fmt.Fprintf(hash, "%s %d\n", m.PkgPath, len(export))
+-	hash.Write(export)
+-	paths, err := readShallowManifest(export)
+-	if err != nil {
+-		log.Fatalf("internal error: bad export data: %v", err)
+-	}
+-	for _, path := range paths {
+-		dep, ok := an.allDeps[PackagePath(path)]
+-		if !ok {
+-			log.Fatalf("%s: missing dependency: %q", an, path)
+-		}
+-		fmt.Fprintf(hash, "%s %s\n", dep.m.PkgPath, dep.summary.DeepExportHash)
+-		an.exportDeps[PackagePath(path)] = dep
+-	}
+-	an.exportDeps[m.PkgPath] = an // self
+-	hash.Sum(pkg.deepExportHash[:0])
 -
 -	return pkg
 -}
 -
+-// readShallowManifest returns the manifest of packages referenced by
+-// a shallow export data file for a package (excluding the package itself).
+-// TODO(adonovan): add a test.
+-func readShallowManifest(export []byte) ([]PackagePath, error) {
+-	const selfPath = "<self>" // dummy path
+-	var paths []PackagePath
+-	getPackages := func(items []gcimporter.GetPackagesItem) error {
+-		paths = []PackagePath{} // non-nil
+-		for _, item := range items {
+-			if item.Path != selfPath {
+-				paths = append(paths, PackagePath(item.Path))
+-			}
+-		}
+-		return errors.New("stop") // terminate importer
+-	}
+-	_, err := gcimporter.IImportShallow(token.NewFileSet(), getPackages, export, selfPath, bug.Reportf)
+-	if paths == nil {
+-		if err != nil {
+-			return nil, err // failed before getPackages callback
+-		}
+-		return nil, bug.Errorf("internal error: IImportShallow did not call getPackages")
+-	}
+-	return paths, nil // success
+-}
+-
 -// analysisPackage contains information about a package, including
 -// syntax trees, used transiently during its type-checking and analysis.
 -type analysisPackage struct {
@@ -12879,8 +14242,8 @@
 -	once  sync.Once
 -	a     *analysis.Analyzer
 -	pkg   *analysisPackage
--	hdeps []*action                     // horizontal dependencies
--	vdeps map[PackageID]*analyzeSummary // vertical dependencies
+-	hdeps []*action                   // horizontal dependencies
+-	vdeps map[PackageID]*analysisNode // vertical dependencies
 -
 -	// results of action.exec():
 -	result  interface{} // result of Run function, of type a.ResultType
@@ -12893,6 +14256,7 @@
 -}
 -
 -// execActions executes a set of action graph nodes in parallel.
+-// Postcondition: each action.summary is set, even in case of error.
 -func execActions(actions []*action) {
 -	var wg sync.WaitGroup
 -	for _, act := range actions {
@@ -12913,6 +14277,9 @@
 -					}
 -				}
 -			})
+-			if act.summary == nil {
+-				panic("nil action.summary (#60551)")
+-			}
 -		}()
 -	}
 -	wg.Wait()
@@ -12934,9 +14301,9 @@
 -	// we return the dependencies' error' unadorned.
 -	if hasFacts {
 -		// TODO(adonovan): use deterministic order.
--		for _, res := range act.vdeps {
--			if vdep := res.Actions[analyzer.Name]; vdep.Err != "" {
--				return nil, nil, errors.New(vdep.Err)
+-		for _, vdep := range act.vdeps {
+-			if summ := vdep.summary.Actions[analyzer.Name]; summ.Err != "" {
+-				return nil, nil, errors.New(summ.Err)
 -			}
 -		}
 -	}
@@ -12958,7 +14325,7 @@
 -	}
 -
 -	// Gather analysis Result values from horizontal dependencies.
--	var inputs = make(map[*analysis.Analyzer]interface{})
+-	inputs := make(map[*analysis.Analyzer]interface{})
 -	for _, dep := range act.hdeps {
 -		inputs[dep.a] = dep.result
 -	}
@@ -12967,26 +14334,28 @@
 -	// efficient to fork and tailor it to our precise needs.
 -	//
 -	// We've already sharded the fact encoding by action
--	// so that it can be done in parallel (hoisting the
--	// ImportMap call so that we build the map once per package).
+-	// so that it can be done in parallel.
 -	// We could eliminate locking.
 -	// We could also dovetail more closely with the export data
 -	// decoder to obtain a more compact representation of
 -	// packages and objects (e.g. its internal IDs, instead
 -	// of PkgPaths and objectpaths.)
+-	// More importantly, we should avoid re-export of
+-	// facts that related to objects that are discarded
+-	// by "deep" export data. Better still, use a "shallow" approach.
 -
--	// Read and decode analysis facts for each imported package.
--	factset, err := pkg.factsDecoder.Decode(func(imp *types.Package) ([]byte, error) {
+-	// Read and decode analysis facts for each direct import.
+-	factset, err := pkg.factsDecoder.Decode(true, func(pkgPath string) ([]byte, error) {
 -		if !hasFacts {
 -			return nil, nil // analyzer doesn't use facts, so no vdeps
 -		}
 -
 -		// Package.Imports() may contain a fake "C" package. Ignore it.
--		if imp.Path() == "C" {
+-		if pkgPath == "C" {
 -			return nil, nil
 -		}
 -
--		id, ok := pkg.m.DepsByPkgPath[PackagePath(imp.Path())]
+-		id, ok := pkg.m.DepsByPkgPath[PackagePath(pkgPath)]
 -		if !ok {
 -			// This may mean imp was synthesized by the type
 -			// checker because it failed to import it for any reason
@@ -13002,11 +14371,12 @@
 -			return nil, nil
 -		}
 -
--		vdep, ok := act.vdeps[id]
--		if !ok {
+-		vdep := act.vdeps[id]
+-		if vdep == nil {
 -			return nil, bug.Errorf("internal error in %s: missing vdep for id=%s", pkg.types.Path(), id)
 -		}
--		return vdep.Actions[analyzer.Name].Facts, nil
+-
+-		return vdep.summary.Actions[analyzer.Name].Facts, nil
 -	})
 -	if err != nil {
 -		return nil, nil, fmt.Errorf("internal error decoding analysis facts: %w", err)
@@ -13047,14 +14417,7 @@
 -		TypeErrors: pkg.typeErrors,
 -		ResultOf:   inputs,
 -		Report: func(d analysis.Diagnostic) {
--			// Prefix the diagnostic category with the analyzer's name.
--			if d.Category == "" {
--				d.Category = analyzer.Name
--			} else {
--				d.Category = analyzer.Name + "." + d.Category
--			}
--
--			diagnostic, err := toGobDiagnostic(posToLocation, d)
+-			diagnostic, err := toGobDiagnostic(posToLocation, analyzer, d)
 -			if err != nil {
 -				bug.Reportf("internal error converting diagnostic from analyzer %q: %v", analyzer.Name, err)
 -				return
@@ -13073,6 +14436,7 @@
 -	// (Use an anonymous function to limit the recover scope.)
 -	var result interface{}
 -	func() {
+-		start := time.Now()
 -		defer func() {
 -			if r := recover(); r != nil {
 -				// An Analyzer panicked, likely due to a bug.
@@ -13095,7 +14459,13 @@
 -					err = fmt.Errorf("analysis %s for package %s panicked: %v", analyzer.Name, pass.Pkg.Path(), r)
 -				}
 -			}
+-
+-			// Accumulate running time for each checker.
+-			analyzerRunTimesMu.Lock()
+-			analyzerRunTimes[analyzer] += time.Since(start)
+-			analyzerRunTimesMu.Unlock()
 -		}()
+-
 -		result, err = pass.Analyzer.Run(pass)
 -	}()
 -	if err != nil {
@@ -13117,7 +14487,7 @@
 -		panic(fmt.Sprintf("%v: Pass.ExportPackageFact(%T) called after Run", act, fact))
 -	}
 -
--	factsdata := factset.Encode()
+-	factsdata := factset.Encode(true)
 -	return result, &actionSummary{
 -		Diagnostics: diagnostics,
 -		Facts:       factsdata,
@@ -13125,6 +14495,32 @@
 -	}, nil
 -}
 -
+-var (
+-	analyzerRunTimesMu sync.Mutex
+-	analyzerRunTimes   = make(map[*analysis.Analyzer]time.Duration)
+-)
+-
+-type LabelDuration struct {
+-	Label    string
+-	Duration time.Duration
+-}
+-
+-// AnalyzerTimes returns the accumulated time spent in each Analyzer's
+-// Run function since process start, in descending order.
+-func AnalyzerRunTimes() []LabelDuration {
+-	analyzerRunTimesMu.Lock()
+-	defer analyzerRunTimesMu.Unlock()
+-
+-	slice := make([]LabelDuration, 0, len(analyzerRunTimes))
+-	for a, t := range analyzerRunTimes {
+-		slice = append(slice, LabelDuration{Label: a.Name, Duration: t})
+-	}
+-	sort.Slice(slice, func(i, j int) bool {
+-		return slice[i].Duration > slice[j].Duration
+-	})
+-	return slice
+-}
+-
 -// requiredAnalyzers returns the transitive closure of required analyzers in preorder.
 -func requiredAnalyzers(analyzers []*analysis.Analyzer) []*analysis.Analyzer {
 -	var result []*analysis.Analyzer
@@ -13143,22 +14539,13 @@
 -	return result
 -}
 -
--func mustEncode(x interface{}) []byte {
--	var buf bytes.Buffer
--	if err := gob.NewEncoder(&buf).Encode(x); err != nil {
--		log.Fatalf("internal error encoding %T: %v", x, err)
--	}
--	return buf.Bytes()
--}
--
--func mustDecode(data []byte, ptr interface{}) {
--	if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil {
--		log.Fatalf("internal error decoding %T: %v", ptr, err)
--	}
--}
+-var analyzeSummaryCodec = frob.CodecFor[*analyzeSummary]()
 -
 -// -- data types for serialization of analysis.Diagnostic and source.Diagnostic --
 -
+-// (The name says gob but we use frob.)
+-var diagnosticsCodec = frob.CodecFor[[]gobDiagnostic]()
+-
 -type gobDiagnostic struct {
 -	Location       protocol.Location
 -	Severity       protocol.DiagnosticSeverity
@@ -13196,7 +14583,7 @@
 -
 -// toGobDiagnostic converts an analysis.Diagnosic to a serializable gobDiagnostic,
 -// which requires expanding token.Pos positions into protocol.Location form.
--func toGobDiagnostic(posToLocation func(start, end token.Pos) (protocol.Location, error), diag analysis.Diagnostic) (gobDiagnostic, error) {
+-func toGobDiagnostic(posToLocation func(start, end token.Pos) (protocol.Location, error), a *analysis.Analyzer, diag analysis.Diagnostic) (gobDiagnostic, error) {
 -	var fixes []gobSuggestedFix
 -	for _, fix := range diag.SuggestedFixes {
 -		var gobEdits []gobTextEdit
@@ -13233,23 +14620,47 @@
 -		return gobDiagnostic{}, err
 -	}
 -
+-	// The Code column of VSCode's Problems table renders this
+-	// information as "Source(Code)" where code is a link to CodeHref.
+-	// (The code field must be nonempty for anything to appear.)
+-	diagURL := effectiveURL(a, diag)
+-	code := "default"
+-	if diag.Category != "" {
+-		code = diag.Category
+-	}
+-
 -	return gobDiagnostic{
 -		Location: loc,
--		// Severity for analysis diagnostics is dynamic, based on user
--		// configuration per analyzer.
--		// Code and CodeHref are unset for Analysis diagnostics,
--		// TODO(rfindley): set Code fields if/when golang/go#57906 is accepted.
--		Source:         diag.Category,
+-		// Severity for analysis diagnostics is dynamic,
+-		// based on user configuration per analyzer.
+-		Code:           code,
+-		CodeHref:       diagURL,
+-		Source:         a.Name,
 -		Message:        diag.Message,
 -		SuggestedFixes: fixes,
 -		Related:        related,
 -		// Analysis diagnostics do not contain tags.
 -	}, nil
 -}
+-
+-// effectiveURL computes the effective URL of diag,
+-// using the algorithm specified at Diagnostic.URL.
+-func effectiveURL(a *analysis.Analyzer, diag analysis.Diagnostic) string {
+-	u := diag.URL
+-	if u == "" && diag.Category != "" {
+-		u = "#" + diag.Category
+-	}
+-	if base, err := urlpkg.Parse(a.URL); err == nil {
+-		if rel, err := urlpkg.Parse(u); err == nil {
+-			u = base.ResolveReference(rel).String()
+-		}
+-	}
+-	return u
+-}
 diff -urN a/gopls/internal/lsp/cache/cache.go b/gopls/internal/lsp/cache/cache.go
 --- a/gopls/internal/lsp/cache/cache.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/cache.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,78 +0,0 @@
++++ b/gopls/internal/lsp/cache/cache.go	1970-01-01 08:00:00
+@@ -1,80 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -13261,8 +14672,8 @@
 -	"reflect"
 -	"strconv"
 -	"sync/atomic"
+-	"time"
 -
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/gocommand"
 -	"golang.org/x/tools/internal/memoize"
@@ -13307,18 +14718,14 @@
 -// The provided optionsOverrides may be nil.
 -//
 -// TODO(rfindley): move this to session.go.
--func NewSession(ctx context.Context, c *Cache, optionsOverrides func(*source.Options)) *Session {
+-func NewSession(ctx context.Context, c *Cache) *Session {
 -	index := atomic.AddInt64(&sessionIndex, 1)
--	options := source.DefaultOptions().Clone()
--	if optionsOverrides != nil {
--		optionsOverrides(options)
--	}
 -	s := &Session{
 -		id:          strconv.FormatInt(index, 10),
 -		cache:       c,
 -		gocmdRunner: &gocommand.Runner{},
--		options:     options,
 -		overlayFS:   newOverlayFS(c),
+-		parseCache:  newParseCache(1 * time.Minute), // keep recently parsed files for a minute, to optimize typing CPU
 -	}
 -	event.Log(ctx, "New session", KeyCreateSession.Of(s))
 -	return s
@@ -13328,10 +14735,16 @@
 -
 -func (c *Cache) ID() string                     { return c.id }
 -func (c *Cache) MemStats() map[reflect.Type]int { return c.store.Stats() }
+-
+-// FileStats returns information about the set of files stored in the cache.
+-// It is intended for debugging only.
+-func (c *Cache) FileStats() (files, largest, errs int) {
+-	return c.fileStats()
+-}
 diff -urN a/gopls/internal/lsp/cache/check.go b/gopls/internal/lsp/cache/check.go
 --- a/gopls/internal/lsp/cache/check.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/check.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1227 +0,0 @@
++++ b/gopls/internal/lsp/cache/check.go	1970-01-01 08:00:00
+@@ -1,1863 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -13343,56 +14756,72 @@
 -	"crypto/sha256"
 -	"fmt"
 -	"go/ast"
+-	"go/parser"
 -	"go/token"
 -	"go/types"
--	"log"
 -	"regexp"
+-	"runtime"
 -	"sort"
 -	"strings"
 -	"sync"
+-	"sync/atomic"
 -
 -	"golang.org/x/mod/module"
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/filecache"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
--	"golang.org/x/tools/gopls/internal/lsp/source/xrefs"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/gcimporter"
--	"golang.org/x/tools/internal/memoize"
 -	"golang.org/x/tools/internal/packagesinternal"
+-	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/typeparams"
 -	"golang.org/x/tools/internal/typesinternal"
 -)
 -
+-// Various optimizations that should not affect correctness.
+-const (
+-	preserveImportGraph = true // hold on to the import graph for open packages
+-)
+-
+-type unit = struct{}
+-
 -// A typeCheckBatch holds data for a logical type-checking operation, which may
 -// type-check many unrelated packages.
 -//
 -// It shares state such as parsed files and imports, to optimize type-checking
 -// for packages with overlapping dependency graphs.
 -type typeCheckBatch struct {
--	meta *metadataGraph
+-	activePackageCache interface {
+-		getActivePackage(id PackageID) *Package
+-		setActivePackage(id PackageID, pkg *Package)
+-	}
+-	syntaxIndex map[PackageID]int // requested ID -> index in ids
+-	pre         preTypeCheck
+-	post        postTypeCheck
+-	handles     map[PackageID]*packageHandle
+-	parseCache  *parseCache
+-	fset        *token.FileSet // describes all parsed or imported files
+-	cpulimit    chan unit      // concurrency limiter for CPU-bound operations
 -
--	parsedFiles map[span.URI]*source.ParsedGoFile // parsed files necessary for type-checking
--	fset        *token.FileSet                    // FileSet describing all parsed files
+-	mu             sync.Mutex
+-	syntaxPackages map[PackageID]*futurePackage // results of processing a requested package; may hold (nil, nil)
+-	importPackages map[PackageID]*futurePackage // package results to use for importing
+-}
 -
--	// Promises holds promises to either read export data for the package, or
--	// parse and type-check its syntax.
--	//
--	// The return value of these promises is not used: after promises are
--	// awaited, they must write an entry into the imports map.
--	promises map[PackageID]*memoize.Promise
--
--	mu         sync.Mutex
--	needFiles  map[span.URI]source.FileHandle // de-duplicated file handles required for type-checking
--	imports    map[PackageID]pkgOrErr         // types.Packages to use for importing
--	exportData map[PackageID][]byte
--	packages   map[PackageID]*Package
+-// A futurePackage is a future result of type checking or importing a package,
+-// to be cached in a map.
+-//
+-// The goroutine that creates the futurePackage is responsible for evaluating
+-// its value, and closing the done channel.
+-type futurePackage struct {
+-	done chan unit
+-	v    pkgOrErr
 -}
 -
 -type pkgOrErr struct {
@@ -13410,6 +14839,406 @@
 -// indicates context cancellation or otherwise significant failure to perform
 -// the type-checking operation.
 -func (s *snapshot) TypeCheck(ctx context.Context, ids ...PackageID) ([]source.Package, error) {
+-	pkgs := make([]source.Package, len(ids))
+-
+-	var (
+-		needIDs []PackageID // ids to type-check
+-		indexes []int       // original index of requested ids
+-	)
+-
+-	// Check for existing active packages, as any package will do.
+-	//
+-	// This is also done inside forEachPackage, but doing it here avoids
+-	// unnecessary set up for type checking (e.g. assembling the package handle
+-	// graph).
+-	for i, id := range ids {
+-		if pkg := s.getActivePackage(id); pkg != nil {
+-			pkgs[i] = pkg
+-		} else {
+-			needIDs = append(needIDs, id)
+-			indexes = append(indexes, i)
+-		}
+-	}
+-
+-	post := func(i int, pkg *Package) {
+-		pkgs[indexes[i]] = pkg
+-	}
+-	return pkgs, s.forEachPackage(ctx, needIDs, nil, post)
+-}
+-
+-// getImportGraph returns a shared import graph use for this snapshot, or nil.
+-//
+-// This is purely an optimization: holding on to more imports allows trading
+-// memory for CPU and latency. Currently, getImportGraph returns an import
+-// graph containing all packages imported by open packages, since these are
+-// highly likely to be needed when packages change.
+-//
+-// Furthermore, since we memoize active packages, including their imports in
+-// the shared import graph means we don't run the risk of pinning duplicate
+-// copies of common imports, if active packages are computed in separate type
+-// checking batches.
+-func (s *snapshot) getImportGraph(ctx context.Context) *importGraph {
+-	if !preserveImportGraph {
+-		return nil
+-	}
+-	s.mu.Lock()
+-
+-	// Evaluate the shared import graph for the snapshot. There are three major
+-	// codepaths here:
+-	//
+-	//  1. importGraphDone == nil, importGraph == nil: it is this goroutine's
+-	//     responsibility to type-check the shared import graph.
+-	//  2. importGraphDone == nil, importGraph != nil: it is this goroutine's
+-	//     responsibility to resolve the import graph, which may result in
+-	//     type-checking only if the existing importGraph (carried over from the
+-	//     preceding snapshot) is invalid.
+-	//  3. importGraphDone != nil: some other goroutine is doing (1) or (2), wait
+-	//     for the work to be done.
+-	done := s.importGraphDone
+-	if done == nil {
+-		done = make(chan unit)
+-		s.importGraphDone = done
+-		release := s.Acquire() // must acquire to use the snapshot asynchronously
+-		go func() {
+-			defer release()
+-			importGraph, err := s.resolveImportGraph() // may be nil
+-			if err != nil {
+-				if ctx.Err() == nil {
+-					event.Error(ctx, "computing the shared import graph", err)
+-				}
+-				importGraph = nil
+-			}
+-			s.mu.Lock()
+-			s.importGraph = importGraph
+-			s.mu.Unlock()
+-			close(done)
+-		}()
+-	}
+-	s.mu.Unlock()
+-
+-	select {
+-	case <-done:
+-		return s.importGraph
+-	case <-ctx.Done():
+-		return nil
+-	}
+-}
+-
+-// resolveImportGraph evaluates the shared import graph to use for
+-// type-checking in this snapshot. This may involve re-using the import graph
+-// of the previous snapshot (stored in s.importGraph), or computing a fresh
+-// import graph.
+-//
+-// resolveImportGraph should only be called from getImportGraph.
+-func (s *snapshot) resolveImportGraph() (*importGraph, error) {
+-	ctx := s.backgroundCtx
+-	ctx, done := event.Start(event.Detach(ctx), "cache.resolveImportGraph")
+-	defer done()
+-
+-	s.mu.Lock()
+-	lastImportGraph := s.importGraph
+-	s.mu.Unlock()
+-
+-	openPackages := make(map[PackageID]bool)
+-	for _, fh := range s.overlays() {
+-		meta, err := s.MetadataForFile(ctx, fh.URI())
+-		if err != nil {
+-			return nil, err
+-		}
+-		source.RemoveIntermediateTestVariants(&meta)
+-		for _, m := range meta {
+-			openPackages[m.ID] = true
+-		}
+-	}
+-
+-	var openPackageIDs []source.PackageID
+-	for id := range openPackages {
+-		openPackageIDs = append(openPackageIDs, id)
+-	}
+-
+-	handles, err := s.getPackageHandles(ctx, openPackageIDs)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	// Subtlety: we erase the upward cone of open packages from the shared import
+-	// graph, to increase reusability.
+-	//
+-	// This is easiest to understand via an example: suppose A imports B, and B
+-	// imports C. Now suppose A and B are open. If we preserve the entire set of
+-	// shared deps by open packages, deps will be {B, C}. But this means that any
+-	// change to the open package B will invalidate the shared import graph,
+-	// meaning we will experience no benefit from sharing when B is edited.
+-	// Consider that this will be a common scenario, when A is foo_test and B is
+-	// foo. Better to just preserve the shared import C.
+-	//
+-	// With precise pruning, we may want to truncate this search based on
+-	// reachability.
+-	//
+-	// TODO(rfindley): this logic could use a unit test.
+-	volatileDeps := make(map[PackageID]bool)
+-	var isVolatile func(*packageHandle) bool
+-	isVolatile = func(ph *packageHandle) (volatile bool) {
+-		if v, ok := volatileDeps[ph.m.ID]; ok {
+-			return v
+-		}
+-		defer func() {
+-			volatileDeps[ph.m.ID] = volatile
+-		}()
+-		if openPackages[ph.m.ID] {
+-			return true
+-		}
+-		for _, dep := range ph.m.DepsByPkgPath {
+-			if isVolatile(handles[dep]) {
+-				return true
+-			}
+-		}
+-		return false
+-	}
+-	for _, dep := range handles {
+-		isVolatile(dep)
+-	}
+-	for id, volatile := range volatileDeps {
+-		if volatile {
+-			delete(handles, id)
+-		}
+-	}
+-
+-	// We reuse the last import graph if and only if none of the dependencies
+-	// have changed. Doing better would involve analyzing dependencies to find
+-	// subgraphs that are still valid. Not worth it, especially when in the
+-	// common case nothing has changed.
+-	unchanged := lastImportGraph != nil && len(handles) == len(lastImportGraph.depKeys)
+-	var ids []PackageID
+-	depKeys := make(map[PackageID]source.Hash)
+-	for id, ph := range handles {
+-		ids = append(ids, id)
+-		depKeys[id] = ph.key
+-		if unchanged {
+-			prevKey, ok := lastImportGraph.depKeys[id]
+-			unchanged = ok && prevKey == ph.key
+-		}
+-	}
+-
+-	if unchanged {
+-		return lastImportGraph, nil
+-	}
+-
+-	b, err := s.forEachPackageInternal(ctx, nil, ids, nil, nil, nil, handles)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	next := &importGraph{
+-		fset:    b.fset,
+-		depKeys: depKeys,
+-		imports: make(map[PackageID]pkgOrErr),
+-	}
+-	for id, fut := range b.importPackages {
+-		if fut.v.pkg == nil && fut.v.err == nil {
+-			panic(fmt.Sprintf("internal error: import node %s is not evaluated", id))
+-		}
+-		next.imports[id] = fut.v
+-	}
+-	return next, nil
+-}
+-
+-// An importGraph holds selected results of a type-checking pass, to be re-used
+-// by subsequent snapshots.
+-type importGraph struct {
+-	fset    *token.FileSet            // fileset used for type checking imports
+-	depKeys map[PackageID]source.Hash // hash of direct dependencies for this graph
+-	imports map[PackageID]pkgOrErr    // results of type checking
+-}
+-
+-// Package visiting functions used by forEachPackage; see the documentation of
+-// forEachPackage for details.
+-type (
+-	preTypeCheck  = func(int, *packageHandle) bool // false => don't type check
+-	postTypeCheck = func(int, *Package)
+-)
+-
+-// forEachPackage does a pre- and post- order traversal of the packages
+-// specified by ids using the provided pre and post functions.
+-//
+-// The pre func is optional. If set, pre is evaluated after the package
+-// handle has been constructed, but before type-checking. If pre returns false,
+-// type-checking is skipped for this package handle.
+-//
+-// post is called with a syntax package after type-checking completes
+-// successfully. It is only called if pre returned true.
+-//
+-// Both pre and post may be called concurrently.
+-func (s *snapshot) forEachPackage(ctx context.Context, ids []PackageID, pre preTypeCheck, post postTypeCheck) error {
+-	ctx, done := event.Start(ctx, "cache.forEachPackage", tag.PackageCount.Of(len(ids)))
+-	defer done()
+-
+-	if len(ids) == 0 {
+-		return nil // short cut: many call sites do not handle empty ids
+-	}
+-
+-	handles, err := s.getPackageHandles(ctx, ids)
+-	if err != nil {
+-		return err
+-	}
+-
+-	impGraph := s.getImportGraph(ctx)
+-	_, err = s.forEachPackageInternal(ctx, impGraph, nil, ids, pre, post, handles)
+-	return err
+-}
+-
+-// forEachPackageInternal is used by both forEachPackage and loadImportGraph to
+-// type-check a graph of packages.
+-//
+-// If a non-nil importGraph is provided, imports in this graph will be reused.
+-func (s *snapshot) forEachPackageInternal(ctx context.Context, importGraph *importGraph, importIDs, syntaxIDs []PackageID, pre preTypeCheck, post postTypeCheck, handles map[PackageID]*packageHandle) (*typeCheckBatch, error) {
+-	b := &typeCheckBatch{
+-		activePackageCache: s,
+-		pre:                pre,
+-		post:               post,
+-		handles:            handles,
+-		parseCache:         s.view.parseCache,
+-		fset:               fileSetWithBase(reservedForParsing),
+-		syntaxIndex:        make(map[PackageID]int),
+-		cpulimit:           make(chan unit, runtime.GOMAXPROCS(0)),
+-		syntaxPackages:     make(map[PackageID]*futurePackage),
+-		importPackages:     make(map[PackageID]*futurePackage),
+-	}
+-
+-	if importGraph != nil {
+-		// Clone the file set every time, to ensure we do not leak files.
+-		b.fset = tokeninternal.CloneFileSet(importGraph.fset)
+-		// Pre-populate future cache with 'done' futures.
+-		done := make(chan unit)
+-		close(done)
+-		for id, res := range importGraph.imports {
+-			b.importPackages[id] = &futurePackage{done, res}
+-		}
+-	} else {
+-		b.fset = fileSetWithBase(reservedForParsing)
+-	}
+-
+-	for i, id := range syntaxIDs {
+-		b.syntaxIndex[id] = i
+-	}
+-
+-	// Start a single goroutine for each requested package.
+-	//
+-	// Other packages are reached recursively, and will not be evaluated if they
+-	// are not needed.
+-	var g errgroup.Group
+-	for _, id := range importIDs {
+-		id := id
+-		g.Go(func() error {
+-			_, err := b.getImportPackage(ctx, id)
+-			return err
+-		})
+-	}
+-	for i, id := range syntaxIDs {
+-		i := i
+-		id := id
+-		g.Go(func() error {
+-			_, err := b.handleSyntaxPackage(ctx, i, id)
+-			return err
+-		})
+-	}
+-	return b, g.Wait()
+-}
+-
+-// TODO(rfindley): re-order the declarations below to read better from top-to-bottom.
+-
+-// getImportPackage returns the *types.Package to use for importing the
+-// package referenced by id.
+-//
+-// This may be the package produced by type-checking syntax (as in the case
+-// where id is in the set of requested IDs), a package loaded from export data,
+-// or a package type-checked for import only.
+-func (b *typeCheckBatch) getImportPackage(ctx context.Context, id PackageID) (pkg *types.Package, err error) {
+-	b.mu.Lock()
+-	f, ok := b.importPackages[id]
+-	if ok {
+-		b.mu.Unlock()
+-
+-		select {
+-		case <-ctx.Done():
+-			return nil, ctx.Err()
+-		case <-f.done:
+-			return f.v.pkg, f.v.err
+-		}
+-	}
+-
+-	f = &futurePackage{done: make(chan unit)}
+-	b.importPackages[id] = f
+-	b.mu.Unlock()
+-
+-	defer func() {
+-		f.v = pkgOrErr{pkg, err}
+-		close(f.done)
+-	}()
+-
+-	if index, ok := b.syntaxIndex[id]; ok {
+-		pkg, err := b.handleSyntaxPackage(ctx, index, id)
+-		if err != nil {
+-			return nil, err
+-		}
+-		if pkg != nil {
+-			return pkg, nil
+-		}
+-		// type-checking was short-circuited by the pre- func.
+-	}
+-
+-	// unsafe cannot be imported or type-checked.
+-	if id == "unsafe" {
+-		return types.Unsafe, nil
+-	}
+-
+-	ph := b.handles[id]
+-
+-	// Do a second check for "unsafe" defensively, due to golang/go#60890.
+-	if ph.m.PkgPath == "unsafe" {
+-		bug.Reportf("encountered \"unsafe\" as %s (golang/go#60890)", id)
+-		return types.Unsafe, nil
+-	}
+-
+-	data, err := filecache.Get(exportDataKind, ph.key)
+-	if err == filecache.ErrNotFound {
+-		// No cached export data: type-check as fast as possible.
+-		return b.checkPackageForImport(ctx, ph)
+-	}
+-	if err != nil {
+-		return nil, fmt.Errorf("failed to read cache data for %s: %v", ph.m.ID, err)
+-	}
+-	return b.importPackage(ctx, ph.m, data)
+-}
+-
+-// handleSyntaxPackage handles one package from the ids slice.
+-//
+-// If type checking occurred while handling the package, it returns the
+-// resulting types.Package so that it may be used for importing.
+-//
+-// handleSyntaxPackage returns (nil, nil) if pre returned false.
+-func (b *typeCheckBatch) handleSyntaxPackage(ctx context.Context, i int, id PackageID) (pkg *types.Package, err error) {
+-	b.mu.Lock()
+-	f, ok := b.syntaxPackages[id]
+-	if ok {
+-		b.mu.Unlock()
+-		<-f.done
+-		return f.v.pkg, f.v.err
+-	}
+-
+-	f = &futurePackage{done: make(chan unit)}
+-	b.syntaxPackages[id] = f
+-	b.mu.Unlock()
+-	defer func() {
+-		f.v = pkgOrErr{pkg, err}
+-		close(f.done)
+-	}()
+-
+-	ph := b.handles[id]
+-	if b.pre != nil && !b.pre(i, ph) {
+-		return nil, nil // skip: export data only
+-	}
+-
 -	// Check for existing active packages.
 -	//
 -	// Since gopls can't depend on package identity, any instance of the
@@ -13419,253 +15248,90 @@
 -	// changes to an open package many LSP clients send several successive
 -	// requests for package information for the modified package (semantic
 -	// tokens, code lens, inlay hints, etc.)
--	pkgs := make([]source.Package, len(ids))
--	needSyntax := make(map[PackageID]bool)
--	for i, id := range ids {
--		if pkg := s.getActivePackage(id); pkg != nil {
--			pkgs[i] = pkg
--		} else {
--			needSyntax[id] = true
+-	if pkg := b.activePackageCache.getActivePackage(id); pkg != nil {
+-		b.post(i, pkg)
+-		return nil, nil // skip: not checked in this batch
+-	}
+-
+-	if err := b.awaitPredecessors(ctx, ph.m); err != nil {
+-		// One failed precessesor should not fail the entire type checking
+-		// operation. Errors related to imports will be reported as type checking
+-		// diagnostics.
+-		if ctx.Err() != nil {
+-			return nil, ctx.Err()
 -		}
 -	}
 -
--	if len(needSyntax) == 0 {
--		return pkgs, nil
--	}
--
--	// Build up shared state for efficient type-checking.
--	b := &typeCheckBatch{
--		parsedFiles: make(map[span.URI]*source.ParsedGoFile),
--		// fset is built during the parsing pass.
--		needFiles: make(map[span.URI]source.FileHandle),
--
--		promises:   make(map[PackageID]*memoize.Promise),
--		imports:    make(map[PackageID]pkgOrErr),
--		exportData: make(map[PackageID][]byte),
--		packages:   make(map[PackageID]*Package),
--	}
--
--	// Capture metadata once to ensure a consistent view.
--	s.mu.Lock()
--	b.meta = s.meta
--	s.mu.Unlock()
--
--	//  -- Step 1: assemble the promises graph --
--
--	var (
--		needExportData = make(map[PackageID]packageHandleKey)
--		packageHandles = make(map[PackageID]*packageHandle)
--	)
--
--	// collectPromises collects promises to load packages from export data or
--	// type-check.
--	var collectPromises func(PackageID) error
--	collectPromises = func(id PackageID) error {
--		if _, ok := b.promises[id]; ok {
--			return nil
--		}
--		b.promises[id] = nil // break cycles
--
--		m := b.meta.metadata[id]
--		if m == nil {
--			return bug.Errorf("missing metadata for %v", id)
--		}
--		for _, id := range m.DepsByPkgPath {
--			if err := collectPromises(id); err != nil {
--				return err
--			}
--		}
--
--		// Note that we can't reuse active packages here, as they will have the
--		// wrong FileSet. Any active packages that exist as dependencies of other
--		// packages will need to be loaded from export data.
--		ph, err := s.buildPackageHandle(ctx, id)
--		if err != nil {
--			return err
--		}
--		packageHandles[id] = ph
--
--		if needSyntax[id] {
--			// We will need to parse and type-check this package.
--			//
--			// We may also need to parse and type-check if export data is missing,
--			// but that is handled after fetching export data below.
--			b.addNeededFiles(ph)
--		} else if id != "unsafe" { // we can't load export data for unsafe
--			needExportData[id] = ph.key
--		}
--
--		debugName := fmt.Sprintf("check(%s)", id)
--		b.promises[id] = memoize.NewPromise(debugName, func(ctx context.Context, _ interface{}) interface{} {
--			var res pkgOrErr
--			if err := b.awaitPredecessors(ctx, ph.m); err != nil {
--				res.err = err
--			} else {
--				b.mu.Lock()
--				data, ok := b.exportData[id]
--				b.mu.Unlock()
--
--				if ok {
--					// We need export data, and have it.
--					res.pkg, res.err = b.importPackage(ctx, m, data)
--				} else if !needSyntax[id] {
--					// We need only a types.Package, but don't have export data.
--					// Type-check as fast as possible (skipping function bodies).
--					res.pkg, res.err = b.checkPackageForImport(ctx, ph)
--				} else {
--					// We need a syntax package.
--					var pkg *Package
--					pkg, res.err = b.checkPackage(ctx, ph)
--					if res.err == nil {
--						res.pkg = pkg.pkg.types
--						b.mu.Lock()
--						b.packages[id] = pkg
--						b.mu.Unlock()
--					}
--				}
--			}
--
--			b.mu.Lock()
--			b.imports[m.ID] = res
--			b.mu.Unlock()
--			return nil
--		})
--		return nil
--	}
--	for id := range needSyntax {
--		collectPromises(id)
--	}
--
--	// -- Step 2: collect export data --
+-	// Wait to acquire a CPU token.
 -	//
--	// This must be done before parsing in order to determine which files must be
--	// parsed.
--	{
--		var g errgroup.Group
--		for id, key := range needExportData {
--			id := id
--			key := key
--			g.Go(func() error {
--				data, err := filecache.Get(exportDataKind, key)
--				if err != nil {
--					if err == filecache.ErrNotFound {
--						ph := packageHandles[id]
--						b.addNeededFiles(ph) // we will need to parse and type check
--						return nil           // ok: we will type check later
--					}
--					return err
--				}
--				b.mu.Lock()
--				b.exportData[id] = data
--				b.mu.Unlock()
--				return nil
--			})
--		}
--		if err := g.Wait(); err != nil {
--			return pkgs, err
--		}
+-	// Note: it is important to acquire this token only after awaiting
+-	// predecessors, to avoid starvation.
+-	select {
+-	case <-ctx.Done():
+-		return nil, ctx.Err()
+-	case b.cpulimit <- unit{}:
+-		defer func() {
+-			<-b.cpulimit // release CPU token
+-		}()
 -	}
 -
--	// -- Step 3: parse files required for type checking. --
--	//
--	// Parse all necessary files in parallel. Unfortunately we can't start
--	// parsing each package's file as soon as we discover that it is a syntax
--	// package, because the parseCache cannot add files to an existing FileSet.
--	{
--		var fhs []source.FileHandle
--		for _, fh := range b.needFiles {
--			fhs = append(fhs, fh)
--		}
--		pgfs, fset, err := s.parseCache.parseFiles(ctx, source.ParseFull, fhs...)
--		if err != nil {
--			return pkgs, err
--		}
--		for _, pgf := range pgfs {
--			b.parsedFiles[pgf.URI] = pgf
--		}
--		b.fset = fset
+-	// We need a syntax package.
+-	syntaxPkg, err := b.checkPackage(ctx, ph)
+-	if err != nil {
+-		return nil, err
 -	}
+-	b.activePackageCache.setActivePackage(id, syntaxPkg)
+-	b.post(i, syntaxPkg)
 -
--	// -- Step 4: await type-checking. --
--	//
--	// Start a single goroutine for each promise.
--	{
--		var g errgroup.Group
--		// TODO(rfindley): find a good way to limit concurrency of type-checking,
--		// which is CPU bound at this point.
--		//
--		// (calling g.SetLimit here is mostly ineffective, as promises are
--		// recursively concurrent.)
--		for _, promise := range b.promises {
--			promise := promise
--			g.Go(func() error {
--				_, err := promise.Get(ctx, nil)
--				return err
--			})
--		}
--		if err := g.Wait(); err != nil {
--			return pkgs, err
--		}
--	}
--
--	// Fill in the gaps of the results slice.
--	var firstErr error
--	for i, id := range ids {
--		if pkgs[i] != nil {
--			continue
--		}
--		if err := b.imports[id].err; err != nil {
--			if firstErr == nil {
--				firstErr = err
--			}
--			continue
--		}
--		pkg := b.packages[id]
--		if pkg == nil {
--			panic("nil package")
--		}
--		if alt := s.memoizeActivePackage(id, pkg); alt != nil && alt != pkg {
--			// pkg is an open package, but we've lost a race and an existing package
--			// has already been memoized.
--			pkg = alt
--		}
--		pkgs[i] = pkg
--	}
--
--	return pkgs, firstErr
--}
--
--// addNeededFiles records the files necessary for type-checking ph, for later
--// parsing.
--func (b *typeCheckBatch) addNeededFiles(ph *packageHandle) {
--	b.mu.Lock()
--	defer b.mu.Unlock()
--
--	// Technically for export-only packages we only need compiledGoFiles, but
--	// these slices are usually redundant.
--	for _, fh := range ph.inputs.goFiles {
--		b.needFiles[fh.URI()] = fh
--	}
--	for _, fh := range ph.inputs.compiledGoFiles {
--		b.needFiles[fh.URI()] = fh
--	}
+-	return syntaxPkg.pkg.types, nil
 -}
 -
 -// importPackage loads the given package from its export data in p.exportData
 -// (which must already be populated).
 -func (b *typeCheckBatch) importPackage(ctx context.Context, m *source.Metadata, data []byte) (*types.Package, error) {
--	impMap, errMap := b.importMap(m.ID)
--	// Any failure to populate an import will cause confusing errors from
--	// IImportShallow below.
--	for path, err := range errMap {
--		return nil, fmt.Errorf("error importing %q for %q: %v", path, m.ID, err)
+-	ctx, done := event.Start(ctx, "cache.typeCheckBatch.importPackage", tag.Package.Of(string(m.ID)))
+-	defer done()
+-
+-	impMap := b.importMap(m.ID)
+-
+-	thisPackage := types.NewPackage(string(m.PkgPath), string(m.Name))
+-	getPackages := func(items []gcimporter.GetPackagesItem) error {
+-		for i, item := range items {
+-			var id PackageID
+-			var pkg *types.Package
+-			if item.Path == string(m.PkgPath) {
+-				id = m.ID
+-				pkg = thisPackage
+-			} else {
+-				id = impMap[item.Path]
+-				var err error
+-				pkg, err = b.getImportPackage(ctx, id)
+-				if err != nil {
+-					return err
+-				}
+-			}
+-			items[i].Pkg = pkg
+-
+-			// debugging issue #60904
+-			if pkg.Name() != item.Name {
+-				return bug.Errorf("internal error: package name is %q, want %q (id=%q, path=%q) (see issue #60904)",
+-					pkg.Name(), item.Name, id, item.Path)
+-			}
+-		}
+-		return nil
 -	}
 -
--	// TODO(rfindley): collect "deep" hashes here using the provided
+-	// Importing is potentially expensive, and might not encounter cancellations
+-	// via dependencies (e.g. if they have already been evaluated).
+-	if ctx.Err() != nil {
+-		return nil, ctx.Err()
+-	}
+-
+-	// TODO(rfindley): collect "deep" hashes here using the getPackages
 -	// callback, for precise pruning.
--	imported, err := gcimporter.IImportShallow(b.fset, impMap, data, string(m.PkgPath), func(*types.Package, string) {})
+-	imported, err := gcimporter.IImportShallow(b.fset, getPackages, data, string(m.PkgPath), bug.Reportf)
 -	if err != nil {
--		return nil, bug.Errorf("invalid export data for %q: %v", m.ID, err)
+-		return nil, fmt.Errorf("import failed for %q: %v", m.ID, err)
 -	}
 -	return imported, nil
 -}
@@ -13673,26 +15339,55 @@
 -// checkPackageForImport type checks, but skips function bodies and does not
 -// record syntax information.
 -func (b *typeCheckBatch) checkPackageForImport(ctx context.Context, ph *packageHandle) (*types.Package, error) {
--	if ph.m.ID == "unsafe" {
--		return types.Unsafe, nil
--	}
--	impMap, errMap := b.importMap(ph.inputs.id)
+-	ctx, done := event.Start(ctx, "cache.typeCheckBatch.checkPackageForImport", tag.Package.Of(string(ph.m.ID)))
+-	defer done()
+-
 -	onError := func(e error) {
 -		// Ignore errors for exporting.
 -	}
--	cfg := b.typesConfig(ph.inputs, onError, impMap, errMap)
--	var files []*ast.File
--	for _, fh := range ph.inputs.compiledGoFiles {
--		pgf := b.parsedFiles[fh.URI()]
--		if pgf == nil {
--			return nil, fmt.Errorf("compiled go file %q failed to parse", fh.URI().Filename())
--		}
--		files = append(files, pgf.File)
--	}
+-	cfg := b.typesConfig(ctx, ph.localInputs, onError)
 -	cfg.IgnoreFuncBodies = true
--	pkg := types.NewPackage(string(ph.inputs.pkgPath), string(ph.inputs.name))
+-
+-	// Parse the compiled go files, bypassing the parse cache as packages checked
+-	// for import are unlikely to get cache hits. Additionally, we can optimize
+-	// parsing slightly by not passing parser.ParseComments.
+-	pgfs := make([]*source.ParsedGoFile, len(ph.localInputs.compiledGoFiles))
+-	{
+-		var group errgroup.Group
+-		// Set an arbitrary concurrency limit; we want some parallelism but don't
+-		// need GOMAXPROCS, as there is already a lot of concurrency among calls to
+-		// checkPackageForImport.
+-		//
+-		// TODO(rfindley): is there a better way to limit parallelism here? We could
+-		// have a global limit on the type-check batch, but would have to be very
+-		// careful to avoid starvation.
+-		group.SetLimit(4)
+-		for i, fh := range ph.localInputs.compiledGoFiles {
+-			i, fh := i, fh
+-			group.Go(func() error {
+-				pgf, err := parseGoImpl(ctx, b.fset, fh, parser.SkipObjectResolution, false)
+-				pgfs[i] = pgf
+-				return err
+-			})
+-		}
+-		if err := group.Wait(); err != nil {
+-			return nil, err // cancelled, or catastrophic error (e.g. missing file)
+-		}
+-	}
+-	pkg := types.NewPackage(string(ph.localInputs.pkgPath), string(ph.localInputs.name))
 -	check := types.NewChecker(cfg, b.fset, pkg, nil)
 -
+-	files := make([]*ast.File, len(pgfs))
+-	for i, pgf := range pgfs {
+-		files[i] = pgf.File
+-	}
+-
+-	// Type checking is expensive, and we may not have ecountered cancellations
+-	// via parsing (e.g. if we got nothing but cache hits for parsed files).
+-	if ctx.Err() != nil {
+-		return nil, ctx.Err()
+-	}
+-
 -	_ = check.Files(files) // ignore errors
 -
 -	// If the context was cancelled, we may have returned a ton of transient
@@ -13703,7 +15398,7 @@
 -
 -	// Asynchronously record export data.
 -	go func() {
--		exportData, err := gcimporter.IExportShallow(b.fset, pkg)
+-		exportData, err := gcimporter.IExportShallow(b.fset, pkg, bug.Reportf)
 -		if err != nil {
 -			bug.Reportf("exporting package %v: %v", ph.m.ID, err)
 -			return
@@ -13717,27 +15412,34 @@
 -
 -// checkPackage "fully type checks" to produce a syntax package.
 -func (b *typeCheckBatch) checkPackage(ctx context.Context, ph *packageHandle) (*Package, error) {
+-	ctx, done := event.Start(ctx, "cache.typeCheckBatch.checkPackage", tag.Package.Of(string(ph.m.ID)))
+-	defer done()
+-
 -	// TODO(rfindley): refactor to inline typeCheckImpl here. There is no need
 -	// for so many layers to build up the package
 -	// (checkPackage->typeCheckImpl->doTypeCheck).
--	pkg, err := typeCheckImpl(ctx, b, ph.inputs)
+-	pkg, err := typeCheckImpl(ctx, b, ph.localInputs)
 -
 -	if err == nil {
 -		// Write package data to disk asynchronously.
 -		go func() {
 -			toCache := map[string][]byte{
--				xrefsKind:       pkg.xrefs,
--				methodSetsKind:  pkg.methodsets.Encode(),
+-				xrefsKind:       pkg.xrefs(),
+-				methodSetsKind:  pkg.methodsets().Encode(),
 -				diagnosticsKind: encodeDiagnostics(pkg.diagnostics),
 -			}
 -
--			if ph.m.ID != "unsafe" { // unsafe cannot be exported
--				exportData, err := gcimporter.IExportShallow(pkg.fset, pkg.types)
+-			if ph.m.PkgPath != "unsafe" { // unsafe cannot be exported
+-				exportData, err := gcimporter.IExportShallow(pkg.fset, pkg.types, bug.Reportf)
 -				if err != nil {
 -					bug.Reportf("exporting package %v: %v", ph.m.ID, err)
 -				} else {
 -					toCache[exportDataKind] = exportData
 -				}
+-			} else if ph.m.ID != "unsafe" {
+-				// golang/go#60890: we should only ever see one variant of the "unsafe"
+-				// package.
+-				bug.Reportf("encountered \"unsafe\" as %s (golang/go#60890)", ph.m.ID)
 -			}
 -
 -			for kind, data := range toCache {
@@ -13751,230 +15453,583 @@
 -	return &Package{ph.m, pkg}, err
 -}
 -
--// awaitPredecessors awaits all promises for m.DepsByPkgPath, returning an
+-// awaitPredecessors awaits all packages for m.DepsByPkgPath, returning an
 -// error if awaiting failed due to context cancellation or if there was an
 -// unrecoverable error loading export data.
+-//
+-// TODO(rfindley): inline, now that this is only called in one place.
 -func (b *typeCheckBatch) awaitPredecessors(ctx context.Context, m *source.Metadata) error {
+-	// await predecessors concurrently, as some of them may be non-syntax
+-	// packages, and therefore will not have been started by the type-checking
+-	// batch.
+-	var g errgroup.Group
 -	for _, depID := range m.DepsByPkgPath {
 -		depID := depID
--		if p, ok := b.promises[depID]; ok {
--			if _, err := p.Get(ctx, nil); err != nil {
--				return err
--			}
--		}
+-		g.Go(func() error {
+-			_, err := b.getImportPackage(ctx, depID)
+-			return err
+-		})
 -	}
--	return nil
+-	return g.Wait()
 -}
 -
--// importMap returns an import map for the given package ID, populated with
--// type-checked packages for its dependencies. It is intended for compatibility
--// with gcimporter.IImportShallow, so the first result uses the map signature
--// of that API, where keys are package path strings.
--//
--// importMap must only be used once all promises for dependencies of id have
--// been awaited.
--//
--// For any missing packages, importMap returns an entry in the resulting errMap
--// reporting the error for that package.
--//
--// Invariant: for all recursive dependencies, either impMap[path] or
--// errMap[path] is set.
--func (b *typeCheckBatch) importMap(id PackageID) (impMap map[string]*types.Package, errMap map[PackagePath]error) {
--	impMap = make(map[string]*types.Package)
--	outerID := id
--	var populateDepsOf func(m *source.Metadata)
--	populateDepsOf = func(parent *source.Metadata) {
+-// importMap returns the map of package path -> package ID relative to the
+-// specified ID.
+-func (b *typeCheckBatch) importMap(id PackageID) map[string]source.PackageID {
+-	impMap := make(map[string]source.PackageID)
+-	var populateDeps func(m *source.Metadata)
+-	populateDeps = func(parent *source.Metadata) {
 -		for _, id := range parent.DepsByPkgPath {
--			m := b.meta.metadata[id]
+-			m := b.handles[id].m
 -			if _, ok := impMap[string(m.PkgPath)]; ok {
 -				continue
 -			}
--			if _, ok := errMap[m.PkgPath]; ok {
--				continue
--			}
--			b.mu.Lock()
--			result, ok := b.imports[m.ID]
--			b.mu.Unlock()
--			if !ok {
--				panic(fmt.Sprintf("import map for %q missing package data for %q", outerID, m.ID))
--			}
--			// We may fail to produce a package due to e.g. context cancellation
--			// (handled elsewhere), or some catastrophic failure such as a package with
--			// no files.
--			switch {
--			case result.err != nil:
--				if errMap == nil {
--					errMap = make(map[PackagePath]error)
--				}
--				errMap[m.PkgPath] = result.err
--			case result.pkg != nil:
--				impMap[string(m.PkgPath)] = result.pkg
--			default:
--				panic("invalid import for " + id)
--			}
--			populateDepsOf(m)
+-			impMap[string(m.PkgPath)] = m.ID
+-			populateDeps(m)
 -		}
 -	}
--	m := b.meta.metadata[id]
--	populateDepsOf(m)
--	return impMap, errMap
+-	m := b.handles[id].m
+-	populateDeps(m)
+-	return impMap
 -}
 -
--// packageData holds binary data (e.g. types, xrefs) extracted from a syntax
--// package.
--type packageData struct {
--	m    *source.Metadata
--	data []byte
--}
--
--// getPackageData gets package data (e.g. types, xrefs) for the requested ids,
--// either loading from the file-based cache or type-checking and extracting
--// data using the provided get function.
--func (s *snapshot) getPackageData(ctx context.Context, kind string, ids []PackageID, get func(*syntaxPackage) []byte) ([]*packageData, error) {
--	var needIDs []PackageID
--	keys := make([]packageHandleKey, len(ids))
--	pkgData := make([]*packageData, len(ids))
--	var firstErr error
--	// Compute package keys and query file cache.
--	for i, id := range ids {
--		ph, err := s.buildPackageHandle(ctx, id)
--		if err != nil {
--			if firstErr == nil {
--				firstErr = err
--			}
--			if ctx.Err() != nil {
--				return pkgData, firstErr
--			}
--			continue
--		}
--		keys[i] = ph.key
--		data, err := filecache.Get(kind, ph.key)
--		switch err {
--		case nil:
--			pkgData[i] = &packageData{m: ph.m, data: data}
--		case filecache.ErrNotFound:
--			needIDs = append(needIDs, id)
--		default:
--			if firstErr == nil {
--				firstErr = err
--			}
--			if ctx.Err() != nil {
--				return pkgData, firstErr
--			}
--		}
--	}
--
--	// Type-check the packages for which we got file-cache misses.
--	pkgs, err := s.TypeCheck(ctx, needIDs...)
--	if err != nil {
--		return nil, err
--	}
--
--	pkgMap := make(map[PackageID]source.Package)
--	for i, id := range needIDs {
--		pkgMap[id] = pkgs[i]
--	}
--
--	// Fill in the gaps using data derived from type checking.
--	for i, id := range ids {
--		if pkgData[i] != nil {
--			continue
--		}
--		result := pkgMap[id]
--		if result == nil {
--			panic(fmt.Sprintf("missing type-check result for %s", id))
--		}
--		data := get(result.(*Package).pkg)
--		pkgData[i] = &packageData{m: result.Metadata(), data: data}
--	}
--
--	return pkgData, firstErr
--}
--
--type packageHandleKey source.Hash
--
--// A packageHandle holds package information, some of which may not be fully
--// evaluated.
+-// A packageHandle holds inputs required to compute a type-checked package,
+-// including inputs to type checking itself, and a key for looking up
+-// precomputed data.
 -//
--// The only methods on packageHandle that are safe to call before calling await
--// are Metadata and await itself.
+-// packageHandles may be invalid following an invalidation via snapshot.clone,
+-// but the handles returned by getPackageHandles will always be valid.
+-//
+-// packageHandles are critical for implementing "precise pruning" in gopls:
+-// packageHandle.key is a hash of a precise set of inputs, such as package
+-// files and "reachable" syntax, that may affect type checking.
+-//
+-// packageHandles also keep track of state that allows gopls to compute, and
+-// then quickly recompute, these keys. This state is split into two categories:
+-//   - local state, which depends only on the package's local files and metadata
+-//   - other state, which includes data derived from dependencies.
+-//
+-// Dividing the data in this way allows gopls to minimize invalidation when a
+-// package is modified. For example, any change to a package file fully
+-// invalidates the package handle. On the other hand, if that change was not
+-// metadata-affecting it may be the case that packages indirectly depending on
+-// the modified package are unaffected by the change. For that reason, we have
+-// two types of invalidation, corresponding to the two types of data above:
+-//   - deletion of the handle, which occurs when the package itself changes
+-//   - clearing of the validated field, which marks the package as possibly
+-//     invalid.
+-//
+-// With the second type of invalidation, packageHandles are re-evaluated from the
+-// bottom up. If this process encounters a packageHandle whose deps have not
+-// changed (as detected by the depkeys field), then the packageHandle in
+-// question must also not have changed, and we need not re-evaluate its key.
 -type packageHandle struct {
 -	m *source.Metadata
 -
--	inputs typeCheckInputs
+-	// Local data:
 -
+-	// localInputs holds all local type-checking localInputs, excluding
+-	// dependencies.
+-	localInputs typeCheckInputs
+-	// localKey is a hash of localInputs.
+-	localKey source.Hash
+-	// refs is the result of syntactic dependency analysis produced by the
+-	// typerefs package.
+-	refs map[string][]typerefs.Symbol
+-
+-	// Data derived from dependencies:
+-
+-	// validated indicates whether the current packageHandle is known to have a
+-	// valid key. Invalidated package handles are stored for packages whose
+-	// type information may have changed.
+-	validated bool
+-	// depKeys records the key of each dependency that was used to calculate the
+-	// key above. If the handle becomes invalid, we must re-check that each still
+-	// matches.
+-	depKeys map[PackageID]source.Hash
 -	// key is the hashed key for the package.
 -	//
 -	// It includes the all bits of the transitive closure of
--	// dependencies's sources. This is more than type checking
--	// really depends on: export data of direct deps should be
--	// enough. (The key for analysis actions could similarly
--	// hash only Facts of direct dependencies.)
--	key packageHandleKey
--
--	// Note: as an optimization, we could join in-flight type-checking by
--	// recording a transient ref-counted promise here.
--	// (This was done previously, but proved to be a premature optimization).
+-	// dependencies's sources.
+-	key source.Hash
 -}
 -
--// buildPackageHandle returns a handle for the future results of
--// type-checking the package identified by id in the given mode.
--// It assumes that the given ID already has metadata available, so it does not
--// attempt to reload missing or invalid metadata. The caller must reload
--// metadata if needed.
--func (s *snapshot) buildPackageHandle(ctx context.Context, id PackageID) (*packageHandle, error) {
--	s.mu.Lock()
--	entry, hit := s.packages.Get(id)
--	m := s.meta.metadata[id]
+-// clone returns a copy of the receiver with the validated bit set to the
+-// provided value.
+-func (ph *packageHandle) clone(validated bool) *packageHandle {
+-	copy := *ph
+-	copy.validated = validated
+-	return &copy
+-}
+-
+-// getPackageHandles gets package handles for all given ids and their
+-// dependencies, recursively.
+-func (s *snapshot) getPackageHandles(ctx context.Context, ids []PackageID) (map[PackageID]*packageHandle, error) {
+-	// perform a two-pass traversal.
+-	//
+-	// On the first pass, build up a bidirectional graph of handle nodes, and collect leaves.
+-	// Then build package handles from bottom up.
+-
+-	s.mu.Lock() // guard s.meta and s.packages below
+-	b := &packageHandleBuilder{
+-		s:              s,
+-		transitiveRefs: make(map[typerefs.IndexID]*partialRefs),
+-		nodes:          make(map[typerefs.IndexID]*handleNode),
+-	}
+-
+-	var leaves []*handleNode
+-	var makeNode func(*handleNode, PackageID) *handleNode
+-	makeNode = func(from *handleNode, id PackageID) *handleNode {
+-		idxID := b.s.pkgIndex.IndexID(id)
+-		n, ok := b.nodes[idxID]
+-		if !ok {
+-			m := s.meta.metadata[id]
+-			if m == nil {
+-				panic(fmt.Sprintf("nil metadata for %q", id))
+-			}
+-			n = &handleNode{
+-				m:               m,
+-				idxID:           idxID,
+-				unfinishedSuccs: int32(len(m.DepsByPkgPath)),
+-			}
+-			if entry, hit := b.s.packages.Get(m.ID); hit {
+-				n.ph = entry
+-			}
+-			if n.unfinishedSuccs == 0 {
+-				leaves = append(leaves, n)
+-			} else {
+-				n.succs = make(map[source.PackageID]*handleNode, n.unfinishedSuccs)
+-			}
+-			b.nodes[idxID] = n
+-			for _, depID := range m.DepsByPkgPath {
+-				n.succs[depID] = makeNode(n, depID)
+-			}
+-		}
+-		// Add edge from predecessor.
+-		if from != nil {
+-			n.preds = append(n.preds, from)
+-		}
+-		return n
+-	}
+-	for _, id := range ids {
+-		makeNode(nil, id)
+-	}
 -	s.mu.Unlock()
 -
--	if m == nil {
--		return nil, fmt.Errorf("no metadata for %s", id)
+-	g, ctx := errgroup.WithContext(ctx)
+-
+-	// files are preloaded, so building package handles is CPU-bound.
+-	//
+-	// Note that we can't use g.SetLimit, as that could result in starvation:
+-	// g.Go blocks until a slot is available, and so all existing goroutines
+-	// could be blocked trying to enqueue a predecessor.
+-	limiter := make(chan unit, runtime.GOMAXPROCS(0))
+-
+-	var enqueue func(*handleNode)
+-	enqueue = func(n *handleNode) {
+-		g.Go(func() error {
+-			limiter <- unit{}
+-			defer func() { <-limiter }()
+-
+-			if ctx.Err() != nil {
+-				return ctx.Err()
+-			}
+-
+-			b.buildPackageHandle(ctx, n)
+-
+-			for _, pred := range n.preds {
+-				if atomic.AddInt32(&pred.unfinishedSuccs, -1) == 0 {
+-					enqueue(pred)
+-				}
+-			}
+-
+-			return n.err
+-		})
+-	}
+-	for _, leaf := range leaves {
+-		enqueue(leaf)
 -	}
 -
--	if hit {
--		return entry.(*packageHandle), nil
--	}
--
--	inputs, err := s.typeCheckInputs(ctx, m)
--	if err != nil {
+-	if err := g.Wait(); err != nil {
 -		return nil, err
 -	}
--	// All the file reading has now been done.
--	// Create a handle for the result of type checking.
--	phKey := computePackageKey(s, inputs)
--	ph := &packageHandle{
--		m:      m,
--		inputs: inputs,
--		key:    phKey,
+-
+-	// Copy handles into the result map.
+-	handles := make(map[PackageID]*packageHandle, len(b.nodes))
+-	for _, v := range b.nodes {
+-		assert(v.ph != nil, "nil handle")
+-		handles[v.m.ID] = v.ph
 -	}
 -
--	s.mu.Lock()
--	defer s.mu.Unlock()
+-	return handles, nil
+-}
+-
+-// A packageHandleBuilder computes a batch of packageHandles concurrently,
+-// sharing computed transitive reachability sets used to compute package keys.
+-type packageHandleBuilder struct {
+-	meta *metadataGraph
+-	s    *snapshot
+-
+-	// nodes are assembled synchronously.
+-	nodes map[typerefs.IndexID]*handleNode
+-
+-	// transitiveRefs is incrementally evaluated as package handles are built.
+-	transitiveRefsMu sync.Mutex
+-	transitiveRefs   map[typerefs.IndexID]*partialRefs // see getTransitiveRefs
+-}
+-
+-// A handleNode represents a to-be-computed packageHandle within a graph of
+-// predecessors and successors.
+-//
+-// It is used to implement a bottom-up construction of packageHandles.
+-type handleNode struct {
+-	m               *source.Metadata
+-	idxID           typerefs.IndexID
+-	ph              *packageHandle
+-	err             error
+-	preds           []*handleNode
+-	succs           map[PackageID]*handleNode
+-	unfinishedSuccs int32
+-}
+-
+-// partialRefs maps names declared by a given package to their set of
+-// transitive references.
+-//
+-// If complete is set, refs is known to be complete for the package in
+-// question. Otherwise, it may only map a subset of all names declared by the
+-// package.
+-type partialRefs struct {
+-	refs     map[string]*typerefs.PackageSet
+-	complete bool
+-}
+-
+-// getTransitiveRefs gets or computes the set of transitively reachable
+-// packages for each exported name in the package specified by id.
+-//
+-// The operation may fail if building a predecessor failed. If and only if this
+-// occurs, the result will be nil.
+-func (b *packageHandleBuilder) getTransitiveRefs(pkgID PackageID) map[string]*typerefs.PackageSet {
+-	b.transitiveRefsMu.Lock()
+-	defer b.transitiveRefsMu.Unlock()
+-
+-	idxID := b.s.pkgIndex.IndexID(pkgID)
+-	trefs, ok := b.transitiveRefs[idxID]
+-	if !ok {
+-		trefs = &partialRefs{
+-			refs: make(map[string]*typerefs.PackageSet),
+-		}
+-		b.transitiveRefs[idxID] = trefs
+-	}
+-
+-	if !trefs.complete {
+-		trefs.complete = true
+-		ph := b.nodes[idxID].ph
+-		for name := range ph.refs {
+-			if ('A' <= name[0] && name[0] <= 'Z') || token.IsExported(name) {
+-				if _, ok := trefs.refs[name]; !ok {
+-					pkgs := b.s.pkgIndex.NewSet()
+-					for _, sym := range ph.refs[name] {
+-						pkgs.Add(sym.Package)
+-						otherSet := b.getOneTransitiveRefLocked(sym)
+-						pkgs.Union(otherSet)
+-					}
+-					trefs.refs[name] = pkgs
+-				}
+-			}
+-		}
+-	}
+-
+-	return trefs.refs
+-}
+-
+-// getOneTransitiveRefLocked computes the full set packages transitively
+-// reachable through the given sym reference.
+-//
+-// It may return nil if the reference is invalid (i.e. the referenced name does
+-// not exist).
+-func (b *packageHandleBuilder) getOneTransitiveRefLocked(sym typerefs.Symbol) *typerefs.PackageSet {
+-	assert(token.IsExported(sym.Name), "expected exported symbol")
+-
+-	trefs := b.transitiveRefs[sym.Package]
+-	if trefs == nil {
+-		trefs = &partialRefs{
+-			refs:     make(map[string]*typerefs.PackageSet),
+-			complete: false,
+-		}
+-		b.transitiveRefs[sym.Package] = trefs
+-	}
+-
+-	pkgs, ok := trefs.refs[sym.Name]
+-	if ok && pkgs == nil {
+-		// See below, where refs is set to nil before recursing.
+-		bug.Reportf("cycle detected to %q in reference graph", sym.Name)
+-	}
+-
+-	// Note that if (!ok && trefs.complete), the name does not exist in the
+-	// referenced package, and we should not write to trefs as that may introduce
+-	// a race.
+-	if !ok && !trefs.complete {
+-		n := b.nodes[sym.Package]
+-		if n == nil {
+-			// We should always have IndexID in our node set, because symbol references
+-			// should only be recorded for packages that actually exist in the import graph.
+-			//
+-			// However, it is not easy to prove this (typerefs are serialized and
+-			// deserialized), so make this code temporarily defensive while we are on a
+-			// point release.
+-			//
+-			// TODO(rfindley): in the future, we should turn this into an assertion.
+-			bug.Reportf("missing reference to package %s", b.s.pkgIndex.PackageID(sym.Package))
+-			return nil
+-		}
+-
+-		// Break cycles. This is perhaps overly defensive as cycles should not
+-		// exist at this point: metadata cycles should have been broken at load
+-		// time, and intra-package reference cycles should have been contracted by
+-		// the typerefs algorithm.
+-		//
+-		// See the "cycle detected" bug report above.
+-		trefs.refs[sym.Name] = nil
+-
+-		pkgs := b.s.pkgIndex.NewSet()
+-		for _, sym2 := range n.ph.refs[sym.Name] {
+-			pkgs.Add(sym2.Package)
+-			otherSet := b.getOneTransitiveRefLocked(sym2)
+-			pkgs.Union(otherSet)
+-		}
+-		trefs.refs[sym.Name] = pkgs
+-	}
+-
+-	return pkgs
+-}
+-
+-// buildPackageHandle gets or builds a package handle for the given id, storing
+-// its result in the snapshot.packages map.
+-//
+-// buildPackageHandle must only be called from getPackageHandles.
+-func (b *packageHandleBuilder) buildPackageHandle(ctx context.Context, n *handleNode) {
+-	var prevPH *packageHandle
+-	if n.ph != nil {
+-		// Existing package handle: if it is valid, return it. Otherwise, create a
+-		// copy to update.
+-		if n.ph.validated {
+-			return
+-		}
+-		prevPH = n.ph
+-		// Either prevPH is still valid, or we will update the key and depKeys of
+-		// this copy. In either case, the result will be valid.
+-		n.ph = prevPH.clone(true)
+-	} else {
+-		// No package handle: read and analyze the package syntax.
+-		inputs, err := b.s.typeCheckInputs(ctx, n.m)
+-		if err != nil {
+-			n.err = err
+-			return
+-		}
+-		refs, err := b.s.typerefs(ctx, n.m, inputs.compiledGoFiles)
+-		if err != nil {
+-			n.err = err
+-			return
+-		}
+-		n.ph = &packageHandle{
+-			m:           n.m,
+-			localInputs: inputs,
+-			localKey:    localPackageKey(inputs),
+-			refs:        refs,
+-			validated:   true,
+-		}
+-	}
+-
+-	// ph either did not exist, or was invalid. We must re-evaluate deps and key.
+-	if err := b.evaluatePackageHandle(prevPH, n); err != nil {
+-		n.err = err
+-		return
+-	}
+-
+-	assert(n.ph.validated, "unvalidated handle")
+-
+-	// Ensure the result (or an equivalent) is recorded in the snapshot.
+-	b.s.mu.Lock()
+-	defer b.s.mu.Unlock()
 -
 -	// Check that the metadata has not changed
 -	// (which should invalidate this handle).
 -	//
--	// (In future, handles should form a graph with edges from a
--	// packageHandle to the handles for parsing its files and the
--	// handles for type-checking its immediate deps, at which
--	// point there will be no need to even access s.meta.)
--	if s.meta.metadata[ph.m.ID] != ph.m {
--		// TODO(rfindley): this should be bug.Errorf.
--		return nil, fmt.Errorf("stale metadata for %s", ph.m.ID)
+-	// TODO(rfindley): eventually promote this to an assert.
+-	// TODO(rfindley): move this to after building the package handle graph?
+-	if b.s.meta.metadata[n.m.ID] != n.m {
+-		bug.Reportf("stale metadata for %s", n.m.ID)
 -	}
 -
--	// Check cache again in case another goroutine got there first.
--	if prev, ok := s.packages.Get(id); ok {
--		prevPH := prev.(*packageHandle)
--		if prevPH.m != ph.m {
--			return nil, bug.Errorf("existing package handle does not match for %s", ph.m.ID)
+-	// Check the packages map again in case another goroutine got there first.
+-	if alt, ok := b.s.packages.Get(n.m.ID); ok && alt.validated {
+-		if alt.m != n.m {
+-			bug.Reportf("existing package handle does not match for %s", n.m.ID)
 -		}
--		return prevPH, nil
+-		n.ph = alt
+-	} else {
+-		b.s.packages.Set(n.m.ID, n.ph, nil)
+-	}
+-}
+-
+-// evaluatePackageHandle validates and/or computes the key of ph, setting key,
+-// depKeys, and the validated flag on ph.
+-//
+-// It uses prevPH to avoid recomputing keys that can't have changed, since
+-// their depKeys did not change.
+-//
+-// See the documentation for packageHandle for more details about packageHandle
+-// state, and see the documentation for the typerefs package for more details
+-// about precise reachability analysis.
+-func (b *packageHandleBuilder) evaluatePackageHandle(prevPH *packageHandle, n *handleNode) error {
+-	// Opt: if no dep keys have changed, we need not re-evaluate the key.
+-	if prevPH != nil {
+-		depsChanged := false
+-		assert(len(prevPH.depKeys) == len(n.succs), "mismatching dep count")
+-		for id, succ := range n.succs {
+-			oldKey, ok := prevPH.depKeys[id]
+-			assert(ok, "missing dep")
+-			if oldKey != succ.ph.key {
+-				depsChanged = true
+-				break
+-			}
+-		}
+-		if !depsChanged {
+-			return nil // key cannot have changed
+-		}
 -	}
 -
--	s.packages.Set(id, ph, nil)
--	return ph, nil
+-	// Deps have changed, so we must re-evaluate the key.
+-	n.ph.depKeys = make(map[PackageID]source.Hash)
+-
+-	// See the typerefs package: the reachable set of packages is defined to be
+-	// the set of packages containing syntax that is reachable through the
+-	// exported symbols in the dependencies of n.ph.
+-	reachable := b.s.pkgIndex.NewSet()
+-	for depID, succ := range n.succs {
+-		n.ph.depKeys[depID] = succ.ph.key
+-		reachable.Add(succ.idxID)
+-		trefs := b.getTransitiveRefs(succ.m.ID)
+-		if trefs == nil {
+-			// A predecessor failed to build due to e.g. context cancellation.
+-			return fmt.Errorf("missing transitive refs for %s", succ.m.ID)
+-		}
+-		for _, set := range trefs {
+-			reachable.Union(set)
+-		}
+-	}
+-
+-	// Collect reachable handles.
+-	var reachableHandles []*packageHandle
+-	// In the presence of context cancellation, any package may be missing.
+-	// We need all dependencies to produce a valid key.
+-	missingReachablePackage := false
+-	reachable.Elems(func(id typerefs.IndexID) {
+-		dh := b.nodes[id]
+-		if dh == nil {
+-			missingReachablePackage = true
+-		} else {
+-			assert(dh.ph.validated, "unvalidated dependency")
+-			reachableHandles = append(reachableHandles, dh.ph)
+-		}
+-	})
+-	if missingReachablePackage {
+-		return fmt.Errorf("missing reachable package")
+-	}
+-	// Sort for stability.
+-	sort.Slice(reachableHandles, func(i, j int) bool {
+-		return reachableHandles[i].m.ID < reachableHandles[j].m.ID
+-	})
+-
+-	// Key is the hash of the local key, and the local key of all reachable
+-	// packages.
+-	depHasher := sha256.New()
+-	depHasher.Write(n.ph.localKey[:])
+-	for _, rph := range reachableHandles {
+-		depHasher.Write(rph.localKey[:])
+-	}
+-	depHasher.Sum(n.ph.key[:0])
+-
+-	return nil
+-}
+-
+-// typerefs returns typerefs for the package described by m and cgfs, after
+-// either computing it or loading it from the file cache.
+-func (s *snapshot) typerefs(ctx context.Context, m *source.Metadata, cgfs []source.FileHandle) (map[string][]typerefs.Symbol, error) {
+-	imports := make(map[ImportPath]*source.Metadata)
+-	for impPath, id := range m.DepsByImpPath {
+-		if id != "" {
+-			imports[impPath] = s.Metadata(id)
+-		}
+-	}
+-
+-	data, err := s.typerefData(ctx, m.ID, imports, cgfs)
+-	if err != nil {
+-		return nil, err
+-	}
+-	classes := typerefs.Decode(s.pkgIndex, m.ID, data)
+-	refs := make(map[string][]typerefs.Symbol)
+-	for _, class := range classes {
+-		for _, decl := range class.Decls {
+-			refs[decl] = class.Refs
+-		}
+-	}
+-	return refs, nil
+-}
+-
+-// typerefData retrieves encoded typeref data from the filecache, or computes it on
+-// a cache miss.
+-func (s *snapshot) typerefData(ctx context.Context, id PackageID, imports map[ImportPath]*source.Metadata, cgfs []source.FileHandle) ([]byte, error) {
+-	key := typerefsKey(id, imports, cgfs)
+-	if data, err := filecache.Get(typerefsKind, key); err == nil {
+-		return data, nil
+-	} else if err != filecache.ErrNotFound {
+-		bug.Reportf("internal error reading typerefs data: %v", err)
+-	}
+-
+-	pgfs, err := s.view.parseCache.parseFiles(ctx, token.NewFileSet(), source.ParseFull&^parser.ParseComments, true, cgfs...)
+-	if err != nil {
+-		return nil, err
+-	}
+-	data := typerefs.Encode(pgfs, id, imports)
+-
+-	// Store the resulting data in the cache.
+-	go func() {
+-		if err := filecache.Set(typerefsKind, key, data); err != nil {
+-			event.Error(ctx, fmt.Sprintf("storing typerefs data for %s", id), err)
+-		}
+-	}()
+-
+-	return data, nil
+-}
+-
+-// typerefsKey produces a key for the reference information produced by the
+-// typerefs package.
+-func typerefsKey(id PackageID, imports map[ImportPath]*source.Metadata, compiledGoFiles []source.FileHandle) source.Hash {
+-	hasher := sha256.New()
+-
+-	fmt.Fprintf(hasher, "typerefs: %s\n", id)
+-
+-	importPaths := make([]string, 0, len(imports))
+-	for impPath := range imports {
+-		importPaths = append(importPaths, string(impPath))
+-	}
+-	sort.Strings(importPaths)
+-	for _, importPath := range importPaths {
+-		imp := imports[ImportPath(importPath)]
+-		// TODO(rfindley): strength reduce the typerefs.Export API to guarantee
+-		// that it only depends on these attributes of dependencies.
+-		fmt.Fprintf(hasher, "import %s %s %s", importPath, imp.ID, imp.Name)
+-	}
+-
+-	fmt.Fprintf(hasher, "compiledGoFiles: %d\n", len(compiledGoFiles))
+-	for _, fh := range compiledGoFiles {
+-		fmt.Fprintln(hasher, fh.FileIdentity())
+-	}
+-
+-	var hash [sha256.Size]byte
+-	hasher.Sum(hash[:0])
+-	return hash
 -}
 -
 -// typeCheckInputs contains the inputs of a call to typeCheckImpl, which
@@ -13990,7 +16045,6 @@
 -	name                     PackageName
 -	goFiles, compiledGoFiles []source.FileHandle
 -	sizes                    types.Sizes
--	deps                     map[PackageID]*packageHandle
 -	depsByImpPath            map[ImportPath]PackageID
 -	goVersion                string // packages.Module.GoVersion, e.g. "1.18"
 -
@@ -14001,38 +16055,21 @@
 -}
 -
 -func (s *snapshot) typeCheckInputs(ctx context.Context, m *source.Metadata) (typeCheckInputs, error) {
--	deps := make(map[PackageID]*packageHandle)
--	for _, depID := range m.DepsByPkgPath {
--		depHandle, err := s.buildPackageHandle(ctx, depID)
--		if err != nil {
--			// If err is non-nil, we either have an invalid dependency, or a
--			// catastrophic failure to read a file (context cancellation or
--			// permission issues).
--			//
--			// We don't want one bad dependency to prevent us from type-checking the
--			// package -- we should instead get an import error. So we only abort
--			// this operation if the context is cancelled.
--			//
--			// We could do a better job of handling permission errors on files, but
--			// this is rare, and it is reasonable to treat the same an invalid
--			// dependency.
--			event.Error(ctx, fmt.Sprintf("%s: no dep handle for %s", m.ID, depID), err, source.SnapshotLabels(s)...)
--			if ctx.Err() != nil {
--				return typeCheckInputs{}, ctx.Err() // cancelled
--			}
--			continue
--		}
--		deps[depID] = depHandle
--	}
--
--	// Read both lists of files of this package, in parallel.
+-	// Read both lists of files of this package.
+-	//
+-	// Parallelism is not necessary here as the files will have already been
+-	// pre-read at load time.
 -	//
 -	// goFiles aren't presented to the type checker--nor
 -	// are they included in the key, unsoundly--but their
 -	// syntax trees are available from (*pkg).File(URI).
 -	// TODO(adonovan): consider parsing them on demand?
 -	// The need should be rare.
--	goFiles, compiledGoFiles, err := readGoFiles(ctx, s, m)
+-	goFiles, err := readFiles(ctx, s, m.GoFiles)
+-	if err != nil {
+-		return typeCheckInputs{}, err
+-	}
+-	compiledGoFiles, err := readFiles(ctx, s, m.CompiledGoFiles)
 -	if err != nil {
 -		return typeCheckInputs{}, err
 -	}
@@ -14049,40 +16086,31 @@
 -		goFiles:         goFiles,
 -		compiledGoFiles: compiledGoFiles,
 -		sizes:           m.TypesSizes,
--		deps:            deps,
 -		depsByImpPath:   m.DepsByImpPath,
 -		goVersion:       goVersion,
 -
--		relatedInformation: s.view.Options().RelatedInformationSupported,
--		linkTarget:         s.view.Options().LinkTarget,
--		moduleMode:         s.moduleMode(),
+-		relatedInformation: s.options.RelatedInformationSupported,
+-		linkTarget:         s.options.LinkTarget,
+-		moduleMode:         s.view.moduleMode(),
 -	}, nil
 -}
 -
--// readGoFiles reads the content of Metadata.GoFiles and
--// Metadata.CompiledGoFiles, in parallel.
--func readGoFiles(ctx context.Context, s *snapshot, m *source.Metadata) (goFiles, compiledGoFiles []source.FileHandle, err error) {
--	var group errgroup.Group
--	getFileHandles := func(files []span.URI) []source.FileHandle {
--		fhs := make([]source.FileHandle, len(files))
--		for i, uri := range files {
--			i, uri := i, uri
--			group.Go(func() (err error) {
--				fhs[i], err = s.GetFile(ctx, uri) // ~25us
--				return
--			})
+-// readFiles reads the content of each file URL from the source
+-// (e.g. snapshot or cache).
+-func readFiles(ctx context.Context, fs source.FileSource, uris []span.URI) (_ []source.FileHandle, err error) {
+-	fhs := make([]source.FileHandle, len(uris))
+-	for i, uri := range uris {
+-		fhs[i], err = fs.ReadFile(ctx, uri)
+-		if err != nil {
+-			return nil, err
 -		}
--		return fhs
 -	}
--	return getFileHandles(m.GoFiles),
--		getFileHandles(m.CompiledGoFiles),
--		group.Wait()
+-	return fhs, nil
 -}
 -
--// computePackageKey returns a key representing the act of type checking
--// a package named id containing the specified files, metadata, and
--// combined dependency hash.
--func computePackageKey(s *snapshot, inputs typeCheckInputs) packageHandleKey {
+-// localPackageKey returns a key for local inputs into type-checking, excluding
+-// dependency information: files, metadata, and configuration.
+-func localPackageKey(inputs typeCheckInputs) source.Hash {
 -	hasher := sha256.New()
 -
 -	// In principle, a key must be the hash of an
@@ -14105,17 +16133,6 @@
 -		fmt.Fprintf(hasher, "import %s %s", impPath, string(inputs.depsByImpPath[ImportPath(impPath)]))
 -	}
 -
--	// deps, in PackageID order
--	depIDs := make([]string, 0, len(inputs.deps))
--	for depID := range inputs.deps {
--		depIDs = append(depIDs, string(depID))
--	}
--	sort.Strings(depIDs)
--	for _, depID := range depIDs {
--		dep := inputs.deps[PackageID(depID)]
--		fmt.Fprintf(hasher, "dep: %s key:%s\n", dep.m.PkgPath, dep.key)
--	}
--
 -	// file names and contents
 -	fmt.Fprintf(hasher, "compiledGoFiles: %d\n", len(inputs.compiledGoFiles))
 -	for _, fh := range inputs.compiledGoFiles {
@@ -14127,8 +16144,9 @@
 -	}
 -
 -	// types sizes
--	sz := inputs.sizes.(*types.StdSizes)
--	fmt.Fprintf(hasher, "sizes: %d %d\n", sz.WordSize, sz.MaxAlign)
+-	wordSize := inputs.sizes.Sizeof(types.Typ[types.Int])
+-	maxAlign := inputs.sizes.Alignof(types.NewPointer(types.Typ[types.Int64]))
+-	fmt.Fprintf(hasher, "sizes: %d %d\n", wordSize, maxAlign)
 -
 -	fmt.Fprintf(hasher, "relatedInformation: %t\n", inputs.relatedInformation)
 -	fmt.Fprintf(hasher, "linkTarget: %s\n", inputs.linkTarget)
@@ -14136,7 +16154,7 @@
 -
 -	var hash [sha256.Size]byte
 -	hasher.Sum(hash[:0])
--	return packageHandleKey(hash)
+-	return hash
 -}
 -
 -// typeCheckImpl type checks the parsed source files in compiledGoFiles.
@@ -14150,8 +16168,6 @@
 -	if err != nil {
 -		return nil, err
 -	}
--	pkg.methodsets = methodsets.NewIndex(pkg.fset, pkg.types)
--	pkg.xrefs = xrefs.Index(pkg.compiledGoFiles, pkg.types, pkg.typesInfo)
 -
 -	// Our heuristic for whether to show type checking errors is:
 -	//  + If any file was 'fixed', don't show type checking errors as we
@@ -14187,7 +16203,13 @@
 -	for _, e := range expandErrors(unexpanded, inputs.relatedInformation) {
 -		diags, err := typeErrorDiagnostics(inputs.moduleMode, inputs.linkTarget, pkg, e)
 -		if err != nil {
--			event.Error(ctx, "unable to compute positions for type errors", err, tag.Package.Of(string(inputs.id)))
+-			// If we fail here and there are no parse errors, it means we are hiding
+-			// a valid type-checking error from the user. This must be a bug, with
+-			// one exception: relocated primary errors may fail processing, because
+-			// they reference locations outside of the package.
+-			if len(pkg.parseErrors) == 0 && !e.relocated {
+-				bug.Reportf("failed to compute position for type error %v: %v", e, err)
+-			}
 -			continue
 -		}
 -		pkg.typeErrors = append(pkg.typeErrors, e.primary)
@@ -14201,13 +16223,20 @@
 -		}
 -	}
 -
+-	// Work around golang/go#61561: interface instances aren't concurrency-safe
+-	// as they are not completed by the type checker.
+-	for _, inst := range typeparams.GetInstances(pkg.typesInfo) {
+-		if iface, _ := inst.Type.Underlying().(*types.Interface); iface != nil {
+-			iface.Complete()
+-		}
+-	}
+-
 -	return pkg, nil
 -}
 -
 -var goVersionRx = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
 -
 -func doTypeCheck(ctx context.Context, b *typeCheckBatch, inputs typeCheckInputs) (*syntaxPackage, error) {
--	impMap, errMap := b.importMap(inputs.id)
 -	pkg := &syntaxPackage{
 -		id:    inputs.id,
 -		fset:  b.fset, // must match parse call below
@@ -14220,30 +16249,24 @@
 -			Selections: make(map[*ast.SelectorExpr]*types.Selection),
 -			Scopes:     make(map[ast.Node]*types.Scope),
 -		},
--		importMap: impMap,
 -	}
 -	typeparams.InitInstanceInfo(pkg.typesInfo)
 -
 -	// Collect parsed files from the type check pass, capturing parse errors from
 -	// compiled files.
--	for _, fh := range inputs.goFiles {
--		pgf := b.parsedFiles[fh.URI()]
--		if pgf == nil {
--			// If go/packages told us that a file is in a package, it should be
--			// parseable (after all, it was parsed by go list).
--			return nil, bug.Errorf("go file %q failed to parse", fh.URI().Filename())
--		}
--		pkg.goFiles = append(pkg.goFiles, pgf)
+-	var err error
+-	pkg.goFiles, err = b.parseCache.parseFiles(ctx, b.fset, source.ParseFull, false, inputs.goFiles...)
+-	if err != nil {
+-		return nil, err
 -	}
--	for _, fh := range inputs.compiledGoFiles {
--		pgf := b.parsedFiles[fh.URI()]
--		if pgf == nil {
--			return nil, fmt.Errorf("compiled go file %q failed to parse", fh.URI().Filename())
--		}
+-	pkg.compiledGoFiles, err = b.parseCache.parseFiles(ctx, b.fset, source.ParseFull, false, inputs.compiledGoFiles...)
+-	if err != nil {
+-		return nil, err
+-	}
+-	for _, pgf := range pkg.compiledGoFiles {
 -		if pgf.ParseErr != nil {
 -			pkg.parseErrors = append(pkg.parseErrors, pgf.ParseErr)
 -		}
--		pkg.compiledGoFiles = append(pkg.compiledGoFiles, pgf)
 -	}
 -
 -	// Use the default type information for the unsafe package.
@@ -14266,7 +16289,7 @@
 -	onError := func(e error) {
 -		pkg.typeErrors = append(pkg.typeErrors, e.(types.Error))
 -	}
--	cfg := b.typesConfig(inputs, onError, impMap, errMap)
+-	cfg := b.typesConfig(ctx, inputs, onError)
 -
 -	check := types.NewChecker(cfg, pkg.fset, pkg.types, pkg.typesInfo)
 -
@@ -14275,6 +16298,12 @@
 -		files = append(files, cgf.File)
 -	}
 -
+-	// Type checking is expensive, and we may not have ecountered cancellations
+-	// via parsing (e.g. if we got nothing but cache hits for parsed files).
+-	if ctx.Err() != nil {
+-		return nil, ctx.Err()
+-	}
+-
 -	// Type checking errors are handled via the config, so ignore them here.
 -	_ = check.Files(files) // 50us-15ms, depending on size of package
 -
@@ -14283,10 +16312,26 @@
 -	if ctx.Err() != nil {
 -		return nil, ctx.Err()
 -	}
+-
+-	// Collect imports by package path for the DependencyTypes API.
+-	pkg.importMap = make(map[PackagePath]*types.Package)
+-	var collectDeps func(*types.Package)
+-	collectDeps = func(p *types.Package) {
+-		pkgPath := PackagePath(p.Path())
+-		if _, ok := pkg.importMap[pkgPath]; ok {
+-			return
+-		}
+-		pkg.importMap[pkgPath] = p
+-		for _, imp := range p.Imports() {
+-			collectDeps(imp)
+-		}
+-	}
+-	collectDeps(pkg.types)
+-
 -	return pkg, nil
 -}
 -
--func (b *typeCheckBatch) typesConfig(inputs typeCheckInputs, onError func(e error), impMap map[string]*types.Package, errMap map[PackagePath]error) *types.Config {
+-func (b *typeCheckBatch) typesConfig(ctx context.Context, inputs typeCheckInputs, onError func(e error)) *types.Config {
 -	cfg := &types.Config{
 -		Sizes: inputs.sizes,
 -		Error: onError,
@@ -14302,23 +16347,15 @@
 -				// See TestFixImportDecl for an example.
 -				return nil, fmt.Errorf("missing metadata for import of %q", path)
 -			}
--			depPH := inputs.deps[id]
+-			depPH := b.handles[id]
 -			if depPH == nil {
 -				// e.g. missing metadata for dependencies in buildPackageHandle
--				return nil, missingPkgError(path, inputs.moduleMode)
+-				return nil, missingPkgError(inputs.id, path, inputs.moduleMode)
 -			}
 -			if !source.IsValidImport(inputs.pkgPath, depPH.m.PkgPath) {
 -				return nil, fmt.Errorf("invalid use of internal package %q", path)
 -			}
--			pkg, ok := impMap[string(depPH.m.PkgPath)]
--			if !ok {
--				err := errMap[depPH.m.PkgPath]
--				if err == nil {
--					log.Fatalf("neither pkg nor error is set")
--				}
--				return nil, err
--			}
--			return pkg, nil
+-			return b.getImportPackage(ctx, id)
 -		}),
 -	}
 -
@@ -14383,7 +16420,7 @@
 -		if err != nil {
 -			return nil, err
 -		}
--		fset := source.FileSetFor(pgf.Tok)
+-		fset := tokeninternal.FileSetFor(pgf.Tok)
 -		// TODO(adonovan): modify Imports() to accept a single token.File (cgf.Tok).
 -		for _, group := range astutil.Imports(fset, pgf.File) {
 -			for _, imp := range group {
@@ -14415,14 +16452,18 @@
 -				if err != nil {
 -					return nil, err
 -				}
--				errors = append(errors, &source.Diagnostic{
+-				diag := &source.Diagnostic{
 -					URI:            imp.cgf.URI,
 -					Range:          rng,
 -					Severity:       protocol.SeverityError,
 -					Source:         source.TypeError,
 -					Message:        fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
 -					SuggestedFixes: fixes,
--				})
+-				}
+-				if !source.BundleQuickFixes(diag) {
+-					bug.Reportf("failed to bundle fixes for diagnostic %q", diag.Message)
+-				}
+-				errors = append(errors, diag)
 -			}
 -		}
 -	}
@@ -14458,14 +16499,18 @@
 -			if err != nil {
 -				return nil, err
 -			}
--			errors = append(errors, &source.Diagnostic{
+-			diag := &source.Diagnostic{
 -				URI:            pm.URI,
 -				Range:          rng,
 -				Severity:       protocol.SeverityError,
 -				Source:         source.TypeError,
 -				Message:        fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
 -				SuggestedFixes: fixes,
--			})
+-			}
+-			if !source.BundleQuickFixes(diag) {
+-				bug.Reportf("failed to bundle fixes for diagnostic %q", diag.Message)
+-			}
+-			errors = append(errors, diag)
 -			break
 -		}
 -	}
@@ -14474,13 +16519,17 @@
 -
 -// missingPkgError returns an error message for a missing package that varies
 -// based on the user's workspace mode.
--func missingPkgError(pkgPath string, moduleMode bool) error {
+-func missingPkgError(from PackageID, pkgPath string, moduleMode bool) error {
 -	// TODO(rfindley): improve this error. Previous versions of this error had
 -	// access to the full snapshot, and could provide more information (such as
 -	// the initialization error).
 -	if moduleMode {
--		// Previously, we would present the initialization error here.
--		return fmt.Errorf("no required module provides package %q", pkgPath)
+-		if source.IsCommandLineArguments(from) {
+-			return fmt.Errorf("current file is not included in a workspace module")
+-		} else {
+-			// Previously, we would present the initialization error here.
+-			return fmt.Errorf("no required module provides package %q", pkgPath)
+-		}
 -	} else {
 -		// Previously, we would list the directories in GOROOT and GOPATH here.
 -		return fmt.Errorf("cannot find package %q in GOROOT or GOPATH", pkgPath)
@@ -14488,6 +16537,7 @@
 -}
 -
 -type extendedError struct {
+-	relocated   bool // if set, this is a relocation of a primary error to a secondary location
 -	primary     types.Error
 -	secondaries []types.Error
 -}
@@ -14540,7 +16590,7 @@
 -
 -			// Copy over the secondary errors, noting the location of the
 -			// current error we're cloning.
--			clonedError := extendedError{primary: relocatedSecondary, secondaries: []types.Error{original.primary}}
+-			clonedError := extendedError{relocated: true, primary: relocatedSecondary, secondaries: []types.Error{original.primary}}
 -			for j, secondary := range original.secondaries {
 -				if i == j {
 -					secondary.Msg += " (this error)"
@@ -14549,7 +16599,6 @@
 -			}
 -			result = append(result, clonedError)
 -		}
--
 -	}
 -	return result
 -}
@@ -14559,10 +16608,10 @@
 -type importerFunc func(path string) (*types.Package, error)
 -
 -func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
-diff -urN a/gopls/internal/lsp/cache/debug.go b/gopls/internal/lsp/cache/debug.go
---- a/gopls/internal/lsp/cache/debug.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/debug.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,55 +0,0 @@
+diff -urN a/gopls/internal/lsp/cache/constraints.go b/gopls/internal/lsp/cache/constraints.go
+--- a/gopls/internal/lsp/cache/constraints.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/constraints.go	1970-01-01 08:00:00
+@@ -1,61 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -14570,58 +16619,365 @@
 -package cache
 -
 -import (
--	"fmt"
--	"os"
--	"sort"
+-	"go/ast"
+-	"go/build/constraint"
+-	"go/parser"
+-	"go/token"
 -)
 -
--// This file contains helpers that can be used to instrument code while
--// debugging.
--
--// debugEnabled toggles the helpers below.
--const debugEnabled = false
--
--// If debugEnabled is true, debugf formats its arguments and prints to stderr.
--// If debugEnabled is false, it is a no-op.
--func debugf(format string, args ...interface{}) {
--	if !debugEnabled {
--		return
--	}
--	if false {
--		_ = fmt.Sprintf(format, args...) // encourage vet to validate format strings
--	}
--	fmt.Fprintf(os.Stderr, ">>> "+format+"\n", args...)
--}
--
--// If debugEnabled is true, dumpWorkspace prints a summary of workspace
--// packages to stderr. If debugEnabled is false, it is a no-op.
--//
--// TODO(rfindley): this has served its purpose. Delete.
--func (s *snapshot) dumpWorkspace(context string) {
--	if !debugEnabled {
--		return
+-// isStandaloneFile reports whether a file with the given contents should be
+-// considered a 'standalone main file', meaning a package that consists of only
+-// a single file.
+-func isStandaloneFile(src []byte, standaloneTags []string) bool {
+-	f, err := parser.ParseFile(token.NewFileSet(), "", src, parser.PackageClauseOnly|parser.ParseComments)
+-	if err != nil {
+-		return false
 -	}
 -
--	debugf("workspace (after %s):", context)
--	var ids []PackageID
--	for id := range s.workspacePackages {
--		ids = append(ids, id)
+-	if f.Name == nil || f.Name.Name != "main" {
+-		return false
 -	}
 -
--	sort.Slice(ids, func(i, j int) bool {
--		return ids[i] < ids[j]
+-	found := false
+-	walkConstraints(f, func(c constraint.Expr) bool {
+-		if tag, ok := c.(*constraint.TagExpr); ok {
+-			for _, t := range standaloneTags {
+-				if t == tag.Tag {
+-					found = true
+-					return false
+-				}
+-			}
+-		}
+-		return true
 -	})
 -
--	for _, id := range ids {
--		pkgPath := s.workspacePackages[id]
--		_, ok := s.meta.metadata[id]
--		debugf("  %s:%s (metadata: %t)", id, pkgPath, ok)
+-	return found
+-}
+-
+-// walkConstraints calls f for each constraint expression in the file, until
+-// all constraints are exhausted or f returns false.
+-func walkConstraints(file *ast.File, f func(constraint.Expr) bool) {
+-	for _, cg := range file.Comments {
+-		// Even with PackageClauseOnly the parser consumes the semicolon following
+-		// the package clause, so we must guard against comments that come after
+-		// the package name.
+-		if cg.Pos() > file.Name.Pos() {
+-			continue
+-		}
+-		for _, comment := range cg.List {
+-			if c, err := constraint.Parse(comment.Text); err == nil {
+-				if !f(c) {
+-					return
+-				}
+-			}
+-		}
+-	}
+-}
+diff -urN a/gopls/internal/lsp/cache/constraints_test.go b/gopls/internal/lsp/cache/constraints_test.go
+--- a/gopls/internal/lsp/cache/constraints_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/constraints_test.go	1970-01-01 08:00:00
+@@ -1,96 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.16
+-// +build go1.16
+-
+-package cache
+-
+-import (
+-	"testing"
+-)
+-
+-func TestIsStandaloneFile(t *testing.T) {
+-	tests := []struct {
+-		desc           string
+-		contents       string
+-		standaloneTags []string
+-		want           bool
+-	}{
+-		{
+-			"new syntax",
+-			"//go:build ignore\n\npackage main\n",
+-			[]string{"ignore"},
+-			true,
+-		},
+-		{
+-			"legacy syntax",
+-			"// +build ignore\n\npackage main\n",
+-			[]string{"ignore"},
+-			true,
+-		},
+-		{
+-			"multiple tags",
+-			"//go:build ignore\n\npackage main\n",
+-			[]string{"exclude", "ignore"},
+-			true,
+-		},
+-		{
+-			"invalid tag",
+-			"// +build ignore\n\npackage main\n",
+-			[]string{"script"},
+-			false,
+-		},
+-		{
+-			"non-main package",
+-			"//go:build ignore\n\npackage p\n",
+-			[]string{"ignore"},
+-			false,
+-		},
+-		{
+-			"alternate tag",
+-			"// +build script\n\npackage main\n",
+-			[]string{"script"},
+-			true,
+-		},
+-		{
+-			"both syntax",
+-			"//go:build ignore\n// +build ignore\n\npackage main\n",
+-			[]string{"ignore"},
+-			true,
+-		},
+-		{
+-			"after comments",
+-			"// A non-directive comment\n//go:build ignore\n\npackage main\n",
+-			[]string{"ignore"},
+-			true,
+-		},
+-		{
+-			"after package decl",
+-			"package main //go:build ignore\n",
+-			[]string{"ignore"},
+-			false,
+-		},
+-		{
+-			"on line after package decl",
+-			"package main\n\n//go:build ignore\n",
+-			[]string{"ignore"},
+-			false,
+-		},
+-		{
+-			"combined with other expressions",
+-			"\n\n//go:build ignore || darwin\n\npackage main\n",
+-			[]string{"ignore"},
+-			false,
+-		},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(test.desc, func(t *testing.T) {
+-			if got := isStandaloneFile([]byte(test.contents), test.standaloneTags); got != test.want {
+-				t.Errorf("isStandaloneFile(%q, %v) = %t, want %t", test.contents, test.standaloneTags, got, test.want)
+-			}
+-		})
+-	}
+-}
+diff -urN a/gopls/internal/lsp/cache/cycle_test.go b/gopls/internal/lsp/cache/cycle_test.go
+--- a/gopls/internal/lsp/cache/cycle_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/cycle_test.go	1970-01-01 08:00:00
+@@ -1,181 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package cache
+-
+-import (
+-	"sort"
+-	"strings"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-)
+-
+-// This is an internal test of the breakImportCycles logic.
+-func TestBreakImportCycles(t *testing.T) {
+-
+-	type Graph = map[PackageID]*source.Metadata
+-
+-	// cyclic returns a description of a cycle,
+-	// if the graph is cyclic, otherwise "".
+-	cyclic := func(graph Graph) string {
+-		const (
+-			unvisited = 0
+-			visited   = 1
+-			onstack   = 2
+-		)
+-		color := make(map[PackageID]int)
+-		var visit func(id PackageID) string
+-		visit = func(id PackageID) string {
+-			switch color[id] {
+-			case unvisited:
+-				color[id] = onstack
+-			case onstack:
+-				return string(id) // cycle!
+-			case visited:
+-				return ""
+-			}
+-			if m := graph[id]; m != nil {
+-				for _, depID := range m.DepsByPkgPath {
+-					if cycle := visit(depID); cycle != "" {
+-						return string(id) + "->" + cycle
+-					}
+-				}
+-			}
+-			color[id] = visited
+-			return ""
+-		}
+-		for id := range graph {
+-			if cycle := visit(id); cycle != "" {
+-				return cycle
+-			}
+-		}
+-		return ""
+-	}
+-
+-	// parse parses an import dependency graph.
+-	// The input is a semicolon-separated list of node descriptions.
+-	// Each node description is a package ID, optionally followed by
+-	// "->" and a comma-separated list of successor IDs.
+-	// Thus "a->b;b->c,d;e" represents the set of nodes {a,b,e}
+-	// and the set of edges {a->b, b->c, b->d}.
+-	parse := func(s string) Graph {
+-		m := make(Graph)
+-		makeNode := func(name string) *source.Metadata {
+-			id := PackageID(name)
+-			n, ok := m[id]
+-			if !ok {
+-				n = &source.Metadata{
+-					ID:            id,
+-					DepsByPkgPath: make(map[PackagePath]PackageID),
+-				}
+-				m[id] = n
+-			}
+-			return n
+-		}
+-		if s != "" {
+-			for _, item := range strings.Split(s, ";") {
+-				nodeID, succIDs, ok := strings.Cut(item, "->")
+-				node := makeNode(nodeID)
+-				if ok {
+-					for _, succID := range strings.Split(succIDs, ",") {
+-						node.DepsByPkgPath[PackagePath(succID)] = PackageID(succID)
+-					}
+-				}
+-			}
+-		}
+-		return m
+-	}
+-
+-	// Sanity check of cycle detector.
+-	{
+-		got := cyclic(parse("a->b;b->c;c->a,d"))
+-		has := func(s string) bool { return strings.Contains(got, s) }
+-		if !(has("a->b") && has("b->c") && has("c->a") && !has("d")) {
+-			t.Fatalf("cyclic: got %q, want a->b->c->a or equivalent", got)
+-		}
+-	}
+-
+-	// format formats an import graph, in lexicographic order,
+-	// in the notation of parse, but with a "!" after the name
+-	// of each node that has errors.
+-	format := func(graph Graph) string {
+-		var items []string
+-		for _, m := range graph {
+-			item := string(m.ID)
+-			if len(m.Errors) > 0 {
+-				item += "!"
+-			}
+-			var succs []string
+-			for _, depID := range m.DepsByPkgPath {
+-				succs = append(succs, string(depID))
+-			}
+-			if succs != nil {
+-				sort.Strings(succs)
+-				item += "->" + strings.Join(succs, ",")
+-			}
+-			items = append(items, item)
+-		}
+-		sort.Strings(items)
+-		return strings.Join(items, ";")
+-	}
+-
+-	// We needn't test self-cycles as they are eliminated at Metadata construction.
+-	for _, test := range []struct {
+-		metadata, updates, want string
+-	}{
+-		// Simple 2-cycle.
+-		{"a->b", "b->a",
+-			"a->b;b!"}, // broke b->a
+-
+-		{"a->b;b->c;c", "b->a,c",
+-			"a->b;b!->c;c"}, // broke b->a
+-
+-		// Reversing direction of p->s edge creates pqrs cycle.
+-		{"a->p,q,r,s;p->q,s,z;q->r,z;r->s,z;s->z", "p->q,z;s->p,z",
+-			"a->p,q,r,s;p!->z;q->r,z;r->s,z;s!->z"}, // broke p->q, s->p
+-
+-		// We break all intra-SCC edges from updated nodes,
+-		// which may be more than necessary (e.g. a->b).
+-		{"a->b;b->c;c;d->a", "a->b,e;c->d",
+-			"a!->e;b->c;c!;d->a"}, // broke a->b, c->d
+-	} {
+-		metadata := parse(test.metadata)
+-		updates := parse(test.updates)
+-
+-		if cycle := cyclic(metadata); cycle != "" {
+-			t.Errorf("initial metadata %s has cycle %s: ", format(metadata), cycle)
+-			continue
+-		}
+-
+-		t.Log("initial", format(metadata))
+-
+-		// Apply updates.
+-		// (parse doesn't have a way to express node deletions,
+-		// but they aren't very interesting.)
+-		for id, m := range updates {
+-			metadata[id] = m
+-		}
+-
+-		t.Log("updated", format(metadata))
+-
+-		// breakImportCycles accesses only these fields of Metadata:
+-		//    DepsByImpPath, ID - read
+-		//    DepsByPkgPath     - read, updated
+-		//    Errors            - updated
+-		breakImportCycles(metadata, updates)
+-
+-		t.Log("acyclic", format(metadata))
+-
+-		if cycle := cyclic(metadata); cycle != "" {
+-			t.Errorf("resulting metadata %s has cycle %s: ", format(metadata), cycle)
+-		}
+-
+-		got := format(metadata)
+-		if got != test.want {
+-			t.Errorf("test.metadata=%s test.updates=%s: got=%s want=%s",
+-				test.metadata, test.updates, got, test.want)
+-		}
+-	}
+-}
+diff -urN a/gopls/internal/lsp/cache/debug.go b/gopls/internal/lsp/cache/debug.go
+--- a/gopls/internal/lsp/cache/debug.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/debug.go	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package cache
+-
+-// assert panics with the given msg if cond is not true.
+-func assert(cond bool, msg string) {
+-	if !cond {
+-		panic(msg)
 -	}
 -}
 diff -urN a/gopls/internal/lsp/cache/errors.go b/gopls/internal/lsp/cache/errors.go
 --- a/gopls/internal/lsp/cache/errors.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/errors.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,528 +0,0 @@
++++ b/gopls/internal/lsp/cache/errors.go	1970-01-01 08:00:00
+@@ -1,545 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -14635,6 +16991,7 @@
 -import (
 -	"context"
 -	"fmt"
+-	"go/parser"
 -	"go/scanner"
 -	"go/token"
 -	"go/types"
@@ -14644,13 +17001,13 @@
 -	"strings"
 -
 -	"golang.org/x/tools/go/packages"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
 -	"golang.org/x/tools/internal/analysisinternal"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/typesinternal"
 -)
 -
@@ -14759,7 +17116,13 @@
 -	for _, secondary := range e.secondaries {
 -		_, secondaryLoc, err := typeErrorData(pkg, secondary)
 -		if err != nil {
--			return nil, err
+-			// We may not be able to compute type error data in scenarios where the
+-			// secondary position is outside of the current package. In this case, we
+-			// don't want to ignore the diagnostic entirely.
+-			//
+-			// See golang/go#59005 for an example where gopls was missing diagnostics
+-			// due to returning an error here.
+-			continue
 -		}
 -		diag.Related = append(diag.Related, protocol.DiagnosticRelatedInformation{
 -			Location: secondaryLoc,
@@ -14866,13 +17229,13 @@
 -		}
 -		gobDiags = append(gobDiags, gobDiag)
 -	}
--	return mustEncode(gobDiags)
+-	return diagnosticsCodec.Encode(gobDiags)
 -}
 -
 -// decodeDiagnostics decodes the given gob-encoded diagnostics.
 -func decodeDiagnostics(data []byte) []*source.Diagnostic {
 -	var gobDiags []gobDiagnostic
--	mustDecode(data, &gobDiags)
+-	diagnosticsCodec.Decode(data, &gobDiags)
 -	var srcDiags []*source.Diagnostic
 -	for _, gobDiag := range gobDiags {
 -		var srcFixes []source.SuggestedFix
@@ -14893,7 +17256,7 @@
 -				srcFix.Edits[uri] = append(srcFix.Edits[uri], srcEdit)
 -			}
 -			if gobCmd := gobFix.Command; gobCmd != nil {
--				gobFix.Command = &gobCommand{
+-				srcFix.Command = &protocol.Command{
 -					Title:     gobCmd.Title,
 -					Command:   gobCmd.Command,
 -					Arguments: gobCmd.Arguments,
@@ -14910,6 +17273,8 @@
 -			URI:            gobDiag.Location.URI.SpanURI(),
 -			Range:          gobDiag.Location.Range,
 -			Severity:       gobDiag.Severity,
+-			Code:           gobDiag.Code,
+-			CodeHref:       gobDiag.CodeHref,
 -			Source:         source.AnalyzerErrorKind(gobDiag.Source),
 -			Message:        gobDiag.Message,
 -			Tags:           gobDiag.Tags,
@@ -14954,17 +17319,23 @@
 -	}
 -
 -	diag := &source.Diagnostic{
--		URI:            gobDiag.Location.URI.SpanURI(),
--		Range:          gobDiag.Location.Range,
--		Severity:       severity,
--		Source:         source.AnalyzerErrorKind(gobDiag.Source),
--		Message:        gobDiag.Message,
--		Related:        related,
--		SuggestedFixes: fixes,
+-		URI:      gobDiag.Location.URI.SpanURI(),
+-		Range:    gobDiag.Location.Range,
+-		Severity: severity,
+-		Code:     gobDiag.Code,
+-		CodeHref: gobDiag.CodeHref,
+-		Source:   source.AnalyzerErrorKind(gobDiag.Source),
+-		Message:  gobDiag.Message,
+-		Related:  related,
+-		Tags:     srcAnalyzer.Tag,
 -	}
+-	if srcAnalyzer.FixesDiagnostic(diag) {
+-		diag.SuggestedFixes = fixes
+-	}
+-
 -	// If the fixes only delete code, assume that the diagnostic is reporting dead code.
 -	if onlyDeletions(fixes) {
--		diag.Tags = []protocol.DiagnosticTag{protocol.Unnecessary}
+-		diag.Tags = append(diag.Tags, protocol.Unnecessary)
 -	}
 -	return diag
 -}
@@ -15052,11 +17423,11 @@
 -// contained in the provided FileSource.
 -func spanToRange(ctx context.Context, fs source.FileSource, spn span.Span) (protocol.Range, error) {
 -	uri := spn.URI()
--	fh, err := fs.GetFile(ctx, uri)
+-	fh, err := fs.ReadFile(ctx, uri)
 -	if err != nil {
 -		return protocol.Range{}, err
 -	}
--	content, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return protocol.Range{}, err
 -	}
@@ -15131,12 +17502,14 @@
 -// to use in a list of file of a package, for example.
 -//
 -// It returns an error if the file could not be read.
--func parseGoURI(ctx context.Context, fs source.FileSource, uri span.URI, mode source.ParseMode) (*source.ParsedGoFile, error) {
--	fh, err := fs.GetFile(ctx, uri)
+-//
+-// TODO(rfindley): eliminate this helper.
+-func parseGoURI(ctx context.Context, fs source.FileSource, uri span.URI, mode parser.Mode) (*source.ParsedGoFile, error) {
+-	fh, err := fs.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
--	return parseGoImpl(ctx, token.NewFileSet(), fh, source.ParseHeader)
+-	return parseGoImpl(ctx, token.NewFileSet(), fh, mode, false)
 -}
 -
 -// parseModURI is a helper to parse the Mod file at the given URI from the file
@@ -15144,7 +17517,7 @@
 -//
 -// It returns an error if the file could not be read.
 -func parseModURI(ctx context.Context, fs source.FileSource, uri span.URI) (*source.ParsedModule, error) {
--	fh, err := fs.GetFile(ctx, uri)
+-	fh, err := fs.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -15152,8 +17525,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/errors_test.go b/gopls/internal/lsp/cache/errors_test.go
 --- a/gopls/internal/lsp/cache/errors_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/errors_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,52 +0,0 @@
++++ b/gopls/internal/lsp/cache/errors_test.go	1970-01-01 08:00:00
+@@ -1,130 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -15161,8 +17534,14 @@
 -package cache
 -
 -import (
+-	"encoding/json"
 -	"strings"
 -	"testing"
+-
+-	"github.com/google/go-cmp/cmp"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
 -)
 -
 -func TestParseErrorMessage(t *testing.T) {
@@ -15206,10 +17585,349 @@
 -		})
 -	}
 -}
+-
+-func TestDiagnosticEncoding(t *testing.T) {
+-	diags := []*source.Diagnostic{
+-		{}, // empty
+-		{
+-			URI: "file///foo",
+-			Range: protocol.Range{
+-				Start: protocol.Position{Line: 4, Character: 2},
+-				End:   protocol.Position{Line: 6, Character: 7},
+-			},
+-			Severity: protocol.SeverityWarning,
+-			Code:     "red",
+-			CodeHref: "https://go.dev",
+-			Source:   "test",
+-			Message:  "something bad happened",
+-			Tags:     []protocol.DiagnosticTag{81},
+-			Related: []protocol.DiagnosticRelatedInformation{
+-				{
+-					Location: protocol.Location{
+-						URI: "file:///other",
+-						Range: protocol.Range{
+-							Start: protocol.Position{Line: 3, Character: 6},
+-							End:   protocol.Position{Line: 4, Character: 9},
+-						},
+-					},
+-					Message: "psst, over here",
+-				},
+-			},
+-
+-			// Fields below are used internally to generate quick fixes. They aren't
+-			// part of the LSP spec and don't leave the server.
+-			SuggestedFixes: []source.SuggestedFix{
+-				{
+-					Title: "fix it!",
+-					Edits: map[span.URI][]protocol.TextEdit{
+-						"file:///foo": {{
+-							Range: protocol.Range{
+-								Start: protocol.Position{Line: 4, Character: 2},
+-								End:   protocol.Position{Line: 6, Character: 7},
+-							},
+-							NewText: "abc",
+-						}},
+-						"file:///other": {{
+-							Range: protocol.Range{
+-								Start: protocol.Position{Line: 4, Character: 2},
+-								End:   protocol.Position{Line: 6, Character: 7},
+-							},
+-							NewText: "!@#!",
+-						}},
+-					},
+-					Command: &protocol.Command{
+-						Title:     "run a command",
+-						Command:   "gopls.fix",
+-						Arguments: []json.RawMessage{json.RawMessage(`{"a":1}`)},
+-					},
+-					ActionKind: protocol.QuickFix,
+-				},
+-			},
+-		},
+-		{
+-			URI: "file//bar",
+-			// other fields tested above
+-		},
+-	}
+-
+-	data := encodeDiagnostics(diags)
+-	diags2 := decodeDiagnostics(data)
+-
+-	if diff := cmp.Diff(diags, diags2); diff != "" {
+-		t.Errorf("decoded diagnostics do not match (-original +decoded):\n%s", diff)
+-	}
+-}
+diff -urN a/gopls/internal/lsp/cache/filemap.go b/gopls/internal/lsp/cache/filemap.go
+--- a/gopls/internal/lsp/cache/filemap.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/filemap.go	1970-01-01 08:00:00
+@@ -1,151 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package cache
+-
+-import (
+-	"path/filepath"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/persistent"
+-)
+-
+-// A fileMap maps files in the snapshot, with some additional bookkeeping:
+-// It keeps track of overlays as well as directories containing any observed
+-// file.
+-type fileMap struct {
+-	files    *persistent.Map[span.URI, source.FileHandle]
+-	overlays *persistent.Map[span.URI, *Overlay] // the subset of files that are overlays
+-	dirs     *persistent.Set[string]             // all dirs containing files; if nil, dirs have not been initialized
+-}
+-
+-func newFileMap() *fileMap {
+-	return &fileMap{
+-		files:    new(persistent.Map[span.URI, source.FileHandle]),
+-		overlays: new(persistent.Map[span.URI, *Overlay]),
+-		dirs:     new(persistent.Set[string]),
+-	}
+-}
+-
+-// Clone creates a copy of the fileMap, incorporating the changes specified by
+-// the changes map.
+-func (m *fileMap) Clone(changes map[span.URI]source.FileHandle) *fileMap {
+-	m2 := &fileMap{
+-		files:    m.files.Clone(),
+-		overlays: m.overlays.Clone(),
+-	}
+-	if m.dirs != nil {
+-		m2.dirs = m.dirs.Clone()
+-	}
+-
+-	// Handle file changes.
+-	//
+-	// Note, we can't simply delete the file unconditionally and let it be
+-	// re-read by the snapshot, as (1) the snapshot must always observe all
+-	// overlays, and (2) deleting a file forces directories to be reevaluated, as
+-	// it may be the last file in a directory. We want to avoid that work in the
+-	// common case where a file has simply changed.
+-	//
+-	// For that reason, we also do this in two passes, processing deletions
+-	// first, as a set before a deletion would result in pointless work.
+-	for uri, fh := range changes {
+-		if !fileExists(fh) {
+-			m2.Delete(uri)
+-		}
+-	}
+-	for uri, fh := range changes {
+-		if fileExists(fh) {
+-			m2.Set(uri, fh)
+-		}
+-	}
+-	return m2
+-}
+-
+-func (m *fileMap) Destroy() {
+-	m.files.Destroy()
+-	m.overlays.Destroy()
+-	if m.dirs != nil {
+-		m.dirs.Destroy()
+-	}
+-}
+-
+-// Get returns the file handle mapped by the given key, or (nil, false) if the
+-// key is not present.
+-func (m *fileMap) Get(key span.URI) (source.FileHandle, bool) {
+-	return m.files.Get(key)
+-}
+-
+-// Range calls f for each (uri, fh) in the map.
+-func (m *fileMap) Range(f func(uri span.URI, fh source.FileHandle)) {
+-	m.files.Range(f)
+-}
+-
+-// Set stores the given file handle for key, updating overlays and directories
+-// accordingly.
+-func (m *fileMap) Set(key span.URI, fh source.FileHandle) {
+-	m.files.Set(key, fh, nil)
+-
+-	// update overlays
+-	if o, ok := fh.(*Overlay); ok {
+-		m.overlays.Set(key, o, nil)
+-	} else {
+-		// Setting a non-overlay must delete the corresponding overlay, to preserve
+-		// the accuracy of the overlay set.
+-		m.overlays.Delete(key)
+-	}
+-
+-	// update dirs, if they have been computed
+-	if m.dirs != nil {
+-		m.addDirs(key)
+-	}
+-}
+-
+-// addDirs adds all directories containing u to the dirs set.
+-func (m *fileMap) addDirs(u span.URI) {
+-	dir := filepath.Dir(u.Filename())
+-	for dir != "" && !m.dirs.Contains(dir) {
+-		m.dirs.Add(dir)
+-		dir = filepath.Dir(dir)
+-	}
+-}
+-
+-// Delete removes a file from the map, and updates overlays and dirs
+-// accordingly.
+-func (m *fileMap) Delete(key span.URI) {
+-	m.files.Delete(key)
+-	m.overlays.Delete(key)
+-
+-	// Deleting a file may cause the set of dirs to shrink; therefore we must
+-	// re-evaluate the dir set.
+-	//
+-	// Do this lazily, to avoid work if there are multiple deletions in a row.
+-	if m.dirs != nil {
+-		m.dirs.Destroy()
+-		m.dirs = nil
+-	}
+-}
+-
+-// Overlays returns a new unordered array of overlay files.
+-func (m *fileMap) Overlays() []*Overlay {
+-	var overlays []*Overlay
+-	m.overlays.Range(func(_ span.URI, o *Overlay) {
+-		overlays = append(overlays, o)
+-	})
+-	return overlays
+-}
+-
+-// Dirs reports returns the set of dirs observed by the fileMap.
+-//
+-// This operation mutates the fileMap.
+-// The result must not be mutated by the caller.
+-func (m *fileMap) Dirs() *persistent.Set[string] {
+-	if m.dirs == nil {
+-		m.dirs = new(persistent.Set[string])
+-		m.files.Range(func(u span.URI, _ source.FileHandle) {
+-			m.addDirs(u)
+-		})
+-	}
+-	return m.dirs
+-}
+diff -urN a/gopls/internal/lsp/cache/filemap_test.go b/gopls/internal/lsp/cache/filemap_test.go
+--- a/gopls/internal/lsp/cache/filemap_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/filemap_test.go	1970-01-01 08:00:00
+@@ -1,108 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package cache
+-
+-import (
+-	"path/filepath"
+-	"sort"
+-	"strings"
+-	"testing"
+-
+-	"github.com/google/go-cmp/cmp"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
+-)
+-
+-func TestFileMap(t *testing.T) {
+-	const (
+-		set = iota
+-		del
+-	)
+-	type op struct {
+-		op      int // set or remove
+-		path    string
+-		overlay bool
+-	}
+-	tests := []struct {
+-		label        string
+-		ops          []op
+-		wantFiles    []string
+-		wantOverlays []string
+-		wantDirs     []string
+-	}{
+-		{"empty", nil, nil, nil, nil},
+-		{"singleton", []op{
+-			{set, "/a/b", false},
+-		}, []string{"/a/b"}, nil, []string{"/", "/a"}},
+-		{"overlay", []op{
+-			{set, "/a/b", true},
+-		}, []string{"/a/b"}, []string{"/a/b"}, []string{"/", "/a"}},
+-		{"replace overlay", []op{
+-			{set, "/a/b", true},
+-			{set, "/a/b", false},
+-		}, []string{"/a/b"}, nil, []string{"/", "/a"}},
+-		{"multi dir", []op{
+-			{set, "/a/b", false},
+-			{set, "/c/d", false},
+-		}, []string{"/a/b", "/c/d"}, nil, []string{"/", "/a", "/c"}},
+-		{"empty dir", []op{
+-			{set, "/a/b", false},
+-			{set, "/c/d", false},
+-			{del, "/a/b", false},
+-		}, []string{"/c/d"}, nil, []string{"/", "/c"}},
+-	}
+-
+-	// Normalize paths for windows compatibility.
+-	normalize := func(path string) string {
+-		return strings.TrimPrefix(filepath.ToSlash(path), "C:") // the span packages adds 'C:'
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(test.label, func(t *testing.T) {
+-			m := newFileMap()
+-			for _, op := range test.ops {
+-				uri := span.URIFromPath(filepath.FromSlash(op.path))
+-				switch op.op {
+-				case set:
+-					var fh source.FileHandle
+-					if op.overlay {
+-						fh = &Overlay{uri: uri}
+-					} else {
+-						fh = &DiskFile{uri: uri}
+-					}
+-					m.Set(uri, fh)
+-				case del:
+-					m.Delete(uri)
+-				}
+-			}
+-
+-			var gotFiles []string
+-			m.Range(func(uri span.URI, _ source.FileHandle) {
+-				gotFiles = append(gotFiles, normalize(uri.Filename()))
+-			})
+-			sort.Strings(gotFiles)
+-			if diff := cmp.Diff(test.wantFiles, gotFiles); diff != "" {
+-				t.Errorf("Files mismatch (-want +got):\n%s", diff)
+-			}
+-
+-			var gotOverlays []string
+-			for _, o := range m.Overlays() {
+-				gotOverlays = append(gotOverlays, normalize(o.URI().Filename()))
+-			}
+-			if diff := cmp.Diff(test.wantOverlays, gotOverlays); diff != "" {
+-				t.Errorf("Overlays mismatch (-want +got):\n%s", diff)
+-			}
+-
+-			var gotDirs []string
+-			m.Dirs().Range(func(dir string) {
+-				gotDirs = append(gotDirs, normalize(dir))
+-			})
+-			sort.Strings(gotDirs)
+-			if diff := cmp.Diff(test.wantDirs, gotDirs); diff != "" {
+-				t.Errorf("Dirs mismatch (-want +got):\n%s", diff)
+-			}
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/lsp/cache/fs_memoized.go b/gopls/internal/lsp/cache/fs_memoized.go
 --- a/gopls/internal/lsp/cache/fs_memoized.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/fs_memoized.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,149 +0,0 @@
++++ b/gopls/internal/lsp/cache/fs_memoized.go	1970-01-01 08:00:00
+@@ -1,167 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -15239,10 +17957,6 @@
 -	filesByID map[robustio.FileID][]*DiskFile
 -}
 -
--func newMemoizedFS() *memoizedFS {
--	return &memoizedFS{filesByID: make(map[robustio.FileID][]*DiskFile)}
--}
--
 -// A DiskFile is a file on the filesystem, or a failure to read one.
 -// It implements the source.FileHandle interface.
 -type DiskFile struct {
@@ -15262,12 +17976,12 @@
 -	}
 -}
 -
--func (h *DiskFile) Saved() bool           { return true }
--func (h *DiskFile) Version() int32        { return 0 }
--func (h *DiskFile) Read() ([]byte, error) { return h.content, h.err }
+-func (h *DiskFile) SameContentsOnDisk() bool { return true }
+-func (h *DiskFile) Version() int32           { return 0 }
+-func (h *DiskFile) Content() ([]byte, error) { return h.content, h.err }
 -
--// GetFile stats and (maybe) reads the file, updates the cache, and returns it.
--func (fs *memoizedFS) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
+-// ReadFile stats and (maybe) reads the file, updates the cache, and returns it.
+-func (fs *memoizedFS) ReadFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
 -	id, mtime, err := robustio.GetFileID(uri.Filename())
 -	if err != nil {
 -		// file does not exist
@@ -15328,6 +18042,28 @@
 -	return fh, nil
 -}
 -
+-// fileStats returns information about the set of files stored in fs. It is
+-// intended for debugging only.
+-func (fs *memoizedFS) fileStats() (files, largest, errs int) {
+-	fs.mu.Lock()
+-	defer fs.mu.Unlock()
+-
+-	files = len(fs.filesByID)
+-	largest = 0
+-	errs = 0
+-
+-	for _, files := range fs.filesByID {
+-		rep := files[0]
+-		if len(rep.content) > largest {
+-			largest = len(rep.content)
+-		}
+-		if rep.err != nil {
+-			errs++
+-		}
+-	}
+-	return files, largest, errs
+-}
+-
 -// ioLimit limits the number of parallel file reads per process.
 -var ioLimit = make(chan struct{}, 128)
 -
@@ -15361,7 +18097,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/fs_overlay.go b/gopls/internal/lsp/cache/fs_overlay.go
 --- a/gopls/internal/lsp/cache/fs_overlay.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/fs_overlay.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cache/fs_overlay.go	1970-01-01 08:00:00
 @@ -1,78 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -15404,14 +18140,14 @@
 -	return overlays
 -}
 -
--func (fs *overlayFS) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
+-func (fs *overlayFS) ReadFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
 -	fs.mu.Lock()
 -	overlay, ok := fs.overlays[uri]
 -	fs.mu.Unlock()
 -	if ok {
 -		return overlay, nil
 -	}
--	return fs.delegate.GetFile(ctx, uri)
+-	return fs.delegate.ReadFile(ctx, uri)
 -}
 -
 -// An Overlay is a file open in the editor. It may have unsaved edits.
@@ -15437,14 +18173,14 @@
 -	}
 -}
 -
--func (o *Overlay) Read() ([]byte, error) { return o.content, nil }
--func (o *Overlay) Version() int32        { return o.version }
--func (o *Overlay) Saved() bool           { return o.saved }
--func (o *Overlay) Kind() source.FileKind { return o.kind }
+-func (o *Overlay) Content() ([]byte, error) { return o.content, nil }
+-func (o *Overlay) Version() int32           { return o.version }
+-func (o *Overlay) SameContentsOnDisk() bool { return o.saved }
+-func (o *Overlay) Kind() source.FileKind    { return o.kind }
 diff -urN a/gopls/internal/lsp/cache/graph.go b/gopls/internal/lsp/cache/graph.go
 --- a/gopls/internal/lsp/cache/graph.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/graph.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,131 +0,0 @@
++++ b/gopls/internal/lsp/cache/graph.go	1970-01-01 08:00:00
+@@ -1,364 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -15454,6 +18190,8 @@
 -import (
 -	"sort"
 -
+-	"golang.org/x/tools/go/packages"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
 -)
@@ -15469,6 +18207,8 @@
 -
 -	// ids maps file URIs to package IDs, sorted by (!valid, cli, packageID).
 -	// A single file may belong to multiple packages due to tests packages.
+-	//
+-	// Invariant: all IDs present in the ids map exist in the metadata map.
 -	ids map[span.URI][]PackageID
 -}
 -
@@ -15478,43 +18218,46 @@
 -}
 -
 -// Clone creates a new metadataGraph, applying the given updates to the
--// receiver.
+-// receiver. A nil map value represents a deletion.
 -func (g *metadataGraph) Clone(updates map[PackageID]*source.Metadata) *metadataGraph {
 -	if len(updates) == 0 {
 -		// Optimization: since the graph is immutable, we can return the receiver.
 -		return g
 -	}
--	result := &metadataGraph{metadata: make(map[PackageID]*source.Metadata, len(g.metadata))}
--	// Copy metadata.
+-
+-	// Copy metadata map then apply updates.
+-	metadata := make(map[PackageID]*source.Metadata, len(g.metadata))
 -	for id, m := range g.metadata {
--		result.metadata[id] = m
+-		metadata[id] = m
 -	}
 -	for id, m := range updates {
 -		if m == nil {
--			delete(result.metadata, id)
+-			delete(metadata, id)
 -		} else {
--			result.metadata[id] = m
+-			metadata[id] = m
 -		}
 -	}
--	result.build()
--	return result
+-
+-	// Break import cycles involving updated nodes.
+-	breakImportCycles(metadata, updates)
+-
+-	return newMetadataGraph(metadata)
 -}
 -
--// build constructs g.importedBy and g.uris from g.metadata.
--//
--// TODO(rfindley): we should enforce that the graph is acyclic here.
--func (g *metadataGraph) build() {
+-// newMetadataGraph returns a new metadataGraph,
+-// deriving relations from the specified metadata.
+-func newMetadataGraph(metadata map[PackageID]*source.Metadata) *metadataGraph {
 -	// Build the import graph.
--	g.importedBy = make(map[PackageID][]PackageID)
--	for id, m := range g.metadata {
+-	importedBy := make(map[PackageID][]PackageID)
+-	for id, m := range metadata {
 -		for _, depID := range m.DepsByPkgPath {
--			g.importedBy[depID] = append(g.importedBy[depID], id)
+-			importedBy[depID] = append(importedBy[depID], id)
 -		}
 -	}
 -
 -	// Collect file associations.
--	g.ids = make(map[span.URI][]PackageID)
--	for id, m := range g.metadata {
+-	uriIDs := make(map[span.URI][]PackageID)
+-	for id, m := range metadata {
 -		uris := map[span.URI]struct{}{}
 -		for _, uri := range m.CompiledGoFiles {
 -			uris[uri] = struct{}{}
@@ -15523,12 +18266,12 @@
 -			uris[uri] = struct{}{}
 -		}
 -		for uri := range uris {
--			g.ids[uri] = append(g.ids[uri], id)
+-			uriIDs[uri] = append(uriIDs[uri], id)
 -		}
 -	}
 -
 -	// Sort and filter file associations.
--	for uri, ids := range g.ids {
+-	for uri, ids := range uriIDs {
 -		sort.Slice(ids, func(i, j int) bool {
 -			cli := source.IsCommandLineArguments(ids[i])
 -			clj := source.IsCommandLineArguments(ids[j])
@@ -15550,11 +18293,17 @@
 -			// If we've seen *anything* prior to command-line arguments package, take
 -			// it. Note that ids[0] may itself be command-line-arguments.
 -			if i > 0 && source.IsCommandLineArguments(id) {
--				g.ids[uri] = ids[:i]
+-				uriIDs[uri] = ids[:i]
 -				break
 -			}
 -		}
 -	}
+-
+-	return &metadataGraph{
+-		metadata:   metadata,
+-		importedBy: importedBy,
+-		ids:        uriIDs,
+-	}
 -}
 -
 -// reverseReflexiveTransitiveClosure returns a new mapping containing the
@@ -15576,10 +18325,230 @@
 -	visitAll(ids)
 -	return seen
 -}
+-
+-// breakImportCycles breaks import cycles in the metadata by deleting
+-// Deps* edges. It modifies only metadata present in the 'updates'
+-// subset. This function has an internal test.
+-func breakImportCycles(metadata, updates map[PackageID]*source.Metadata) {
+-	// 'go list' should never report a cycle without flagging it
+-	// as such, but we're extra cautious since we're combining
+-	// information from multiple runs of 'go list'. Also, Bazel
+-	// may silently report cycles.
+-	cycles := detectImportCycles(metadata, updates)
+-	if len(cycles) > 0 {
+-		// There were cycles (uncommon). Break them.
+-		//
+-		// The naive way to break cycles would be to perform a
+-		// depth-first traversal and to detect and delete
+-		// cycle-forming edges as we encounter them.
+-		// However, we're not allowed to modify the existing
+-		// Metadata records, so we can only break edges out of
+-		// the 'updates' subset.
+-		//
+-		// Another possibility would be to delete not the
+-		// cycle forming edge but the topmost edge on the
+-		// stack whose tail is an updated node.
+-		// However, this would require that we retroactively
+-		// undo all the effects of the traversals that
+-		// occurred since that edge was pushed on the stack.
+-		//
+-		// We use a simpler scheme: we compute the set of cycles.
+-		// All cyclic paths necessarily involve at least one
+-		// updated node, so it is sufficient to break all
+-		// edges from each updated node to other members of
+-		// the strong component.
+-		//
+-		// This may result in the deletion of dominating
+-		// edges, causing some dependencies to appear
+-		// spuriously unreachable. Consider A <-> B -> C
+-		// where updates={A,B}. The cycle is {A,B} so the
+-		// algorithm will break both A->B and B->A, causing
+-		// A to no longer depend on B or C.
+-		//
+-		// But that's ok: any error in Metadata.Errors is
+-		// conservatively assumed by snapshot.clone to be a
+-		// potential import cycle error, and causes special
+-		// invalidation so that if B later drops its
+-		// cycle-forming import of A, both A and B will be
+-		// invalidated.
+-		for _, cycle := range cycles {
+-			cyclic := make(map[PackageID]bool)
+-			for _, m := range cycle {
+-				cyclic[m.ID] = true
+-			}
+-			for id := range cyclic {
+-				if m := updates[id]; m != nil {
+-					for path, depID := range m.DepsByImpPath {
+-						if cyclic[depID] {
+-							delete(m.DepsByImpPath, path)
+-						}
+-					}
+-					for path, depID := range m.DepsByPkgPath {
+-						if cyclic[depID] {
+-							delete(m.DepsByPkgPath, path)
+-						}
+-					}
+-
+-					// Set m.Errors to enable special
+-					// invalidation logic in snapshot.clone.
+-					if len(m.Errors) == 0 {
+-						m.Errors = []packages.Error{{
+-							Msg:  "detected import cycle",
+-							Kind: packages.ListError,
+-						}}
+-					}
+-				}
+-			}
+-		}
+-
+-		// double-check when debugging
+-		if false {
+-			if cycles := detectImportCycles(metadata, updates); len(cycles) > 0 {
+-				bug.Reportf("unbroken cycle: %v", cycles)
+-			}
+-		}
+-	}
+-}
+-
+-// detectImportCycles reports cycles in the metadata graph. It returns a new
+-// unordered array of all cycles (nontrivial strong components) in the
+-// metadata graph reachable from a non-nil 'updates' value.
+-func detectImportCycles(metadata, updates map[PackageID]*source.Metadata) [][]*source.Metadata {
+-	// We use the depth-first algorithm of Tarjan.
+-	// https://doi.org/10.1137/0201010
+-	//
+-	// TODO(adonovan): when we can use generics, consider factoring
+-	// in common with the other implementation of Tarjan (in typerefs),
+-	// abstracting over the node and edge representation.
+-
+-	// A node wraps a Metadata with its working state.
+-	// (Unfortunately we can't intrude on shared Metadata.)
+-	type node struct {
+-		rep            *node
+-		m              *source.Metadata
+-		index, lowlink int32
+-		scc            int8 // TODO(adonovan): opt: cram these 1.5 bits into previous word
+-	}
+-	nodes := make(map[PackageID]*node, len(metadata))
+-	nodeOf := func(id PackageID) *node {
+-		n, ok := nodes[id]
+-		if !ok {
+-			m := metadata[id]
+-			if m == nil {
+-				// Dangling import edge.
+-				// Not sure whether a go/packages driver ever
+-				// emits this, but create a dummy node in case.
+-				// Obviously it won't be part of any cycle.
+-				m = &source.Metadata{ID: id}
+-			}
+-			n = &node{m: m}
+-			n.rep = n
+-			nodes[id] = n
+-		}
+-		return n
+-	}
+-
+-	// find returns the canonical node decl.
+-	// (The nodes form a disjoint set forest.)
+-	var find func(*node) *node
+-	find = func(n *node) *node {
+-		rep := n.rep
+-		if rep != n {
+-			rep = find(rep)
+-			n.rep = rep // simple path compression (no union-by-rank)
+-		}
+-		return rep
+-	}
+-
+-	// global state
+-	var (
+-		index int32 = 1
+-		stack []*node
+-		sccs  [][]*source.Metadata // set of nontrivial strongly connected components
+-	)
+-
+-	// visit implements the depth-first search of Tarjan's SCC algorithm
+-	// Precondition: x is canonical.
+-	var visit func(*node)
+-	visit = func(x *node) {
+-		x.index = index
+-		x.lowlink = index
+-		index++
+-
+-		stack = append(stack, x) // push
+-		x.scc = -1
+-
+-		for _, yid := range x.m.DepsByPkgPath {
+-			y := nodeOf(yid)
+-			// Loop invariant: x is canonical.
+-			y = find(y)
+-			if x == y {
+-				continue // nodes already combined (self-edges are impossible)
+-			}
+-
+-			switch {
+-			case y.scc > 0:
+-				// y is already a collapsed SCC
+-
+-			case y.scc < 0:
+-				// y is on the stack, and thus in the current SCC.
+-				if y.index < x.lowlink {
+-					x.lowlink = y.index
+-				}
+-
+-			default:
+-				// y is unvisited; visit it now.
+-				visit(y)
+-				// Note: x and y are now non-canonical.
+-				x = find(x)
+-				if y.lowlink < x.lowlink {
+-					x.lowlink = y.lowlink
+-				}
+-			}
+-		}
+-
+-		// Is x the root of an SCC?
+-		if x.lowlink == x.index {
+-			// Gather all metadata in the SCC (if nontrivial).
+-			var scc []*source.Metadata
+-			for {
+-				// Pop y from stack.
+-				i := len(stack) - 1
+-				y := stack[i]
+-				stack = stack[:i]
+-				if x != y || scc != nil {
+-					scc = append(scc, y.m)
+-				}
+-				if x == y {
+-					break // complete
+-				}
+-				// x becomes y's canonical representative.
+-				y.rep = x
+-			}
+-			if scc != nil {
+-				sccs = append(sccs, scc)
+-			}
+-			x.scc = 1
+-		}
+-	}
+-
+-	// Visit only the updated nodes:
+-	// the existing metadata graph has no cycles,
+-	// so any new cycle must involve an updated node.
+-	for id, m := range updates {
+-		if m != nil {
+-			if n := nodeOf(id); n.index == 0 { // unvisited
+-				visit(n)
+-			}
+-		}
+-	}
+-
+-	return sccs
+-}
 diff -urN a/gopls/internal/lsp/cache/imports.go b/gopls/internal/lsp/cache/imports.go
 --- a/gopls/internal/lsp/cache/imports.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/imports.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,188 +0,0 @@
++++ b/gopls/internal/lsp/cache/imports.go	1970-01-01 08:00:00
+@@ -1,182 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -15611,16 +18580,12 @@
 -	cachedModFileHash      source.Hash
 -	cachedBuildFlags       []string
 -	cachedDirectoryFilters []string
--
--	// runOnce records whether runProcessEnvFunc has been called at least once.
--	// This is necessary to avoid resetting state before the process env is
--	// populated.
--	//
--	// TODO(rfindley): this shouldn't be necessary.
--	runOnce bool
 -}
 -
--func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(*imports.Options) error) error {
+-func (s *importsState) runProcessEnvFunc(ctx context.Context, snapshot *snapshot, fn func(context.Context, *imports.Options) error) error {
+-	ctx, done := event.Start(ctx, "cache.importsState.runProcessEnvFunc")
+-	defer done()
+-
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
@@ -15631,7 +18596,7 @@
 -	// TODO(rfindley): consider instead hashing on-disk modfiles here.
 -	var modFileHash source.Hash
 -	for m := range snapshot.workspaceModFiles {
--		fh, err := snapshot.GetFile(ctx, m)
+-		fh, err := snapshot.ReadFile(ctx, m)
 -		if err != nil {
 -			return err
 -		}
@@ -15640,38 +18605,31 @@
 -
 -	// view.goEnv is immutable -- changes make a new view. Options can change.
 -	// We can't compare build flags directly because we may add -modfile.
--	snapshot.view.optionsMu.Lock()
--	localPrefix := snapshot.view.options.Local
--	currentBuildFlags := snapshot.view.options.BuildFlags
--	currentDirectoryFilters := snapshot.view.options.DirectoryFilters
+-	localPrefix := snapshot.options.Local
+-	currentBuildFlags := snapshot.options.BuildFlags
+-	currentDirectoryFilters := snapshot.options.DirectoryFilters
 -	changed := !reflect.DeepEqual(currentBuildFlags, s.cachedBuildFlags) ||
--		snapshot.view.options.VerboseOutput != (s.processEnv.Logf != nil) ||
+-		snapshot.options.VerboseOutput != (s.processEnv.Logf != nil) ||
 -		modFileHash != s.cachedModFileHash ||
--		!reflect.DeepEqual(snapshot.view.options.DirectoryFilters, s.cachedDirectoryFilters)
--	snapshot.view.optionsMu.Unlock()
+-		!reflect.DeepEqual(snapshot.options.DirectoryFilters, s.cachedDirectoryFilters)
 -
 -	// If anything relevant to imports has changed, clear caches and
 -	// update the processEnv. Clearing caches blocks on any background
 -	// scans.
 -	if changed {
--		// As a special case, skip cleanup the first time -- we haven't fully
--		// initialized the environment yet and calling GetResolver will do
--		// unnecessary work and potentially mess up the go.mod file.
--		if s.runOnce {
--			if resolver, err := s.processEnv.GetResolver(); err == nil {
--				if modResolver, ok := resolver.(*imports.ModuleResolver); ok {
--					modResolver.ClearForNewMod()
--				}
+-		if err := populateProcessEnvFromSnapshot(ctx, s.processEnv, snapshot); err != nil {
+-			return err
+-		}
+-
+-		if resolver, err := s.processEnv.GetResolver(); err == nil {
+-			if modResolver, ok := resolver.(*imports.ModuleResolver); ok {
+-				modResolver.ClearForNewMod()
 -			}
 -		}
 -
 -		s.cachedModFileHash = modFileHash
 -		s.cachedBuildFlags = currentBuildFlags
 -		s.cachedDirectoryFilters = currentDirectoryFilters
--		if err := s.populateProcessEnv(ctx, snapshot); err != nil {
--			return err
--		}
--		s.runOnce = true
 -	}
 -
 -	// Run the user function.
@@ -15687,7 +18645,7 @@
 -		LocalPrefix: localPrefix,
 -	}
 -
--	if err := fn(opts); err != nil {
+-	if err := fn(ctx, opts); err != nil {
 -		return err
 -	}
 -
@@ -15704,12 +18662,14 @@
 -	return nil
 -}
 -
--// populateProcessEnv sets the dynamically configurable fields for the view's
--// process environment. Assumes that the caller is holding the s.view.importsMu.
--func (s *importsState) populateProcessEnv(ctx context.Context, snapshot *snapshot) error {
--	pe := s.processEnv
+-// populateProcessEnvFromSnapshot sets the dynamically configurable fields for
+-// the view's process environment. Assumes that the caller is holding the
+-// importsState mutex.
+-func populateProcessEnvFromSnapshot(ctx context.Context, pe *imports.ProcessEnv, snapshot *snapshot) error {
+-	ctx, done := event.Start(ctx, "cache.populateProcessEnvFromSnapshot")
+-	defer done()
 -
--	if snapshot.view.Options().VerboseOutput {
+-	if snapshot.options.VerboseOutput {
 -		pe.Logf = func(format string, args ...interface{}) {
 -			event.Log(ctx, fmt.Sprintf(format, args...))
 -		}
@@ -15724,7 +18684,7 @@
 -	// and has led to memory leaks in the past, when the snapshot was
 -	// unintentionally held past its lifetime.
 -	_, inv, cleanupInvocation, err := snapshot.goCommandInvocation(ctx, source.LoadWorkspace, &gocommand.Invocation{
--		WorkingDir: snapshot.view.workingDir().Filename(),
+-		WorkingDir: snapshot.view.goCommandDir.Filename(),
 -	})
 -	if err != nil {
 -		return err
@@ -15743,11 +18703,14 @@
 -	// We don't actually use the invocation, so clean it up now.
 -	cleanupInvocation()
 -	// TODO(rfindley): should this simply be inv.WorkingDir?
--	pe.WorkingDir = snapshot.view.workingDir().Filename()
+-	pe.WorkingDir = snapshot.view.goCommandDir.Filename()
 -	return nil
 -}
 -
 -func (s *importsState) refreshProcessEnv() {
+-	ctx, done := event.Start(s.ctx, "cache.importsState.refreshProcessEnv")
+-	defer done()
+-
 -	start := time.Now()
 -
 -	s.mu.Lock()
@@ -15759,9 +18722,9 @@
 -
 -	event.Log(s.ctx, "background imports cache refresh starting")
 -	if err := imports.PrimeCache(context.Background(), env); err == nil {
--		event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)))
+-		event.Log(ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)))
 -	} else {
--		event.Log(s.ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)), keys.Err.Of(err))
+-		event.Log(ctx, fmt.Sprintf("background refresh finished after %v", time.Since(start)), keys.Err.Of(err))
 -	}
 -	s.mu.Lock()
 -	s.cacheRefreshDuration = time.Since(start)
@@ -15770,7 +18733,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/keys.go b/gopls/internal/lsp/cache/keys.go
 --- a/gopls/internal/lsp/cache/keys.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/keys.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cache/keys.go	1970-01-01 08:00:00
 @@ -1,52 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -15826,8 +18789,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/load.go b/gopls/internal/lsp/cache/load.go
 --- a/gopls/internal/lsp/cache/load.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/load.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,782 +0,0 @@
++++ b/gopls/internal/lsp/cache/load.go	1970-01-01 08:00:00
+@@ -1,762 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -15846,10 +18809,10 @@
 -	"time"
 -
 -	"golang.org/x/tools/go/packages"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/gocommand"
@@ -15866,12 +18829,15 @@
 -//
 -// The resulting error may wrap the moduleErrorMap error type, representing
 -// errors associated with specific modules.
+-//
+-// If scopes contains a file scope there must be exactly one scope.
 -func (s *snapshot) load(ctx context.Context, allowNetwork bool, scopes ...loadScope) (err error) {
 -	id := atomic.AddUint64(&loadID, 1)
 -	eventName := fmt.Sprintf("go/packages.Load #%d", id) // unique name for logging
 -
 -	var query []string
 -	var containsDir bool // for logging
+-	var standalone bool  // whether this is a load of a standalone file
 -
 -	// Keep track of module query -> module path so that we can later correlate query
 -	// errors with errors.
@@ -15885,36 +18851,39 @@
 -			query = append(query, string(scope))
 -
 -		case fileLoadScope:
+-			// Given multiple scopes, the resulting load might contain inaccurate
+-			// information. For example go/packages returns at most one command-line
+-			// arguments package, and does not handle a combination of standalone
+-			// files and packages.
 -			uri := span.URI(scope)
+-			if len(scopes) > 1 {
+-				panic(fmt.Sprintf("internal error: load called with multiple scopes when a file scope is present (file: %s)", uri))
+-			}
 -			fh := s.FindFile(uri)
--			if fh == nil || s.View().FileKind(fh) != source.Go {
+-			if fh == nil || s.FileKind(fh) != source.Go {
 -				// Don't try to load a file that doesn't exist, or isn't a go file.
 -				continue
 -			}
--			contents, err := fh.Read()
+-			contents, err := fh.Content()
 -			if err != nil {
 -				continue
 -			}
--			if isStandaloneFile(contents, s.view.Options().StandaloneTags) {
+-			if isStandaloneFile(contents, s.options.StandaloneTags) {
+-				standalone = true
 -				query = append(query, uri.Filename())
 -			} else {
 -				query = append(query, fmt.Sprintf("file=%s", uri.Filename()))
 -			}
 -
 -		case moduleLoadScope:
--			switch scope {
--			case "std", "cmd":
--				query = append(query, string(scope))
--			default:
--				modQuery := fmt.Sprintf("%s/...", scope)
--				query = append(query, modQuery)
--				moduleQueries[modQuery] = string(scope)
--			}
+-			modQuery := fmt.Sprintf("%s%c...", scope.dir, filepath.Separator)
+-			query = append(query, modQuery)
+-			moduleQueries[modQuery] = string(scope.modulePath)
 -
 -		case viewLoadScope:
 -			// If we are outside of GOPATH, a module, or some other known
 -			// build system, don't load subdirectories.
--			if !s.ValidBuildConfiguration() {
+-			if !s.validBuildConfiguration() {
 -				query = append(query, "./")
 -			} else {
 -				query = append(query, "./...")
@@ -15933,7 +18902,7 @@
 -	}
 -	sort.Strings(query) // for determinism
 -
--	ctx, done := event.Start(ctx, "cache.view.load", tag.Query.Of(query))
+-	ctx, done := event.Start(ctx, "cache.snapshot.load", tag.Query.Of(query))
 -	defer done()
 -
 -	flags := source.LoadWorkspace
@@ -15941,7 +18910,7 @@
 -		flags |= source.AllowNetwork
 -	}
 -	_, inv, cleanup, err := s.goCommandInvocation(ctx, flags, &gocommand.Invocation{
--		WorkingDir: s.view.workingDir().Filename(),
+-		WorkingDir: s.view.goCommandDir.Filename(),
 -	})
 -	if err != nil {
 -		return err
@@ -15979,8 +18948,12 @@
 -		return fmt.Errorf("packages.Load error: %w", err)
 -	}
 -
+-	if standalone && len(pkgs) > 1 {
+-		return bug.Errorf("internal error: go/packages returned multiple packages for standalone file")
+-	}
+-
 -	moduleErrs := make(map[string][]packages.Error) // module path -> errors
--	filterFunc := s.view.filterFunc()
+-	filterFunc := s.filterFunc()
 -	newMetadata := make(map[PackageID]*source.Metadata)
 -	for _, pkg := range pkgs {
 -		// The Go command returns synthetic list results for module queries that
@@ -15998,7 +18971,7 @@
 -			continue
 -		}
 -
--		if !containsDir || s.view.Options().VerboseOutput {
+-		if !containsDir || s.options.VerboseOutput {
 -			event.Log(ctx, eventName, append(
 -				source.SnapshotLabels(s),
 -				tag.Package.Of(pkg.ID),
@@ -16031,31 +19004,36 @@
 -		if allFilesExcluded(pkg.GoFiles, filterFunc) {
 -			continue
 -		}
--		if err := buildMetadata(ctx, pkg, cfg, query, newMetadata, nil); err != nil {
--			return err
--		}
+-		buildMetadata(newMetadata, pkg, cfg.Dir, standalone)
 -	}
 -
 -	s.mu.Lock()
 -
+-	// Assert the invariant s.packages.Get(id).m == s.meta.metadata[id].
+-	s.packages.Range(func(id PackageID, ph *packageHandle) {
+-		if s.meta.metadata[id] != ph.m {
+-			panic("inconsistent metadata")
+-		}
+-	})
+-
 -	// Compute the minimal metadata updates (for Clone)
--	// required to preserve this invariant:
--	// for all id, s.packages.Get(id).m == s.meta.metadata[id].
+-	// required to preserve the above invariant.
+-	var files []span.URI // files to preload
+-	seenFiles := make(map[span.URI]bool)
 -	updates := make(map[PackageID]*source.Metadata)
 -	for _, m := range newMetadata {
 -		if existing := s.meta.metadata[m.ID]; existing == nil {
+-			// Record any new files we should pre-load.
+-			for _, uri := range m.CompiledGoFiles {
+-				if !seenFiles[uri] {
+-					seenFiles[uri] = true
+-					files = append(files, uri)
+-				}
+-			}
 -			updates[m.ID] = m
 -			delete(s.shouldLoad, m.ID)
 -		}
 -	}
--	// Assert the invariant.
--	s.packages.Range(func(k, v interface{}) {
--		id, ph := k.(PackageID), v.(*packageHandle)
--		if s.meta.metadata[id] != ph.m {
--			// TODO(adonovan): upgrade to unconditional panic after Jan 2023.
--			bug.Reportf("inconsistent metadata")
--		}
--	})
 -
 -	event.Log(ctx, fmt.Sprintf("%s: updating metadata for %d packages", eventName, len(updates)))
 -
@@ -16065,31 +19043,26 @@
 -	meta := s.meta.Clone(updates)
 -	workspacePackages := computeWorkspacePackagesLocked(s, meta)
 -	for _, update := range updates {
--		if err := computeLoadDiagnostics(ctx, update, meta, lockedSnapshot{s}, workspacePackages); err != nil {
--			return err
--		}
+-		computeLoadDiagnostics(ctx, update, meta, lockedSnapshot{s}, workspacePackages)
 -	}
 -	s.meta = meta
 -	s.workspacePackages = workspacePackages
 -	s.resetActivePackagesLocked()
 -
--	s.dumpWorkspace("load")
 -	s.mu.Unlock()
 -
--	// Recompute the workspace package handle for any packages we invalidated.
+-	// Opt: preLoad files in parallel.
 -	//
--	// This is (putatively) an optimization since handle construction prefetches
--	// the content of all Go source files.
--	//
--	// However, one necessary side effect of this operation is that we are
--	// guaranteed to visit all package files during load. This is required for
--	// e.g. determining the set of directories to watch.
+-	// Requesting files in batch optimizes the underlying filesystem reads.
+-	// However, this is also currently necessary for correctness: populating all
+-	// files in the snapshot is necessary for certain operations that rely on the
+-	// completeness of the file map, e.g. computing the set of directories to
+-	// watch.
 -	//
 -	// TODO(rfindley, golang/go#57558): determine the set of directories based on
--	// loaded packages, and skip this precomputation.
--	for _, m := range updates {
--		s.buildPackageHandle(ctx, m.ID) // ignore error
--	}
+-	// loaded packages, so that reading files here is not necessary for
+-	// correctness.
+-	s.preloadFiles(ctx, files)
 -
 -	if len(moduleErrs) > 0 {
 -		return &moduleErrorMap{moduleErrs}
@@ -16147,12 +19120,12 @@
 -
 -	// Apply diagnostics about the workspace configuration to relevant open
 -	// files.
--	openFiles := s.openFiles()
+-	openFiles := s.overlays()
 -
 -	// If the snapshot does not have a valid build configuration, it may be
 -	// that the user has opened a directory that contains multiple modules.
 -	// Check for that an warn about it.
--	if !s.ValidBuildConfiguration() {
+-	if !s.validBuildConfiguration() {
 -		var msg string
 -		if s.view.goversion >= 18 {
 -			msg = `gopls was not able to find modules in your workspace.
@@ -16171,62 +19144,15 @@
 -		return fmt.Errorf(msg), s.applyCriticalErrorToFiles(ctx, msg, openFiles)
 -	}
 -
--	// If the user has one active go.mod file, they may still be editing files
--	// in nested modules. Check the module of each open file and add warnings
--	// that the nested module must be opened as a workspace folder.
--	if len(s.workspaceModFiles) == 1 {
--		// Get the active root go.mod file to compare against.
--		var rootMod string
--		for uri := range s.workspaceModFiles {
--			rootMod = uri.Filename()
--		}
--		rootDir := filepath.Dir(rootMod)
--		nestedModules := make(map[string][]source.FileHandle)
--		for _, fh := range openFiles {
--			mod, err := findRootPattern(ctx, filepath.Dir(fh.URI().Filename()), "go.mod", s)
--			if err != nil {
--				if ctx.Err() != nil {
--					return ctx.Err(), nil
--				}
--				continue
--			}
--			if mod == "" {
--				continue
--			}
--			if mod != rootMod && source.InDir(rootDir, mod) {
--				modDir := filepath.Dir(mod)
--				nestedModules[modDir] = append(nestedModules[modDir], fh)
--			}
--		}
--		var multiModuleMsg string
--		if s.view.goversion >= 18 {
--			multiModuleMsg = `To work on multiple modules at once, please use a go.work file.
--See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.`
--		} else {
--			multiModuleMsg = `To work on multiple modules at once, please upgrade to Go 1.18 and use a go.work file.
--See https://github.com/golang/tools/blob/master/gopls/doc/workspace.md for more information on using workspaces.`
--		}
--		// Add a diagnostic to each file in a nested module to mark it as
--		// "orphaned". Don't show a general diagnostic in the progress bar,
--		// because the user may still want to edit a file in a nested module.
--		var srcDiags []*source.Diagnostic
--		for modDir, uris := range nestedModules {
--			msg := fmt.Sprintf("This file is in %s, which is a nested module in the %s module.\n%s", modDir, rootMod, multiModuleMsg)
--			srcDiags = append(srcDiags, s.applyCriticalErrorToFiles(ctx, msg, uris)...)
--		}
--		if len(srcDiags) != 0 {
--			return fmt.Errorf("You have opened a nested module.\n%s", multiModuleMsg), srcDiags
--		}
--	}
 -	return nil, nil
 -}
 -
--func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, files []source.FileHandle) []*source.Diagnostic {
+-func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, files []*Overlay) []*source.Diagnostic {
 -	var srcDiags []*source.Diagnostic
 -	for _, fh := range files {
 -		// Place the diagnostics on the package or module declarations.
 -		var rng protocol.Range
--		switch s.view.FileKind(fh) {
+-		switch s.FileKind(fh) {
 -		case source.Go:
 -			if pgf, err := s.ParseGo(ctx, fh, source.ParseHeader); err == nil {
 -				// Check that we have a valid `package foo` range to use for positioning the error.
@@ -16255,35 +19181,29 @@
 -// buildMetadata populates the updates map with metadata updates to
 -// apply, based on the given pkg. It recurs through pkg.Imports to ensure that
 -// metadata exists for all dependencies.
--func buildMetadata(ctx context.Context, pkg *packages.Package, cfg *packages.Config, query []string, updates map[PackageID]*source.Metadata, path []PackageID) error {
+-func buildMetadata(updates map[PackageID]*source.Metadata, pkg *packages.Package, loadDir string, standalone bool) {
 -	// Allow for multiple ad-hoc packages in the workspace (see #47584).
 -	pkgPath := PackagePath(pkg.PkgPath)
 -	id := PackageID(pkg.ID)
+-
 -	if source.IsCommandLineArguments(id) {
--		suffix := ":" + strings.Join(query, ",")
+-		if len(pkg.CompiledGoFiles) != 1 {
+-			bug.Reportf("unexpected files in command-line-arguments package: %v", pkg.CompiledGoFiles)
+-			return
+-		}
+-		suffix := pkg.CompiledGoFiles[0]
 -		id = PackageID(pkg.ID + suffix)
 -		pkgPath = PackagePath(pkg.PkgPath + suffix)
 -	}
 -
+-	// Duplicate?
 -	if _, ok := updates[id]; ok {
--		// If we've already seen this dependency, there may be an import cycle, or
--		// we may have reached the same package transitively via distinct paths.
--		// Check the path to confirm.
--
--		// TODO(rfindley): this doesn't look sufficient. Any single piece of new
--		// metadata could theoretically introduce import cycles in the metadata
--		// graph. What's the point of this limited check here (and is it even
--		// possible to get an import cycle in data from go/packages)? Consider
--		// simply returning, so that this function need not return an error.
--		//
--		// We should consider doing a more complete guard against import cycles
--		// elsewhere.
--		for _, prev := range path {
--			if prev == id {
--				return fmt.Errorf("import cycle detected: %q", id)
--			}
--		}
--		return nil
+-		// A package was encountered twice due to shared
+-		// subgraphs (common) or cycles (rare). Although "go
+-		// list" usually breaks cycles, we don't rely on it.
+-		// breakImportCycles in metadataGraph.Clone takes care
+-		// of it later.
+-		return
 -	}
 -
 -	// Recreate the metadata rather than reusing it to avoid locking.
@@ -16293,10 +19213,11 @@
 -		Name:       PackageName(pkg.Name),
 -		ForTest:    PackagePath(packagesinternal.GetForTest(pkg)),
 -		TypesSizes: pkg.TypesSizes,
--		LoadDir:    cfg.Dir,
+-		LoadDir:    loadDir,
 -		Module:     pkg.Module,
 -		Errors:     pkg.Errors,
 -		DepsErrors: packagesinternal.GetDepsErrors(pkg),
+-		Standalone: standalone,
 -	}
 -
 -	updates[id] = m
@@ -16309,6 +19230,10 @@
 -		uri := span.URIFromPath(filename)
 -		m.GoFiles = append(m.GoFiles, uri)
 -	}
+-	for _, filename := range pkg.IgnoredFiles {
+-		uri := span.URIFromPath(filename)
+-		m.IgnoredFiles = append(m.IgnoredFiles, uri)
+-	}
 -
 -	depsByImpPath := make(map[ImportPath]PackageID)
 -	depsByPkgPath := make(map[PackagePath]PackageID)
@@ -16386,25 +19311,42 @@
 -			continue
 -		}
 -
+-		// Don't record self-import edges.
+-		// (This simplifies metadataGraph's cycle check.)
+-		if PackageID(imported.ID) == id {
+-			if len(pkg.Errors) == 0 {
+-				bug.Reportf("self-import without error in package %s", id)
+-			}
+-			continue
+-		}
+-
+-		buildMetadata(updates, imported, loadDir, false) // only top level packages can be standalone
+-
+-		// Don't record edges to packages with no name, as they cause trouble for
+-		// the importer (golang/go#60952).
+-		//
+-		// However, we do want to insert these packages into the update map
+-		// (buildMetadata above), so that we get type-checking diagnostics for the
+-		// invalid packages.
+-		if imported.Name == "" {
+-			depsByImpPath[importPath] = "" // missing
+-			continue
+-		}
+-
 -		depsByImpPath[importPath] = PackageID(imported.ID)
 -		depsByPkgPath[PackagePath(imported.PkgPath)] = PackageID(imported.ID)
--		if err := buildMetadata(ctx, imported, cfg, query, updates, append(path, id)); err != nil {
--			event.Error(ctx, "error in dependency", err)
--		}
 -	}
 -	m.DepsByImpPath = depsByImpPath
 -	m.DepsByPkgPath = depsByPkgPath
 -
 -	// m.Diagnostics is set later in the loading pass, using
 -	// computeLoadDiagnostics.
--
--	return nil
 -}
 -
 -// computeLoadDiagnostics computes and sets m.Diagnostics for the given metadata m.
 -//
 -// It should only be called during metadata construction in snapshot.load.
--func computeLoadDiagnostics(ctx context.Context, m *source.Metadata, meta *metadataGraph, fs source.FileSource, workspacePackages map[PackageID]PackagePath) error {
+-func computeLoadDiagnostics(ctx context.Context, m *source.Metadata, meta *metadataGraph, fs source.FileSource, workspacePackages map[PackageID]PackagePath) {
 -	for _, packagesErr := range m.Errors {
 -		// Filter out parse errors from go list. We'll get them when we
 -		// actually parse, and buggy overlay support may generate spurious
@@ -16432,10 +19374,8 @@
 -			// not normally fail.
 -			event.Error(ctx, "unable to compute deps errors", err, tag.Package.Of(string(m.ID)))
 -		}
--		return nil
 -	}
 -	m.Diagnostics = append(m.Diagnostics, depsDiags...)
--	return nil
 -}
 -
 -// containsPackageLocked reports whether p is a workspace package for the
@@ -16469,7 +19409,7 @@
 -			uris[uri] = struct{}{}
 -		}
 -
--		filterFunc := s.view.filterFunc()
+-		filterFunc := s.filterFunc()
 -		for uri := range uris {
 -			// Don't use view.contains here. go.work files may include modules
 -			// outside of the workspace folder.
@@ -16497,7 +19437,8 @@
 -	}
 -
 -	for uri := range uris {
--		if s.isOpenLocked(uri) {
+-		fh, _ := s.files.Get(uri)
+-		if _, open := fh.(*Overlay); open {
 -			return true
 -		}
 -	}
@@ -16523,15 +19464,16 @@
 -
 -		// The package's files are in this view. It may be a workspace package.
 -		// Vendored packages are not likely to be interesting to the user.
--		if !strings.Contains(string(uri), "/vendor/") && s.view.contains(uri) {
+-		if !strings.Contains(string(uri), "/vendor/") && s.contains(uri) {
 -			return true
 -		}
 -	}
 -	return false
 -}
 -
--// computeWorkspacePackagesLocked computes workspace packages in the snapshot s
--// for the given metadata graph.
+-// computeWorkspacePackagesLocked computes workspace packages in the
+-// snapshot s for the given metadata graph. The result does not
+-// contain intermediate test variants.
 -//
 -// s.mu must be held while calling this function.
 -func computeWorkspacePackagesLocked(s *snapshot, meta *metadataGraph) map[PackageID]PackagePath {
@@ -16565,6 +19507,7 @@
 -			//
 -			// Notably, this excludes intermediate test variants from workspace
 -			// packages.
+-			assert(!m.IsIntermediateTestVariant(), "unexpected ITV")
 -			workspacePackages[m.ID] = m.ForTest
 -		}
 -	}
@@ -16610,135 +19553,10 @@
 -	}
 -	return true
 -}
-diff -urN a/gopls/internal/lsp/cache/maps.go b/gopls/internal/lsp/cache/maps.go
---- a/gopls/internal/lsp/cache/maps.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/maps.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,121 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package cache
--
--import (
--	"strings"
--
--	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/persistent"
--)
--
--// TODO(euroelessar): Use generics once support for go1.17 is dropped.
--
--type filesMap struct {
--	impl *persistent.Map
--}
--
--// uriLessInterface is the < relation for "any" values containing span.URIs.
--func uriLessInterface(a, b interface{}) bool {
--	return a.(span.URI) < b.(span.URI)
--}
--
--func newFilesMap() filesMap {
--	return filesMap{
--		impl: persistent.NewMap(uriLessInterface),
--	}
--}
--
--func (m filesMap) Clone() filesMap {
--	return filesMap{
--		impl: m.impl.Clone(),
--	}
--}
--
--func (m filesMap) Destroy() {
--	m.impl.Destroy()
--}
--
--func (m filesMap) Get(key span.URI) (source.FileHandle, bool) {
--	value, ok := m.impl.Get(key)
--	if !ok {
--		return nil, false
--	}
--	return value.(source.FileHandle), true
--}
--
--func (m filesMap) Range(do func(key span.URI, value source.FileHandle)) {
--	m.impl.Range(func(key, value interface{}) {
--		do(key.(span.URI), value.(source.FileHandle))
--	})
--}
--
--func (m filesMap) Set(key span.URI, value source.FileHandle) {
--	m.impl.Set(key, value, nil)
--}
--
--func (m filesMap) Delete(key span.URI) {
--	m.impl.Delete(key)
--}
--
--func packageIDLessInterface(x, y interface{}) bool {
--	return x.(PackageID) < y.(PackageID)
--}
--
--type knownDirsSet struct {
--	impl *persistent.Map
--}
--
--func newKnownDirsSet() knownDirsSet {
--	return knownDirsSet{
--		impl: persistent.NewMap(func(a, b interface{}) bool {
--			return a.(span.URI) < b.(span.URI)
--		}),
--	}
--}
--
--func (s knownDirsSet) Clone() knownDirsSet {
--	return knownDirsSet{
--		impl: s.impl.Clone(),
--	}
--}
--
--func (s knownDirsSet) Destroy() {
--	s.impl.Destroy()
--}
--
--func (s knownDirsSet) Contains(key span.URI) bool {
--	_, ok := s.impl.Get(key)
--	return ok
--}
--
--func (s knownDirsSet) Range(do func(key span.URI)) {
--	s.impl.Range(func(key, value interface{}) {
--		do(key.(span.URI))
--	})
--}
--
--func (s knownDirsSet) SetAll(other knownDirsSet) {
--	s.impl.SetAll(other.impl)
--}
--
--func (s knownDirsSet) Insert(key span.URI) {
--	s.impl.Set(key, nil, nil)
--}
--
--func (s knownDirsSet) Remove(key span.URI) {
--	s.impl.Delete(key)
--}
--
--// analysisKeyLessInterface is the less-than relation for analysisKey
--// values wrapped in an interface.
--func analysisKeyLessInterface(a, b interface{}) bool {
--	x, y := a.(analysisKey), b.(analysisKey)
--	if cmp := strings.Compare(x.analyzerNames, y.analyzerNames); cmp != 0 {
--		return cmp < 0
--	}
--	return x.pkgid < y.pkgid
--}
 diff -urN a/gopls/internal/lsp/cache/mod.go b/gopls/internal/lsp/cache/mod.go
 --- a/gopls/internal/lsp/cache/mod.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/mod.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,522 +0,0 @@
++++ b/gopls/internal/lsp/cache/mod.go	1970-01-01 08:00:00
+@@ -1,518 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -16793,7 +19611,7 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -16807,7 +19625,7 @@
 -	_, done := event.Start(ctx, "cache.ParseMod", tag.URI.Of(fh.URI()))
 -	defer done()
 -
--	contents, err := fh.Read()
+-	contents, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -16871,7 +19689,7 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -16884,12 +19702,12 @@
 -	_, done := event.Start(ctx, "cache.ParseWork", tag.URI.Of(fh.URI()))
 -	defer done()
 -
--	contents, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
--	m := protocol.NewMapper(fh.URI(), contents)
--	file, parseErr := modfile.ParseWork(fh.URI().Filename(), contents, nil)
+-	m := protocol.NewMapper(fh.URI(), content)
+-	file, parseErr := modfile.ParseWork(fh.URI().Filename(), content, nil)
 -	// Attempt to convert the error to a standardized parse error.
 -	var parseErrors []*source.Diagnostic
 -	if parseErr != nil {
@@ -16923,7 +19741,7 @@
 -// it doesn't exist, it returns nil.
 -func (s *snapshot) goSum(ctx context.Context, modURI span.URI) []byte {
 -	// Get the go.sum file, either from the snapshot or directly from the
--	// cache. Avoid (*snapshot).GetFile here, as we don't want to add
+-	// cache. Avoid (*snapshot).ReadFile here, as we don't want to add
 -	// nonexistent file handles to the snapshot if the file does not exist.
 -	//
 -	// TODO(rfindley): but that's not right. Changes to sum files should
@@ -16932,12 +19750,12 @@
 -	var sumFH source.FileHandle = s.FindFile(sumURI)
 -	if sumFH == nil {
 -		var err error
--		sumFH, err = s.view.fs.GetFile(ctx, sumURI)
+-		sumFH, err = s.view.fs.ReadFile(ctx, sumURI)
 -		if err != nil {
 -			return nil
 -		}
 -	}
--	content, err := sumFH.Read()
+-	content, err := sumFH.Content()
 -	if err != nil {
 -		return nil
 -	}
@@ -16954,7 +19772,7 @@
 -func (s *snapshot) ModWhy(ctx context.Context, fh source.FileHandle) (map[string]string, error) {
 -	uri := fh.URI()
 -
--	if s.View().FileKind(fh) != source.Mod {
+-	if s.FileKind(fh) != source.Mod {
 -		return nil, fmt.Errorf("%s is not a go.mod file", uri)
 -	}
 -
@@ -16981,7 +19799,7 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -17035,7 +19853,7 @@
 -	}
 -
 -	type locatedErr struct {
--		spn span.Span
+-		loc protocol.Location
 -		msg string
 -	}
 -	diagLocations := map[*source.ParsedModule]locatedErr{}
@@ -17048,7 +19866,7 @@
 -
 -	// Match the error against all the mod files in the workspace.
 -	for _, uri := range s.ModFiles() {
--		fh, err := s.GetFile(ctx, uri)
+-		fh, err := s.ReadFile(ctx, uri)
 -		if err != nil {
 -			event.Error(ctx, "getting modfile for Go command error", err)
 -			continue
@@ -17076,13 +19894,13 @@
 -				// file/position information, so don't even try to find it.
 -				continue
 -			}
--			spn, found, err := s.matchErrorToModule(ctx, pm, msg)
+-			loc, found, err := s.matchErrorToModule(ctx, pm, msg)
 -			if err != nil {
 -				event.Error(ctx, "matching error to module", err)
 -				continue
 -			}
 -			le := locatedErr{
--				spn: spn,
+-				loc: loc,
 -				msg: msg,
 -			}
 -			if found {
@@ -17100,7 +19918,7 @@
 -
 -	var srcErrs []*source.Diagnostic
 -	for pm, le := range diagLocations {
--		diag, err := s.goCommandDiagnostic(pm, le.spn, le.msg)
+-		diag, err := s.goCommandDiagnostic(pm, le.loc, le.msg)
 -		if err != nil {
 -			event.Error(ctx, "building go command diagnostic", err)
 -			continue
@@ -17121,7 +19939,7 @@
 -//
 -// It returns the location of a reference to the one of the modules and true
 -// if one exists. If none is found it returns a fallback location and false.
--func (s *snapshot) matchErrorToModule(ctx context.Context, pm *source.ParsedModule, goCmdError string) (span.Span, bool, error) {
+-func (s *snapshot) matchErrorToModule(ctx context.Context, pm *source.ParsedModule, goCmdError string) (protocol.Location, bool, error) {
 -	var reference *modfile.Line
 -	matches := moduleVersionInErrorRe.FindAllStringSubmatch(goCmdError, -1)
 -
@@ -17140,25 +19958,21 @@
 -		// No match for the module path was found in the go.mod file.
 -		// Show the error on the module declaration, if one exists, or
 -		// just the first line of the file.
--		if pm.File.Module == nil {
--			return span.New(pm.URI, span.NewPoint(1, 1, 0), span.Point{}), false, nil
+-		var start, end int
+-		if pm.File.Module != nil && pm.File.Module.Syntax != nil {
+-			syntax := pm.File.Module.Syntax
+-			start, end = syntax.Start.Byte, syntax.End.Byte
 -		}
--		syntax := pm.File.Module.Syntax
--		spn, err := pm.Mapper.OffsetSpan(syntax.Start.Byte, syntax.End.Byte)
--		return spn, false, err
+-		loc, err := pm.Mapper.OffsetLocation(start, end)
+-		return loc, false, err
 -	}
 -
--	spn, err := pm.Mapper.OffsetSpan(reference.Start.Byte, reference.End.Byte)
--	return spn, true, err
+-	loc, err := pm.Mapper.OffsetLocation(reference.Start.Byte, reference.End.Byte)
+-	return loc, true, err
 -}
 -
 -// goCommandDiagnostic creates a diagnostic for a given go command error.
--func (s *snapshot) goCommandDiagnostic(pm *source.ParsedModule, spn span.Span, goCmdError string) (*source.Diagnostic, error) {
--	rng, err := pm.Mapper.SpanRange(spn)
--	if err != nil {
--		return nil, err
--	}
--
+-func (s *snapshot) goCommandDiagnostic(pm *source.ParsedModule, loc protocol.Location, goCmdError string) (*source.Diagnostic, error) {
 -	matches := moduleVersionInErrorRe.FindAllStringSubmatch(goCmdError, -1)
 -	var innermost *module.Version
 -	for i := len(matches) - 1; i >= 0; i-- {
@@ -17178,7 +19992,7 @@
 -		}
 -		return &source.Diagnostic{
 -			URI:      pm.URI,
--			Range:    rng,
+-			Range:    loc.Range,
 -			Severity: protocol.SeverityError,
 -			Source:   source.ListError,
 -			Message: `Inconsistent vendoring detected. Please re-run "go mod vendor".
@@ -17205,7 +20019,7 @@
 -		}
 -		return &source.Diagnostic{
 -			URI:      pm.URI,
--			Range:    rng,
+-			Range:    loc.Range,
 -			Severity: protocol.SeverityError,
 -			Source:   source.ListError,
 -			Message:  msg,
@@ -17226,7 +20040,7 @@
 -		}
 -		return &source.Diagnostic{
 -			URI:            pm.URI,
--			Range:          rng,
+-			Range:          loc.Range,
 -			Severity:       protocol.SeverityError,
 -			Message:        fmt.Sprintf("%v@%v has not been downloaded", innermost.Path, innermost.Version),
 -			Source:         source.ListError,
@@ -17235,7 +20049,7 @@
 -	default:
 -		return &source.Diagnostic{
 -			URI:      pm.URI,
--			Range:    rng,
+-			Range:    loc.Range,
 -			Severity: protocol.SeverityError,
 -			Source:   source.ListError,
 -			Message:  goCmdError,
@@ -17263,8 +20077,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/mod_tidy.go b/gopls/internal/lsp/cache/mod_tidy.go
 --- a/gopls/internal/lsp/cache/mod_tidy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/mod_tidy.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,469 +0,0 @@
++++ b/gopls/internal/lsp/cache/mod_tidy.go	1970-01-01 08:00:00
+@@ -1,501 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -17275,7 +20089,7 @@
 -	"context"
 -	"fmt"
 -	"go/ast"
--	"io/ioutil"
+-	"go/token"
 -	"os"
 -	"path/filepath"
 -	"strconv"
@@ -17295,6 +20109,9 @@
 -// ModTidy returns the go.mod file that would be obtained by running
 -// "go mod tidy". Concurrent requests are combined into a single command.
 -func (s *snapshot) ModTidy(ctx context.Context, pm *source.ParsedModule) (*source.TidiedModule, error) {
+-	ctx, done := event.Start(ctx, "cache.snapshot.ModTidy")
+-	defer done()
+-
 -	uri := pm.URI
 -	if pm.File == nil {
 -		return nil, fmt.Errorf("cannot tidy unparseable go.mod file: %v", uri)
@@ -17314,7 +20131,7 @@
 -		// If the file handle is an overlay, it may not be written to disk.
 -		// The go.mod file has to be on disk for `go mod tidy` to work.
 -		// TODO(rfindley): is this still true with Go 1.16 overlay support?
--		fh, err := s.GetFile(ctx, pm.URI)
+-		fh, err := s.ReadFile(ctx, pm.URI)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -17324,7 +20141,7 @@
 -			}
 -		}
 -
--		if criticalErr := s.GetCriticalError(ctx); criticalErr != nil {
+-		if criticalErr := s.CriticalError(ctx); criticalErr != nil {
 -			return &source.TidiedModule{
 -				Diagnostics: criticalErr.Diagnostics,
 -			}, nil
@@ -17349,7 +20166,7 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -17381,7 +20198,7 @@
 -
 -	// Go directly to disk to get the temporary mod file,
 -	// since it is always on disk.
--	tempContents, err := ioutil.ReadFile(tmpURI.Filename())
+-	tempContents, err := os.ReadFile(tmpURI.Filename())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -17432,7 +20249,7 @@
 -	for _, req := range wrongDirectness {
 -		// Handle dependencies that are incorrectly labeled indirect and
 -		// vice versa.
--		srcDiag, err := directnessDiagnostic(pm.Mapper, req, snapshot.View().Options().ComputeEdits)
+-		srcDiag, err := directnessDiagnostic(pm.Mapper, req, snapshot.Options().ComputeEdits)
 -		if err != nil {
 -			// We're probably in a bad state if we can't compute a
 -			// directnessDiagnostic, but try to keep going so as to not suppress
@@ -17446,7 +20263,33 @@
 -	// go.mod file. The fixes will be for the go.mod file, but the
 -	// diagnostics should also appear in both the go.mod file and the import
 -	// statements in the Go files in which the dependencies are used.
+-	// Finally, add errors for any unused dependencies.
+-	if len(missing) > 0 {
+-		missingModuleDiagnostics, err := missingModuleDiagnostics(ctx, snapshot, pm, ideal, missing)
+-		if err != nil {
+-			return nil, err
+-		}
+-		diagnostics = append(diagnostics, missingModuleDiagnostics...)
+-	}
+-
+-	// Opt: if this is the only diagnostic, we can avoid textual edits and just
+-	// run the Go command.
+-	//
+-	// See also the documentation for command.RemoveDependencyArgs.OnlyDiagnostic.
+-	onlyDiagnostic := len(diagnostics) == 0 && len(unused) == 1
+-	for _, req := range unused {
+-		srcErr, err := unusedDiagnostic(pm.Mapper, req, onlyDiagnostic)
+-		if err != nil {
+-			return nil, err
+-		}
+-		diagnostics = append(diagnostics, srcErr)
+-	}
+-	return diagnostics, nil
+-}
+-
+-func missingModuleDiagnostics(ctx context.Context, snapshot *snapshot, pm *source.ParsedModule, ideal *modfile.File, missing map[string]*modfile.Require) ([]*source.Diagnostic, error) {
 -	missingModuleFixes := map[*modfile.Require][]source.SuggestedFix{}
+-	var diagnostics []*source.Diagnostic
 -	for _, req := range missing {
 -		srcDiag, err := missingModuleDiagnostic(pm, req)
 -		if err != nil {
@@ -17455,12 +20298,24 @@
 -		missingModuleFixes[req] = srcDiag.SuggestedFixes
 -		diagnostics = append(diagnostics, srcDiag)
 -	}
+-
 -	// Add diagnostics for missing modules anywhere they are imported in the
 -	// workspace.
+-	metas, err := snapshot.WorkspaceMetadata(ctx)
+-	if err != nil {
+-		return nil, err
+-	}
 -	// TODO(adonovan): opt: opportunities for parallelism abound.
--	for _, m := range snapshot.workspaceMetadata() {
--		// Read both lists of files of this package, in parallel.
--		goFiles, compiledGoFiles, err := readGoFiles(ctx, snapshot, m)
+-	for _, m := range metas {
+-		// Read both lists of files of this package.
+-		//
+-		// Parallelism is not necessary here as the files will have already been
+-		// pre-read at load time.
+-		goFiles, err := readFiles(ctx, snapshot, m.GoFiles)
+-		if err != nil {
+-			return nil, err
+-		}
+-		compiledGoFiles, err := readFiles(ctx, snapshot, m.CompiledGoFiles)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -17541,15 +20396,6 @@
 -			}
 -		}
 -	}
--	// Finally, add errors for any unused dependencies.
--	onlyDiagnostic := len(diagnostics) == 0 && len(unused) == 1
--	for _, req := range unused {
--		srcErr, err := unusedDiagnostic(pm.Mapper, req, onlyDiagnostic)
--		if err != nil {
--			return nil, err
--		}
--		diagnostics = append(diagnostics, srcErr)
--	}
 -	return diagnostics, nil
 -}
 -
@@ -17720,7 +20566,7 @@
 -//
 -// TODO(rfindley): this should key off source.ImportPath.
 -func parseImports(ctx context.Context, s *snapshot, files []source.FileHandle) (map[string]bool, error) {
--	pgfs, _, err := s.parseCache.parseFiles(ctx, source.ParseHeader, files...)
+-	pgfs, err := s.view.parseCache.parseFiles(ctx, token.NewFileSet(), source.ParseHeader, false, files...)
 -	if err != nil { // e.g. context cancellation
 -		return nil, err
 -	}
@@ -17736,8 +20582,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/mod_vuln.go b/gopls/internal/lsp/cache/mod_vuln.go
 --- a/gopls/internal/lsp/cache/mod_vuln.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/mod_vuln.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,75 +0,0 @@
++++ b/gopls/internal/lsp/cache/mod_vuln.go	1970-01-01 08:00:00
+@@ -1,48 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -17746,45 +20592,29 @@
 -
 -import (
 -	"context"
--	"os"
 -
--	"golang.org/x/tools/gopls/internal/govulncheck"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
 -	"golang.org/x/tools/gopls/internal/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/scan"
 -	"golang.org/x/tools/internal/memoize"
 -)
 -
 -// ModVuln returns import vulnerability analysis for the given go.mod URI.
 -// Concurrent requests are combined into a single command.
--func (s *snapshot) ModVuln(ctx context.Context, modURI span.URI) (*govulncheck.Result, error) {
+-func (s *snapshot) ModVuln(ctx context.Context, modURI span.URI) (*vulncheck.Result, error) {
 -	s.mu.Lock()
 -	entry, hit := s.modVulnHandles.Get(modURI)
 -	s.mu.Unlock()
 -
 -	type modVuln struct {
--		result *govulncheck.Result
+-		result *vulncheck.Result
 -		err    error
 -	}
 -
 -	// Cache miss?
 -	if !hit {
--		// If the file handle is an overlay, it may not be written to disk.
--		// The go.mod file has to be on disk for vulncheck to work.
--		//
--		// TODO(hyangah): use overlays for vulncheck.
--		fh, err := s.GetFile(ctx, modURI)
--		if err != nil {
--			return nil, err
--		}
--		if _, ok := fh.(*Overlay); ok {
--			if info, _ := os.Stat(modURI.Filename()); info == nil {
--				return nil, source.ErrNoModOnDisk
--			}
--		}
--
 -		handle := memoize.NewPromise("modVuln", func(ctx context.Context, arg interface{}) interface{} {
--			result, err := modVulnImpl(ctx, arg.(*snapshot), modURI)
+-			result, err := scan.VulnerablePackages(ctx, arg.(*snapshot))
 -			return modVuln{result, err}
 -		})
 -
@@ -17795,27 +20625,16 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
 -	res := v.(modVuln)
 -	return res.result, res.err
 -}
--
--func modVulnImpl(ctx context.Context, s *snapshot, uri span.URI) (*govulncheck.Result, error) {
--	if vulncheck.VulnerablePackages == nil {
--		return &govulncheck.Result{}, nil
--	}
--	fh, err := s.GetFile(ctx, uri)
--	if err != nil {
--		return nil, err
--	}
--	return vulncheck.VulnerablePackages(ctx, s, fh)
--}
 diff -urN a/gopls/internal/lsp/cache/os_darwin.go b/gopls/internal/lsp/cache/os_darwin.go
 --- a/gopls/internal/lsp/cache/os_darwin.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/os_darwin.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cache/os_darwin.go	1970-01-01 08:00:00
 @@ -1,59 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -17878,7 +20697,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/os_windows.go b/gopls/internal/lsp/cache/os_windows.go
 --- a/gopls/internal/lsp/cache/os_windows.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/os_windows.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cache/os_windows.go	1970-01-01 08:00:00
 @@ -1,56 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -17936,458 +20755,10 @@
 -	}
 -	return nil
 -}
-diff -urN a/gopls/internal/lsp/cache/parse_cache.go b/gopls/internal/lsp/cache/parse_cache.go
---- a/gopls/internal/lsp/cache/parse_cache.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/parse_cache.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,298 +0,0 @@
--// Copyright 2023 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package cache
--
--import (
--	"container/heap"
--	"context"
--	"go/token"
--	"runtime"
--	"sort"
--	"sync"
--
--	"golang.org/x/sync/errgroup"
--	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/internal/memoize"
--)
--
--// This file contains an implementation of a bounded-size parse cache, that
--// offsets the base token.Pos value of each cached file so that they may be
--// later described by a single dedicated FileSet.
--//
--// This is achieved by tracking a monotonic offset in the token.Pos space, that
--// is incremented before parsing allow room for the resulting parsed file.
--
--// Keep 200 recently parsed files, based on the following rationale:
--//   - One of the most important benefits of caching is avoiding re-parsing
--//     everything in a package when working on a single file. No packages in
--//     Kubernetes have > 200 files (only one has > 100).
--//   - Experience has shown that ~1000 parsed files can use noticeable space.
--//     200 feels like a sweet spot between limiting cache size and optimizing
--//     cache hits for low-latency operations.
--const parseCacheMaxFiles = 200
--
--// parsePadding is additional padding allocated between entries in the parse
--// cache to allow for increases in length (such as appending missing braces)
--// caused by fixAST.
--//
--// This is used to mitigate a chicken and egg problem: we must know the base
--// offset of the file we're about to parse, before we start parsing, and yet
--// src fixups may affect the actual size of the parsed content (and therefore
--// the offsets of subsequent files).
--//
--// When we encounter a file that no longer fits in its allocated space in the
--// fileset, we have no choice but to re-parse it. Leaving a generous padding
--// reduces the likelihood of this "slow path".
--//
--// This value is mutable for testing, so that we can exercise the slow path.
--var parsePadding = 1000 // mutable for testing
--
--// A parseCache holds a bounded number of recently accessed parsed Go files. As
--// new files are stored, older files may be evicted from the cache.
--//
--// The parseCache.parseFiles method exposes a batch API for parsing (and
--// caching) multiple files. This is necessary for type-checking, where files
--// must be parsed in a common fileset.
--type parseCache struct {
--	mu         sync.Mutex
--	m          map[parseKey]*parseCacheEntry
--	lru        queue     // min-atime priority queue of *parseCacheEntry
--	clock      uint64    // clock time, incremented when the cache is updated
--	nextOffset token.Pos // token.Pos offset for the next parsed file
--}
--
--// parseKey uniquely identifies a parsed Go file.
--type parseKey struct {
--	file source.FileIdentity
--	mode source.ParseMode
--}
--
--type parseCacheEntry struct {
--	key      parseKey
--	promise  *memoize.Promise // memoize.Promise[*source.ParsedGoFile]
--	atime    uint64           // clock time of last access
--	lruIndex int
--}
--
--// startParse prepares a parsing pass, using the following steps:
--//   - search for cache hits
--//   - create new promises for cache misses
--//   - store as many new promises in the cache as space will allow
--//
--// The resulting slice has an entry for every given file handle, though some
--// entries may be nil if there was an error reading the file (in which case the
--// resulting error will be non-nil).
--func (c *parseCache) startParse(mode source.ParseMode, fhs ...source.FileHandle) ([]*memoize.Promise, error) {
--	c.mu.Lock()
--	defer c.mu.Unlock()
--
--	// Any parsing pass increments the clock, as we'll update access times.
--	// (technically, if fhs is empty this isn't necessary, but that's a degenerate case).
--	//
--	// All entries parsed from a single call get the same access time.
--	c.clock++
--
--	// Read file data and collect cacheable files.
--	var (
--		data           = make([][]byte, len(fhs)) // file content for each readable file
--		promises       = make([]*memoize.Promise, len(fhs))
--		firstReadError error // first error from fh.Read, or nil
--	)
--	for i, fh := range fhs {
--		src, err := fh.Read()
--		if err != nil {
--			if firstReadError == nil {
--				firstReadError = err
--			}
--			continue
--		}
--		data[i] = src
--
--		key := parseKey{
--			file: fh.FileIdentity(),
--			mode: mode,
--		}
--
--		// Check for a cache hit.
--		if e, ok := c.m[key]; ok {
--			e.atime = c.clock
--			heap.Fix(&c.lru, e.lruIndex)
--			promises[i] = e.promise
--			continue
--		}
--
--		// ...otherwise, create a new promise to parse with a non-overlapping offset
--		fset := token.NewFileSet()
--		if c.nextOffset > 0 {
--			// Add a dummy file so that this parsed file does not overlap with others.
--			fset.AddFile("", 1, int(c.nextOffset))
--		}
--		c.nextOffset += token.Pos(len(src) + parsePadding + 1) // leave room for src fixes
--		fh := fh
--		promise := memoize.NewPromise(string(fh.URI()), func(ctx context.Context, _ interface{}) interface{} {
--			return parseGoSrc(ctx, fset, fh.URI(), src, mode)
--		})
--		promises[i] = promise
--
--		var e *parseCacheEntry
--		if len(c.lru) < parseCacheMaxFiles {
--			// add new entry
--			e = new(parseCacheEntry)
--			if c.m == nil {
--				c.m = make(map[parseKey]*parseCacheEntry)
--			}
--		} else {
--			// evict oldest entry
--			e = heap.Pop(&c.lru).(*parseCacheEntry)
--			delete(c.m, e.key)
--		}
--		e.key = key
--		e.promise = promise
--		e.atime = c.clock
--		c.m[e.key] = e
--		heap.Push(&c.lru, e)
--	}
--
--	if len(c.m) != len(c.lru) {
--		panic("map and LRU are inconsistent")
--	}
--
--	return promises, firstReadError
--}
--
--// parseFiles returns a ParsedGoFile for the given file handles in the
--// requested parse mode.
--//
--// If parseFiles returns an error, it still returns a slice,
--// but with a nil entry for each file that could not be parsed.
--//
--// The second result is a FileSet describing all resulting parsed files.
--//
--// For parsed files that already exists in the cache, access time will be
--// updated. For others, parseFiles will parse and store as many results in the
--// cache as space allows.
--func (c *parseCache) parseFiles(ctx context.Context, mode source.ParseMode, fhs ...source.FileHandle) ([]*source.ParsedGoFile, *token.FileSet, error) {
--	promises, firstReadError := c.startParse(mode, fhs...)
--
--	// Await all parsing.
--	var g errgroup.Group
--	g.SetLimit(runtime.GOMAXPROCS(-1)) // parsing is CPU-bound.
--	pgfs := make([]*source.ParsedGoFile, len(fhs))
--	for i, promise := range promises {
--		if promise == nil {
--			continue
--		}
--		i := i
--		promise := promise
--		g.Go(func() error {
--			result, err := promise.Get(ctx, nil)
--			if err != nil {
--				return err
--			}
--			pgfs[i] = result.(*source.ParsedGoFile)
--			return nil
--		})
--	}
--	if err := g.Wait(); err != nil {
--		return nil, nil, err
--	}
--
--	// Construct a token.FileSet mapping all parsed files, and update their
--	// Tok to the corresponding file in the new fileset.
--	//
--	// In the unlikely event that a parsed file no longer fits in its allocated
--	// space in the FileSet range, it will need to be re-parsed.
--
--	var tokenFiles []*token.File
--	fileIndex := make(map[*token.File]int) // to look up original indexes after sorting
--	for i, pgf := range pgfs {
--		if pgf == nil {
--			continue
--		}
--		fileIndex[pgf.Tok] = i
--		tokenFiles = append(tokenFiles, pgf.Tok)
--	}
--
--	sort.Slice(tokenFiles, func(i, j int) bool {
--		return tokenFiles[i].Base() < tokenFiles[j].Base()
--	})
--
--	var needReparse []int // files requiring reparsing
--	out := tokenFiles[:0]
--	for i, f := range tokenFiles {
--		if i < len(tokenFiles)-1 && f.Base()+f.Size() >= tokenFiles[i+1].Base() {
--			if f != tokenFiles[i+1] { // no need to re-parse duplicates
--				needReparse = append(needReparse, fileIndex[f])
--			}
--		} else {
--			out = append(out, f)
--		}
--	}
--	fset := source.FileSetFor(out...)
--
--	// Re-parse any remaining files using the stitched fileSet.
--	for _, i := range needReparse {
--		// Start from scratch, rather than using ParsedGoFile.Src, so that source
--		// fixing operates exactly the same (note that fixing stops after a limited
--		// number of tries).
--		fh := fhs[i]
--		src, err := fh.Read()
--		if err != nil {
--			if firstReadError == nil {
--				firstReadError = err
--			}
--			continue
--		}
--		pgfs[i] = parseGoSrc(ctx, fset, fh.URI(), src, mode)
--	}
--
--	// Ensure each PGF refers to a token.File from the new FileSet.
--	for i, pgf := range pgfs {
--		if pgf == nil {
--			continue
--		}
--		newTok := fset.File(token.Pos(pgf.Tok.Base()))
--		if newTok == nil {
--			panic("internal error: missing tok for " + pgf.URI)
--		}
--		if newTok.Base() != pgf.Tok.Base() || newTok.Size() != pgf.Tok.Size() {
--			panic("internal error: mismatching token.File in synthetic FileSet")
--		}
--		pgf2 := *pgf
--		pgf2.Tok = newTok
--		pgfs[i] = &pgf2
--	}
--
--	return pgfs, fset, firstReadError
--}
--
--// -- priority queue boilerplate --
--
--// queue is a min-atime prority queue of cache entries.
--type queue []*parseCacheEntry
--
--func (q queue) Len() int { return len(q) }
--
--func (q queue) Less(i, j int) bool { return q[i].atime < q[j].atime }
--
--func (q queue) Swap(i, j int) {
--	q[i], q[j] = q[j], q[i]
--	q[i].lruIndex = i
--	q[j].lruIndex = j
--}
--
--func (q *queue) Push(x interface{}) {
--	e := x.(*parseCacheEntry)
--	e.lruIndex = len(*q)
--	*q = append(*q, e)
--}
--
--func (q *queue) Pop() interface{} {
--	last := len(*q) - 1
--	e := (*q)[last]
--	(*q)[last] = nil // aid GC
--	*q = (*q)[:last]
--	return e
--}
-diff -urN a/gopls/internal/lsp/cache/parse_cache_test.go b/gopls/internal/lsp/cache/parse_cache_test.go
---- a/gopls/internal/lsp/cache/parse_cache_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/parse_cache_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,142 +0,0 @@
--// Copyright 2023 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package cache
--
--import (
--	"context"
--	"fmt"
--	"go/token"
--	"testing"
--
--	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/span"
--)
--
--func TestParseCache(t *testing.T) {
--	ctx := context.Background()
--	uri := span.URI("file:///myfile")
--	fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\""))
--
--	var cache parseCache
--	pgfs1, _, err := cache.parseFiles(ctx, source.ParseFull, fh)
--	if err != nil {
--		t.Fatal(err)
--	}
--	pgf1 := pgfs1[0]
--	pgfs2, _, err := cache.parseFiles(ctx, source.ParseFull, fh)
--	pgf2 := pgfs2[0]
--	if err != nil {
--		t.Fatal(err)
--	}
--	if pgf1.File != pgf2.File {
--		t.Errorf("parseFiles(%q): unexpected cache miss on repeated call", uri)
--	}
--
--	// Fill up the cache with other files, but don't evict the file above.
--	files := []source.FileHandle{fh}
--	files = append(files, dummyFileHandles(parseCacheMaxFiles-1)...)
--	pgfs3, fset, err := cache.parseFiles(ctx, source.ParseFull, files...)
--	pgf3 := pgfs3[0]
--	if pgf3.File != pgf1.File {
--		t.Errorf("parseFiles(%q, ...): unexpected cache miss", uri)
--	}
--	if pgf3.Tok == pgf1.Tok {
--		t.Errorf("parseFiles(%q, ...): unexpectedly matching token file", uri)
--	}
--	if pgf3.Tok.Base() != pgf1.Tok.Base() || pgf3.Tok.Size() != pgf1.Tok.Size() {
--		t.Errorf("parseFiles(%q, ...): result.Tok has base: %d, size: %d, want (%d, %d)", uri, pgf3.Tok.Base(), pgf3.Tok.Size(), pgf1.Tok.Base(), pgf1.Tok.Size())
--	}
--	if tok := fset.File(token.Pos(pgf3.Tok.Base())); tok != pgf3.Tok {
--		t.Errorf("parseFiles(%q, ...): result.Tok not contained in FileSet", uri)
--	}
--
--	// Now overwrite the cache, after which we should get new results.
--	files = dummyFileHandles(parseCacheMaxFiles)
--	_, _, err = cache.parseFiles(ctx, source.ParseFull, files...)
--	if err != nil {
--		t.Fatal(err)
--	}
--	pgfs4, _, err := cache.parseFiles(ctx, source.ParseFull, fh)
--	if err != nil {
--		t.Fatal(err)
--	}
--	if pgfs4[0].File == pgf1.File {
--		t.Errorf("parseFiles(%q): unexpected cache hit after overwriting cache", uri)
--	}
--}
--
--func TestParseCache_Reparsing(t *testing.T) {
--	defer func(padding int) {
--		parsePadding = padding
--	}(parsePadding)
--	parsePadding = 0
--
--	files := dummyFileHandles(parseCacheMaxFiles)
--	danglingSelector := []byte("package p\nfunc _() {\n\tx.\n}")
--	files = append(files, makeFakeFileHandle("file:///bad1", danglingSelector))
--	files = append(files, makeFakeFileHandle("file:///bad2", danglingSelector))
--
--	// Parsing should succeed even though we overflow the padding.
--	var cache parseCache
--	_, _, err := cache.parseFiles(context.Background(), source.ParseFull, files...)
--	if err != nil {
--		t.Fatal(err)
--	}
--}
--
--func TestParseCache_Duplicates(t *testing.T) {
--	ctx := context.Background()
--	uri := span.URI("file:///myfile")
--	fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\""))
--
--	var cache parseCache
--	pgfs, _, err := cache.parseFiles(ctx, source.ParseFull, fh, fh)
--	if err != nil {
--		t.Fatal(err)
--	}
--	if pgfs[0].File != pgfs[1].File {
--		t.Errorf("parseFiles(fh, fh): = [%p, %p], want duplicate files", pgfs[0].File, pgfs[1].File)
--	}
--}
--
--func dummyFileHandles(n int) []source.FileHandle {
--	var fhs []source.FileHandle
--	for i := 0; i < n; i++ {
--		uri := span.URI(fmt.Sprintf("file:///_%d", i))
--		src := []byte(fmt.Sprintf("package p\nvar _ = %d", i))
--		fhs = append(fhs, makeFakeFileHandle(uri, src))
--	}
--	return fhs
--}
--
--func makeFakeFileHandle(uri span.URI, src []byte) fakeFileHandle {
--	return fakeFileHandle{
--		uri:  uri,
--		data: src,
--		hash: source.HashOf(src),
--	}
--}
--
--type fakeFileHandle struct {
--	source.FileHandle
--	uri  span.URI
--	data []byte
--	hash source.Hash
--}
--
--func (h fakeFileHandle) URI() span.URI {
--	return h.uri
--}
--
--func (h fakeFileHandle) Read() ([]byte, error) {
--	return h.data, nil
--}
--
--func (h fakeFileHandle) FileIdentity() source.FileIdentity {
--	return source.FileIdentity{
--		URI:  h.uri,
--		Hash: h.hash,
--	}
--}
 diff -urN a/gopls/internal/lsp/cache/parse.go b/gopls/internal/lsp/cache/parse.go
 --- a/gopls/internal/lsp/cache/parse.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/parse.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,900 +0,0 @@
++++ b/gopls/internal/lsp/cache/parse.go	1970-01-01 08:00:00
+@@ -1,969 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -18405,6 +20776,7 @@
 -	"path/filepath"
 -	"reflect"
 -
+-	goplsastutil "golang.org/x/tools/gopls/internal/astutil"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
@@ -18416,8 +20788,8 @@
 -
 -// ParseGo parses the file whose contents are provided by fh, using a cache.
 -// The resulting tree may have beeen fixed up.
--func (s *snapshot) ParseGo(ctx context.Context, fh source.FileHandle, mode source.ParseMode) (*source.ParsedGoFile, error) {
--	pgfs, _, err := s.parseCache.parseFiles(ctx, mode, fh)
+-func (s *snapshot) ParseGo(ctx context.Context, fh source.FileHandle, mode parser.Mode) (*source.ParsedGoFile, error) {
+-	pgfs, err := s.view.parseCache.parseFiles(ctx, token.NewFileSet(), mode, false, fh)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -18425,29 +20797,34 @@
 -}
 -
 -// parseGoImpl parses the Go source file whose content is provided by fh.
--func parseGoImpl(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode source.ParseMode) (*source.ParsedGoFile, error) {
--	ctx, done := event.Start(ctx, "cache.parseGo", tag.File.Of(fh.URI().Filename()))
--	defer done()
--
+-func parseGoImpl(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode parser.Mode, purgeFuncBodies bool) (*source.ParsedGoFile, error) {
 -	ext := filepath.Ext(fh.URI().Filename())
 -	if ext != ".go" && ext != "" { // files generated by cgo have no extension
 -		return nil, fmt.Errorf("cannot parse non-Go file %s", fh.URI())
 -	}
--	src, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
--	return parseGoSrc(ctx, fset, fh.URI(), src, mode), nil
+-	// Check for context cancellation before actually doing the parse.
+-	if ctx.Err() != nil {
+-		return nil, ctx.Err()
+-	}
+-	pgf, _ := ParseGoSrc(ctx, fset, fh.URI(), content, mode, purgeFuncBodies)
+-	return pgf, nil
 -}
 -
--// parseGoSrc parses a buffer of Go source, repairing the tree if necessary.
--func parseGoSrc(ctx context.Context, fset *token.FileSet, uri span.URI, src []byte, mode source.ParseMode) (res *source.ParsedGoFile) {
--	parserMode := parser.AllErrors | parser.ParseComments
--	if mode == source.ParseHeader {
--		parserMode = parser.ImportsOnly | parser.ParseComments
+-// ParseGoSrc parses a buffer of Go source, repairing the tree if necessary.
+-//
+-// The provided ctx is used only for logging.
+-func ParseGoSrc(ctx context.Context, fset *token.FileSet, uri span.URI, src []byte, mode parser.Mode, purgeFuncBodies bool) (res *source.ParsedGoFile, fixes []fixType) {
+-	if purgeFuncBodies {
+-		src = goplsastutil.PurgeFuncBodies(src)
 -	}
+-	ctx, done := event.Start(ctx, "cache.ParseGoSrc", tag.File.Of(uri.Filename()))
+-	defer done()
 -
--	file, err := parser.ParseFile(fset, uri.Filename(), src, parserMode)
+-	file, err := parser.ParseFile(fset, uri.Filename(), src, mode)
 -	var parseErr scanner.ErrorList
 -	if err != nil {
 -		// We passed a byte slice, so the only possible error is a parse error.
@@ -18463,15 +20840,20 @@
 -		tok.SetLinesForContent(src)
 -	}
 -
--	fixed := false
+-	fixedSrc := false
+-	fixedAST := false
 -	// If there were parse errors, attempt to fix them up.
 -	if parseErr != nil {
 -		// Fix any badly parsed parts of the AST.
--		fixed = fixAST(file, tok, src)
+-		astFixes := fixAST(file, tok, src)
+-		fixedAST = len(fixes) > 0
+-		if fixedAST {
+-			fixes = append(fixes, astFixes...)
+-		}
 -
 -		for i := 0; i < 10; i++ {
 -			// Fix certain syntax errors that render the file unparseable.
--			newSrc := fixSrc(file, tok, src)
+-			newSrc, srcFix := fixSrc(file, tok, src)
 -			if newSrc == nil {
 -				break
 -			}
@@ -18484,14 +20866,30 @@
 -				event.Log(ctx, fmt.Sprintf("fixSrc loop - last diff:\n%v", unified), tag.File.Of(tok.Name()))
 -			}
 -
--			newFile, _ := parser.ParseFile(fset, uri.Filename(), newSrc, parserMode)
--			if newFile != nil {
--				// Maintain the original parseError so we don't try formatting the doctored file.
--				file = newFile
--				src = newSrc
--				tok = fset.File(file.Pos())
+-			newFile, newErr := parser.ParseFile(fset, uri.Filename(), newSrc, mode)
+-			if newFile == nil {
+-				break // no progress
+-			}
 -
--				fixed = fixAST(file, tok, src)
+-			// Maintain the original parseError so we don't try formatting the
+-			// doctored file.
+-			file = newFile
+-			src = newSrc
+-			tok = fset.File(file.Pos())
+-
+-			// Only now that we accept the fix do we record the src fix from above.
+-			fixes = append(fixes, srcFix)
+-			fixedSrc = true
+-
+-			if newErr == nil {
+-				break // nothing to fix
+-			}
+-
+-			// Note that fixedAST is reset after we fix src.
+-			astFixes = fixAST(file, tok, src)
+-			fixedAST = len(astFixes) > 0
+-			if fixedAST {
+-				fixes = append(fixes, astFixes...)
 -			}
 -		}
 -	}
@@ -18500,12 +20898,13 @@
 -		URI:      uri,
 -		Mode:     mode,
 -		Src:      src,
--		Fixed:    fixed,
+-		FixedSrc: fixedSrc,
+-		FixedAST: fixedAST,
 -		File:     file,
 -		Tok:      tok,
 -		Mapper:   protocol.NewMapper(uri, src),
 -		ParseErr: parseErr,
--	}
+-	}, fixes
 -}
 -
 -// fixAST inspects the AST and potentially modifies any *ast.BadStmts so that it can be
@@ -18513,22 +20912,26 @@
 -//
 -// If fixAST returns true, the resulting AST is considered "fixed", meaning
 -// positions have been mangled, and type checker errors may not make sense.
--func fixAST(n ast.Node, tok *token.File, src []byte) (fixed bool) {
+-func fixAST(n ast.Node, tok *token.File, src []byte) (fixes []fixType) {
 -	var err error
 -	walkASTWithParent(n, func(n, parent ast.Node) bool {
 -		switch n := n.(type) {
 -		case *ast.BadStmt:
--			if fixed = fixDeferOrGoStmt(n, parent, tok, src); fixed {
+-			if fixDeferOrGoStmt(n, parent, tok, src) {
+-				fixes = append(fixes, fixedDeferOrGo)
 -				// Recursively fix in our fixed node.
--				_ = fixAST(parent, tok, src)
+-				moreFixes := fixAST(parent, tok, src)
+-				fixes = append(fixes, moreFixes...)
 -			} else {
 -				err = fmt.Errorf("unable to parse defer or go from *ast.BadStmt: %v", err)
 -			}
 -			return false
 -		case *ast.BadExpr:
--			if fixed = fixArrayType(n, parent, tok, src); fixed {
+-			if fixArrayType(n, parent, tok, src) {
+-				fixes = append(fixes, fixedArrayType)
 -				// Recursively fix in our fixed node.
--				_ = fixAST(parent, tok, src)
+-				moreFixes := fixAST(parent, tok, src)
+-				fixes = append(fixes, moreFixes...)
 -				return false
 -			}
 -
@@ -18538,15 +20941,18 @@
 -			//   // "i := foo" is init statement, not condition.
 -			//   for i := foo
 -			//
--			fixInitStmt(n, parent, tok, src)
--
+-			if fixInitStmt(n, parent, tok, src) {
+-				fixes = append(fixes, fixedInit)
+-			}
 -			return false
 -		case *ast.SelectorExpr:
 -			// Fix cases where a keyword prefix results in a phantom "_" selector, e.g.:
 -			//
 -			//   foo.var<> // want to complete to "foo.variance"
 -			//
--			fixPhantomSelector(n, tok, src)
+-			if fixPhantomSelector(n, tok, src) {
+-				fixes = append(fixes, fixedPhantomSelector)
+-			}
 -			return true
 -
 -		case *ast.BlockStmt:
@@ -18554,7 +20960,9 @@
 -			case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt:
 -				// Adjust closing curly brace of empty switch/select
 -				// statements so we can complete inside them.
--				fixEmptySwitch(n, tok, src)
+-				if fixEmptySwitch(n, tok, src) {
+-					fixes = append(fixes, fixedEmptySwitch)
+-				}
 -			}
 -
 -			return true
@@ -18562,7 +20970,7 @@
 -			return true
 -		}
 -	})
--	return fixed
+-	return fixes
 -}
 -
 -// walkASTWithParent walks the AST rooted at n. The semantics are
@@ -18590,9 +20998,26 @@
 -	})
 -}
 -
+-// TODO(rfindley): revert this intrumentation once we're certain the crash in
+-// #59097 is fixed.
+-type fixType int
+-
+-const (
+-	noFix fixType = iota
+-	fixedCurlies
+-	fixedDanglingSelector
+-	fixedDeferOrGo
+-	fixedArrayType
+-	fixedInit
+-	fixedPhantomSelector
+-	fixedEmptySwitch
+-)
+-
 -// fixSrc attempts to modify the file's source code to fix certain
 -// syntax errors that leave the rest of the file unparsed.
--func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte) {
+-//
+-// fixSrc returns a non-nil result if and only if a fix was applied.
+-func fixSrc(f *ast.File, tf *token.File, src []byte) (newSrc []byte, fix fixType) {
 -	walkASTWithParent(f, func(n, parent ast.Node) bool {
 -		if newSrc != nil {
 -			return false
@@ -18601,14 +21026,20 @@
 -		switch n := n.(type) {
 -		case *ast.BlockStmt:
 -			newSrc = fixMissingCurlies(f, n, parent, tf, src)
+-			if newSrc != nil {
+-				fix = fixedCurlies
+-			}
 -		case *ast.SelectorExpr:
 -			newSrc = fixDanglingSelector(n, tf, src)
+-			if newSrc != nil {
+-				fix = fixedDanglingSelector
+-			}
 -		}
 -
 -		return newSrc == nil
 -	})
 -
--	return newSrc
+-	return newSrc, fix
 -}
 -
 -// fixMissingCurlies adds in curly braces for block statements that
@@ -18632,7 +21063,7 @@
 -		}
 -	}
 -
--	parentLine := tok.Line(parent.Pos())
+-	parentLine := safetoken.Line(tok, parent.Pos())
 -
 -	if parentLine >= tok.LineCount() {
 -		// If we are the last line in the file, no need to fix anything.
@@ -18727,30 +21158,33 @@
 -//	switch {
 -//
 -//	}
--func fixEmptySwitch(body *ast.BlockStmt, tok *token.File, src []byte) {
+-//
+-// The resulting bool reports whether any fixing occurred.
+-func fixEmptySwitch(body *ast.BlockStmt, tok *token.File, src []byte) bool {
 -	// We only care about empty switch statements.
 -	if len(body.List) > 0 || !body.Rbrace.IsValid() {
--		return
+-		return false
 -	}
 -
 -	// If the right brace is actually in the source code at the
 -	// specified position, don't mess with it.
 -	braceOffset, err := safetoken.Offset(tok, body.Rbrace)
 -	if err != nil {
--		return
+-		return false
 -	}
 -	if braceOffset < len(src) && src[braceOffset] == '}' {
--		return
+-		return false
 -	}
 -
--	braceLine := tok.Line(body.Rbrace)
+-	braceLine := safetoken.Line(tok, body.Rbrace)
 -	if braceLine >= tok.LineCount() {
 -		// If we are the last line in the file, no need to fix anything.
--		return
+-		return false
 -	}
 -
 -	// Move the right brace down one line.
 -	body.Rbrace = tok.LineStart(braceLine + 1)
+-	return true
 -}
 -
 -// fixDanglingSelector inserts real "_" selector expressions in place
@@ -18801,9 +21235,11 @@
 -// yields a "_" selector instead of "var" since "var" is a keyword.
 -//
 -// TODO(rfindley): should this constitute an ast 'fix'?
--func fixPhantomSelector(sel *ast.SelectorExpr, tf *token.File, src []byte) {
+-//
+-// The resulting bool reports whether any fixing occurred.
+-func fixPhantomSelector(sel *ast.SelectorExpr, tf *token.File, src []byte) bool {
 -	if !isPhantomUnderscore(sel.Sel, tf, src) {
--		return
+-		return false
 -	}
 -
 -	// Only consider selectors directly abutting the selector ".". This
@@ -18813,15 +21249,15 @@
 -	//   var bar = 123
 -	//
 -	if sel.Sel.Pos() != sel.X.End()+1 {
--		return
+-		return false
 -	}
 -
 -	maybeKeyword := readKeyword(sel.Sel.Pos(), tf, src)
 -	if maybeKeyword == "" {
--		return
+-		return false
 -	}
 -
--	replaceNode(sel, sel.Sel, &ast.Ident{
+-	return replaceNode(sel, sel.Sel, &ast.Ident{
 -		Name:    maybeKeyword,
 -		NamePos: sel.Sel.Pos(),
 -	})
@@ -18850,21 +21286,21 @@
 -// parser is looking for the conditional expression. However, "i := 0"
 -// are not valid expressions, so we get a BadExpr.
 -//
--// fixInitStmt returns valid AST for the original source.
--func fixInitStmt(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) {
+-// The resulting bool reports whether any fixing occurred.
+-func fixInitStmt(bad *ast.BadExpr, parent ast.Node, tok *token.File, src []byte) bool {
 -	if !bad.Pos().IsValid() || !bad.End().IsValid() {
--		return
+-		return false
 -	}
 -
 -	// Try to extract a statement from the BadExpr.
 -	start, end, err := safetoken.Offsets(tok, bad.Pos(), bad.End()-1)
 -	if err != nil {
--		return
+-		return false
 -	}
 -	stmtBytes := src[start : end+1]
 -	stmt, err := parseStmt(bad.Pos(), stmtBytes)
 -	if err != nil {
--		return
+-		return false
 -	}
 -
 -	// If the parent statement doesn't already have an "init" statement,
@@ -18873,29 +21309,33 @@
 -	switch p := parent.(type) {
 -	case *ast.IfStmt:
 -		if p.Init != nil {
--			return
+-			return false
 -		}
 -		p.Init = stmt
 -		p.Cond = &ast.Ident{
 -			Name:    "_",
 -			NamePos: stmt.End(),
 -		}
+-		return true
 -	case *ast.ForStmt:
 -		if p.Init != nil {
--			return
+-			return false
 -		}
 -		p.Init = stmt
 -		p.Cond = &ast.Ident{
 -			Name:    "_",
 -			NamePos: stmt.End(),
 -		}
+-		return true
 -	case *ast.SwitchStmt:
 -		if p.Init != nil {
--			return
+-			return false
 -		}
 -		p.Init = stmt
 -		p.Tag = nil
+-		return true
 -	}
+-	return false
 -}
 -
 -// readKeyword reads the keyword starting at pos, if any.
@@ -19073,7 +21513,7 @@
 -		// the period is likely a dangling selector and needs a phantom
 -		// "_". Likewise if the current token is on a different line than
 -		// the period, the period is likely a dangling selector.
--		if lastToken == token.PERIOD && (tkn == token.RBRACE || tok.Line(to) > tok.Line(last)) {
+-		if lastToken == token.PERIOD && (tkn == token.RBRACE || safetoken.Line(tok, to) > safetoken.Line(tok, last)) {
 -			// Insert phantom "_" selector after the dangling ".".
 -			phantomSelectors = append(phantomSelectors, last+1)
 -			// If we aren't in a block then end the expression after the ".".
@@ -19288,41 +21728,669 @@
 -
 -	return false
 -}
-diff -urN a/gopls/internal/lsp/cache/parsemode_go116.go b/gopls/internal/lsp/cache/parsemode_go116.go
---- a/gopls/internal/lsp/cache/parsemode_go116.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/parsemode_go116.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
+diff -urN a/gopls/internal/lsp/cache/parse_cache.go b/gopls/internal/lsp/cache/parse_cache.go
+--- a/gopls/internal/lsp/cache/parse_cache.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/parse_cache.go	1970-01-01 08:00:00
+@@ -1,418 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
--//go:build !go1.17
--// +build !go1.17
--
 -package cache
 -
--// The parser.SkipObjectResolution mode flag is not supported before Go 1.17.
--const skipObjectResolution = 0
-diff -urN a/gopls/internal/lsp/cache/parsemode_go117.go b/gopls/internal/lsp/cache/parsemode_go117.go
---- a/gopls/internal/lsp/cache/parsemode_go117.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/parsemode_go117.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
+-import (
+-	"bytes"
+-	"container/heap"
+-	"context"
+-	"fmt"
+-	"go/parser"
+-	"go/token"
+-	"math/bits"
+-	"runtime"
+-	"sync"
+-	"time"
+-
+-	"golang.org/x/sync/errgroup"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/memoize"
+-	"golang.org/x/tools/internal/tokeninternal"
+-)
+-
+-// This file contains an implementation of an LRU parse cache, that offsets the
+-// base token.Pos value of each cached file so that they may be later described
+-// by a single dedicated FileSet.
+-//
+-// This is achieved by tracking a monotonic offset in the token.Pos space, that
+-// is incremented before parsing allow room for the resulting parsed file.
+-
+-// reservedForParsing defines the room in the token.Pos space reserved for
+-// cached parsed files.
+-//
+-// Files parsed through the parseCache are guaranteed not to have overlapping
+-// spans: the parseCache tracks a monotonic base for newly parsed files.
+-//
+-// By offsetting the initial base of a FileSet, we can allow other operations
+-// accepting the FileSet (such as the gcimporter) to add new files using the
+-// normal FileSet APIs without overlapping with cached parsed files.
+-//
+-// Note that 1<<60 represents an exabyte of parsed data, more than any gopls
+-// process can ever parse.
+-//
+-// On 32-bit systems we don't cache parse results (see parseFiles).
+-const reservedForParsing = 1 << (bits.UintSize - 4)
+-
+-// fileSetWithBase returns a new token.FileSet with Base() equal to the
+-// requested base.
+-//
+-// If base < 1, fileSetWithBase panics.
+-// (1 is the smallest permitted FileSet base).
+-func fileSetWithBase(base int) *token.FileSet {
+-	fset := token.NewFileSet()
+-	if base > 1 {
+-		// Add a dummy file to set the base of fset. We won't ever use the
+-		// resulting FileSet, so it doesn't matter how we achieve this.
+-		//
+-		// FileSets leave a 1-byte padding between files, so we set the base by
+-		// adding a zero-length file at base-1.
+-		fset.AddFile("", base-1, 0)
+-	}
+-	if fset.Base() != base {
+-		panic("unexpected FileSet.Base")
+-	}
+-	return fset
+-}
+-
+-const (
+-	// Always keep 100 recent files, independent of their wall-clock age, to
+-	// optimize the case where the user resumes editing after a delay.
+-	parseCacheMinFiles = 100
+-)
+-
+-// parsePadding is additional padding allocated to allow for increases in
+-// length (such as appending missing braces) caused by fixAST.
+-//
+-// This is used to mitigate a chicken and egg problem: we must know the base
+-// offset of the file we're about to parse, before we start parsing, and yet
+-// src fixups may affect the actual size of the parsed content (and therefore
+-// the offsets of subsequent files).
+-//
+-// When we encounter a file that no longer fits in its allocated space in the
+-// fileset, we have no choice but to re-parse it. Leaving a generous padding
+-// reduces the likelihood of this "slow path".
+-//
+-// This value is mutable for testing, so that we can exercise the slow path.
+-var parsePadding = 1000 // mutable for testing
+-
+-// A parseCache holds recently accessed parsed Go files. After new files are
+-// stored, older files may be evicted from the cache via garbage collection.
+-//
+-// The parseCache.parseFiles method exposes a batch API for parsing (and
+-// caching) multiple files. This is necessary for type-checking, where files
+-// must be parsed in a common fileset.
+-type parseCache struct {
+-	expireAfter time.Duration // interval at which to collect expired cache entries
+-	done        chan struct{} // closed when GC is stopped
+-
+-	mu       sync.Mutex
+-	m        map[parseKey]*parseCacheEntry
+-	lru      queue  // min-atime priority queue of *parseCacheEntry
+-	clock    uint64 // clock time, incremented when the cache is updated
+-	nextBase int    // base offset for the next parsed file
+-}
+-
+-// newParseCache creates a new parse cache and starts a goroutine to garbage
+-// collect entries whose age is at least expireAfter.
+-//
+-// Callers must call parseCache.stop when the parse cache is no longer in use.
+-func newParseCache(expireAfter time.Duration) *parseCache {
+-	c := &parseCache{
+-		expireAfter: expireAfter,
+-		m:           make(map[parseKey]*parseCacheEntry),
+-		done:        make(chan struct{}),
+-	}
+-	go c.gc()
+-	return c
+-}
+-
+-// stop causes the GC goroutine to exit.
+-func (c *parseCache) stop() {
+-	close(c.done)
+-}
+-
+-// parseKey uniquely identifies a parsed Go file.
+-type parseKey struct {
+-	uri             span.URI
+-	mode            parser.Mode
+-	purgeFuncBodies bool
+-}
+-
+-type parseCacheEntry struct {
+-	key      parseKey
+-	hash     source.Hash
+-	promise  *memoize.Promise // memoize.Promise[*source.ParsedGoFile]
+-	atime    uint64           // clock time of last access, for use in LRU sorting
+-	walltime time.Time        // actual time of last access, for use in time-based eviction; too coarse for LRU on some systems
+-	lruIndex int              // owned by the queue implementation
+-}
+-
+-// startParse prepares a parsing pass, creating new promises in the cache for
+-// any cache misses.
+-//
+-// The resulting slice has an entry for every given file handle, though some
+-// entries may be nil if there was an error reading the file (in which case the
+-// resulting error will be non-nil).
+-func (c *parseCache) startParse(mode parser.Mode, purgeFuncBodies bool, fhs ...source.FileHandle) ([]*memoize.Promise, error) {
+-	c.mu.Lock()
+-	defer c.mu.Unlock()
+-
+-	// Any parsing pass increments the clock, as we'll update access times.
+-	// (technically, if fhs is empty this isn't necessary, but that's a degenerate case).
+-	//
+-	// All entries parsed from a single call get the same access time.
+-	c.clock++
+-	walltime := time.Now()
+-
+-	// Read file data and collect cacheable files.
+-	var (
+-		data           = make([][]byte, len(fhs)) // file content for each readable file
+-		promises       = make([]*memoize.Promise, len(fhs))
+-		firstReadError error // first error from fh.Read, or nil
+-	)
+-	for i, fh := range fhs {
+-		content, err := fh.Content()
+-		if err != nil {
+-			if firstReadError == nil {
+-				firstReadError = err
+-			}
+-			continue
+-		}
+-		data[i] = content
+-
+-		key := parseKey{
+-			uri:             fh.URI(),
+-			mode:            mode,
+-			purgeFuncBodies: purgeFuncBodies,
+-		}
+-
+-		if e, ok := c.m[key]; ok {
+-			if e.hash == fh.FileIdentity().Hash { // cache hit
+-				e.atime = c.clock
+-				e.walltime = walltime
+-				heap.Fix(&c.lru, e.lruIndex)
+-				promises[i] = e.promise
+-				continue
+-			} else {
+-				// A cache hit, for a different version. Delete it.
+-				delete(c.m, e.key)
+-				heap.Remove(&c.lru, e.lruIndex)
+-			}
+-		}
+-
+-		uri := fh.URI()
+-		promise := memoize.NewPromise("parseCache.parse", func(ctx context.Context, _ interface{}) interface{} {
+-			// Allocate 2*len(content)+parsePadding to allow for re-parsing once
+-			// inside of parseGoSrc without exceeding the allocated space.
+-			base, nextBase := c.allocateSpace(2*len(content) + parsePadding)
+-
+-			pgf, fixes1 := ParseGoSrc(ctx, fileSetWithBase(base), uri, content, mode, purgeFuncBodies)
+-			file := pgf.Tok
+-			if file.Base()+file.Size()+1 > nextBase {
+-				// The parsed file exceeds its allocated space, likely due to multiple
+-				// passes of src fixing. In this case, we have no choice but to re-do
+-				// the operation with the correct size.
+-				//
+-				// Even though the final successful parse requires only file.Size()
+-				// bytes of Pos space, we need to accommodate all the missteps to get
+-				// there, as parseGoSrc will repeat them.
+-				actual := file.Base() + file.Size() - base // actual size consumed, after re-parsing
+-				base2, nextBase2 := c.allocateSpace(actual)
+-				pgf2, fixes2 := ParseGoSrc(ctx, fileSetWithBase(base2), uri, content, mode, purgeFuncBodies)
+-
+-				// In golang/go#59097 we observed that this panic condition was hit.
+-				// One bug was found and fixed, but record more information here in
+-				// case there is still a bug here.
+-				if end := pgf2.Tok.Base() + pgf2.Tok.Size(); end != nextBase2-1 {
+-					var errBuf bytes.Buffer
+-					fmt.Fprintf(&errBuf, "internal error: non-deterministic parsing result:\n")
+-					fmt.Fprintf(&errBuf, "\t%q (%d-%d) does not span %d-%d\n", uri, pgf2.Tok.Base(), base2, end, nextBase2-1)
+-					fmt.Fprintf(&errBuf, "\tfirst %q (%d-%d)\n", pgf.URI, pgf.Tok.Base(), pgf.Tok.Base()+pgf.Tok.Size())
+-					fmt.Fprintf(&errBuf, "\tfirst space: (%d-%d), second space: (%d-%d)\n", base, nextBase, base2, nextBase2)
+-					fmt.Fprintf(&errBuf, "\tfirst mode: %v, second mode: %v", pgf.Mode, pgf2.Mode)
+-					fmt.Fprintf(&errBuf, "\tfirst err: %v, second err: %v", pgf.ParseErr, pgf2.ParseErr)
+-					fmt.Fprintf(&errBuf, "\tfirst fixes: %v, second fixes: %v", fixes1, fixes2)
+-					panic(errBuf.String())
+-				}
+-				pgf = pgf2
+-			}
+-			return pgf
+-		})
+-		promises[i] = promise
+-
+-		// add new entry; entries are gc'ed asynchronously
+-		e := &parseCacheEntry{
+-			key:      key,
+-			hash:     fh.FileIdentity().Hash,
+-			promise:  promise,
+-			atime:    c.clock,
+-			walltime: walltime,
+-		}
+-		c.m[e.key] = e
+-		heap.Push(&c.lru, e)
+-	}
+-
+-	if len(c.m) != len(c.lru) {
+-		panic("map and LRU are inconsistent")
+-	}
+-
+-	return promises, firstReadError
+-}
+-
+-func (c *parseCache) gc() {
+-	const period = 10 * time.Second // gc period
+-	timer := time.NewTicker(period)
+-	defer timer.Stop()
+-
+-	for {
+-		select {
+-		case <-c.done:
+-			return
+-		case <-timer.C:
+-		}
+-
+-		c.gcOnce()
+-	}
+-}
+-
+-func (c *parseCache) gcOnce() {
+-	now := time.Now()
+-	c.mu.Lock()
+-	defer c.mu.Unlock()
+-
+-	for len(c.m) > parseCacheMinFiles {
+-		e := heap.Pop(&c.lru).(*parseCacheEntry)
+-		if now.Sub(e.walltime) >= c.expireAfter {
+-			delete(c.m, e.key)
+-		} else {
+-			heap.Push(&c.lru, e)
+-			break
+-		}
+-	}
+-}
+-
+-// allocateSpace reserves the next n bytes of token.Pos space in the
+-// cache.
+-//
+-// It returns the resulting file base, next base, and an offset FileSet to use
+-// for parsing.
+-func (c *parseCache) allocateSpace(size int) (int, int) {
+-	c.mu.Lock()
+-	defer c.mu.Unlock()
+-
+-	if c.nextBase == 0 {
+-		// FileSet base values must be at least 1.
+-		c.nextBase = 1
+-	}
+-	base := c.nextBase
+-	c.nextBase += size + 1
+-	return base, c.nextBase
+-}
+-
+-// parseFiles returns a ParsedGoFile for each file handle in fhs, in the
+-// requested parse mode.
+-//
+-// For parsed files that already exists in the cache, access time will be
+-// updated. For others, parseFiles will parse and store as many results in the
+-// cache as space allows.
+-//
+-// The token.File for each resulting parsed file will be added to the provided
+-// FileSet, using the tokeninternal.AddExistingFiles API. Consequently, the
+-// given fset should only be used in other APIs if its base is >=
+-// reservedForParsing.
+-//
+-// If parseFiles returns an error, it still returns a slice,
+-// but with a nil entry for each file that could not be parsed.
+-func (c *parseCache) parseFiles(ctx context.Context, fset *token.FileSet, mode parser.Mode, purgeFuncBodies bool, fhs ...source.FileHandle) ([]*source.ParsedGoFile, error) {
+-	pgfs := make([]*source.ParsedGoFile, len(fhs))
+-
+-	// Temporary fall-back for 32-bit systems, where reservedForParsing is too
+-	// small to be viable. We don't actually support 32-bit systems, so this
+-	// workaround is only for tests and can be removed when we stop running
+-	// 32-bit TryBots for gopls.
+-	if bits.UintSize == 32 {
+-		for i, fh := range fhs {
+-			var err error
+-			pgfs[i], err = parseGoImpl(ctx, fset, fh, mode, purgeFuncBodies)
+-			if err != nil {
+-				return pgfs, err
+-			}
+-		}
+-		return pgfs, nil
+-	}
+-
+-	promises, firstErr := c.startParse(mode, purgeFuncBodies, fhs...)
+-
+-	// Await all parsing.
+-	var g errgroup.Group
+-	g.SetLimit(runtime.GOMAXPROCS(-1)) // parsing is CPU-bound.
+-	for i, promise := range promises {
+-		if promise == nil {
+-			continue
+-		}
+-		i := i
+-		promise := promise
+-		g.Go(func() error {
+-			result, err := promise.Get(ctx, nil)
+-			if err != nil {
+-				return err
+-			}
+-			pgfs[i] = result.(*source.ParsedGoFile)
+-			return nil
+-		})
+-	}
+-
+-	if err := g.Wait(); err != nil && firstErr == nil {
+-		firstErr = err
+-	}
+-
+-	// Augment the FileSet to map all parsed files.
+-	var tokenFiles []*token.File
+-	for _, pgf := range pgfs {
+-		if pgf == nil {
+-			continue
+-		}
+-		tokenFiles = append(tokenFiles, pgf.Tok)
+-	}
+-	tokeninternal.AddExistingFiles(fset, tokenFiles)
+-
+-	const debugIssue59080 = true
+-	if debugIssue59080 {
+-		for _, f := range tokenFiles {
+-			pos := token.Pos(f.Base())
+-			f2 := fset.File(pos)
+-			if f2 != f {
+-				panic(fmt.Sprintf("internal error: File(%d (start)) = %v, not %v", pos, f2, f))
+-			}
+-			pos = token.Pos(f.Base() + f.Size())
+-			f2 = fset.File(pos)
+-			if f2 != f {
+-				panic(fmt.Sprintf("internal error: File(%d (end)) = %v, not %v", pos, f2, f))
+-			}
+-		}
+-	}
+-
+-	return pgfs, firstErr
+-}
+-
+-// -- priority queue boilerplate --
+-
+-// queue is a min-atime prority queue of cache entries.
+-type queue []*parseCacheEntry
+-
+-func (q queue) Len() int { return len(q) }
+-
+-func (q queue) Less(i, j int) bool { return q[i].atime < q[j].atime }
+-
+-func (q queue) Swap(i, j int) {
+-	q[i], q[j] = q[j], q[i]
+-	q[i].lruIndex = i
+-	q[j].lruIndex = j
+-}
+-
+-func (q *queue) Push(x interface{}) {
+-	e := x.(*parseCacheEntry)
+-	e.lruIndex = len(*q)
+-	*q = append(*q, e)
+-}
+-
+-func (q *queue) Pop() interface{} {
+-	last := len(*q) - 1
+-	e := (*q)[last]
+-	(*q)[last] = nil // aid GC
+-	*q = (*q)[:last]
+-	return e
+-}
+diff -urN a/gopls/internal/lsp/cache/parse_cache_test.go b/gopls/internal/lsp/cache/parse_cache_test.go
+--- a/gopls/internal/lsp/cache/parse_cache_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cache/parse_cache_test.go	1970-01-01 08:00:00
+@@ -1,233 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
--//go:build go1.17
--// +build go1.17
--
 -package cache
 -
--import "go/parser"
+-import (
+-	"context"
+-	"fmt"
+-	"go/token"
+-	"math/bits"
+-	"testing"
+-	"time"
 -
--const skipObjectResolution = parser.SkipObjectResolution
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
+-)
+-
+-func skipIfNoParseCache(t *testing.T) {
+-	if bits.UintSize == 32 {
+-		t.Skip("the parse cache is not supported on 32-bit systems")
+-	}
+-}
+-
+-func TestParseCache(t *testing.T) {
+-	skipIfNoParseCache(t)
+-
+-	ctx := context.Background()
+-	uri := span.URI("file:///myfile")
+-	fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\""))
+-	fset := token.NewFileSet()
+-
+-	cache := newParseCache(0)
+-	pgfs1, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	pgf1 := pgfs1[0]
+-	pgfs2, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh)
+-	pgf2 := pgfs2[0]
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	if pgf1 != pgf2 {
+-		t.Errorf("parseFiles(%q): unexpected cache miss on repeated call", uri)
+-	}
+-
+-	// Fill up the cache with other files, but don't evict the file above.
+-	cache.gcOnce()
+-	files := []source.FileHandle{fh}
+-	files = append(files, dummyFileHandles(parseCacheMinFiles-1)...)
+-
+-	pgfs3, err := cache.parseFiles(ctx, fset, source.ParseFull, false, files...)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	pgf3 := pgfs3[0]
+-	if pgf3 != pgf1 {
+-		t.Errorf("parseFiles(%q, ...): unexpected cache miss", uri)
+-	}
+-	if pgf3.Tok.Base() != pgf1.Tok.Base() || pgf3.Tok.Size() != pgf1.Tok.Size() {
+-		t.Errorf("parseFiles(%q, ...): result.Tok has base: %d, size: %d, want (%d, %d)", uri, pgf3.Tok.Base(), pgf3.Tok.Size(), pgf1.Tok.Base(), pgf1.Tok.Size())
+-	}
+-	if tok := fset.File(token.Pos(pgf3.Tok.Base())); tok != pgf3.Tok {
+-		t.Errorf("parseFiles(%q, ...): result.Tok not contained in FileSet", uri)
+-	}
+-
+-	// Now overwrite the cache, after which we should get new results.
+-	cache.gcOnce()
+-	files = dummyFileHandles(parseCacheMinFiles)
+-	_, err = cache.parseFiles(ctx, fset, source.ParseFull, false, files...)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	// force a GC, which should collect the recently parsed files
+-	cache.gcOnce()
+-	pgfs4, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	if pgfs4[0] == pgf1 {
+-		t.Errorf("parseFiles(%q): unexpected cache hit after overwriting cache", uri)
+-	}
+-}
+-
+-func TestParseCache_Reparsing(t *testing.T) {
+-	skipIfNoParseCache(t)
+-
+-	defer func(padding int) {
+-		parsePadding = padding
+-	}(parsePadding)
+-	parsePadding = 0
+-
+-	files := dummyFileHandles(parseCacheMinFiles)
+-	danglingSelector := []byte("package p\nfunc _() {\n\tx.\n}")
+-	files = append(files, makeFakeFileHandle("file:///bad1", danglingSelector))
+-	files = append(files, makeFakeFileHandle("file:///bad2", danglingSelector))
+-
+-	// Parsing should succeed even though we overflow the padding.
+-	cache := newParseCache(0)
+-	_, err := cache.parseFiles(context.Background(), token.NewFileSet(), source.ParseFull, false, files...)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-}
+-
+-// Re-parsing the first file should not panic.
+-func TestParseCache_Issue59097(t *testing.T) {
+-	skipIfNoParseCache(t)
+-
+-	defer func(padding int) {
+-		parsePadding = padding
+-	}(parsePadding)
+-	parsePadding = 0
+-
+-	danglingSelector := []byte("package p\nfunc _() {\n\tx.\n}")
+-	files := []source.FileHandle{makeFakeFileHandle("file:///bad", danglingSelector)}
+-
+-	// Parsing should succeed even though we overflow the padding.
+-	cache := newParseCache(0)
+-	_, err := cache.parseFiles(context.Background(), token.NewFileSet(), source.ParseFull, false, files...)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-}
+-
+-func TestParseCache_TimeEviction(t *testing.T) {
+-	skipIfNoParseCache(t)
+-
+-	ctx := context.Background()
+-	fset := token.NewFileSet()
+-	uri := span.URI("file:///myfile")
+-	fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\""))
+-
+-	const gcDuration = 10 * time.Millisecond
+-	cache := newParseCache(gcDuration)
+-	cache.stop() // we'll manage GC manually, for testing.
+-
+-	pgfs0, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	files := dummyFileHandles(parseCacheMinFiles)
+-	_, err = cache.parseFiles(ctx, fset, source.ParseFull, false, files...)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	// Even after filling up the 'min' files, we get a cache hit for our original file.
+-	pgfs1, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	if pgfs0[0] != pgfs1[0] {
+-		t.Errorf("before GC, got unexpected cache miss")
+-	}
+-
+-	// But after GC, we get a cache miss.
+-	_, err = cache.parseFiles(ctx, fset, source.ParseFull, false, files...) // mark dummy files as newer
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	time.Sleep(gcDuration)
+-	cache.gcOnce()
+-
+-	pgfs2, err := cache.parseFiles(ctx, fset, source.ParseFull, false, fh, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	if pgfs0[0] == pgfs2[0] {
+-		t.Errorf("after GC, got unexpected cache hit for %s", pgfs0[0].URI)
+-	}
+-}
+-
+-func TestParseCache_Duplicates(t *testing.T) {
+-	skipIfNoParseCache(t)
+-
+-	ctx := context.Background()
+-	uri := span.URI("file:///myfile")
+-	fh := makeFakeFileHandle(uri, []byte("package p\n\nconst _ = \"foo\""))
+-
+-	cache := newParseCache(0)
+-	pgfs, err := cache.parseFiles(ctx, token.NewFileSet(), source.ParseFull, false, fh, fh)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	if pgfs[0] != pgfs[1] {
+-		t.Errorf("parseFiles(fh, fh): = [%p, %p], want duplicate files", pgfs[0].File, pgfs[1].File)
+-	}
+-}
+-
+-func dummyFileHandles(n int) []source.FileHandle {
+-	var fhs []source.FileHandle
+-	for i := 0; i < n; i++ {
+-		uri := span.URI(fmt.Sprintf("file:///_%d", i))
+-		src := []byte(fmt.Sprintf("package p\nvar _ = %d", i))
+-		fhs = append(fhs, makeFakeFileHandle(uri, src))
+-	}
+-	return fhs
+-}
+-
+-func makeFakeFileHandle(uri span.URI, src []byte) fakeFileHandle {
+-	return fakeFileHandle{
+-		uri:  uri,
+-		data: src,
+-		hash: source.HashOf(src),
+-	}
+-}
+-
+-type fakeFileHandle struct {
+-	source.FileHandle
+-	uri  span.URI
+-	data []byte
+-	hash source.Hash
+-}
+-
+-func (h fakeFileHandle) URI() span.URI {
+-	return h.uri
+-}
+-
+-func (h fakeFileHandle) Content() ([]byte, error) {
+-	return h.data, nil
+-}
+-
+-func (h fakeFileHandle) FileIdentity() source.FileIdentity {
+-	return source.FileIdentity{
+-		URI:  h.uri,
+-		Hash: h.hash,
+-	}
+-}
 diff -urN a/gopls/internal/lsp/cache/pkg.go b/gopls/internal/lsp/cache/pkg.go
 --- a/gopls/internal/lsp/cache/pkg.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/pkg.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,165 +0,0 @@
++++ b/gopls/internal/lsp/cache/pkg.go	1970-01-01 08:00:00
+@@ -1,177 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -19336,11 +22404,12 @@
 -	"go/scanner"
 -	"go/token"
 -	"go/types"
+-	"sync"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
+-	"golang.org/x/tools/gopls/internal/lsp/source/xrefs"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/memoize"
 -)
 -
 -// Convenient local aliases for typed strings.
@@ -19351,11 +22420,10 @@
 -	ImportPath  = source.ImportPath
 -)
 -
--// A Package is the union of snapshot-local information (Metadata) and shared
--// type-checking information (a syntaxPackage).
+-// A Package is the union of package metadata and type checking results.
 -//
 -// TODO(rfindley): for now, we do not persist the post-processing of
--// loadDiagnostics, because the value of the snapshot.packages map  is just the
+-// loadDiagnostics, because the value of the snapshot.packages map is just the
 -// package handle. Fix this.
 -type Package struct {
 -	m   *source.Metadata
@@ -19365,8 +22433,7 @@
 -// syntaxPackage contains parse trees and type information for a package.
 -type syntaxPackage struct {
 -	// -- identifiers --
--	id   PackageID
--	mode source.ParseMode
+-	id PackageID
 -
 -	// -- outputs --
 -	fset            *token.FileSet // for now, same as the snapshot's FileSet
@@ -19377,11 +22444,28 @@
 -	typeErrors      []types.Error
 -	types           *types.Package
 -	typesInfo       *types.Info
--	importMap       map[string]*types.Package // keys are PackagePaths
--	hasFixedFiles   bool                      // if true, AST was sufficiently mangled that we should hide type errors
--	analyses        memoize.Store             // maps analyzer.Name to Promise[actionResult]
--	xrefs           []byte
--	methodsets      *methodsets.Index
+-	importMap       map[PackagePath]*types.Package
+-	hasFixedFiles   bool // if true, AST was sufficiently mangled that we should hide type errors
+-
+-	xrefsOnce sync.Once
+-	_xrefs    []byte // only used by the xrefs method
+-
+-	methodsetsOnce sync.Once
+-	_methodsets    *methodsets.Index // only used by the methodsets method
+-}
+-
+-func (p *syntaxPackage) xrefs() []byte {
+-	p.xrefsOnce.Do(func() {
+-		p._xrefs = xrefs.Index(p.compiledGoFiles, p.types, p.typesInfo)
+-	})
+-	return p._xrefs
+-}
+-
+-func (p *syntaxPackage) methodsets() *methodsets.Index {
+-	p.methodsetsOnce.Do(func() {
+-		p._methodsets = methodsets.NewIndex(p.fset, p.types)
+-	})
+-	return p._methodsets
 -}
 -
 -func (p *Package) String() string { return string(p.m.ID) }
@@ -19398,8 +22482,11 @@
 -type (
 -	fileLoadScope    span.URI // load packages containing a file (including command-line-arguments)
 -	packageLoadScope string   // load a specific package (the value is its PackageID)
--	moduleLoadScope  string   // load packages in a specific module
--	viewLoadScope    span.URI // load the workspace
+-	moduleLoadScope  struct {
+-		dir        string // dir containing the go.mod file
+-		modulePath string // parsed module path
+-	}
+-	viewLoadScope span.URI // load the workspace
 -)
 -
 -// Implement the loadScope interface.
@@ -19408,10 +22495,6 @@
 -func (moduleLoadScope) aScope()  {}
 -func (viewLoadScope) aScope()    {}
 -
--func (p *Package) ParseMode() source.ParseMode {
--	return p.pkg.mode
--}
--
 -func (p *Package) CompiledGoFiles() []*source.ParsedGoFile {
 -	return p.pkg.compiledGoFiles
 -}
@@ -19459,18 +22542,15 @@
 -// dependencies of p, or if no symbols from that package were
 -// referenced during the type-checking of p.
 -func (p *Package) DependencyTypes(path source.PackagePath) *types.Package {
--	if path == p.m.PkgPath {
--		return p.pkg.types
--	}
--	return p.pkg.importMap[string(path)]
+-	return p.pkg.importMap[path]
 -}
 -
--func (p *Package) HasParseErrors() bool {
--	return len(p.pkg.parseErrors) != 0
+-func (p *Package) GetParseErrors() []scanner.ErrorList {
+-	return p.pkg.parseErrors
 -}
 -
--func (p *Package) HasTypeErrors() bool {
--	return len(p.pkg.typeErrors) != 0
+-func (p *Package) GetTypeErrors() []types.Error {
+-	return p.pkg.typeErrors
 -}
 -
 -func (p *Package) DiagnosticsForFile(ctx context.Context, s source.Snapshot, uri span.URI) ([]*source.Diagnostic, error) {
@@ -19490,8 +22570,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/session.go b/gopls/internal/lsp/cache/session.go
 --- a/gopls/internal/lsp/cache/session.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/session.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,730 +0,0 @@
++++ b/gopls/internal/lsp/cache/session.go	1970-01-01 08:00:00
+@@ -1,715 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -19506,13 +22586,15 @@
 -	"sync"
 -	"sync/atomic"
 -
--	"golang.org/x/tools/gopls/internal/govulncheck"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/gocommand"
 -	"golang.org/x/tools/internal/imports"
+-	"golang.org/x/tools/internal/memoize"
 -	"golang.org/x/tools/internal/persistent"
 -	"golang.org/x/tools/internal/xcontext"
 -)
@@ -19525,12 +22607,11 @@
 -	cache       *Cache            // shared cache
 -	gocmdRunner *gocommand.Runner // limits go command concurrency
 -
--	optionsMu sync.Mutex
--	options   *source.Options
--
 -	viewMu  sync.Mutex
 -	views   []*View
--	viewMap map[span.URI]*View // map of URI->best view
+-	viewMap map[span.URI]*View // file->best view
+-
+-	parseCache *parseCache
 -
 -	*overlayFS
 -}
@@ -19539,18 +22620,9 @@
 -func (s *Session) ID() string     { return s.id }
 -func (s *Session) String() string { return s.id }
 -
--// Options returns a copy of the SessionOptions for this session.
--func (s *Session) Options() *source.Options {
--	s.optionsMu.Lock()
--	defer s.optionsMu.Unlock()
--	return s.options
--}
--
--// SetOptions sets the options of this session to new values.
--func (s *Session) SetOptions(options *source.Options) {
--	s.optionsMu.Lock()
--	defer s.optionsMu.Unlock()
--	s.options = options
+-// GoCommandRunner returns the gocommand Runner for this session.
+-func (s *Session) GoCommandRunner() *gocommand.Runner {
+-	return s.gocmdRunner
 -}
 -
 -// Shutdown the session and all views it has created.
@@ -19564,6 +22636,7 @@
 -	for _, view := range views {
 -		view.shutdown()
 -	}
+-	s.parseCache.stop()
 -	event.Log(ctx, "Shutdown session", KeyShutdownSession.Of(s))
 -}
 -
@@ -19597,16 +22670,18 @@
 -
 -// TODO(rfindley): clarify that createView can never be cancelled (with the
 -// possible exception of server shutdown).
+-// On success, the caller becomes responsible for calling the release function once.
 -func (s *Session) createView(ctx context.Context, name string, folder span.URI, options *source.Options, seqID uint64) (*View, *snapshot, func(), error) {
 -	index := atomic.AddInt64(&viewIndex, 1)
 -
 -	// Get immutable workspace information.
 -	info, err := s.getWorkspaceInformation(ctx, folder, options)
 -	if err != nil {
--		return nil, nil, func() {}, err
+-		return nil, nil, nil, err
 -	}
 -
--	wsModFiles, wsModFilesErr := computeWorkspaceModFiles(ctx, info.gomod, info.effectiveGOWORK(), info.effectiveGO111MODULE(), s)
+-	gowork, _ := info.GOWORK()
+-	wsModFiles, wsModFilesErr := computeWorkspaceModFiles(ctx, info.gomod, gowork, info.effectiveGO111MODULE(), s)
 -
 -	// We want a true background context and not a detached context here
 -	// the spans need to be unrelated and no tag values should pollute it.
@@ -19616,14 +22691,14 @@
 -	v := &View{
 -		id:                   strconv.FormatInt(index, 10),
 -		gocmdRunner:          s.gocmdRunner,
+-		lastOptions:          options,
 -		initialWorkspaceLoad: make(chan struct{}),
 -		initializationSema:   make(chan struct{}, 1),
--		options:              options,
 -		baseCtx:              baseCtx,
 -		name:                 name,
--		folder:               folder,
 -		moduleUpgrades:       map[span.URI]map[string]string{},
--		vulns:                map[span.URI]*govulncheck.Result{},
+-		vulns:                map[span.URI]*vulncheck.Result{},
+-		parseCache:           s.parseCache,
 -		fs:                   s.overlayFS,
 -		workspaceInformation: info,
 -	}
@@ -19651,23 +22726,22 @@
 -		backgroundCtx:        backgroundCtx,
 -		cancel:               cancel,
 -		store:                s.cache.store,
--		packages:             persistent.NewMap(packageIDLessInterface),
+-		packages:             new(persistent.Map[PackageID, *packageHandle]),
 -		meta:                 new(metadataGraph),
--		files:                newFilesMap(),
--		parseCache:           new(parseCache),
--		activePackages:       persistent.NewMap(packageIDLessInterface),
--		symbolizeHandles:     persistent.NewMap(uriLessInterface),
--		analyses:             persistent.NewMap(analysisKeyLessInterface),
+-		files:                newFileMap(),
+-		activePackages:       new(persistent.Map[PackageID, *Package]),
+-		symbolizeHandles:     new(persistent.Map[span.URI, *memoize.Promise]),
 -		workspacePackages:    make(map[PackageID]PackagePath),
--		unloadableFiles:      make(map[span.URI]struct{}),
--		parseModHandles:      persistent.NewMap(uriLessInterface),
--		parseWorkHandles:     persistent.NewMap(uriLessInterface),
--		modTidyHandles:       persistent.NewMap(uriLessInterface),
--		modVulnHandles:       persistent.NewMap(uriLessInterface),
--		modWhyHandles:        persistent.NewMap(uriLessInterface),
--		knownSubdirs:         newKnownDirsSet(),
+-		unloadableFiles:      new(persistent.Set[span.URI]),
+-		parseModHandles:      new(persistent.Map[span.URI, *memoize.Promise]),
+-		parseWorkHandles:     new(persistent.Map[span.URI, *memoize.Promise]),
+-		modTidyHandles:       new(persistent.Map[span.URI, *memoize.Promise]),
+-		modVulnHandles:       new(persistent.Map[span.URI, *memoize.Promise]),
+-		modWhyHandles:        new(persistent.Map[span.URI, *memoize.Promise]),
 -		workspaceModFiles:    wsModFiles,
 -		workspaceModFilesErr: wsModFilesErr,
+-		pkgIndex:             typerefs.NewPackageIndex(),
+-		options:              options,
 -	}
 -	// Save one reference in the view.
 -	v.releaseSnapshot = v.snapshot.Acquire()
@@ -19691,8 +22765,8 @@
 -	return v, snapshot, snapshot.Acquire(), nil
 -}
 -
--// View returns a view with a matching name, if the session has one.
--func (s *Session) View(name string) *View {
+-// ViewByName returns a view with a matching name, if the session has one.
+-func (s *Session) ViewByName(name string) *View {
 -	s.viewMu.Lock()
 -	defer s.viewMu.Unlock()
 -	for _, view := range s.views {
@@ -19703,6 +22777,18 @@
 -	return nil
 -}
 -
+-// View returns the view with a matching id, if present.
+-func (s *Session) View(id string) (*View, error) {
+-	s.viewMu.Lock()
+-	defer s.viewMu.Unlock()
+-	for _, view := range s.views {
+-		if view.ID() == id {
+-			return view, nil
+-		}
+-	}
+-	return nil, fmt.Errorf("no view with ID %q", id)
+-}
+-
 -// ViewOf returns a view corresponding to the given URI.
 -// If the file is not already associated with a view, pick one using some heuristics.
 -func (s *Session) ViewOf(uri span.URI) (*View, error) {
@@ -19744,9 +22830,15 @@
 -		}
 -		// TODO(rfindley): this should consider the workspace layout (i.e.
 -		// go.work).
--		if view.contains(uri) {
+-		snapshot, release, err := view.getSnapshot()
+-		if err != nil {
+-			// view is shutdown
+-			continue
+-		}
+-		if snapshot.contains(uri) {
 -			longest = view
 -		}
+-		release()
 -	}
 -	if longest != nil {
 -		return longest
@@ -19765,6 +22857,7 @@
 -func (s *Session) RemoveView(view *View) {
 -	s.viewMu.Lock()
 -	defer s.viewMu.Unlock()
+-
 -	i := s.dropView(view)
 -	if i == -1 { // error reported elsewhere
 -		return
@@ -19774,18 +22867,11 @@
 -	s.views = removeElement(s.views, i)
 -}
 -
--// updateView recreates the view with the given options.
+-// updateViewLocked recreates the view with the given options.
 -//
 -// If the resulting error is non-nil, the view may or may not have already been
 -// dropped from the session.
--func (s *Session) updateView(ctx context.Context, view *View, options *source.Options) (*View, error) {
--	s.viewMu.Lock()
--	defer s.viewMu.Unlock()
--
--	return s.updateViewLocked(ctx, view, options)
--}
--
--func (s *Session) updateViewLocked(ctx context.Context, view *View, options *source.Options) (*View, error) {
+-func (s *Session) updateViewLocked(ctx context.Context, view *View, options *source.Options) error {
 -	// Preserve the snapshot ID if we are recreating the view.
 -	view.snapshotMu.Lock()
 -	if view.snapshot == nil {
@@ -19797,22 +22883,32 @@
 -
 -	i := s.dropView(view)
 -	if i == -1 {
--		return nil, fmt.Errorf("view %q not found", view.id)
+-		return fmt.Errorf("view %q not found", view.id)
 -	}
 -
--	v, _, release, err := s.createView(ctx, view.name, view.folder, options, seqID)
--	release()
--
+-	v, snapshot, release, err := s.createView(ctx, view.name, view.folder, options, seqID)
 -	if err != nil {
 -		// we have dropped the old view, but could not create the new one
 -		// this should not happen and is very bad, but we still need to clean
 -		// up the view array if it happens
 -		s.views = removeElement(s.views, i)
--		return nil, err
+-		return err
 -	}
+-	defer release()
+-
+-	// The new snapshot has lost the history of the previous view. As a result,
+-	// it may not see open files that aren't in its build configuration (as it
+-	// would have done via didOpen notifications). This can lead to inconsistent
+-	// behavior when configuration is changed mid-session.
+-	//
+-	// Ensure the new snapshot observes all open files.
+-	for _, o := range v.fs.Overlays() {
+-		_, _ = snapshot.ReadFile(ctx, o.URI())
+-	}
+-
 -	// substitute the new view into the array where the old view was
 -	s.views[i] = v
--	return v, nil
+-	return nil
 -}
 -
 -// removeElement removes the ith element from the slice replacing it with the last element.
@@ -19850,19 +22946,6 @@
 -	return err
 -}
 -
--// TODO(rfindley): fileChange seems redundant with source.FileModification.
--// De-dupe into a common representation for changes.
--type fileChange struct {
--	content    []byte
--	exists     bool
--	fileHandle source.FileHandle
--
--	// isUnchanged indicates whether the file action is one that does not
--	// change the actual contents of the file. Opens and closes should not
--	// be treated like other changes, since the file content doesn't change.
--	isUnchanged bool
--}
--
 -// DidModifyFiles reports a file modification to the session. It returns
 -// the new snapshots after the modifications have been applied, paired with
 -// the affected file URIs for those snapshots.
@@ -19896,6 +22979,8 @@
 -	checkViews := false
 -
 -	for _, c := range changes {
+-		// TODO(rfindley): go.work files need not be named "go.work" -- we need to
+-		// check each view's source.
 -		if isGoMod(c.URI) || isGoWork(c.URI) {
 -			// Change, InvalidateMetadata, and UnknownFileAction actions do not cause
 -			// us to re-evaluate views.
@@ -19916,7 +23001,7 @@
 -			// synchronously to change processing? Can we assume that the env did not
 -			// change, and derive go.work using a combination of the configured
 -			// GOWORK value and filesystem?
--			info, err := s.getWorkspaceInformation(ctx, view.folder, view.Options())
+-			info, err := s.getWorkspaceInformation(ctx, view.folder, view.lastOptions)
 -			if err != nil {
 -				// Catastrophic failure, equivalent to a failure of session
 -				// initialization and therefore should almost never happen. One
@@ -19930,8 +23015,7 @@
 -			}
 -
 -			if info != view.workspaceInformation {
--				_, err := s.updateViewLocked(ctx, view, view.Options())
--				if err != nil {
+-				if err := s.updateViewLocked(ctx, view, view.lastOptions); err != nil {
 -					// More catastrophic failure. The view may or may not still exist.
 -					// The best we can do is log and move on.
 -					event.Error(ctx, "recreating view", err)
@@ -19941,7 +23025,7 @@
 -	}
 -
 -	// Collect information about views affected by these changes.
--	views := make(map[*View]map[span.URI]*fileChange)
+-	views := make(map[*View]map[span.URI]source.FileHandle)
 -	affectedViews := map[span.URI][]*View{}
 -	// forceReloadMetadata records whether any change is the magic
 -	// source.InvalidateMetadata action.
@@ -19974,37 +23058,22 @@
 -		}
 -		affectedViews[c.URI] = changedViews
 -
--		isUnchanged := c.Action == source.Open || c.Action == source.Close
--
 -		// Apply the changes to all affected views.
+-		fh := mustReadFile(ctx, s, c.URI)
 -		for _, view := range changedViews {
 -			// Make sure that the file is added to the view's seenFiles set.
 -			view.markKnown(c.URI)
 -			if _, ok := views[view]; !ok {
--				views[view] = make(map[span.URI]*fileChange)
+-				views[view] = make(map[span.URI]source.FileHandle)
 -			}
--			fh, err := s.GetFile(ctx, c.URI)
--			if err != nil {
--				return nil, nil, err
--			}
--			content, err := fh.Read()
--			if err != nil {
--				// Ignore the error: the file may be deleted.
--				content = nil
--			}
--			views[view][c.URI] = &fileChange{
--				content:     content,
--				exists:      err == nil,
--				fileHandle:  fh,
--				isUnchanged: isUnchanged,
--			}
+-			views[view][c.URI] = fh
 -		}
 -	}
 -
 -	var releases []func()
 -	viewToSnapshot := map[*View]*snapshot{}
 -	for view, changed := range views {
--		snapshot, release := view.invalidateContent(ctx, changed, forceReloadMetadata)
+-		snapshot, release := view.invalidateContent(ctx, changed, nil, forceReloadMetadata)
 -		releases = append(releases, release)
 -		viewToSnapshot[view] = snapshot
 -	}
@@ -20054,61 +23123,36 @@
 -	}
 -	s.viewMu.Unlock()
 -
--	knownDirs := knownDirectories(ctx, snapshots)
--	defer knownDirs.Destroy()
--
+-	// Expand the modification to any file we could care about, which we define
+-	// to be any file observed by any of the snapshots.
+-	//
+-	// There may be other files in the directory, but if we haven't read them yet
+-	// we don't need to invalidate them.
 -	var result []source.FileModification
 -	for _, c := range changes {
--		if !knownDirs.Contains(c.URI) {
+-		expanded := make(map[span.URI]bool)
+-		for _, snapshot := range snapshots {
+-			for _, uri := range snapshot.filesInDir(c.URI) {
+-				expanded[uri] = true
+-			}
+-		}
+-		if len(expanded) == 0 {
 -			result = append(result, c)
--			continue
+-		} else {
+-			for uri := range expanded {
+-				result = append(result, source.FileModification{
+-					URI:        uri,
+-					Action:     c.Action,
+-					LanguageID: "",
+-					OnDisk:     c.OnDisk,
+-					// changes to directories cannot include text or versions
+-				})
+-			}
 -		}
--		affectedFiles := knownFilesInDir(ctx, snapshots, c.URI)
--		var fileChanges []source.FileModification
--		for uri := range affectedFiles {
--			fileChanges = append(fileChanges, source.FileModification{
--				URI:        uri,
--				Action:     c.Action,
--				LanguageID: "",
--				OnDisk:     c.OnDisk,
--				// changes to directories cannot include text or versions
--			})
--		}
--		result = append(result, fileChanges...)
 -	}
 -	return result
 -}
 -
--// knownDirectories returns all of the directories known to the given
--// snapshots, including workspace directories and their subdirectories.
--// It is responsibility of the caller to destroy the returned set.
--func knownDirectories(ctx context.Context, snapshots []*snapshot) knownDirsSet {
--	result := newKnownDirsSet()
--	for _, snapshot := range snapshots {
--		dirs := snapshot.dirs(ctx)
--		for _, dir := range dirs {
--			result.Insert(dir)
--		}
--		knownSubdirs := snapshot.getKnownSubdirs(dirs)
--		result.SetAll(knownSubdirs)
--		knownSubdirs.Destroy()
--	}
--	return result
--}
--
--// knownFilesInDir returns the files known to the snapshots in the session.
--// It does not respect symlinks.
--func knownFilesInDir(ctx context.Context, snapshots []*snapshot, dir span.URI) map[span.URI]struct{} {
--	files := map[span.URI]struct{}{}
--
--	for _, snapshot := range snapshots {
--		for _, uri := range snapshot.knownFilesInDir(ctx, dir) {
--			files[uri] = struct{}{}
--		}
--	}
--	return files
--}
--
 -// Precondition: caller holds s.viewMu lock.
 -// TODO(rfindley): move this to fs_overlay.go.
 -func (fs *overlayFS) updateOverlays(ctx context.Context, changes []source.FileModification) error {
@@ -20178,11 +23222,8 @@
 -			}
 -			sameContentOnDisk = true
 -		default:
--			fh, err := fs.delegate.GetFile(ctx, c.URI)
--			if err != nil {
--				return err
--			}
--			_, readErr := fh.Read()
+-			fh := mustReadFile(ctx, fs.delegate, c.URI)
+-			_, readErr := fh.Content()
 -			sameContentOnDisk = (readErr == nil && fh.FileIdentity().Hash == hash)
 -		}
 -		o = &Overlay{
@@ -20203,9 +23244,33 @@
 -	return nil
 -}
 -
--// FileWatchingGlobPatterns returns glob patterns to watch every directory
--// known by the view. For views within a module, this is the module root,
--// any directory in the module root, and any replace targets.
+-func mustReadFile(ctx context.Context, fs source.FileSource, uri span.URI) source.FileHandle {
+-	ctx = xcontext.Detach(ctx)
+-	fh, err := fs.ReadFile(ctx, uri)
+-	if err != nil {
+-		// ReadFile cannot fail with an uncancellable context.
+-		bug.Reportf("reading file failed unexpectedly: %v", err)
+-		return brokenFile{uri, err}
+-	}
+-	return fh
+-}
+-
+-// A brokenFile represents an unexpected failure to read a file.
+-type brokenFile struct {
+-	uri span.URI
+-	err error
+-}
+-
+-func (b brokenFile) URI() span.URI                     { return b.uri }
+-func (b brokenFile) FileIdentity() source.FileIdentity { return source.FileIdentity{URI: b.uri} }
+-func (b brokenFile) SameContentsOnDisk() bool          { return false }
+-func (b brokenFile) Version() int32                    { return 0 }
+-func (b brokenFile) Content() ([]byte, error)          { return nil, b.err }
+-
+-// FileWatchingGlobPatterns returns a new set of glob patterns to
+-// watch every directory known by the view. For views within a module,
+-// this is the module root, any directory in the module root, and any
+-// replace targets.
 -func (s *Session) FileWatchingGlobPatterns(ctx context.Context) map[string]struct{} {
 -	s.viewMu.Lock()
 -	defer s.viewMu.Unlock()
@@ -20224,8 +23289,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/snapshot.go b/gopls/internal/lsp/cache/snapshot.go
 --- a/gopls/internal/lsp/cache/snapshot.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/snapshot.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2214 +0,0 @@
++++ b/gopls/internal/lsp/cache/snapshot.go	1970-01-01 08:00:00
+@@ -1,2472 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -20238,10 +23303,10 @@
 -	"errors"
 -	"fmt"
 -	"go/ast"
+-	"go/build/constraint"
 -	"go/token"
 -	"go/types"
 -	"io"
--	"io/ioutil"
 -	"log"
 -	"os"
 -	"path/filepath"
@@ -20257,12 +23322,15 @@
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/packages"
 -	"golang.org/x/tools/go/types/objectpath"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/filecache"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
 -	"golang.org/x/tools/gopls/internal/lsp/source/xrefs"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/gocommand"
@@ -20300,14 +23368,17 @@
 -	// view.initializationSema.
 -	initialized bool
 -	// initializedErr holds the last error resulting from initialization. If
--	// initialization fails, we only retry when the the workspace modules change,
+-	// initialization fails, we only retry when the workspace modules change,
 -	// to avoid too many go/packages calls.
 -	initializedErr *source.CriticalError
 -
 -	// mu guards all of the maps in the snapshot, as well as the builtin URI.
 -	mu sync.Mutex
 -
--	// builtin pins the AST and package for builtin.go in memory.
+-	// builtin is the location of builtin.go in GOROOT.
+-	//
+-	// TODO(rfindley): would it make more sense to eagerly parse builtin, and
+-	// instead store a *ParsedGoFile here?
 -	builtin span.URI
 -
 -	// meta holds loaded metadata.
@@ -20319,14 +23390,11 @@
 -
 -	// files maps file URIs to their corresponding FileHandles.
 -	// It may invalidated when a file's content changes.
--	files filesMap
--
--	// parseCache holds an LRU cache of recently parsed files.
--	parseCache *parseCache
+-	files *fileMap
 -
 -	// symbolizeHandles maps each file URI to a handle for the future
 -	// result of computing the symbols declared in that file.
--	symbolizeHandles *persistent.Map // from span.URI to *memoize.Promise[symbolizeResult]
+-	symbolizeHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[symbolizeResult]
 -
 -	// packages maps a packageKey to a *packageHandle.
 -	// It may be invalidated when a file's content changes.
@@ -20335,21 +23403,17 @@
 -	//  - packages.Get(id).meta == meta.metadata[id] for all ids
 -	//  - if a package is in packages, then all of its dependencies should also
 -	//    be in packages, unless there is a missing import
--	packages *persistent.Map // from packageID to *packageHandle
+-	packages *persistent.Map[PackageID, *packageHandle]
 -
 -	// activePackages maps a package ID to a memoized active package, or nil if
 -	// the package is known not to be open.
 -	//
 -	// IDs not contained in the map are not known to be open or not open.
--	activePackages *persistent.Map // from packageID to *Package
--
--	// analyses maps an analysisKey (which identifies a package
--	// and a set of analyzers) to the handle for the future result
--	// of loading the package and analyzing it.
--	analyses *persistent.Map // from analysisKey to analysisPromise
+-	activePackages *persistent.Map[PackageID, *Package]
 -
 -	// workspacePackages contains the workspace's packages, which are loaded
--	// when the view is created.
+-	// when the view is created. It contains no intermediate test variants.
+-	// TODO(rfindley): use a persistent.Map.
 -	workspacePackages map[PackageID]PackagePath
 -
 -	// shouldLoad tracks packages that need to be reloaded, mapping a PackageID
@@ -20360,34 +23424,25 @@
 -	shouldLoad map[PackageID][]PackagePath
 -
 -	// unloadableFiles keeps track of files that we've failed to load.
--	unloadableFiles map[span.URI]struct{}
+-	unloadableFiles *persistent.Set[span.URI]
 -
 -	// TODO(rfindley): rename the handles below to "promises". A promise is
 -	// different from a handle (we mutate the package handle.)
 -
 -	// parseModHandles keeps track of any parseModHandles for the snapshot.
 -	// The handles need not refer to only the view's go.mod file.
--	parseModHandles *persistent.Map // from span.URI to *memoize.Promise[parseModResult]
+-	parseModHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[parseModResult]
 -
 -	// parseWorkHandles keeps track of any parseWorkHandles for the snapshot.
 -	// The handles need not refer to only the view's go.work file.
--	parseWorkHandles *persistent.Map // from span.URI to *memoize.Promise[parseWorkResult]
+-	parseWorkHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[parseWorkResult]
 -
 -	// Preserve go.mod-related handles to avoid garbage-collecting the results
 -	// of various calls to the go command. The handles need not refer to only
 -	// the view's go.mod file.
--	modTidyHandles *persistent.Map // from span.URI to *memoize.Promise[modTidyResult]
--	modWhyHandles  *persistent.Map // from span.URI to *memoize.Promise[modWhyResult]
--	modVulnHandles *persistent.Map // from span.URI to *memoize.Promise[modVulnResult]
--
--	// knownSubdirs is the set of subdirectories in the workspace, used to
--	// create glob patterns for file watching.
--	knownSubdirs             knownDirsSet
--	knownSubdirsPatternCache string
--	// unprocessedSubdirChanges are any changes that might affect the set of
--	// subdirectories in the workspace. They are not reflected to knownSubdirs
--	// during the snapshot cloning step as it can slow down cloning.
--	unprocessedSubdirChanges []*fileChange
+-	modTidyHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modTidyResult]
+-	modWhyHandles  *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modWhyResult]
+-	modVulnHandles *persistent.Map[span.URI, *memoize.Promise] // *memoize.Promise[modVulnResult]
 -
 -	// workspaceModFiles holds the set of mod files active in this snapshot.
 -	//
@@ -20397,6 +23452,26 @@
 -	// This set is immutable inside the snapshot, and therefore is not guarded by mu.
 -	workspaceModFiles    map[span.URI]struct{}
 -	workspaceModFilesErr error // error encountered computing workspaceModFiles
+-
+-	// importGraph holds a shared import graph to use for type-checking. Adding
+-	// more packages to this import graph can speed up type checking, at the
+-	// expense of in-use memory.
+-	//
+-	// See getImportGraph for additional documentation.
+-	importGraphDone chan struct{} // closed when importGraph is set; may be nil
+-	importGraph     *importGraph  // copied from preceding snapshot and re-evaluated
+-
+-	// pkgIndex is an index of package IDs, for efficient storage of typerefs.
+-	pkgIndex *typerefs.PackageIndex
+-
+-	// Only compute module prefixes once, as they are used with high frequency to
+-	// detect ignored files.
+-	ignoreFilterOnce sync.Once
+-	ignoreFilter     *ignoreFilter
+-
+-	// options holds the user configuration at the time this snapshot was
+-	// created.
+-	options *source.Options
 -}
 -
 -var globalSnapshotID uint64
@@ -20441,7 +23516,7 @@
 -// The destroyedBy argument is used for debugging.
 -//
 -// v.snapshotMu must be held while calling this function, in order to preserve
--// the invariants described by the the docstring for v.snapshot.
+-// the invariants described by the docstring for v.snapshot.
 -func (v *View) destroy(s *snapshot, destroyedBy string) {
 -	v.snapshotWG.Add(1)
 -	go func() {
@@ -20463,15 +23538,14 @@
 -
 -	s.packages.Destroy()
 -	s.activePackages.Destroy()
--	s.analyses.Destroy()
 -	s.files.Destroy()
--	s.knownSubdirs.Destroy()
 -	s.symbolizeHandles.Destroy()
 -	s.parseModHandles.Destroy()
 -	s.parseWorkHandles.Destroy()
 -	s.modTidyHandles.Destroy()
 -	s.modVulnHandles.Destroy()
 -	s.modWhyHandles.Destroy()
+-	s.unloadableFiles.Destroy()
 -}
 -
 -func (s *snapshot) SequenceID() uint64 {
@@ -20486,6 +23560,41 @@
 -	return s.view
 -}
 -
+-func (s *snapshot) FileKind(fh source.FileHandle) source.FileKind {
+-	// The kind of an unsaved buffer comes from the
+-	// TextDocumentItem.LanguageID field in the didChange event,
+-	// not from the file name. They may differ.
+-	if o, ok := fh.(*Overlay); ok {
+-		if o.kind != source.UnknownKind {
+-			return o.kind
+-		}
+-	}
+-
+-	fext := filepath.Ext(fh.URI().Filename())
+-	switch fext {
+-	case ".go":
+-		return source.Go
+-	case ".mod":
+-		return source.Mod
+-	case ".sum":
+-		return source.Sum
+-	case ".work":
+-		return source.Work
+-	}
+-	exts := s.options.TemplateExtensions
+-	for _, ext := range exts {
+-		if fext == ext || fext == "."+ext {
+-			return source.Tmpl
+-		}
+-	}
+-	// and now what? This should never happen, but it does for cgo before go1.15
+-	return source.Go
+-}
+-
+-func (s *snapshot) Options() *source.Options {
+-	return s.options // temporarily return view options.
+-}
+-
 -func (s *snapshot) BackgroundContext() context.Context {
 -	return s.backgroundCtx
 -}
@@ -20499,7 +23608,8 @@
 -}
 -
 -func (s *snapshot) WorkFile() span.URI {
--	return s.view.effectiveGOWORK()
+-	gowork, _ := s.view.GOWORK()
+-	return gowork
 -}
 -
 -func (s *snapshot) Templates() map[span.URI]source.FileHandle {
@@ -20508,60 +23618,32 @@
 -
 -	tmpls := map[span.URI]source.FileHandle{}
 -	s.files.Range(func(k span.URI, fh source.FileHandle) {
--		if s.view.FileKind(fh) == source.Tmpl {
+-		if s.FileKind(fh) == source.Tmpl {
 -			tmpls[k] = fh
 -		}
 -	})
 -	return tmpls
 -}
 -
--func (s *snapshot) ValidBuildConfiguration() bool {
+-func (s *snapshot) validBuildConfiguration() bool {
 -	// Since we only really understand the `go` command, if the user has a
 -	// different GOPACKAGESDRIVER, assume that their configuration is valid.
 -	if s.view.hasGopackagesDriver {
 -		return true
 -	}
+-
 -	// Check if the user is working within a module or if we have found
 -	// multiple modules in the workspace.
 -	if len(s.workspaceModFiles) > 0 {
 -		return true
 -	}
--	// The user may have a multiple directories in their GOPATH.
--	// Check if the workspace is within any of them.
+-
 -	// TODO(rfindley): this should probably be subject to "if GO111MODULES = off {...}".
--	for _, gp := range filepath.SplitList(s.view.gopath) {
--		if source.InDir(filepath.Join(gp, "src"), s.view.folder.Filename()) {
--			return true
--		}
--	}
--	return false
--}
--
--// moduleMode reports whether the current snapshot uses Go modules.
--//
--// From https://go.dev/ref/mod, module mode is active if either of the
--// following hold:
--//   - GO111MODULE=on
--//   - GO111MODULE=auto and we are inside a module or have a GOWORK value.
--//
--// Additionally, this method returns false if GOPACKAGESDRIVER is set.
--//
--// TODO(rfindley): use this more widely.
--func (s *snapshot) moduleMode() bool {
--	// Since we only really understand the `go` command, if the user has a
--	// different GOPACKAGESDRIVER, assume that their configuration is valid.
--	if s.view.hasGopackagesDriver {
--		return false
--	}
--
--	switch s.view.effectiveGO111MODULE() {
--	case on:
+-	if s.view.inGOPATH {
 -		return true
--	case off:
--		return false
--	default:
--		return len(s.workspaceModFiles) > 0 || s.view.gowork != ""
 -	}
+-
+-	return false
 -}
 -
 -// workspaceMode describes the way in which the snapshot's workspace should
@@ -20573,7 +23655,7 @@
 -
 -	// If the view has an invalid configuration, don't build the workspace
 -	// module.
--	validBuildConfiguration := s.ValidBuildConfiguration()
+-	validBuildConfiguration := s.validBuildConfiguration()
 -	if !validBuildConfiguration {
 -		return mode
 -	}
@@ -20584,8 +23666,7 @@
 -		return mode
 -	}
 -	mode |= moduleMode
--	options := s.view.Options()
--	if options.TempModfile {
+-	if s.options.TempModfile {
 -		mode |= tempModfile
 -	}
 -	return mode
@@ -20598,9 +23679,6 @@
 -// multiple modules in on config, so buildOverlay needs to filter overlays by
 -// module.
 -func (s *snapshot) config(ctx context.Context, inv *gocommand.Invocation) *packages.Config {
--	s.view.optionsMu.Lock()
--	verboseOutput := s.view.options.VerboseOutput
--	s.view.optionsMu.Unlock()
 -
 -	cfg := &packages.Config{
 -		Context:    ctx,
@@ -20623,7 +23701,7 @@
 -			panic("go/packages must not be used to parse files")
 -		},
 -		Logf: func(format string, args ...interface{}) {
--			if verboseOutput {
+-			if s.options.VerboseOutput {
 -				event.Log(ctx, fmt.Sprintf(format, args...))
 -			}
 -		},
@@ -20685,11 +23763,11 @@
 -		return false, nil, nil, nil
 -	}
 -	var modBytes, sumBytes []byte
--	modBytes, err = ioutil.ReadFile(tmpURI.Filename())
+-	modBytes, err = os.ReadFile(tmpURI.Filename())
 -	if err != nil && !os.IsNotExist(err) {
 -		return false, nil, nil, err
 -	}
--	sumBytes, err = ioutil.ReadFile(strings.TrimSuffix(tmpURI.Filename(), ".mod") + ".sum")
+-	sumBytes, err = os.ReadFile(strings.TrimSuffix(tmpURI.Filename(), ".mod") + ".sum")
 -	if err != nil && !os.IsNotExist(err) {
 -		return false, nil, nil, err
 -	}
@@ -20705,18 +23783,16 @@
 -// it used only after call to tempModFile. Clarify that it is only
 -// non-nil on success.
 -func (s *snapshot) goCommandInvocation(ctx context.Context, flags source.InvocationFlags, inv *gocommand.Invocation) (tmpURI span.URI, updatedInv *gocommand.Invocation, cleanup func(), err error) {
--	s.view.optionsMu.Lock()
--	allowModfileModificationOption := s.view.options.AllowModfileModifications
--	allowNetworkOption := s.view.options.AllowImplicitNetworkAccess
+-	allowModfileModificationOption := s.options.AllowModfileModifications
+-	allowNetworkOption := s.options.AllowImplicitNetworkAccess
 -
 -	// TODO(rfindley): this is very hard to follow, and may not even be doing the
 -	// right thing: should inv.Env really trample view.options? Do we ever invoke
 -	// this with a non-empty inv.Env?
 -	//
 -	// We should refactor to make it clearer that the correct env is being used.
--	inv.Env = append(append(append(os.Environ(), s.view.options.EnvSlice()...), inv.Env...), "GO111MODULE="+s.view.GO111MODULE())
--	inv.BuildFlags = append([]string{}, s.view.options.BuildFlags...)
--	s.view.optionsMu.Unlock()
+-	inv.Env = append(append(append(os.Environ(), s.options.EnvSlice()...), inv.Env...), "GO111MODULE="+s.view.GO111MODULE())
+-	inv.BuildFlags = append([]string{}, s.options.BuildFlags...)
 -	cleanup = func() {} // fallback
 -
 -	// All logic below is for module mode.
@@ -20750,7 +23826,7 @@
 -	// the main (workspace) module. Otherwise, we should use the module for
 -	// the passed-in working dir.
 -	if mode == source.LoadWorkspace {
--		if s.view.effectiveGOWORK() == "" && s.view.gomod != "" {
+-		if gowork, _ := s.view.GOWORK(); gowork == "" && s.view.gomod != "" {
 -			modURI = s.view.gomod
 -		}
 -	} else {
@@ -20759,11 +23835,11 @@
 -
 -	var modContent []byte
 -	if modURI != "" {
--		modFH, err := s.GetFile(ctx, modURI)
+-		modFH, err := s.ReadFile(ctx, modURI)
 -		if err != nil {
 -			return "", nil, cleanup, err
 -		}
--		modContent, err = modFH.Read()
+-		modContent, err = modFH.Content()
 -		if err != nil {
 -			return "", nil, cleanup, err
 -		}
@@ -20816,7 +23892,7 @@
 -		if modURI == "" {
 -			return "", nil, cleanup, fmt.Errorf("no go.mod file found in %s", inv.WorkingDir)
 -		}
--		modFH, err := s.GetFile(ctx, modURI)
+-		modFH, err := s.ReadFile(ctx, modURI)
 -		if err != nil {
 -			return "", nil, cleanup, err
 -		}
@@ -20833,22 +23909,24 @@
 -}
 -
 -func (s *snapshot) buildOverlay() map[string][]byte {
+-	overlays := make(map[string][]byte)
+-	for _, overlay := range s.overlays() {
+-		if overlay.saved {
+-			continue
+-		}
+-		// TODO(rfindley): previously, there was a todo here to make sure we don't
+-		// send overlays outside of the current view. IMO we should instead make
+-		// sure this doesn't matter.
+-		overlays[overlay.URI().Filename()] = overlay.content
+-	}
+-	return overlays
+-}
+-
+-func (s *snapshot) overlays() []*Overlay {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	overlays := make(map[string][]byte)
--	s.files.Range(func(uri span.URI, fh source.FileHandle) {
--		overlay, ok := fh.(*Overlay)
--		if !ok {
--			return
--		}
--		if overlay.saved {
--			return
--		}
--		// TODO(rstambler): Make sure not to send overlays outside of the current view.
--		overlays[uri.Filename()] = overlay.content
--	})
--	return overlays
+-	return s.files.Overlays()
 -}
 -
 -// Package data kinds, identifying various package data that may be stored in
@@ -20858,37 +23936,59 @@
 -	methodSetsKind  = "methodsets"
 -	exportDataKind  = "export"
 -	diagnosticsKind = "diagnostics"
+-	typerefsKind    = "typerefs"
 -)
 -
 -func (s *snapshot) PackageDiagnostics(ctx context.Context, ids ...PackageID) (map[span.URI][]*source.Diagnostic, error) {
--	// TODO(rfindley): opt: avoid unnecessary encode->decode after type-checking.
--	data, err := s.getPackageData(ctx, diagnosticsKind, ids, func(p *syntaxPackage) []byte {
--		return encodeDiagnostics(p.diagnostics)
--	})
+-	ctx, done := event.Start(ctx, "cache.snapshot.PackageDiagnostics")
+-	defer done()
+-
+-	var mu sync.Mutex
 -	perFile := make(map[span.URI][]*source.Diagnostic)
--	for _, data := range data {
--		if data != nil {
--			for _, diag := range data.m.Diagnostics {
--				perFile[diag.URI] = append(perFile[diag.URI], diag)
--			}
--			diags := decodeDiagnostics(data.data)
--			for _, diag := range diags {
--				perFile[diag.URI] = append(perFile[diag.URI], diag)
--			}
+-	collect := func(diags []*source.Diagnostic) {
+-		mu.Lock()
+-		defer mu.Unlock()
+-		for _, diag := range diags {
+-			perFile[diag.URI] = append(perFile[diag.URI], diag)
 -		}
 -	}
--	return perFile, err
+-	pre := func(i int, ph *packageHandle) bool {
+-		data, err := filecache.Get(diagnosticsKind, ph.key)
+-		if err == nil { // hit
+-			collect(ph.m.Diagnostics)
+-			collect(decodeDiagnostics(data))
+-			return false
+-		} else if err != filecache.ErrNotFound {
+-			event.Error(ctx, "reading diagnostics from filecache", err)
+-		}
+-		return true
+-	}
+-	post := func(_ int, pkg *Package) {
+-		collect(pkg.m.Diagnostics)
+-		collect(pkg.pkg.diagnostics)
+-	}
+-	return perFile, s.forEachPackage(ctx, ids, pre, post)
 -}
 -
 -func (s *snapshot) References(ctx context.Context, ids ...PackageID) ([]source.XrefIndex, error) {
--	data, err := s.getPackageData(ctx, xrefsKind, ids, func(p *syntaxPackage) []byte { return p.xrefs })
+-	ctx, done := event.Start(ctx, "cache.snapshot.References")
+-	defer done()
+-
 -	indexes := make([]source.XrefIndex, len(ids))
--	for i, data := range data {
--		if data != nil {
--			indexes[i] = XrefIndex{m: data.m, data: data.data}
+-	pre := func(i int, ph *packageHandle) bool {
+-		data, err := filecache.Get(xrefsKind, ph.key)
+-		if err == nil { // hit
+-			indexes[i] = XrefIndex{m: ph.m, data: data}
+-			return false
+-		} else if err != filecache.ErrNotFound {
+-			event.Error(ctx, "reading xrefs from filecache", err)
 -		}
+-		return true
 -	}
--	return indexes, err
+-	post := func(i int, pkg *Package) {
+-		indexes[i] = XrefIndex{m: pkg.m, data: pkg.pkg.xrefs()}
+-	}
+-	return indexes, s.forEachPackage(ctx, ids, pre, post)
 -}
 -
 -// An XrefIndex is a helper for looking up a package in a given package.
@@ -20902,24 +24002,39 @@
 -}
 -
 -func (s *snapshot) MethodSets(ctx context.Context, ids ...PackageID) ([]*methodsets.Index, error) {
--	// TODO(rfindley): opt: avoid unnecessary encode->decode after type-checking.
--	data, err := s.getPackageData(ctx, methodSetsKind, ids, func(p *syntaxPackage) []byte {
--		return p.methodsets.Encode()
--	})
+-	ctx, done := event.Start(ctx, "cache.snapshot.MethodSets")
+-	defer done()
+-
 -	indexes := make([]*methodsets.Index, len(ids))
--	for i, data := range data {
--		if data != nil {
--			indexes[i] = methodsets.Decode(data.data)
--		} else if ids[i] == "unsafe" {
--			indexes[i] = &methodsets.Index{}
--		} else {
--			panic(fmt.Sprintf("nil data for %s", ids[i]))
+-	pre := func(i int, ph *packageHandle) bool {
+-		data, err := filecache.Get(methodSetsKind, ph.key)
+-		if err == nil { // hit
+-			indexes[i] = methodsets.Decode(data)
+-			return false
+-		} else if err != filecache.ErrNotFound {
+-			event.Error(ctx, "reading methodsets from filecache", err)
 -		}
+-		return true
 -	}
--	return indexes, err
+-	post := func(i int, pkg *Package) {
+-		indexes[i] = pkg.pkg.methodsets()
+-	}
+-	return indexes, s.forEachPackage(ctx, ids, pre, post)
 -}
 -
 -func (s *snapshot) MetadataForFile(ctx context.Context, uri span.URI) ([]*source.Metadata, error) {
+-	if s.view.ViewType() == AdHocView {
+-		// As described in golang/go#57209, in ad-hoc workspaces (where we load ./
+-		// rather than ./...), preempting the directory load with file loads can
+-		// lead to an inconsistent outcome, where certain files are loaded with
+-		// command-line-arguments packages and others are loaded only in the ad-hoc
+-		// package. Therefore, ensure that the workspace is loaded before doing any
+-		// file loads.
+-		if err := s.awaitLoaded(ctx); err != nil {
+-			return nil, err
+-		}
+-	}
+-
 -	s.mu.Lock()
 -
 -	// Start with the set of package associations derived from the last load.
@@ -20933,7 +24048,7 @@
 -	}
 -
 -	// Check if uri is known to be unloadable.
--	_, unloadable := s.unloadableFiles[uri]
+-	unloadable := s.unloadableFiles.Contains(uri)
 -
 -	s.mu.Unlock()
 -
@@ -20945,12 +24060,22 @@
 -		scope := fileLoadScope(uri)
 -		err := s.load(ctx, false, scope)
 -
--		// Guard against failed loads due to context cancellation.
 -		//
 -		// Return the context error here as the current operation is no longer
 -		// valid.
--		if ctxErr := ctx.Err(); ctxErr != nil {
--			return nil, ctxErr
+-		if err != nil {
+-			// Guard against failed loads due to context cancellation. We don't want
+-			// to mark loads as completed if they failed due to context cancellation.
+-			if ctx.Err() != nil {
+-				return nil, ctx.Err()
+-			}
+-
+-			// Don't return an error here, as we may still return stale IDs.
+-			// Furthermore, the result of MetadataForFile should be consistent upon
+-			// subsequent calls, even if the file is marked as unloadable.
+-			if !errors.Is(err, errNoPackages) {
+-				event.Error(ctx, "MetadataForFile", err)
+-			}
 -		}
 -
 -		// We must clear scopes after loading.
@@ -20959,13 +24084,6 @@
 -		// packages as loaded. We could do this from snapshot.load and avoid
 -		// raciness.
 -		s.clearShouldLoad(scope)
--
--		// Don't return an error here, as we may still return stale IDs.
--		// Furthermore, the result of MetadataForFile should be consistent upon
--		// subsequent calls, even if the file is marked as unloadable.
--		if err != nil && !errors.Is(err, errNoPackages) {
--			event.Error(ctx, "MetadataForFile", err)
--		}
 -	}
 -
 -	// Retrieve the metadata.
@@ -20983,17 +24101,27 @@
 -	// so if we get here and still have
 -	// no IDs, uri is unloadable.
 -	if !unloadable && len(ids) == 0 {
--		s.unloadableFiles[uri] = struct{}{}
+-		s.unloadableFiles.Add(uri)
 -	}
 -
--	// Sort packages "narrowest" to "widest" (in practice: non-tests before tests).
+-	// Sort packages "narrowest" to "widest" (in practice:
+-	// non-tests before tests), and regular packages before
+-	// their intermediate test variants (which have the same
+-	// files but different imports).
 -	sort.Slice(metas, func(i, j int) bool {
--		return len(metas[i].CompiledGoFiles) < len(metas[j].CompiledGoFiles)
+-		x, y := metas[i], metas[j]
+-		xfiles, yfiles := len(x.CompiledGoFiles), len(y.CompiledGoFiles)
+-		if xfiles != yfiles {
+-			return xfiles < yfiles
+-		}
+-		return boolLess(x.IsIntermediateTestVariant(), y.IsIntermediateTestVariant())
 -	})
 -
 -	return metas, nil
 -}
 -
+-func boolLess(x, y bool) bool { return !x && y } // false < true
+-
 -func (s *snapshot) ReverseDependencies(ctx context.Context, id PackageID, transitive bool) (map[PackageID]*source.Metadata, error) {
 -	if err := s.awaitLoaded(ctx); err != nil {
 -		return nil, err
@@ -21024,21 +24152,15 @@
 -	return rdeps, nil
 -}
 -
--func (s *snapshot) workspaceMetadata() (meta []*source.Metadata) {
--	s.mu.Lock()
--	defer s.mu.Unlock()
--
--	for id := range s.workspacePackages {
--		meta = append(meta, s.meta.metadata[id])
--	}
--	return meta
--}
--
 -// -- Active package tracking --
 -//
--// We say a package is "active" if any of its files are open. After
--// type-checking we keep active packages in memory. The activePackages
--// peristent map does bookkeeping for the set of active packages.
+-// We say a package is "active" if any of its files are open.
+-// This is an optimization: the "active" concept is an
+-// implementation detail of the cache and is not exposed
+-// in the source or Snapshot API.
+-// After type-checking we keep active packages in memory.
+-// The activePackages persistent map does bookkeeping for
+-// the set of active packages.
 -
 -// getActivePackage returns a the memoized active package for id, if it exists.
 -// If id is not active or has not yet been type-checked, it returns nil.
@@ -21047,49 +24169,36 @@
 -	defer s.mu.Unlock()
 -
 -	if value, ok := s.activePackages.Get(id); ok {
--		return value.(*Package) // possibly nil, if we have already checked this id.
+-		return value
 -	}
 -	return nil
 -}
 -
--// memoizeActivePackage checks if pkg is active, and if so either records it in
+-// setActivePackage checks if pkg is active, and if so either records it in
 -// the active packages map or returns the existing memoized active package for id.
--//
--// The resulting package is non-nil if and only if the specified package is open.
--func (s *snapshot) memoizeActivePackage(id PackageID, pkg *Package) (active *Package) {
+-func (s *snapshot) setActivePackage(id PackageID, pkg *Package) {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	if value, ok := s.activePackages.Get(id); ok {
--		return value.(*Package) // possibly nil, if we have already checked this id.
+-	if _, ok := s.activePackages.Get(id); ok {
+-		return // already memoized
 -	}
 -
--	defer func() {
--		s.activePackages.Set(id, active, nil) // store the result either way: remember that pkg is not open
--	}()
--	for _, cgf := range pkg.Metadata().GoFiles {
--		if s.isOpenLocked(cgf) {
--			return pkg
--		}
+-	if containsOpenFileLocked(s, pkg.Metadata()) {
+-		s.activePackages.Set(id, pkg, nil)
+-	} else {
+-		s.activePackages.Set(id, (*Package)(nil), nil) // remember that pkg is not open
 -	}
--	for _, cgf := range pkg.Metadata().CompiledGoFiles {
--		if s.isOpenLocked(cgf) {
--			return pkg
--		}
--	}
--	return nil
 -}
 -
 -func (s *snapshot) resetActivePackagesLocked() {
 -	s.activePackages.Destroy()
--	s.activePackages = persistent.NewMap(packageIDLessInterface)
+-	s.activePackages = new(persistent.Map[PackageID, *Package])
 -}
 -
--const fileExtensions = "go,mod,sum,work"
--
 -func (s *snapshot) fileWatchingGlobPatterns(ctx context.Context) map[string]struct{} {
--	extensions := fileExtensions
--	for _, ext := range s.View().Options().TemplateExtensions {
+-	extensions := "go,mod,sum,work"
+-	for _, ext := range s.Options().TemplateExtensions {
 -		extensions += "," + ext
 -	}
 -	// Work-around microsoft/vscode#100870 by making sure that we are,
@@ -21100,194 +24209,177 @@
 -	}
 -
 -	// If GOWORK is outside the folder, ensure we are watching it.
--	gowork := s.view.effectiveGOWORK()
+-	gowork, _ := s.view.GOWORK()
 -	if gowork != "" && !source.InDir(s.view.folder.Filename(), gowork.Filename()) {
 -		patterns[gowork.Filename()] = struct{}{}
 -	}
 -
 -	// Add a pattern for each Go module in the workspace that is not within the view.
--	dirs := s.dirs(ctx)
+-	dirs := s.workspaceDirs(ctx)
 -	for _, dir := range dirs {
--		dirName := dir.Filename()
--
 -		// If the directory is within the view's folder, we're already watching
 -		// it with the first pattern above.
--		if source.InDir(s.view.folder.Filename(), dirName) {
+-		if source.InDir(s.view.folder.Filename(), dir) {
 -			continue
 -		}
 -		// TODO(rstambler): If microsoft/vscode#3025 is resolved before
 -		// microsoft/vscode#101042, we will need a work-around for Windows
 -		// drive letter casing.
--		patterns[fmt.Sprintf("%s/**/*.{%s}", dirName, extensions)] = struct{}{}
+-		patterns[fmt.Sprintf("%s/**/*.{%s}", dir, extensions)] = struct{}{}
 -	}
 -
--	// Some clients do not send notifications for changes to directories that
--	// contain Go code (golang/go#42348). To handle this, explicitly watch all
--	// of the directories in the workspace. We find them by adding the
--	// directories of every file in the snapshot's workspace directories.
--	// There may be thousands.
--	if pattern := s.getKnownSubdirsPattern(dirs); pattern != "" {
--		patterns[pattern] = struct{}{}
+-	if s.watchSubdirs() {
+-		// Some clients (e.g. VS Code) do not send notifications for changes to
+-		// directories that contain Go code (golang/go#42348). To handle this,
+-		// explicitly watch all of the directories in the workspace. We find them
+-		// by adding the directories of every file in the snapshot's workspace
+-		// directories. There may be thousands of patterns, each a single
+-		// directory.
+-		//
+-		// We compute this set by looking at files that we've previously observed.
+-		// This may miss changed to directories that we haven't observed, but that
+-		// shouldn't matter as there is nothing to invalidate (if a directory falls
+-		// in forest, etc).
+-		//
+-		// (A previous iteration created a single glob pattern holding a union of
+-		// all the directories, but this was found to cause VS Code to get stuck
+-		// for several minutes after a buffer was saved twice in a workspace that
+-		// had >8000 watched directories.)
+-		//
+-		// Some clients (notably coc.nvim, which uses watchman for globs) perform
+-		// poorly with a large list of individual directories.
+-		s.addKnownSubdirs(patterns, dirs)
 -	}
 -
 -	return patterns
 -}
 -
--func (s *snapshot) getKnownSubdirsPattern(wsDirs []span.URI) string {
+-func (s *snapshot) addKnownSubdirs(patterns map[string]unit, wsDirs []string) {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	// First, process any pending changes and update the set of known
--	// subdirectories.
--	// It may change list of known subdirs and therefore invalidate the cache.
--	s.applyKnownSubdirsChangesLocked(wsDirs)
--
--	if s.knownSubdirsPatternCache == "" {
--		var builder strings.Builder
--		s.knownSubdirs.Range(func(uri span.URI) {
--			if builder.Len() == 0 {
--				builder.WriteString("{")
--			} else {
--				builder.WriteString(",")
+-	s.files.Dirs().Range(func(dir string) {
+-		for _, wsDir := range wsDirs {
+-			if source.InDir(wsDir, dir) {
+-				patterns[dir] = unit{}
 -			}
--			builder.WriteString(uri.Filename())
--		})
--		if builder.Len() > 0 {
--			builder.WriteString("}")
--			s.knownSubdirsPatternCache = builder.String()
 -		}
--	}
--
--	return s.knownSubdirsPatternCache
--}
--
--// collectAllKnownSubdirs collects all of the subdirectories within the
--// snapshot's workspace directories. None of the workspace directories are
--// included.
--func (s *snapshot) collectAllKnownSubdirs(ctx context.Context) {
--	dirs := s.dirs(ctx)
--
--	s.mu.Lock()
--	defer s.mu.Unlock()
--
--	s.knownSubdirs.Destroy()
--	s.knownSubdirs = newKnownDirsSet()
--	s.knownSubdirsPatternCache = ""
--	s.files.Range(func(uri span.URI, fh source.FileHandle) {
--		s.addKnownSubdirLocked(uri, dirs)
 -	})
 -}
 -
--func (s *snapshot) getKnownSubdirs(wsDirs []span.URI) knownDirsSet {
+-// workspaceDirs returns the workspace directories for the loaded modules.
+-//
+-// A workspace directory is, roughly speaking, a directory for which we care
+-// about file changes.
+-func (s *snapshot) workspaceDirs(ctx context.Context) []string {
+-	dirSet := make(map[string]unit)
+-
+-	// Dirs should, at the very least, contain the working directory and folder.
+-	dirSet[s.view.goCommandDir.Filename()] = unit{}
+-	dirSet[s.view.folder.Filename()] = unit{}
+-
+-	// Additionally, if e.g. go.work indicates other workspace modules, we should
+-	// include their directories too.
+-	if s.workspaceModFilesErr == nil {
+-		for modFile := range s.workspaceModFiles {
+-			dir := filepath.Dir(modFile.Filename())
+-			dirSet[dir] = unit{}
+-		}
+-	}
+-	var dirs []string
+-	for d := range dirSet {
+-		dirs = append(dirs, d)
+-	}
+-	sort.Strings(dirs)
+-	return dirs
+-}
+-
+-// watchSubdirs reports whether gopls should request separate file watchers for
+-// each relevant subdirectory. This is necessary only for clients (namely VS
+-// Code) that do not send notifications for individual files in a directory
+-// when the entire directory is deleted.
+-func (s *snapshot) watchSubdirs() bool {
+-	switch p := s.options.SubdirWatchPatterns; p {
+-	case source.SubdirWatchPatternsOn:
+-		return true
+-	case source.SubdirWatchPatternsOff:
+-		return false
+-	case source.SubdirWatchPatternsAuto:
+-		// See the documentation of InternalOptions.SubdirWatchPatterns for an
+-		// explanation of why VS Code gets a different default value here.
+-		//
+-		// Unfortunately, there is no authoritative list of client names, nor any
+-		// requirements that client names do not change. We should update the VS
+-		// Code extension to set a default value of "subdirWatchPatterns" to "on",
+-		// so that this workaround is only temporary.
+-		if s.options.ClientInfo != nil && s.options.ClientInfo.Name == "Visual Studio Code" {
+-			return true
+-		}
+-		return false
+-	default:
+-		bug.Reportf("invalid subdirWatchPatterns: %q", p)
+-		return false
+-	}
+-}
+-
+-// filesInDir returns all files observed by the snapshot that are contained in
+-// a directory with the provided URI.
+-func (s *snapshot) filesInDir(uri span.URI) []span.URI {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	// First, process any pending changes and update the set of known
--	// subdirectories.
--	s.applyKnownSubdirsChangesLocked(wsDirs)
--
--	return s.knownSubdirs.Clone()
--}
--
--func (s *snapshot) applyKnownSubdirsChangesLocked(wsDirs []span.URI) {
--	for _, c := range s.unprocessedSubdirChanges {
--		if c.isUnchanged {
--			continue
--		}
--		if !c.exists {
--			s.removeKnownSubdirLocked(c.fileHandle.URI())
--		} else {
--			s.addKnownSubdirLocked(c.fileHandle.URI(), wsDirs)
--		}
+-	dir := uri.Filename()
+-	if !s.files.Dirs().Contains(dir) {
+-		return nil
 -	}
--	s.unprocessedSubdirChanges = nil
--}
--
--func (s *snapshot) addKnownSubdirLocked(uri span.URI, dirs []span.URI) {
--	dir := filepath.Dir(uri.Filename())
--	// First check if the directory is already known, because then we can
--	// return early.
--	if s.knownSubdirs.Contains(span.URIFromPath(dir)) {
--		return
--	}
--	var matched span.URI
--	for _, wsDir := range dirs {
--		if source.InDir(wsDir.Filename(), dir) {
--			matched = wsDir
--			break
--		}
--	}
--	// Don't watch any directory outside of the workspace directories.
--	if matched == "" {
--		return
--	}
--	for {
--		if dir == "" || dir == matched.Filename() {
--			break
--		}
--		uri := span.URIFromPath(dir)
--		if s.knownSubdirs.Contains(uri) {
--			break
--		}
--		s.knownSubdirs.Insert(uri)
--		dir = filepath.Dir(dir)
--		s.knownSubdirsPatternCache = ""
--	}
--}
--
--func (s *snapshot) removeKnownSubdirLocked(uri span.URI) {
--	dir := filepath.Dir(uri.Filename())
--	for dir != "" {
--		uri := span.URIFromPath(dir)
--		if !s.knownSubdirs.Contains(uri) {
--			break
--		}
--		if info, _ := os.Stat(dir); info == nil {
--			s.knownSubdirs.Remove(uri)
--			s.knownSubdirsPatternCache = ""
--		}
--		dir = filepath.Dir(dir)
--	}
--}
--
--// knownFilesInDir returns the files known to the given snapshot that are in
--// the given directory. It does not respect symlinks.
--func (s *snapshot) knownFilesInDir(ctx context.Context, dir span.URI) []span.URI {
 -	var files []span.URI
--	s.mu.Lock()
--	defer s.mu.Unlock()
--
--	s.files.Range(func(uri span.URI, fh source.FileHandle) {
--		if source.InDir(dir.Filename(), uri.Filename()) {
+-	s.files.Range(func(uri span.URI, _ source.FileHandle) {
+-		if source.InDir(dir, uri.Filename()) {
 -			files = append(files, uri)
 -		}
 -	})
 -	return files
 -}
 -
--func (s *snapshot) ActiveMetadata(ctx context.Context) ([]*source.Metadata, error) {
+-func (s *snapshot) WorkspaceMetadata(ctx context.Context) ([]*source.Metadata, error) {
 -	if err := s.awaitLoaded(ctx); err != nil {
 -		return nil, err
 -	}
--	return s.workspaceMetadata(), nil
+-
+-	s.mu.Lock()
+-	defer s.mu.Unlock()
+-
+-	meta := make([]*source.Metadata, 0, len(s.workspacePackages))
+-	for id := range s.workspacePackages {
+-		meta = append(meta, s.meta.metadata[id])
+-	}
+-	return meta, nil
 -}
 -
 -// Symbols extracts and returns symbol information for every file contained in
 -// a loaded package. It awaits snapshot loading.
 -//
 -// TODO(rfindley): move this to the top of cache/symbols.go
--func (s *snapshot) Symbols(ctx context.Context) (map[span.URI][]source.Symbol, error) {
+-func (s *snapshot) Symbols(ctx context.Context, workspaceOnly bool) (map[span.URI][]source.Symbol, error) {
 -	if err := s.awaitLoaded(ctx); err != nil {
 -		return nil, err
 -	}
 -
--	// Build symbols for all loaded Go files.
--	s.mu.Lock()
--	meta := s.meta
--	s.mu.Unlock()
+-	var (
+-		meta []*source.Metadata
+-		err  error
+-	)
+-	if workspaceOnly {
+-		meta, err = s.WorkspaceMetadata(ctx)
+-	} else {
+-		meta, err = s.AllMetadata(ctx)
+-	}
+-	if err != nil {
+-		return nil, fmt.Errorf("loading metadata: %v", err)
+-	}
 -
 -	goFiles := make(map[span.URI]struct{})
--	for _, m := range meta.metadata {
+-	for _, m := range meta {
 -		for _, uri := range m.GoFiles {
 -			goFiles[uri] = struct{}{}
 -		}
@@ -21350,7 +24442,7 @@
 -func moduleForURI(modFiles map[span.URI]struct{}, uri span.URI) span.URI {
 -	var match span.URI
 -	for modURI := range modFiles {
--		if !source.InDir(span.Dir(modURI).Filename(), uri.Filename()) {
+-		if !source.InDir(filepath.Dir(modURI.Filename()), uri.Filename()) {
 -			continue
 -		}
 -		if len(modURI) > len(match) {
@@ -21365,7 +24457,6 @@
 -//
 -// The given uri must be a file, not a directory.
 -func nearestModFile(ctx context.Context, uri span.URI, fs source.FileSource) (span.URI, error) {
--	// TODO(rfindley)
 -	dir := filepath.Dir(uri.Filename())
 -	mod, err := findRootPattern(ctx, dir, "go.mod", fs)
 -	if err != nil {
@@ -21411,25 +24502,6 @@
 -	}
 -}
 -
--// noValidMetadataForURILocked reports whether there is any valid metadata for
--// the given URI.
--func (s *snapshot) noValidMetadataForURILocked(uri span.URI) bool {
--	for _, id := range s.meta.ids[uri] {
--		if _, ok := s.meta.metadata[id]; ok {
--			return false
--		}
--	}
--	return true
--}
--
--func (s *snapshot) isWorkspacePackage(id PackageID) bool {
--	s.mu.Lock()
--	defer s.mu.Unlock()
--
--	_, ok := s.workspacePackages[id]
--	return ok
--}
--
 -func (s *snapshot) FindFile(uri span.URI) source.FileHandle {
 -	s.view.markKnown(uri)
 -
@@ -21440,29 +24512,65 @@
 -	return result
 -}
 -
--// GetFile returns a File for the given URI. If the file is unknown it is added
+-// ReadFile returns a File for the given URI. If the file is unknown it is added
 -// to the managed set.
 -//
--// GetFile succeeds even if the file does not exist. A non-nil error return
+-// ReadFile succeeds even if the file does not exist. A non-nil error return
 -// indicates some type of internal error, for example if ctx is cancelled.
--func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
+-func (s *snapshot) ReadFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	return lockedSnapshot{s}.GetFile(ctx, uri)
+-	return lockedSnapshot{s}.ReadFile(ctx, uri)
+-}
+-
+-// preloadFiles delegates to the view FileSource to read the requested uris in
+-// parallel, without holding the snapshot lock.
+-func (s *snapshot) preloadFiles(ctx context.Context, uris []span.URI) {
+-	files := make([]source.FileHandle, len(uris))
+-	var wg sync.WaitGroup
+-	iolimit := make(chan struct{}, 20) // I/O concurrency limiting semaphore
+-	for i, uri := range uris {
+-		wg.Add(1)
+-		iolimit <- struct{}{}
+-		go func(i int, uri span.URI) {
+-			defer wg.Done()
+-			fh, err := s.view.fs.ReadFile(ctx, uri)
+-			<-iolimit
+-			if err != nil && ctx.Err() == nil {
+-				event.Error(ctx, fmt.Sprintf("reading %s", uri), err)
+-				return
+-			}
+-			files[i] = fh
+-		}(i, uri)
+-	}
+-	wg.Wait()
+-
+-	s.mu.Lock()
+-	defer s.mu.Unlock()
+-
+-	for i, fh := range files {
+-		if fh == nil {
+-			continue // error logged above
+-		}
+-		uri := uris[i]
+-		if _, ok := s.files.Get(uri); !ok {
+-			s.files.Set(uri, fh)
+-		}
+-	}
 -}
 -
 -// A lockedSnapshot implements the source.FileSource interface while holding
 -// the lock for the wrapped snapshot.
 -type lockedSnapshot struct{ wrapped *snapshot }
 -
--func (s lockedSnapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
+-func (s lockedSnapshot) ReadFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
 -	s.wrapped.view.markKnown(uri)
 -	if fh, ok := s.wrapped.files.Get(uri); ok {
 -		return fh, nil
 -	}
 -
--	fh, err := s.wrapped.view.fs.GetFile(ctx, uri) // read the file
+-	fh, err := s.wrapped.view.fs.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -21473,33 +24581,13 @@
 -func (s *snapshot) IsOpen(uri span.URI) bool {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
--	return s.isOpenLocked(uri)
 -
--}
--
--func (s *snapshot) openFiles() []source.FileHandle {
--	s.mu.Lock()
--	defer s.mu.Unlock()
--
--	var open []source.FileHandle
--	s.files.Range(func(uri span.URI, fh source.FileHandle) {
--		if isFileOpen(fh) {
--			open = append(open, fh)
--		}
--	})
--	return open
--}
--
--func (s *snapshot) isOpenLocked(uri span.URI) bool {
 -	fh, _ := s.files.Get(uri)
--	return isFileOpen(fh)
--}
--
--func isFileOpen(fh source.FileHandle) bool {
 -	_, open := fh.(*Overlay)
 -	return open
 -}
 -
+-// TODO(rfindley): it would make sense for awaitLoaded to return metadata.
 -func (s *snapshot) awaitLoaded(ctx context.Context) error {
 -	loadErr := s.awaitLoadedAllErrors(ctx)
 -
@@ -21511,7 +24599,7 @@
 -	return nil
 -}
 -
--func (s *snapshot) GetCriticalError(ctx context.Context) *source.CriticalError {
+-func (s *snapshot) CriticalError(ctx context.Context) *source.CriticalError {
 -	// If we couldn't compute workspace mod files, then the load below is
 -	// invalid.
 -	//
@@ -21528,7 +24616,7 @@
 -	// Even if packages didn't fail to load, we still may want to show
 -	// additional warnings.
 -	if loadErr == nil {
--		active, _ := s.ActiveMetadata(ctx)
+-		active, _ := s.WorkspaceMetadata(ctx)
 -		if msg := shouldShowAdHocPackagesWarning(s, active); msg != "" {
 -			return &source.CriticalError{
 -				MainError: errors.New(msg),
@@ -21579,8 +24667,8 @@
 -If you are using modules, please open your editor to a directory in your module.
 -If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.`
 -
--func shouldShowAdHocPackagesWarning(snapshot source.Snapshot, active []*source.Metadata) string {
--	if !snapshot.ValidBuildConfiguration() {
+-func shouldShowAdHocPackagesWarning(snapshot *snapshot, active []*source.Metadata) string {
+-	if !snapshot.validBuildConfiguration() {
 -		for _, m := range active {
 -			// A blank entry in DepsByImpPath
 -			// indicates a missing dependency.
@@ -21690,7 +24778,7 @@
 -
 -	// If the view's build configuration is invalid, we cannot reload by
 -	// package path. Just reload the directory instead.
--	if !s.ValidBuildConfiguration() {
+-	if !s.validBuildConfiguration() {
 -		scopes = []loadScope{viewLoadScope("LOAD_INVALID_VIEW")}
 -	}
 -
@@ -21705,86 +24793,307 @@
 -	return err
 -}
 -
+-// reloadOrphanedOpenFiles attempts to load a package for each open file that
+-// does not yet have an associated package. If loading finishes without being
+-// canceled, any files still not contained in a package are marked as unloadable.
+-//
+-// An error is returned if the load is canceled.
 -func (s *snapshot) reloadOrphanedOpenFiles(ctx context.Context) error {
+-	s.mu.Lock()
+-	meta := s.meta
+-	s.mu.Unlock()
 -	// When we load ./... or a package path directly, we may not get packages
 -	// that exist only in overlays. As a workaround, we search all of the files
 -	// available in the snapshot and reload their metadata individually using a
 -	// file= query if the metadata is unavailable.
--	files := s.orphanedOpenFiles()
--
--	// Files without a valid package declaration can't be loaded. Don't try.
--	var scopes []loadScope
--	for _, file := range files {
--		pgf, err := s.ParseGo(ctx, file, source.ParseHeader)
--		if err != nil {
+-	open := s.overlays()
+-	var files []*Overlay
+-	for _, o := range open {
+-		uri := o.URI()
+-		if s.IsBuiltin(uri) || s.FileKind(o) != source.Go {
 -			continue
 -		}
--		if !pgf.File.Package.IsValid() {
--			continue
+-		if len(meta.ids[uri]) == 0 {
+-			files = append(files, o)
 -		}
--
--		scopes = append(scopes, fileLoadScope(file.URI()))
 -	}
 -
--	if len(scopes) == 0 {
+-	// Filter to files that are not known to be unloadable.
+-	s.mu.Lock()
+-	loadable := files[:0]
+-	for _, file := range files {
+-		if !s.unloadableFiles.Contains(file.URI()) {
+-			loadable = append(loadable, file)
+-		}
+-	}
+-	files = loadable
+-	s.mu.Unlock()
+-
+-	if len(files) == 0 {
 -		return nil
 -	}
 -
--	// The regtests match this exact log message, keep them in sync.
--	event.Log(ctx, "reloadOrphanedFiles reloading", tag.Query.Of(scopes))
--	err := s.load(ctx, false, scopes...)
+-	var uris []span.URI
+-	for _, file := range files {
+-		uris = append(uris, file.URI())
+-	}
+-
+-	event.Log(ctx, "reloadOrphanedFiles reloading", tag.Files.Of(uris))
+-
+-	var g errgroup.Group
+-
+-	cpulimit := runtime.GOMAXPROCS(0)
+-	g.SetLimit(cpulimit)
+-
+-	// Load files one-at-a-time. go/packages can return at most one
+-	// command-line-arguments package per query.
+-	for _, file := range files {
+-		file := file
+-		g.Go(func() error {
+-			return s.load(ctx, false, fileLoadScope(file.URI()))
+-		})
+-	}
 -
 -	// If we failed to load some files, i.e. they have no metadata,
 -	// mark the failures so we don't bother retrying until the file's
 -	// content changes.
 -	//
--	// TODO(rstambler): This may be an overestimate if the load stopped
--	// early for an unrelated errors. Add a fallback?
--	//
--	// Check for context cancellation so that we don't incorrectly mark files
--	// as unloadable, but don't return before setting all workspace packages.
--	if ctx.Err() == nil && err != nil {
--		event.Error(ctx, "reloadOrphanedFiles: failed to load", err, tag.Query.Of(scopes))
--		s.mu.Lock()
--		for _, scope := range scopes {
--			uri := span.URI(scope.(fileLoadScope))
--			if s.noValidMetadataForURILocked(uri) {
--				s.unloadableFiles[uri] = struct{}{}
--			}
+-	// TODO(rfindley): is it possible that the load stopped early for an
+-	// unrelated errors? If so, add a fallback?
+-
+-	if err := g.Wait(); err != nil {
+-		// Check for context cancellation so that we don't incorrectly mark files
+-		// as unloadable, but don't return before setting all workspace packages.
+-		if ctx.Err() != nil {
+-			return ctx.Err()
 -		}
--		s.mu.Unlock()
+-
+-		if !errors.Is(err, errNoPackages) {
+-			event.Error(ctx, "reloadOrphanedFiles: failed to load", err, tag.Files.Of(uris))
+-		}
 -	}
+-
+-	// If the context was not canceled, we assume that the result of loading
+-	// packages is deterministic (though as we saw in golang/go#59318, it may not
+-	// be in the presence of bugs). Marking all unloaded files as unloadable here
+-	// prevents us from falling into recursive reloading where we only make a bit
+-	// of progress each time.
+-	s.mu.Lock()
+-	defer s.mu.Unlock()
+-	for _, file := range files {
+-		// TODO(rfindley): instead of locking here, we should have load return the
+-		// metadata graph that resulted from loading.
+-		uri := file.URI()
+-		if len(s.meta.ids[uri]) == 0 {
+-			s.unloadableFiles.Add(uri)
+-		}
+-	}
+-
 -	return nil
 -}
 -
--func (s *snapshot) orphanedOpenFiles() []source.FileHandle {
--	s.mu.Lock()
--	defer s.mu.Unlock()
+-// OrphanedFileDiagnostics reports diagnostics describing why open files have
+-// no packages or have only command-line-arguments packages.
+-//
+-// If the resulting diagnostic is nil, the file is either not orphaned or we
+-// can't produce a good diagnostic.
+-//
+-// TODO(rfindley): reconcile the definition of "orphaned" here with
+-// reloadOrphanedFiles. The latter does not include files with
+-// command-line-arguments packages.
+-func (s *snapshot) OrphanedFileDiagnostics(ctx context.Context) (map[span.URI]*source.Diagnostic, error) {
+-	if err := s.awaitLoaded(ctx); err != nil {
+-		return nil, err
+-	}
 -
--	var files []source.FileHandle
--	s.files.Range(func(uri span.URI, fh source.FileHandle) {
--		// Only consider open files, which will be represented as overlays.
--		if _, isOverlay := fh.(*Overlay); !isOverlay {
--			return
+-	var files []*Overlay
+-
+-searchOverlays:
+-	for _, o := range s.overlays() {
+-		uri := o.URI()
+-		if s.IsBuiltin(uri) || s.FileKind(o) != source.Go {
+-			continue
 -		}
--		// Don't try to reload metadata for go.mod files.
--		if s.view.FileKind(fh) != source.Go {
--			return
+-		md, err := s.MetadataForFile(ctx, uri)
+-		if err != nil {
+-			return nil, err
 -		}
--		// If the URI doesn't belong to this view, then it's not in a workspace
--		// package and should not be reloaded directly.
--		if !source.InDir(s.view.folder.Filename(), uri.Filename()) {
--			return
+-		for _, m := range md {
+-			if !source.IsCommandLineArguments(m.ID) || m.Standalone {
+-				continue searchOverlays
+-			}
 -		}
--		// Don't reload metadata for files we've already deemed unloadable.
--		if _, ok := s.unloadableFiles[uri]; ok {
--			return
+-		files = append(files, o)
+-	}
+-	if len(files) == 0 {
+-		return nil, nil
+-	}
+-
+-	loadedModFiles := make(map[span.URI]struct{}) // all mod files, including dependencies
+-	ignoredFiles := make(map[span.URI]bool)       // files reported in packages.Package.IgnoredFiles
+-
+-	meta, err := s.AllMetadata(ctx)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	for _, meta := range meta {
+-		if meta.Module != nil && meta.Module.GoMod != "" {
+-			gomod := span.URIFromPath(meta.Module.GoMod)
+-			loadedModFiles[gomod] = struct{}{}
 -		}
--		if s.noValidMetadataForURILocked(uri) {
--			files = append(files, fh)
+-		for _, ignored := range meta.IgnoredFiles {
+-			ignoredFiles[ignored] = true
 -		}
--	})
--	return files
+-	}
+-
+-	diagnostics := make(map[span.URI]*source.Diagnostic)
+-	for _, fh := range files {
+-		// Only warn about orphaned files if the file is well-formed enough to
+-		// actually be part of a package.
+-		//
+-		// Use ParseGo as for open files this is likely to be a cache hit (we'll have )
+-		pgf, err := s.ParseGo(ctx, fh, source.ParseHeader)
+-		if err != nil {
+-			continue
+-		}
+-		if !pgf.File.Name.Pos().IsValid() {
+-			continue
+-		}
+-		rng, err := pgf.PosRange(pgf.File.Name.Pos(), pgf.File.Name.End())
+-		if err != nil {
+-			continue
+-		}
+-
+-		var (
+-			msg            string                // if non-empty, report a diagnostic with this message
+-			suggestedFixes []source.SuggestedFix // associated fixes, if any
+-		)
+-
+-		// If we have a relevant go.mod file, check whether the file is orphaned
+-		// due to its go.mod file being inactive. We could also offer a
+-		// prescriptive diagnostic in the case that there is no go.mod file, but it
+-		// is harder to be precise in that case, and less important.
+-		if goMod, err := nearestModFile(ctx, fh.URI(), s); err == nil && goMod != "" {
+-			if _, ok := loadedModFiles[goMod]; !ok {
+-				modDir := filepath.Dir(goMod.Filename())
+-				viewDir := s.view.folder.Filename()
+-
+-				// When the module is underneath the view dir, we offer
+-				// "use all modules" quick-fixes.
+-				inDir := source.InDir(viewDir, modDir)
+-
+-				if rel, err := filepath.Rel(viewDir, modDir); err == nil {
+-					modDir = rel
+-				}
+-
+-				var fix string
+-				if s.view.goversion >= 18 {
+-					if s.view.gowork != "" {
+-						fix = fmt.Sprintf("To fix this problem, you can add this module to your go.work file (%s)", s.view.gowork)
+-						if cmd, err := command.NewRunGoWorkCommandCommand("Run `go work use`", command.RunGoWorkArgs{
+-							ViewID: s.view.ID(),
+-							Args:   []string{"use", modDir},
+-						}); err == nil {
+-							suggestedFixes = append(suggestedFixes, source.SuggestedFix{
+-								Title:      "Use this module in your go.work file",
+-								Command:    &cmd,
+-								ActionKind: protocol.QuickFix,
+-							})
+-						}
+-
+-						if inDir {
+-							if cmd, err := command.NewRunGoWorkCommandCommand("Run `go work use -r`", command.RunGoWorkArgs{
+-								ViewID: s.view.ID(),
+-								Args:   []string{"use", "-r", "."},
+-							}); err == nil {
+-								suggestedFixes = append(suggestedFixes, source.SuggestedFix{
+-									Title:      "Use all modules in your workspace",
+-									Command:    &cmd,
+-									ActionKind: protocol.QuickFix,
+-								})
+-							}
+-						}
+-					} else {
+-						fix = "To fix this problem, you can add a go.work file that uses this directory."
+-
+-						if cmd, err := command.NewRunGoWorkCommandCommand("Run `go work init && go work use`", command.RunGoWorkArgs{
+-							ViewID:    s.view.ID(),
+-							InitFirst: true,
+-							Args:      []string{"use", modDir},
+-						}); err == nil {
+-							suggestedFixes = []source.SuggestedFix{
+-								{
+-									Title:      "Add a go.work file using this module",
+-									Command:    &cmd,
+-									ActionKind: protocol.QuickFix,
+-								},
+-							}
+-						}
+-
+-						if inDir {
+-							if cmd, err := command.NewRunGoWorkCommandCommand("Run `go work init && go work use -r`", command.RunGoWorkArgs{
+-								ViewID:    s.view.ID(),
+-								InitFirst: true,
+-								Args:      []string{"use", "-r", "."},
+-							}); err == nil {
+-								suggestedFixes = append(suggestedFixes, source.SuggestedFix{
+-									Title:      "Add a go.work file using all modules in your workspace",
+-									Command:    &cmd,
+-									ActionKind: protocol.QuickFix,
+-								})
+-							}
+-						}
+-					}
+-				} else {
+-					fix = `To work with multiple modules simultaneously, please upgrade to Go 1.18 or
+-later, reinstall gopls, and use a go.work file.`
+-				}
+-				msg = fmt.Sprintf(`This file is within module %q, which is not included in your workspace.
+-%s
+-See the documentation for more information on setting up your workspace:
+-https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.`, modDir, fix)
+-			}
+-		}
+-
+-		if msg == "" && ignoredFiles[fh.URI()] {
+-			// TODO(rfindley): use the constraint package to check if the file
+-			// _actually_ satisfies the current build context.
+-			hasConstraint := false
+-			walkConstraints(pgf.File, func(constraint.Expr) bool {
+-				hasConstraint = true
+-				return false
+-			})
+-			var fix string
+-			if hasConstraint {
+-				fix = `This file may be excluded due to its build tags; try adding "-tags=<build tag>" to your gopls "buildFlags" configuration
+-See the documentation for more information on working with build tags:
+-https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string.`
+-			} else if strings.Contains(filepath.Base(fh.URI().Filename()), "_") {
+-				fix = `This file may be excluded due to its GOOS/GOARCH, or other build constraints.`
+-			} else {
+-				fix = `This file is ignored by your gopls build.` // we don't know why
+-			}
+-			msg = fmt.Sprintf("No packages found for open file %s.\n%s", fh.URI().Filename(), fix)
+-		}
+-
+-		if msg != "" {
+-			d := &source.Diagnostic{
+-				URI:            fh.URI(),
+-				Range:          rng,
+-				Severity:       protocol.SeverityWarning,
+-				Source:         source.ListError,
+-				Message:        msg,
+-				SuggestedFixes: suggestedFixes,
+-			}
+-			if ok := source.BundleQuickFixes(d); !ok {
+-				bug.Reportf("failed to bundle quick fixes for %v", d)
+-			}
+-			// Only report diagnostics if we detect an actual exclusion.
+-			diagnostics[fh.URI()] = d
+-		}
+-	}
+-	return diagnostics, nil
 -}
 -
 -// TODO(golang/go#53756): this function needs to consider more than just the
@@ -21795,93 +25104,19 @@
 -// Most likely, each call site of inVendor needs to be reconsidered to
 -// understand and correctly implement the desired behavior.
 -func inVendor(uri span.URI) bool {
--	_, after, found := cut(string(uri), "/vendor/")
+-	_, after, found := strings.Cut(string(uri), "/vendor/")
 -	// Only subdirectories of /vendor/ are considered vendored
 -	// (/vendor/a/foo.go is vendored, /vendor/foo.go is not).
 -	return found && strings.Contains(after, "/")
 -}
 -
--// TODO(adonovan): replace with strings.Cut when we can assume go1.18.
--func cut(s, sep string) (before, after string, found bool) {
--	if i := strings.Index(s, sep); i >= 0 {
--		return s[:i], s[i+len(sep):], true
--	}
--	return s, "", false
--}
--
--// unappliedChanges is a file source that handles an uncloned snapshot.
--type unappliedChanges struct {
--	originalSnapshot *snapshot
--	changes          map[span.URI]*fileChange
--}
--
--func (ac *unappliedChanges) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
--	if c, ok := ac.changes[uri]; ok {
--		return c.fileHandle, nil
--	}
--	return ac.originalSnapshot.GetFile(ctx, uri)
--}
--
--func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]*fileChange, forceReloadMetadata bool) (*snapshot, func()) {
--	ctx, done := event.Start(ctx, "snapshot.clone")
+-func (s *snapshot) clone(ctx, bgCtx context.Context, changes map[span.URI]source.FileHandle, newOptions *source.Options, forceReloadMetadata bool) (*snapshot, func()) {
+-	ctx, done := event.Start(ctx, "cache.snapshot.clone")
 -	defer done()
 -
--	reinit := false
--	wsModFiles, wsModFilesErr := s.workspaceModFiles, s.workspaceModFilesErr
--
--	if workURI := s.view.effectiveGOWORK(); workURI != "" {
--		if change, ok := changes[workURI]; ok {
--			wsModFiles, wsModFilesErr = computeWorkspaceModFiles(ctx, s.view.gomod, workURI, s.view.effectiveGO111MODULE(), &unappliedChanges{
--				originalSnapshot: s,
--				changes:          changes,
--			})
--			// TODO(rfindley): don't rely on 'isUnchanged' here. Use a content hash instead.
--			reinit = change.fileHandle.Saved() && !change.isUnchanged
--		}
--	}
--
--	// Reinitialize if any workspace mod file has changed on disk.
--	for uri, change := range changes {
--		if _, ok := wsModFiles[uri]; ok && change.fileHandle.Saved() && !change.isUnchanged {
--			reinit = true
--		}
--	}
--
--	// Finally, process sumfile changes that may affect loading.
--	for uri, change := range changes {
--		if !change.fileHandle.Saved() {
--			continue // like with go.mod files, we only reinit when things are saved
--		}
--		if filepath.Base(uri.Filename()) == "go.work.sum" && s.view.gowork != "" {
--			if filepath.Dir(uri.Filename()) == filepath.Dir(s.view.gowork) {
--				reinit = true
--			}
--		}
--		if filepath.Base(uri.Filename()) == "go.sum" {
--			dir := filepath.Dir(uri.Filename())
--			modURI := span.URIFromPath(filepath.Join(dir, "go.mod"))
--			if _, active := wsModFiles[modURI]; active {
--				reinit = true
--			}
--		}
--	}
--
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -
--	// Changes to vendor tree may require reinitialization,
--	// either because of an initialization error
--	// (e.g. "inconsistent vendoring detected"), or because
--	// one or more modules may have moved into or out of the
--	// vendor tree after 'go mod vendor' or 'rm -fr vendor/'.
--	for uri := range changes {
--		if inVendor(uri) && s.initializedErr != nil ||
--			strings.HasSuffix(string(uri), "/vendor/modules.txt") {
--			reinit = true
--			break
--		}
--	}
--
 -	bgCtx, cancel := context.WithCancel(bgCtx)
 -	result := &snapshot{
 -		sequenceID:           s.sequenceID + 1,
@@ -21895,26 +25130,24 @@
 -		initializedErr:       s.initializedErr,
 -		packages:             s.packages.Clone(),
 -		activePackages:       s.activePackages.Clone(),
--		analyses:             s.analyses.Clone(),
--		files:                s.files.Clone(),
--		parseCache:           s.parseCache,
--		symbolizeHandles:     s.symbolizeHandles.Clone(),
+-		files:                s.files.Clone(changes),
+-		symbolizeHandles:     cloneWithout(s.symbolizeHandles, changes),
 -		workspacePackages:    make(map[PackageID]PackagePath, len(s.workspacePackages)),
--		unloadableFiles:      make(map[span.URI]struct{}, len(s.unloadableFiles)),
--		parseModHandles:      s.parseModHandles.Clone(),
--		parseWorkHandles:     s.parseWorkHandles.Clone(),
--		modTidyHandles:       s.modTidyHandles.Clone(),
--		modWhyHandles:        s.modWhyHandles.Clone(),
--		modVulnHandles:       s.modVulnHandles.Clone(),
--		knownSubdirs:         s.knownSubdirs.Clone(),
--		workspaceModFiles:    wsModFiles,
--		workspaceModFilesErr: wsModFilesErr,
+-		unloadableFiles:      s.unloadableFiles.Clone(), // not cloneWithout: typing in a file doesn't necessarily make it loadable
+-		parseModHandles:      cloneWithout(s.parseModHandles, changes),
+-		parseWorkHandles:     cloneWithout(s.parseWorkHandles, changes),
+-		modTidyHandles:       cloneWithout(s.modTidyHandles, changes),
+-		modWhyHandles:        cloneWithout(s.modWhyHandles, changes),
+-		modVulnHandles:       cloneWithout(s.modVulnHandles, changes),
+-		workspaceModFiles:    s.workspaceModFiles,
+-		workspaceModFilesErr: s.workspaceModFilesErr,
+-		importGraph:          s.importGraph,
+-		pkgIndex:             s.pkgIndex,
+-		options:              s.options,
 -	}
 -
--	// The snapshot should be initialized if either s was uninitialized, or we've
--	// detected a change that triggers reinitialization.
--	if reinit {
--		result.initialized = false
+-	if newOptions != nil {
+-		result.options = newOptions
 -	}
 -
 -	// Create a lease on the new snapshot.
@@ -21922,24 +25155,87 @@
 -	// incref/decref operation that might destroy it prematurely.)
 -	release := result.Acquire()
 -
--	// Copy the set of unloadable files.
+-	reinit := false
+-
+-	// Changes to vendor tree may require reinitialization,
+-	// either because of an initialization error
+-	// (e.g. "inconsistent vendoring detected"), or because
+-	// one or more modules may have moved into or out of the
+-	// vendor tree after 'go mod vendor' or 'rm -fr vendor/'.
 -	//
--	// TODO(rfindley): this looks wrong. Shouldn't we clear unloadableFiles on
--	// changes to environment or workspace layout, or more generally on any
--	// metadata change?
--	//
--	// Maybe not, as major configuration changes cause a new view.
--	for k, v := range s.unloadableFiles {
--		result.unloadableFiles[k] = v
+-	// TODO(rfindley): revisit the location of this check.
+-	for uri := range changes {
+-		if inVendor(uri) && s.initializedErr != nil ||
+-			strings.HasSuffix(string(uri), "/vendor/modules.txt") {
+-			reinit = true
+-			break
+-		}
 -	}
 -
--	// Add all of the known subdirectories, but don't update them for the
--	// changed files. We need to rebuild the workspace module to know the
--	// true set of known subdirectories, but we don't want to do that in clone.
--	result.knownSubdirs = s.knownSubdirs.Clone()
--	result.knownSubdirsPatternCache = s.knownSubdirsPatternCache
--	for _, c := range changes {
--		result.unprocessedSubdirChanges = append(result.unprocessedSubdirChanges, c)
+-	// Collect observed file handles for changed URIs from the old snapshot, if
+-	// they exist. Importantly, we don't call ReadFile here: consider the case
+-	// where a file is added on disk; we don't want to read the newly added file
+-	// into the old snapshot, as that will break our change detection below.
+-	oldFiles := make(map[span.URI]source.FileHandle)
+-	for uri := range changes {
+-		if fh, ok := s.files.Get(uri); ok {
+-			oldFiles[uri] = fh
+-		}
+-	}
+-	// changedOnDisk determines if the new file handle may have changed on disk.
+-	// It over-approximates, returning true if the new file is saved and either
+-	// the old file wasn't saved, or the on-disk contents changed.
+-	//
+-	// oldFH may be nil.
+-	changedOnDisk := func(oldFH, newFH source.FileHandle) bool {
+-		if !newFH.SameContentsOnDisk() {
+-			return false
+-		}
+-		if oe, ne := (oldFH != nil && fileExists(oldFH)), fileExists(newFH); !oe || !ne {
+-			return oe != ne
+-		}
+-		return !oldFH.SameContentsOnDisk() || oldFH.FileIdentity() != newFH.FileIdentity()
+-	}
+-
+-	if workURI, _ := s.view.GOWORK(); workURI != "" {
+-		if newFH, ok := changes[workURI]; ok {
+-			result.workspaceModFiles, result.workspaceModFilesErr = computeWorkspaceModFiles(ctx, s.view.gomod, workURI, s.view.effectiveGO111MODULE(), result)
+-			if changedOnDisk(oldFiles[workURI], newFH) {
+-				reinit = true
+-			}
+-		}
+-	}
+-
+-	// Reinitialize if any workspace mod file has changed on disk.
+-	for uri, newFH := range changes {
+-		if _, ok := result.workspaceModFiles[uri]; ok && changedOnDisk(oldFiles[uri], newFH) {
+-			reinit = true
+-		}
+-	}
+-
+-	// Finally, process sumfile changes that may affect loading.
+-	for uri, newFH := range changes {
+-		if !changedOnDisk(oldFiles[uri], newFH) {
+-			continue // like with go.mod files, we only reinit when things change on disk
+-		}
+-		dir, base := filepath.Split(uri.Filename())
+-		if base == "go.work.sum" && s.view.gowork != "" {
+-			if dir == filepath.Dir(s.view.gowork) {
+-				reinit = true
+-			}
+-		}
+-		if base == "go.sum" {
+-			modURI := span.URIFromPath(filepath.Join(dir, "go.mod"))
+-			if _, active := result.workspaceModFiles[modURI]; active {
+-				reinit = true
+-			}
+-		}
+-	}
+-
+-	// The snapshot should be initialized if either s was uninitialized, or we've
+-	// detected a change that triggers reinitialization.
+-	if reinit {
+-		result.initialized = false
 -	}
 -
 -	// directIDs keeps track of package IDs that have directly changed.
@@ -21949,6 +25245,7 @@
 -	// Invalidate all package metadata if the workspace module has changed.
 -	if reinit {
 -		for k := range s.meta.metadata {
+-			// TODO(rfindley): this seems brittle; can we just start over?
 -			directIDs[k] = true
 -		}
 -	}
@@ -21958,22 +25255,14 @@
 -	anyFileOpenedOrClosed := false // opened files affect workspace packages
 -	anyFileAdded := false          // adding a file can resolve missing dependencies
 -
--	for uri, change := range changes {
--		// Invalidate go.mod-related handles.
--		result.modTidyHandles.Delete(uri)
--		result.modWhyHandles.Delete(uri)
--		result.modVulnHandles.Delete(uri)
--
--		// Invalidate handles for cached symbols.
--		result.symbolizeHandles.Delete(uri)
--
+-	for uri, newFH := range changes {
 -		// The original FileHandle for this URI is cached on the snapshot.
--		originalFH, _ := s.files.Get(uri)
--		var originalOpen, newOpen bool
--		_, originalOpen = originalFH.(*Overlay)
--		_, newOpen = change.fileHandle.(*Overlay)
--		anyFileOpenedOrClosed = anyFileOpenedOrClosed || (originalOpen != newOpen)
--		anyFileAdded = anyFileAdded || (originalFH == nil && change.fileHandle != nil)
+-		oldFH, _ := oldFiles[uri] // may be nil
+-		_, oldOpen := oldFH.(*Overlay)
+-		_, newOpen := newFH.(*Overlay)
+-
+-		anyFileOpenedOrClosed = anyFileOpenedOrClosed || (oldOpen != newOpen)
+-		anyFileAdded = anyFileAdded || (oldFH == nil || !fileExists(oldFH)) && fileExists(newFH)
 -
 -		// If uri is a Go file, check if it has changed in a way that would
 -		// invalidate metadata. Note that we can't use s.view.FileKind here,
@@ -21981,7 +25270,11 @@
 -		// but what the Go command sees.
 -		var invalidateMetadata, pkgFileChanged, importDeleted bool
 -		if strings.HasSuffix(uri.Filename(), ".go") {
--			invalidateMetadata, pkgFileChanged, importDeleted = metadataChanges(ctx, s, originalFH, change.fileHandle)
+-			invalidateMetadata, pkgFileChanged, importDeleted = metadataChanges(ctx, s, oldFH, newFH)
+-		}
+-		if invalidateMetadata {
+-			// If this is a metadata-affecting change, perhaps a reload will succeed.
+-			result.unloadableFiles.Remove(uri)
 -		}
 -
 -		invalidateMetadata = invalidateMetadata || forceReloadMetadata || reinit
@@ -21995,26 +25288,45 @@
 -
 -		// Invalidate the previous modTidyHandle if any of the files have been
 -		// saved or if any of the metadata has been invalidated.
--		if invalidateMetadata || fileWasSaved(originalFH, change.fileHandle) {
--			// TODO(maybe): Only delete mod handles for
--			// which the withoutURI is relevant.
--			// Requires reverse-engineering the go command. (!)
--			result.modTidyHandles.Clear()
+-		//
+-		// TODO(rfindley): this seems like too-aggressive invalidation of mod
+-		// results. We should instead thread through overlays to the Go command
+-		// invocation and only run this if invalidateMetadata (and perhaps then
+-		// still do it less frequently).
+-		if invalidateMetadata || fileWasSaved(oldFH, newFH) {
+-			// Only invalidate mod tidy results for the most relevant modfile in the
+-			// workspace. This is a potentially lossy optimization for workspaces
+-			// with many modules (such as google-cloud-go, which has 145 modules as
+-			// of writing).
+-			//
+-			// While it is theoretically possible that a change in workspace module A
+-			// could affect the mod-tidiness of workspace module B (if B transitively
+-			// requires A), such changes are probably unlikely and not worth the
+-			// penalty of re-running go mod tidy for everything. Note that mod tidy
+-			// ignores GOWORK, so the two modules would have to be related by a chain
+-			// of replace directives.
+-			//
+-			// We could improve accuracy by inspecting replace directives, using
+-			// overlays in go mod tidy, and/or checking for metadata changes from the
+-			// on-disk content.
+-			//
+-			// Note that we iterate the modTidyHandles map here, rather than e.g.
+-			// using nearestModFile, because we don't have access to an accurate
+-			// FileSource at this point in the snapshot clone.
+-			const onlyInvalidateMostRelevant = true
+-			if onlyInvalidateMostRelevant {
+-				deleteMostRelevantModFile(result.modTidyHandles, uri)
+-			} else {
+-				result.modTidyHandles.Clear()
+-			}
+-
+-			// TODO(rfindley): should we apply the above heuristic to mod vuln or mod
+-			// why handles as well?
+-			//
+-			// TODO(rfindley): no tests fail if I delete the line below.
 -			result.modWhyHandles.Clear()
 -			result.modVulnHandles.Clear()
 -		}
--
--		result.parseModHandles.Delete(uri)
--		result.parseWorkHandles.Delete(uri)
--		// Handle the invalidated file; it may have new contents or not exist.
--		if !change.exists {
--			result.files.Delete(uri)
--		} else {
--			result.files.Set(uri, change.fileHandle)
--		}
--
--		// Make sure to remove the changed file from the unloadable set.
--		delete(result.unloadableFiles, uri)
 -	}
 -
 -	// Deleting an import can cause list errors due to import cycles to be
@@ -22078,41 +25390,17 @@
 -		addRevDeps(id, invalidateMetadata)
 -	}
 -
--	// Delete invalidated package type information.
--	for id := range idsToInvalidate {
--		result.packages.Delete(id)
--		result.activePackages.Delete(id)
--	}
--
--	// Delete invalidated analysis actions.
--	var actionsToDelete []analysisKey
--	result.analyses.Range(func(k, _ interface{}) {
--		key := k.(analysisKey)
--		if _, ok := idsToInvalidate[key.pkgid]; ok {
--			actionsToDelete = append(actionsToDelete, key)
--		}
--	})
--	for _, key := range actionsToDelete {
--		result.analyses.Delete(key)
--	}
--
--	// If a file has been deleted, we must delete metadata for all packages
--	// containing that file.
--	//
--	// TODO(rfindley): why not keep invalid metadata in this case? If we
--	// otherwise allow operate on invalid metadata, why not continue to do so,
--	// skipping the missing file?
--	skipID := map[PackageID]bool{}
--	for _, c := range changes {
--		if c.exists {
--			continue
--		}
--		// The file has been deleted.
--		if ids, ok := s.meta.ids[c.fileHandle.URI()]; ok {
--			for _, id := range ids {
--				skipID[id] = true
+-	// Invalidated package information.
+-	for id, invalidateMetadata := range idsToInvalidate {
+-		if _, ok := directIDs[id]; ok || invalidateMetadata {
+-			result.packages.Delete(id)
+-		} else {
+-			if entry, hit := result.packages.Get(id); hit {
+-				ph := entry.clone(false)
+-				result.packages.Set(id, ph, nil)
 -			}
 -		}
+-		result.activePackages.Delete(id)
 -	}
 -
 -	// Any packages that need loading in s still need loading in the new
@@ -22151,10 +25439,11 @@
 -		}
 -
 -		// Check whether the metadata should be deleted.
--		if skipID[k] || invalidateMetadata {
+-		if invalidateMetadata {
 -			metadataUpdates[k] = nil
 -			continue
 -		}
+-
 -	}
 -
 -	// Update metadata, if necessary.
@@ -22180,10 +25469,41 @@
 -	if workspaceModeChanged {
 -		result.workspacePackages = map[PackageID]PackagePath{}
 -	}
--	result.dumpWorkspace("clone")
 -	return result, release
 -}
 -
+-func cloneWithout[V any](m *persistent.Map[span.URI, V], changes map[span.URI]source.FileHandle) *persistent.Map[span.URI, V] {
+-	m2 := m.Clone()
+-	for k := range changes {
+-		m2.Delete(k)
+-	}
+-	return m2
+-}
+-
+-// deleteMostRelevantModFile deletes the mod file most likely to be the mod
+-// file for the changed URI, if it exists.
+-//
+-// Specifically, this is the longest mod file path in a directory containing
+-// changed. This might not be accurate if there is another mod file closer to
+-// changed that happens not to be present in the map, but that's OK: the goal
+-// of this function is to guarantee that IF the nearest mod file is present in
+-// the map, it is invalidated.
+-func deleteMostRelevantModFile(m *persistent.Map[span.URI, *memoize.Promise], changed span.URI) {
+-	var mostRelevant span.URI
+-	changedFile := changed.Filename()
+-
+-	m.Range(func(modURI span.URI, _ *memoize.Promise) {
+-		if len(modURI) > len(mostRelevant) {
+-			if source.InDir(filepath.Dir(modURI.Filename()), changedFile) {
+-				mostRelevant = modURI
+-			}
+-		}
+-	})
+-	if mostRelevant != "" {
+-		m.Delete(mostRelevant)
+-	}
+-}
+-
 -// invalidatedPackageIDs returns all packages invalidated by a change to uri.
 -// If we haven't seen this URI before, we guess based on files in the same
 -// directory. This is of course incorrect in build systems where packages are
@@ -22277,9 +25597,9 @@
 -//   - importDeleted means that an import has been deleted, or we can't
 -//     determine if an import was deleted due to errors.
 -func metadataChanges(ctx context.Context, lockedSnapshot *snapshot, oldFH, newFH source.FileHandle) (invalidate, pkgFileChanged, importDeleted bool) {
--	if oldFH == nil || newFH == nil { // existential changes
--		changed := (oldFH == nil) != (newFH == nil)
--		return changed, changed, (newFH == nil) // we don't know if an import was deleted
+-	if oe, ne := oldFH != nil && fileExists(oldFH), fileExists(newFH); !oe || !ne { // existential changes
+-		changed := oe != ne
+-		return changed, changed, !ne // we don't know if an import was deleted
 -	}
 -
 -	// If the file hasn't changed, there's no need to reload.
@@ -22287,16 +25607,12 @@
 -		return false, false, false
 -	}
 -
+-	fset := token.NewFileSet()
 -	// Parse headers to compare package names and imports.
--	oldHeads, _, oldErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseHeader, oldFH)
--	newHeads, _, newErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseHeader, newFH)
+-	oldHeads, oldErr := lockedSnapshot.view.parseCache.parseFiles(ctx, fset, source.ParseHeader, false, oldFH)
+-	newHeads, newErr := lockedSnapshot.view.parseCache.parseFiles(ctx, fset, source.ParseHeader, false, newFH)
 -
 -	if oldErr != nil || newErr != nil {
--		// TODO(rfindley): we can get here if newFH does not exist. There is
--		// asymmetry, in that newFH may be non-nil even if the underlying file does
--		// not exist.
--		//
--		// We should not produce a non-nil filehandle for a file that does not exist.
 -		errChanged := (oldErr == nil) != (newErr == nil)
 -		return errChanged, errChanged, (newErr != nil) // we don't know if an import was deleted
 -	}
@@ -22340,8 +25656,8 @@
 -	// Note: if this affects performance we can probably avoid parsing in the
 -	// common case by first scanning the source for potential comments.
 -	if !invalidate {
--		origFulls, _, oldErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseFull, oldFH)
--		newFulls, _, newErr := lockedSnapshot.parseCache.parseFiles(ctx, source.ParseFull, newFH)
+-		origFulls, oldErr := lockedSnapshot.view.parseCache.parseFiles(ctx, fset, source.ParseFull, false, oldFH)
+-		newFulls, newErr := lockedSnapshot.view.parseCache.parseFiles(ctx, fset, source.ParseFull, false, newFH)
 -		if oldErr == nil && newErr == nil {
 -			invalidate = magicCommentsChanged(origFulls[0].File, newFulls[0].File)
 -		} else {
@@ -22419,14 +25735,21 @@
 -		return nil, fmt.Errorf("no builtin package for view %s", s.view.name)
 -	}
 -
--	fh, err := s.GetFile(ctx, builtin)
+-	fh, err := s.ReadFile(ctx, builtin)
 -	if err != nil {
 -		return nil, err
 -	}
--	return s.ParseGo(ctx, fh, source.ParseFull)
+-	// For the builtin file only, we need syntactic object resolution
+-	// (since we can't type check).
+-	mode := source.ParseFull &^ source.SkipObjectResolution
+-	pgfs, err := s.view.parseCache.parseFiles(ctx, token.NewFileSet(), mode, false, fh)
+-	if err != nil {
+-		return nil, err
+-	}
+-	return pgfs[0], nil
 -}
 -
--func (s *snapshot) IsBuiltin(ctx context.Context, uri span.URI) bool {
+-func (s *snapshot) IsBuiltin(uri span.URI) bool {
 -	s.mu.Lock()
 -	defer s.mu.Unlock()
 -	// We should always get the builtin URI in a canonical form, so use simple
@@ -22440,182 +25763,10 @@
 -
 -	s.builtin = span.URIFromPath(path)
 -}
-diff -urN a/gopls/internal/lsp/cache/standalone_go115.go b/gopls/internal/lsp/cache/standalone_go115.go
---- a/gopls/internal/lsp/cache/standalone_go115.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/standalone_go115.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build !go1.16
--// +build !go1.16
--
--package cache
--
--// isStandaloneFile returns false, as the 'standaloneTags' setting is
--// unsupported on Go 1.15 and earlier.
--func isStandaloneFile(src []byte, standaloneTags []string) bool {
--	return false
--}
-diff -urN a/gopls/internal/lsp/cache/standalone_go116.go b/gopls/internal/lsp/cache/standalone_go116.go
---- a/gopls/internal/lsp/cache/standalone_go116.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/standalone_go116.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,50 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.16
--// +build go1.16
--
--package cache
--
--import (
--	"go/build/constraint"
--	"go/parser"
--	"go/token"
--)
--
--// isStandaloneFile reports whether a file with the given contents should be
--// considered a 'standalone main file', meaning a package that consists of only
--// a single file.
--func isStandaloneFile(src []byte, standaloneTags []string) bool {
--	f, err := parser.ParseFile(token.NewFileSet(), "", src, parser.PackageClauseOnly|parser.ParseComments)
--	if err != nil {
--		return false
--	}
--
--	if f.Name == nil || f.Name.Name != "main" {
--		return false
--	}
--
--	for _, cg := range f.Comments {
--		// Even with PackageClauseOnly the parser consumes the semicolon following
--		// the package clause, so we must guard against comments that come after
--		// the package name.
--		if cg.Pos() > f.Name.Pos() {
--			continue
--		}
--		for _, comment := range cg.List {
--			if c, err := constraint.Parse(comment.Text); err == nil {
--				if tag, ok := c.(*constraint.TagExpr); ok {
--					for _, t := range standaloneTags {
--						if t == tag.Tag {
--							return true
--						}
--					}
--				}
--			}
--		}
--	}
--
--	return false
--}
-diff -urN a/gopls/internal/lsp/cache/standalone_go116_test.go b/gopls/internal/lsp/cache/standalone_go116_test.go
---- a/gopls/internal/lsp/cache/standalone_go116_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/standalone_go116_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,96 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.16
--// +build go1.16
--
--package cache
--
--import (
--	"testing"
--)
--
--func TestIsStandaloneFile(t *testing.T) {
--	tests := []struct {
--		desc           string
--		contents       string
--		standaloneTags []string
--		want           bool
--	}{
--		{
--			"new syntax",
--			"//go:build ignore\n\npackage main\n",
--			[]string{"ignore"},
--			true,
--		},
--		{
--			"legacy syntax",
--			"// +build ignore\n\npackage main\n",
--			[]string{"ignore"},
--			true,
--		},
--		{
--			"multiple tags",
--			"//go:build ignore\n\npackage main\n",
--			[]string{"exclude", "ignore"},
--			true,
--		},
--		{
--			"invalid tag",
--			"// +build ignore\n\npackage main\n",
--			[]string{"script"},
--			false,
--		},
--		{
--			"non-main package",
--			"//go:build ignore\n\npackage p\n",
--			[]string{"ignore"},
--			false,
--		},
--		{
--			"alternate tag",
--			"// +build script\n\npackage main\n",
--			[]string{"script"},
--			true,
--		},
--		{
--			"both syntax",
--			"//go:build ignore\n// +build ignore\n\npackage main\n",
--			[]string{"ignore"},
--			true,
--		},
--		{
--			"after comments",
--			"// A non-directive comment\n//go:build ignore\n\npackage main\n",
--			[]string{"ignore"},
--			true,
--		},
--		{
--			"after package decl",
--			"package main //go:build ignore\n",
--			[]string{"ignore"},
--			false,
--		},
--		{
--			"on line after package decl",
--			"package main\n\n//go:build ignore\n",
--			[]string{"ignore"},
--			false,
--		},
--		{
--			"combined with other expressions",
--			"\n\n//go:build ignore || darwin\n\npackage main\n",
--			[]string{"ignore"},
--			false,
--		},
--	}
--
--	for _, test := range tests {
--		t.Run(test.desc, func(t *testing.T) {
--			if got := isStandaloneFile([]byte(test.contents), test.standaloneTags); got != test.want {
--				t.Errorf("isStandaloneFile(%q, %v) = %t, want %t", test.contents, test.standaloneTags, got, test.want)
--			}
--		})
--	}
--}
 diff -urN a/gopls/internal/lsp/cache/symbols.go b/gopls/internal/lsp/cache/symbols.go
 --- a/gopls/internal/lsp/cache/symbols.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/symbols.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,213 +0,0 @@
++++ b/gopls/internal/lsp/cache/symbols.go	1970-01-01 08:00:00
+@@ -1,192 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -22629,10 +25780,10 @@
 -	"go/types"
 -	"strings"
 -
+-	"golang.org/x/tools/gopls/internal/astutil"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/memoize"
 -)
 -
 -// symbolize returns the result of symbolizing the file identified by uri, using a cache.
@@ -22649,7 +25800,7 @@
 -
 -	// Cache miss?
 -	if !hit {
--		fh, err := s.GetFile(ctx, uri)
+-		fh, err := s.ReadFile(ctx, uri)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -22668,7 +25819,7 @@
 -	}
 -
 -	// Await result.
--	v, err := s.awaitPromise(ctx, entry.(*memoize.Promise))
+-	v, err := s.awaitPromise(ctx, entry)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -22677,10 +25828,8 @@
 -}
 -
 -// symbolizeImpl reads and parses a file and extracts symbols from it.
--// It may use a parsed file already present in the cache but
--// otherwise does not populate the cache.
 -func symbolizeImpl(ctx context.Context, snapshot *snapshot, fh source.FileHandle) ([]source.Symbol, error) {
--	pgfs, _, err := snapshot.parseCache.parseFiles(ctx, source.ParseFull, fh)
+-	pgfs, err := snapshot.view.parseCache.parseFiles(ctx, token.NewFileSet(), source.ParseFull, false, fh)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -22740,7 +25889,7 @@
 -			var recv *ast.Ident
 -			if decl.Recv.NumFields() > 0 {
 -				kind = protocol.Method
--				recv = unpackRecv(decl.Recv.List[0].Type)
+-				_, recv, _ = astutil.UnpackRecv(decl.Recv.List[0].Type)
 -			}
 -			w.atNode(decl.Name, decl.Name.Name, kind, recv)
 -		case *ast.GenDecl:
@@ -22776,25 +25925,6 @@
 -	return protocol.Class
 -}
 -
--func unpackRecv(rtyp ast.Expr) *ast.Ident {
--	// Extract the receiver identifier. Lifted from go/types/resolver.go
--L:
--	for {
--		switch t := rtyp.(type) {
--		case *ast.ParenExpr:
--			rtyp = t.X
--		case *ast.StarExpr:
--			rtyp = t.X
--		default:
--			break L
--		}
--	}
--	if name, _ := rtyp.(*ast.Ident); name != nil {
--		return name
--	}
--	return nil
--}
--
 -// walkType processes symbols related to a type expression. path is path of
 -// nested type identifiers to the type expression.
 -func (w *symbolWalker) walkType(typ ast.Expr, path ...*ast.Ident) {
@@ -22831,8 +25961,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/view.go b/gopls/internal/lsp/cache/view.go
 --- a/gopls/internal/lsp/cache/view.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/view.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1142 +0,0 @@
++++ b/gopls/internal/lsp/cache/view.go	1970-01-01 08:00:00
+@@ -1,1286 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -22846,7 +25976,6 @@
 -	"encoding/json"
 -	"errors"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"path"
 -	"path/filepath"
@@ -22860,10 +25989,10 @@
 -	"golang.org/x/mod/modfile"
 -	"golang.org/x/mod/semver"
 -	exec "golang.org/x/sys/execabs"
--	"golang.org/x/tools/gopls/internal/govulncheck"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/gocommand"
 -	"golang.org/x/tools/internal/imports"
@@ -22882,14 +26011,16 @@
 -	// name is the user-specified name of this view.
 -	name string
 -
--	optionsMu sync.Mutex
--	options   *source.Options
+-	// lastOptions holds the most recent options on this view, used for detecting
+-	// major changes.
+-	//
+-	// Guarded by Session.viewMu.
+-	lastOptions *source.Options
 -
 -	// Workspace information. The fields below are immutable, and together with
 -	// options define the build list. Any change to these fields results in a new
 -	// View.
--	folder               span.URI // user-specified workspace folder
--	workspaceInformation          // Go environment information
+-	workspaceInformation // Go environment information
 -
 -	importsState *importsState
 -
@@ -22900,12 +26031,15 @@
 -
 -	// vulns maps each go.mod file's URI to its known vulnerabilities.
 -	vulnsMu sync.Mutex
--	vulns   map[span.URI]*govulncheck.Result
+-	vulns   map[span.URI]*vulncheck.Result
+-
+-	// parseCache holds an LRU cache of recently parsed files.
+-	parseCache *parseCache
 -
 -	// fs is the file source used to populate this view.
--	fs source.FileSource
+-	fs *overlayFS
 -
--	// seenFiles tracks files that the view has accessed.
+-	// knownFiles tracks files that the view has accessed.
 -	// TODO(golang/go#57558): this notion is fundamentally problematic, and
 -	// should be removed.
 -	knownFilesMu sync.Mutex
@@ -22947,6 +26081,9 @@
 -//
 -// This type is compared to see if the View needs to be reconstructed.
 -type workspaceInformation struct {
+-	// folder is the LSP workspace folder.
+-	folder span.URI
+-
 -	// `go env` variables that need to be tracked by gopls.
 -	goEnv
 -
@@ -22965,6 +26102,17 @@
 -	// GOPACKAGESDRIVER environment variable or a gopackagesdriver binary on
 -	// their machine.
 -	hasGopackagesDriver bool
+-
+-	// inGOPATH reports whether the workspace directory is contained in a GOPATH
+-	// directory.
+-	inGOPATH bool
+-
+-	// goCommandDir is the dir to use for running go commands.
+-	//
+-	// The only case where this should matter is if we've narrowed the workspace to
+-	// a single nested module. In that case, the go command won't be able to find
+-	// the module unless we tell it the nested directory.
+-	goCommandDir span.URI
 -}
 -
 -// effectiveGO111MODULE reports the value of GO111MODULE effective in the go
@@ -22980,13 +26128,89 @@
 -	}
 -}
 -
--// effectiveGOWORK returns the effective GOWORK value for this workspace, if
--// any, in URI form.
--func (w workspaceInformation) effectiveGOWORK() span.URI {
--	if w.gowork == "off" || w.gowork == "" {
--		return ""
+-// A ViewType describes how we load package information for a view.
+-//
+-// This is used for constructing the go/packages.Load query, and for
+-// interpreting missing packages, imports, or errors.
+-//
+-// Each view has a ViewType which is derived from its immutable workspace
+-// information -- any environment change that would affect the view type
+-// results in a new view.
+-type ViewType int
+-
+-const (
+-	// GoPackagesDriverView is a view with a non-empty GOPACKAGESDRIVER
+-	// environment variable.
+-	GoPackagesDriverView ViewType = iota
+-
+-	// GOPATHView is a view in GOPATH mode.
+-	//
+-	// I.e. in GOPATH, with GO111MODULE=off, or GO111MODULE=auto with no
+-	// go.mod file.
+-	GOPATHView
+-
+-	// GoModuleView is a view in module mode with a single Go module.
+-	GoModuleView
+-
+-	// GoWorkView is a view in module mode with a go.work file.
+-	GoWorkView
+-
+-	// An AdHocView is a collection of files in a given directory, not in GOPATH
+-	// or a module.
+-	AdHocView
+-)
+-
+-// ViewType derives the type of the view from its workspace information.
+-//
+-// TODO(rfindley): this logic is overlapping and slightly inconsistent with
+-// validBuildConfiguration. As part of zero-config-gopls (golang/go#57979), fix
+-// this inconsistency and consolidate on the ViewType abstraction.
+-func (w workspaceInformation) ViewType() ViewType {
+-	if w.hasGopackagesDriver {
+-		return GoPackagesDriverView
 -	}
--	return span.URIFromPath(w.gowork)
+-	go111module := w.effectiveGO111MODULE()
+-	if w.gowork != "" && go111module != off {
+-		return GoWorkView
+-	}
+-	if w.gomod != "" && go111module != off {
+-		return GoModuleView
+-	}
+-	if w.inGOPATH && go111module != on {
+-		return GOPATHView
+-	}
+-	return AdHocView
+-}
+-
+-// moduleMode reports whether the current snapshot uses Go modules.
+-//
+-// From https://go.dev/ref/mod, module mode is active if either of the
+-// following hold:
+-//   - GO111MODULE=on
+-//   - GO111MODULE=auto and we are inside a module or have a GOWORK value.
+-//
+-// Additionally, this method returns false if GOPACKAGESDRIVER is set.
+-//
+-// TODO(rfindley): use this more widely.
+-func (w workspaceInformation) moduleMode() bool {
+-	switch w.ViewType() {
+-	case GoModuleView, GoWorkView:
+-		return true
+-	default:
+-		return false
+-	}
+-}
+-
+-// GOWORK returns the effective GOWORK value for this workspace, if
+-// any, in URI form.
+-//
+-// The second result reports whether the effective GOWORK value is "" because
+-// GOWORK=off.
+-func (w workspaceInformation) GOWORK() (span.URI, bool) {
+-	if w.gowork == "off" || w.gowork == "" {
+-		return "", w.gowork == "off"
+-	}
+-	return span.URIFromPath(w.gowork), false
 -}
 -
 -// GO111MODULE returns the value of GO111MODULE to use for running the go
@@ -23103,7 +26327,7 @@
 -// longer needed.
 -func tempModFile(modFh source.FileHandle, gosum []byte) (tmpURI span.URI, cleanup func(), err error) {
 -	filenameHash := source.Hashf("%s", modFh.URI().Filename())
--	tmpMod, err := ioutil.TempFile("", fmt.Sprintf("go.%s.*.mod", filenameHash))
+-	tmpMod, err := os.CreateTemp("", fmt.Sprintf("go.%s.*.mod", filenameHash))
 -	if err != nil {
 -		return "", nil, err
 -	}
@@ -23112,7 +26336,7 @@
 -	tmpURI = span.URIFromPath(tmpMod.Name())
 -	tmpSumName := sumFilename(tmpURI)
 -
--	content, err := modFh.Read()
+-	content, err := modFh.Content()
 -	if err != nil {
 -		return "", nil, err
 -	}
@@ -23138,7 +26362,7 @@
 -
 -	// Create an analogous go.sum, if one exists.
 -	if gosum != nil {
--		if err := ioutil.WriteFile(tmpSumName, gosum, 0655); err != nil {
+-		if err := os.WriteFile(tmpSumName, gosum, 0655); err != nil {
 -			return "", nil, err
 -		}
 -	}
@@ -23156,44 +26380,19 @@
 -	return v.folder
 -}
 -
--func (v *View) Options() *source.Options {
--	v.optionsMu.Lock()
--	defer v.optionsMu.Unlock()
--	return v.options
--}
--
--func (v *View) FileKind(fh source.FileHandle) source.FileKind {
--	// The kind of an unsaved buffer comes from the
--	// TextDocumentItem.LanguageID field in the didChange event,
--	// not from the file name. They may differ.
--	if o, ok := fh.(*Overlay); ok {
--		if o.kind != source.UnknownKind {
--			return o.kind
--		}
--	}
--
--	fext := filepath.Ext(fh.URI().Filename())
--	switch fext {
--	case ".go":
--		return source.Go
--	case ".mod":
--		return source.Mod
--	case ".sum":
--		return source.Sum
--	case ".work":
--		return source.Work
--	}
--	exts := v.Options().TemplateExtensions
--	for _, ext := range exts {
--		if fext == ext || fext == "."+ext {
--			return source.Tmpl
--		}
--	}
--	// and now what? This should never happen, but it does for cgo before go1.15
--	return source.Go
--}
--
 -func minorOptionsChange(a, b *source.Options) bool {
+-	// TODO(rfindley): this function detects whether a view should be recreated,
+-	// but this is also checked by the getWorkspaceInformation logic.
+-	//
+-	// We should eliminate this redundancy.
+-	//
+-	// Additionally, this function has existed for a long time, but git history
+-	// suggests that it was added arbitrarily, not due to an actual performance
+-	// problem.
+-	//
+-	// Especially now that we have optimized reinitialization of the session, we
+-	// should consider just always creating a new view on any options change.
+-
 -	// Check if any of the settings that modify our understanding of files have
 -	// been changed.
 -	if !reflect.DeepEqual(a.Env, b.Env) {
@@ -23221,29 +26420,42 @@
 -	return reflect.DeepEqual(aBuildFlags, bBuildFlags)
 -}
 -
--// SetViewOptions sets the options of the given view to new values. Calling
--// this may cause the view to be invalidated and a replacement view added to
--// the session. If so the new view will be returned, otherwise the original one
--// will be returned.
--func (s *Session) SetViewOptions(ctx context.Context, v *View, options *source.Options) (*View, error) {
--	// no need to rebuild the view if the options were not materially changed
--	v.optionsMu.Lock()
--	if minorOptionsChange(v.options, options) {
--		v.options = options
--		v.optionsMu.Unlock()
--		return v, nil
+-// SetFolderOptions updates the options of each View associated with the folder
+-// of the given URI.
+-//
+-// Calling this may cause each related view to be invalidated and a replacement
+-// view added to the session.
+-func (s *Session) SetFolderOptions(ctx context.Context, uri span.URI, options *source.Options) error {
+-	s.viewMu.Lock()
+-	defer s.viewMu.Unlock()
+-
+-	for _, v := range s.views {
+-		if v.folder == uri {
+-			if err := s.setViewOptions(ctx, v, options); err != nil {
+-				return err
+-			}
+-		}
 -	}
--	v.optionsMu.Unlock()
--	newView, err := s.updateView(ctx, v, options)
--	return newView, err
+-	return nil
+-}
+-
+-func (s *Session) setViewOptions(ctx context.Context, v *View, options *source.Options) error {
+-	// no need to rebuild the view if the options were not materially changed
+-	if minorOptionsChange(v.lastOptions, options) {
+-		_, release := v.invalidateContent(ctx, nil, options, false)
+-		release()
+-		v.lastOptions = options
+-		return nil
+-	}
+-	return s.updateViewLocked(ctx, v, options)
 -}
 -
 -// viewEnv returns a string describing the environment of a newly created view.
 -//
 -// It must not be called concurrently with any other view methods.
 -func viewEnv(v *View) string {
--	env := v.options.EnvSlice()
--	buildFlags := append([]string{}, v.options.BuildFlags...)
+-	env := v.snapshot.options.EnvSlice()
+-	buildFlags := append([]string{}, v.snapshot.options.BuildFlags...)
 -
 -	var buf bytes.Buffer
 -	fmt.Fprintf(&buf, `go info for %v
@@ -23254,9 +26466,9 @@
 -(selected go env: %v)
 -`,
 -		v.folder.Filename(),
--		v.workingDir().Filename(),
+-		v.goCommandDir.Filename(),
 -		strings.TrimRight(v.workspaceInformation.goversionOutput, "\n"),
--		v.snapshot.ValidBuildConfiguration(),
+-		v.snapshot.validBuildConfiguration(),
 -		buildFlags,
 -		v.goEnv,
 -	)
@@ -23271,7 +26483,7 @@
 -	return buf.String()
 -}
 -
--func (s *snapshot) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error {
+-func (s *snapshot) RunProcessEnvFunc(ctx context.Context, fn func(context.Context, *imports.Options) error) error {
 -	return s.view.importsState.runProcessEnvFunc(ctx, s, fn)
 -}
 -
@@ -23292,13 +26504,13 @@
 -// locateTemplateFiles ensures that the snapshot has mapped template files
 -// within the workspace folder.
 -func (s *snapshot) locateTemplateFiles(ctx context.Context) {
--	if len(s.view.Options().TemplateExtensions) == 0 {
+-	if len(s.options.TemplateExtensions) == 0 {
 -		return
 -	}
--	suffixes := s.view.Options().TemplateExtensions
+-	suffixes := s.options.TemplateExtensions
 -
 -	searched := 0
--	filterFunc := s.view.filterFunc()
+-	filterFunc := s.filterFunc()
 -	err := filepath.WalkDir(s.view.folder.Filename(), func(path string, entry os.DirEntry, err error) error {
 -		if err != nil {
 -			return err
@@ -23324,7 +26536,7 @@
 -		//
 -		// Furthermore, this operation must ignore errors, including context
 -		// cancellation, or risk leaving the snapshot in an undefined state.
--		s.GetFile(ctx, uri)
+-		s.ReadFile(ctx, uri)
 -		return nil
 -	})
 -	if err != nil {
@@ -23332,33 +26544,33 @@
 -	}
 -}
 -
--func (v *View) contains(uri span.URI) bool {
+-func (s *snapshot) contains(uri span.URI) bool {
 -	// If we've expanded the go dir to a parent directory, consider if the
 -	// expanded dir contains the uri.
 -	// TODO(rfindley): should we ignore the root here? It is not provided by the
 -	// user. It would be better to explicitly consider the set of active modules
 -	// wherever relevant.
 -	inGoDir := false
--	if source.InDir(v.workingDir().Filename(), v.folder.Filename()) {
--		inGoDir = source.InDir(v.workingDir().Filename(), uri.Filename())
+-	if source.InDir(s.view.goCommandDir.Filename(), s.view.folder.Filename()) {
+-		inGoDir = source.InDir(s.view.goCommandDir.Filename(), uri.Filename())
 -	}
--	inFolder := source.InDir(v.folder.Filename(), uri.Filename())
+-	inFolder := source.InDir(s.view.folder.Filename(), uri.Filename())
 -
 -	if !inGoDir && !inFolder {
 -		return false
 -	}
 -
--	return !v.filterFunc()(uri)
+-	return !s.filterFunc()(uri)
 -}
 -
 -// filterFunc returns a func that reports whether uri is filtered by the currently configured
 -// directoryFilters.
--func (v *View) filterFunc() func(span.URI) bool {
--	filterer := buildFilterer(v.folder.Filename(), v.gomodcache, v.Options())
+-func (s *snapshot) filterFunc() func(span.URI) bool {
+-	filterer := buildFilterer(s.view.folder.Filename(), s.view.gomodcache, s.options)
 -	return func(uri span.URI) bool {
 -		// Only filter relative to the configured root directory.
--		if source.InDir(v.folder.Filename(), uri.Filename()) {
--			return pathExcludedByFilter(strings.TrimPrefix(uri.Filename(), v.folder.Filename()), filterer)
+-		if source.InDir(s.view.folder.Filename(), uri.Filename()) {
+-			return pathExcludedByFilter(strings.TrimPrefix(uri.Filename(), s.view.folder.Filename()), filterer)
 -		}
 -		return false
 -	}
@@ -23375,7 +26587,7 @@
 -	//
 -	// TODO(rfindley): Make sure the go.work files are always known
 -	// to the view.
--	if c.URI == v.effectiveGOWORK() {
+-	if gowork, _ := v.GOWORK(); gowork == c.URI {
 -		return true
 -	}
 -
@@ -23385,7 +26597,12 @@
 -	// had neither test nor associated issue, and cited only emacs behavior, this
 -	// logic was deleted.
 -
--	return v.contains(c.URI)
+-	snapshot, release, err := v.getSnapshot()
+-	if err != nil {
+-		return false // view was shut down
+-	}
+-	defer release()
+-	return snapshot.contains(c.URI)
 -}
 -
 -func (v *View) markKnown(uri span.URI) {
@@ -23412,6 +26629,7 @@
 -
 -	v.snapshotMu.Lock()
 -	if v.snapshot != nil {
+-		v.snapshot.cancel()
 -		v.releaseSnapshot()
 -		v.destroy(v.snapshot, "View.shutdown")
 -		v.snapshot = nil
@@ -23422,22 +26640,57 @@
 -	v.snapshotWG.Wait()
 -}
 -
+-// While go list ./... skips directories starting with '.', '_', or 'testdata',
+-// gopls may still load them via file queries. Explicitly filter them out.
 -func (s *snapshot) IgnoredFile(uri span.URI) bool {
--	filename := uri.Filename()
--	var prefixes []string
--	if len(s.workspaceModFiles) == 0 {
--		for _, entry := range filepath.SplitList(s.view.gopath) {
--			prefixes = append(prefixes, filepath.Join(entry, "src"))
--		}
--	} else {
--		prefixes = append(prefixes, s.view.gomodcache)
--		for m := range s.workspaceModFiles {
--			prefixes = append(prefixes, span.Dir(m).Filename())
+-	// Fast path: if uri doesn't contain '.', '_', or 'testdata', it is not
+-	// possible that it is ignored.
+-	{
+-		uriStr := string(uri)
+-		if !strings.Contains(uriStr, ".") && !strings.Contains(uriStr, "_") && !strings.Contains(uriStr, "testdata") {
+-			return false
 -		}
 -	}
--	for _, prefix := range prefixes {
--		if strings.HasPrefix(filename, prefix) {
--			return checkIgnored(filename[len(prefix):])
+-
+-	s.ignoreFilterOnce.Do(func() {
+-		var dirs []string
+-		if len(s.workspaceModFiles) == 0 {
+-			for _, entry := range filepath.SplitList(s.view.gopath) {
+-				dirs = append(dirs, filepath.Join(entry, "src"))
+-			}
+-		} else {
+-			dirs = append(dirs, s.view.gomodcache)
+-			for m := range s.workspaceModFiles {
+-				dirs = append(dirs, filepath.Dir(m.Filename()))
+-			}
+-		}
+-		s.ignoreFilter = newIgnoreFilter(dirs)
+-	})
+-
+-	return s.ignoreFilter.ignored(uri.Filename())
+-}
+-
+-// An ignoreFilter implements go list's exclusion rules via its 'ignored' method.
+-type ignoreFilter struct {
+-	prefixes []string // root dirs, ending in filepath.Separator
+-}
+-
+-// newIgnoreFilter returns a new ignoreFilter implementing exclusion rules
+-// relative to the provided directories.
+-func newIgnoreFilter(dirs []string) *ignoreFilter {
+-	f := new(ignoreFilter)
+-	for _, d := range dirs {
+-		f.prefixes = append(f.prefixes, filepath.Clean(d)+string(filepath.Separator))
+-	}
+-	return f
+-}
+-
+-func (f *ignoreFilter) ignored(filename string) bool {
+-	for _, prefix := range f.prefixes {
+-		if suffix := strings.TrimPrefix(filename, prefix); suffix != filename {
+-			if checkIgnored(suffix) {
+-				return true
+-			}
 -		}
 -	}
 -	return false
@@ -23449,6 +26702,8 @@
 -//	Directory and file names that begin with "." or "_" are ignored
 -//	by the go tool, as are directories named "testdata".
 -func checkIgnored(suffix string) bool {
+-	// Note: this could be further optimized by writing a HasSegment helper, a
+-	// segment-boundary respecting variant of strings.Contains.
 -	for _, component := range strings.Split(suffix, string(filepath.Separator)) {
 -		if len(component) == 0 {
 -			continue
@@ -23493,7 +26748,6 @@
 -	}
 -
 -	s.loadWorkspace(ctx, firstAttempt)
--	s.collectAllKnownSubdirs(ctx)
 -}
 -
 -func (s *snapshot) loadWorkspace(ctx context.Context, firstAttempt bool) (loadErr error) {
@@ -23534,30 +26788,43 @@
 -		})
 -	}
 -
+-	// TODO(rfindley): this should be predicated on the s.view.moduleMode().
+-	// There is no point loading ./... if we have an empty go.work.
 -	if len(s.workspaceModFiles) > 0 {
 -		for modURI := range s.workspaceModFiles {
+-			// Verify that the modfile is valid before trying to load it.
+-			//
+-			// TODO(rfindley): now that we no longer need to parse the modfile in
+-			// order to load scope, we could move these diagnostics to a more general
+-			// location where we diagnose problems with modfiles or the workspace.
+-			//
 -			// Be careful not to add context cancellation errors as critical module
 -			// errors.
--			fh, err := s.GetFile(ctx, modURI)
+-			fh, err := s.ReadFile(ctx, modURI)
 -			if err != nil {
--				if ctx.Err() == nil {
--					addError(modURI, err)
+-				if ctx.Err() != nil {
+-					return ctx.Err()
 -				}
+-				addError(modURI, err)
 -				continue
 -			}
 -			parsed, err := s.ParseMod(ctx, fh)
 -			if err != nil {
--				if ctx.Err() == nil {
--					addError(modURI, err)
+-				if ctx.Err() != nil {
+-					return ctx.Err()
 -				}
+-				addError(modURI, err)
 -				continue
 -			}
 -			if parsed.File == nil || parsed.File.Module == nil {
 -				addError(modURI, fmt.Errorf("no module path for %s", modURI))
 -				continue
 -			}
--			path := parsed.File.Module.Mod.Path
--			scopes = append(scopes, moduleLoadScope(path))
+-			moduleDir := filepath.Dir(modURI.Filename())
+-			// Previously, we loaded <modulepath>/... for each module path, but that
+-			// is actually incorrect when the pattern may match packages in more than
+-			// one module. See golang/go#59458 for more details.
+-			scopes = append(scopes, moduleLoadScope{dir: moduleDir, modulePath: parsed.File.Module.Mod.Path})
 -		}
 -	} else {
 -		scopes = append(scopes, viewLoadScope("LOAD_VIEW"))
@@ -23613,7 +26880,9 @@
 -//
 -// invalidateContent returns a non-nil snapshot for the new content, along with
 -// a callback which the caller must invoke to release that snapshot.
--func (v *View) invalidateContent(ctx context.Context, changes map[span.URI]*fileChange, forceReloadMetadata bool) (*snapshot, func()) {
+-//
+-// newOptions may be nil, in which case options remain unchanged.
+-func (v *View) invalidateContent(ctx context.Context, changes map[span.URI]source.FileHandle, newOptions *source.Options, forceReloadMetadata bool) (*snapshot, func()) {
 -	// Detach the context so that content invalidation cannot be canceled.
 -	ctx = xcontext.Detach(ctx)
 -
@@ -23635,7 +26904,7 @@
 -	prevSnapshot.AwaitInitialized(ctx)
 -
 -	// Save one lease of the cloned snapshot in the view.
--	v.snapshot, v.releaseSnapshot = prevSnapshot.clone(ctx, v.baseCtx, changes, forceReloadMetadata)
+-	v.snapshot, v.releaseSnapshot = prevSnapshot.clone(ctx, v.baseCtx, changes, newOptions, forceReloadMetadata)
 -
 -	prevReleaseSnapshot()
 -	v.destroy(prevSnapshot, "View.invalidateContent")
@@ -23649,7 +26918,9 @@
 -		return workspaceInformation{}, fmt.Errorf("invalid workspace folder path: %w; check that the casing of the configured workspace folder path agrees with the casing reported by the operating system", err)
 -	}
 -	var err error
--	var info workspaceInformation
+-	info := workspaceInformation{
+-		folder: folder,
+-	}
 -	inv := gocommand.Invocation{
 -		WorkingDir: folder.Filename(),
 -		Env:        options.EnvSlice(),
@@ -23662,7 +26933,7 @@
 -	if err != nil {
 -		return info, err
 -	}
--	if err := info.goEnv.load(ctx, folder.Filename(), options.EnvSlice(), s.gocmdRunner); err != nil {
+-	if err := info.load(ctx, folder.Filename(), options.EnvSlice(), s.gocmdRunner); err != nil {
 -		return info, err
 -	}
 -	// The value of GOPACKAGESDRIVER is not returned through the go command.
@@ -23680,6 +26951,27 @@
 -		return info, err
 -	}
 -
+-	// Check if the workspace is within any GOPATH directory.
+-	for _, gp := range filepath.SplitList(info.gopath) {
+-		if source.InDir(filepath.Join(gp, "src"), folder.Filename()) {
+-			info.inGOPATH = true
+-			break
+-		}
+-	}
+-
+-	// Compute the "working directory", which is where we run go commands.
+-	//
+-	// Note: if gowork is in use, this will default to the workspace folder. In
+-	// the past, we would instead use the folder containing go.work. This should
+-	// not make a difference, and in fact may improve go list error messages.
+-	//
+-	// TODO(golang/go#57514): eliminate the expandWorkspaceToModule setting
+-	// entirely.
+-	if options.ExpandWorkspaceToModule && info.gomod != "" {
+-		info.goCommandDir = span.URIFromPath(filepath.Dir(info.gomod.Filename()))
+-	} else {
+-		info.goCommandDir = folder
+-	}
 -	return info, nil
 -}
 -
@@ -23721,24 +27013,6 @@
 -	return "", nil
 -}
 -
--// workingDir returns the directory from which to run Go commands.
--//
--// The only case where this should matter is if we've narrowed the workspace to
--// a singular nested module. In that case, the go command won't be able to find
--// the module unless we tell it the nested directory.
--func (v *View) workingDir() span.URI {
--	// Note: if gowork is in use, this will default to the workspace folder. In
--	// the past, we would instead use the folder containing go.work. This should
--	// not make a difference, and in fact may improve go list error messages.
--	//
--	// TODO(golang/go#57514): eliminate the expandWorkspaceToModule setting
--	// entirely.
--	if v.Options().ExpandWorkspaceToModule && v.gomod != "" {
--		return span.Dir(v.gomod)
--	}
--	return v.folder
--}
--
 -// findRootPattern looks for files with the given basename in dir or any parent
 -// directory of dir, using the provided FileSource. It returns the first match,
 -// starting from dir and search parents.
@@ -23748,11 +27022,11 @@
 -func findRootPattern(ctx context.Context, dir, basename string, fs source.FileSource) (string, error) {
 -	for dir != "" {
 -		target := filepath.Join(dir, basename)
--		exists, err := fileExists(ctx, span.URIFromPath(target), fs)
+-		fh, err := fs.ReadFile(ctx, span.URIFromPath(target))
 -		if err != nil {
--			return "", err // not readable or context cancelled
+-			return "", err // context cancelled
 -		}
--		if exists {
+-		if fileExists(fh) {
 -			return target, nil
 -		}
 -		// Trailing separators must be trimmed, otherwise filepath.Split is a noop.
@@ -23816,8 +27090,8 @@
 -const maxGovulncheckResultAge = 1 * time.Hour // Invalidate results older than this limit.
 -var timeNow = time.Now                        // for testing
 -
--func (v *View) Vulnerabilities(modfiles ...span.URI) map[span.URI]*govulncheck.Result {
--	m := make(map[span.URI]*govulncheck.Result)
+-func (v *View) Vulnerabilities(modfiles ...span.URI) map[span.URI]*vulncheck.Result {
+-	m := make(map[span.URI]*vulncheck.Result)
 -	now := timeNow()
 -	v.vulnsMu.Lock()
 -	defer v.vulnsMu.Unlock()
@@ -23838,7 +27112,7 @@
 -	return m
 -}
 -
--func (v *View) SetVulnerabilities(modfile span.URI, vulns *govulncheck.Result) {
+-func (v *View) SetVulnerabilities(modfile span.URI, vulns *vulncheck.Result) {
 -	v.vulnsMu.Lock()
 -	defer v.vulnsMu.Unlock()
 -
@@ -23927,7 +27201,7 @@
 -	// No vendor directory?
 -	// TODO(golang/go#57514): this is wrong if the working dir is not the module
 -	// root.
--	if fi, err := os.Stat(filepath.Join(s.view.workingDir().Filename(), "vendor")); err != nil || !fi.IsDir() {
+-	if fi, err := os.Stat(filepath.Join(s.view.goCommandDir.Filename(), "vendor")); err != nil || !fi.IsDir() {
 -		return false, nil
 -	}
 -
@@ -23977,8 +27251,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cache/view_test.go b/gopls/internal/lsp/cache/view_test.go
 --- a/gopls/internal/lsp/cache/view_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/view_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,278 +0,0 @@
++++ b/gopls/internal/lsp/cache/view_test.go	1970-01-01 08:00:00
+@@ -1,303 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -23987,31 +27261,27 @@
 -import (
 -	"context"
 -	"encoding/json"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"testing"
 -	"time"
 -
 -	"github.com/google/go-cmp/cmp"
--	"golang.org/x/tools/gopls/internal/govulncheck"
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
 -)
 -
 -func TestCaseInsensitiveFilesystem(t *testing.T) {
--	base, err := ioutil.TempDir("", t.Name())
--	if err != nil {
--		t.Fatal(err)
--	}
+-	base := t.TempDir()
 -
 -	inner := filepath.Join(base, "a/B/c/DEFgh")
 -	if err := os.MkdirAll(inner, 0777); err != nil {
 -		t.Fatal(err)
 -	}
 -	file := filepath.Join(inner, "f.go")
--	if err := ioutil.WriteFile(file, []byte("hi"), 0777); err != nil {
+-	if err := os.WriteFile(file, []byte("hi"), 0777); err != nil {
 -		t.Fatal(err)
 -	}
 -	if _, err := os.Stat(filepath.Join(inner, "F.go")); err != nil {
@@ -24201,19 +27471,19 @@
 -	now := time.Now()
 -
 -	view := &View{
--		vulns: make(map[span.URI]*govulncheck.Result),
+-		vulns: make(map[span.URI]*vulncheck.Result),
 -	}
 -	file1, file2 := span.URIFromPath("f1/go.mod"), span.URIFromPath("f2/go.mod")
 -
--	vuln1 := &govulncheck.Result{AsOf: now.Add(-(maxGovulncheckResultAge * 3) / 4)} // already ~3/4*maxGovulncheckResultAge old
+-	vuln1 := &vulncheck.Result{AsOf: now.Add(-(maxGovulncheckResultAge * 3) / 4)} // already ~3/4*maxGovulncheckResultAge old
 -	view.SetVulnerabilities(file1, vuln1)
 -
--	vuln2 := &govulncheck.Result{AsOf: now} // fresh.
+-	vuln2 := &vulncheck.Result{AsOf: now} // fresh.
 -	view.SetVulnerabilities(file2, vuln2)
 -
 -	t.Run("fresh", func(t *testing.T) {
 -		got := view.Vulnerabilities()
--		want := map[span.URI]*govulncheck.Result{
+-		want := map[span.URI]*vulncheck.Result{
 -			file1: vuln1,
 -			file2: vuln2,
 -		}
@@ -24227,7 +27497,7 @@
 -	timeNow = func() time.Time { return now.Add(maxGovulncheckResultAge / 2) }
 -	t.Run("after30min", func(t *testing.T) {
 -		got := view.Vulnerabilities()
--		want := map[span.URI]*govulncheck.Result{
+-		want := map[span.URI]*vulncheck.Result{
 -			file1: nil, // expired.
 -			file2: vuln2,
 -		}
@@ -24242,7 +27512,7 @@
 -
 -	t.Run("after1hr", func(t *testing.T) {
 -		got := view.Vulnerabilities()
--		want := map[span.URI]*govulncheck.Result{
+-		want := map[span.URI]*vulncheck.Result{
 -			file1: nil,
 -			file2: nil,
 -		}
@@ -24257,10 +27527,39 @@
 -	b, _ := json.MarshalIndent(x, "", " ")
 -	return string(b)
 -}
+-
+-func TestIgnoreFilter(t *testing.T) {
+-	tests := []struct {
+-		dirs []string
+-		path string
+-		want bool
+-	}{
+-		{[]string{"a"}, "a/testdata/foo", true},
+-		{[]string{"a"}, "a/_ignore/foo", true},
+-		{[]string{"a"}, "a/.ignore/foo", true},
+-		{[]string{"a"}, "b/testdata/foo", false},
+-		{[]string{"a"}, "testdata/foo", false},
+-		{[]string{"a", "b"}, "b/testdata/foo", true},
+-		{[]string{"a"}, "atestdata/foo", false},
+-	}
+-
+-	for _, test := range tests {
+-		// convert to filepaths, for convenience
+-		for i, dir := range test.dirs {
+-			test.dirs[i] = filepath.FromSlash(dir)
+-		}
+-		test.path = filepath.FromSlash(test.path)
+-
+-		f := newIgnoreFilter(test.dirs)
+-		if got := f.ignored(test.path); got != test.want {
+-			t.Errorf("newIgnoreFilter(%q).ignore(%q) = %t, want %t", test.dirs, test.path, got, test.want)
+-		}
+-	}
+-}
 diff -urN a/gopls/internal/lsp/cache/workspace.go b/gopls/internal/lsp/cache/workspace.go
 --- a/gopls/internal/lsp/cache/workspace.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cache/workspace.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,177 +0,0 @@
++++ b/gopls/internal/lsp/cache/workspace.go	1970-01-01 08:00:00
+@@ -1,133 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -24271,9 +27570,8 @@
 -	"context"
 -	"errors"
 -	"fmt"
--	"os"
+-	"io/fs"
 -	"path/filepath"
--	"sort"
 -	"strings"
 -
 -	"golang.org/x/mod/modfile"
@@ -24291,11 +27589,11 @@
 -		return nil, nil
 -	}
 -	if gowork != "" {
--		fh, err := fs.GetFile(ctx, gowork)
+-		fh, err := fs.ReadFile(ctx, gowork)
 -		if err != nil {
 -			return nil, err
 -		}
--		content, err := fh.Read()
+-		content, err := fh.Content()
 -		if err != nil {
 -			return nil, err
 -		}
@@ -24322,38 +27620,6 @@
 -	return nil, nil
 -}
 -
--// dirs returns the workspace directories for the loaded modules.
--//
--// A workspace directory is, roughly speaking, a directory for which we care
--// about file changes. This is used for the purpose of registering file
--// watching patterns, and expanding directory modifications to their adjacent
--// files.
--//
--// TODO(rfindley): move this to snapshot.go.
--// TODO(rfindley): can we make this abstraction simpler and/or more accurate?
--func (s *snapshot) dirs(ctx context.Context) []span.URI {
--	dirSet := make(map[span.URI]struct{})
--
--	// Dirs should, at the very least, contain the working directory and folder.
--	dirSet[s.view.workingDir()] = struct{}{}
--	dirSet[s.view.folder] = struct{}{}
--
--	// Additionally, if e.g. go.work indicates other workspace modules, we should
--	// include their directories too.
--	if s.workspaceModFilesErr == nil {
--		for modFile := range s.workspaceModFiles {
--			dir := filepath.Dir(modFile.Filename())
--			dirSet[span.URIFromPath(dir)] = struct{}{}
--		}
--	}
--	var dirs []span.URI
--	for d := range dirSet {
--		dirs = append(dirs, d)
--	}
--	sort.Slice(dirs, func(i, j int) bool { return dirs[i] < dirs[j] })
--	return dirs
--}
--
 -// isGoMod reports if uri is a go.mod file.
 -func isGoMod(uri span.URI) bool {
 -	return filepath.Base(uri.Filename()) == "go.mod"
@@ -24364,25 +27630,11 @@
 -	return filepath.Base(uri.Filename()) == "go.work"
 -}
 -
--// fileExists reports if the file uri exists within source.
--func fileExists(ctx context.Context, uri span.URI, source source.FileSource) (bool, error) {
--	fh, err := source.GetFile(ctx, uri)
--	if err != nil {
--		return false, err
--	}
--	return fileHandleExists(fh)
--}
--
--// fileHandleExists reports if the file underlying fh actually exits.
--func fileHandleExists(fh source.FileHandle) (bool, error) {
--	_, err := fh.Read()
--	if err == nil {
--		return true, nil
--	}
--	if os.IsNotExist(err) {
--		return false, nil
--	}
--	return false, err
+-// fileExists reports whether the file has a Content (which may be empty).
+-// An overlay exists even if it is not reflected in the file system.
+-func fileExists(fh source.FileHandle) bool {
+-	_, err := fh.Content()
+-	return err == nil
 -}
 -
 -// errExhausted is returned by findModules if the file scan limit is reached.
@@ -24390,7 +27642,10 @@
 -
 -// Limit go.mod search to 1 million files. As a point of reference,
 -// Kubernetes has 22K files (as of 2020-11-24).
--const fileLimit = 1000000
+-//
+-// Note: per golang/go#56496, the previous limit of 1M files was too slow, at
+-// which point this limit was decreased to 100K.
+-const fileLimit = 100_000
 -
 -// findModules recursively walks the root directory looking for go.mod files,
 -// returning the set of modules it discovers. If modLimit is non-zero,
@@ -24402,7 +27657,7 @@
 -	modFiles := make(map[span.URI]struct{})
 -	searched := 0
 -	errDone := errors.New("done")
--	err := filepath.Walk(root.Filename(), func(path string, info os.FileInfo, err error) error {
+-	err := filepath.WalkDir(root.Filename(), func(path string, info fs.DirEntry, err error) error {
 -		if err != nil {
 -			// Probably a permission error. Keep looking.
 -			return filepath.SkipDir
@@ -24440,8 +27695,8 @@
 -}
 diff -urN a/gopls/internal/lsp/call_hierarchy.go b/gopls/internal/lsp/call_hierarchy.go
 --- a/gopls/internal/lsp/call_hierarchy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/call_hierarchy.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,42 +0,0 @@
++++ b/gopls/internal/lsp/call_hierarchy.go	1970-01-01 08:00:00
+@@ -1,52 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -24453,9 +27708,13 @@
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
 -)
 -
 -func (s *Server) prepareCallHierarchy(ctx context.Context, params *protocol.CallHierarchyPrepareParams) ([]protocol.CallHierarchyItem, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.prepareCallHierarchy")
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -24466,6 +27725,9 @@
 -}
 -
 -func (s *Server) incomingCalls(ctx context.Context, params *protocol.CallHierarchyIncomingCallsParams) ([]protocol.CallHierarchyIncomingCall, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.incomingCalls")
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.Item.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -24476,6 +27738,9 @@
 -}
 -
 -func (s *Server) outgoingCalls(ctx context.Context, params *protocol.CallHierarchyOutgoingCallsParams) ([]protocol.CallHierarchyOutgoingCall, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.outgoingCalls")
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.Item.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -24486,8 +27751,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/call_hierarchy.go b/gopls/internal/lsp/cmd/call_hierarchy.go
 --- a/gopls/internal/lsp/cmd/call_hierarchy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/call_hierarchy.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,142 +0,0 @@
++++ b/gopls/internal/lsp/cmd/call_hierarchy.go	1970-01-01 08:00:00
+@@ -1,144 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -24530,16 +27795,16 @@
 -		return tool.CommandLineErrorf("call_hierarchy expects 1 argument (position)")
 -	}
 -
--	conn, err := c.app.connect(ctx)
+-	conn, err := c.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -
 -	loc, err := file.mapper.SpanLocation(from)
@@ -24601,27 +27866,29 @@
 -// callItemPrintString returns a protocol.CallHierarchyItem object represented as a string.
 -// item and call ranges (protocol.Range) are converted to user friendly spans (1-indexed).
 -func callItemPrintString(ctx context.Context, conn *connection, item protocol.CallHierarchyItem, callsURI protocol.DocumentURI, calls []protocol.Range) (string, error) {
--	itemFile := conn.openFile(ctx, item.URI.SpanURI())
--	if itemFile.err != nil {
--		return "", itemFile.err
+-	itemFile, err := conn.openFile(ctx, item.URI.SpanURI())
+-	if err != nil {
+-		return "", err
 -	}
--	itemSpan, err := itemFile.mapper.LocationSpan(protocol.Location{URI: item.URI, Range: item.Range})
+-	itemSpan, err := itemFile.mapper.RangeSpan(item.Range)
 -	if err != nil {
 -		return "", err
 -	}
 -
--	callsFile := conn.openFile(ctx, callsURI.SpanURI())
--	if callsURI != "" && callsFile.err != nil {
--		return "", callsFile.err
--	}
 -	var callRanges []string
--	for _, rng := range calls {
--		call, err := callsFile.mapper.RangeSpan(rng)
+-	if callsURI != "" {
+-		callsFile, err := conn.openFile(ctx, callsURI.SpanURI())
 -		if err != nil {
 -			return "", err
 -		}
--		callRange := fmt.Sprintf("%d:%d-%d", call.Start().Line(), call.Start().Column(), call.End().Column())
--		callRanges = append(callRanges, callRange)
+-		for _, rng := range calls {
+-			call, err := callsFile.mapper.RangeSpan(rng)
+-			if err != nil {
+-				return "", err
+-			}
+-			callRange := fmt.Sprintf("%d:%d-%d", call.Start().Line(), call.Start().Column(), call.End().Column())
+-			callRanges = append(callRanges, callRange)
+-		}
 -	}
 -
 -	printString := fmt.Sprintf("function %s in %v", item.Name, itemSpan)
@@ -24632,8 +27899,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/capabilities_test.go b/gopls/internal/lsp/cmd/capabilities_test.go
 --- a/gopls/internal/lsp/cmd/capabilities_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/capabilities_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,166 +0,0 @@
++++ b/gopls/internal/lsp/cmd/capabilities_test.go	1970-01-01 08:00:00
+@@ -1,176 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -24643,7 +27910,6 @@
 -import (
 -	"context"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"testing"
@@ -24651,36 +27917,44 @@
 -	"golang.org/x/tools/gopls/internal/lsp"
 -	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -// TestCapabilities does some minimal validation of the server's adherence to the LSP.
 -// The checks in the test are added as changes are made and errors noticed.
 -func TestCapabilities(t *testing.T) {
--	tmpDir, err := ioutil.TempDir("", "fake")
+-	// TODO(bcmills): This test fails on js/wasm, which is not unexpected, but the
+-	// failure mode is that the DidOpen call below reports "no views in session",
+-	// which seems a little too cryptic.
+-	// Is there some missing error reporting somewhere?
+-	testenv.NeedsTool(t, "go")
+-
+-	tmpDir, err := os.MkdirTemp("", "fake")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
 -	tmpFile := filepath.Join(tmpDir, "fake.go")
--	if err := ioutil.WriteFile(tmpFile, []byte(""), 0775); err != nil {
+-	if err := os.WriteFile(tmpFile, []byte(""), 0775); err != nil {
 -		t.Fatal(err)
 -	}
--	if err := ioutil.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module fake\n\ngo 1.12\n"), 0775); err != nil {
+-	if err := os.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module fake\n\ngo 1.12\n"), 0775); err != nil {
 -		t.Fatal(err)
 -	}
 -	defer os.RemoveAll(tmpDir)
 -
 -	app := New("gopls-test", tmpDir, os.Environ(), nil)
--	c := newConnection(app)
--	ctx := context.Background()
--	defer c.terminate(ctx)
 -
 -	params := &protocol.ParamInitialize{}
--	params.RootURI = protocol.URIFromPath(c.Client.app.wd)
+-	params.RootURI = protocol.URIFromPath(app.wd)
 -	params.Capabilities.Workspace.Configuration = true
 -
 -	// Send an initialize request to the server.
--	c.Server = lsp.NewServer(cache.NewSession(ctx, cache.New(nil), app.options), c.Client)
--	result, err := c.Server.Initialize(ctx, params)
+-	ctx := context.Background()
+-	client := newClient(app, nil)
+-	options := source.DefaultOptions(app.options)
+-	server := lsp.NewServer(cache.NewSession(ctx, cache.New(nil)), client, options)
+-	result, err := server.Initialize(ctx, params)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -24689,10 +27963,13 @@
 -		t.Error(err)
 -	}
 -	// Complete initialization of server.
--	if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil {
+-	if err := server.Initialized(ctx, &protocol.InitializedParams{}); err != nil {
 -		t.Fatal(err)
 -	}
 -
+-	c := newConnection(server, client)
+-	defer c.terminate(ctx)
+-
 -	// Open the file on the server side.
 -	uri := protocol.URIFromPath(tmpFile)
 -	if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{
@@ -24802,7 +28079,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/check.go b/gopls/internal/lsp/cmd/check.go
 --- a/gopls/internal/lsp/cmd/check.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/check.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/check.go	1970-01-01 08:00:00
 @@ -1,73 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -24846,7 +28123,7 @@
 -	checking := map[span.URI]*cmdFile{}
 -	var uris []span.URI
 -	// now we ready to kick things off
--	conn, err := c.app.connect(ctx)
+-	conn, err := c.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -24854,17 +28131,17 @@
 -	for _, arg := range args {
 -		uri := span.URIFromPath(arg)
 -		uris = append(uris, uri)
--		file := conn.openFile(ctx, uri)
--		if file.err != nil {
--			return file.err
+-		file, err := conn.openFile(ctx, uri)
+-		if err != nil {
+-			return err
 -		}
 -		checking[uri] = file
 -	}
 -	if err := conn.diagnoseFiles(ctx, uris); err != nil {
 -		return err
 -	}
--	conn.Client.filesMu.Lock()
--	defer conn.Client.filesMu.Unlock()
+-	conn.client.filesMu.Lock()
+-	defer conn.client.filesMu.Unlock()
 -
 -	for _, file := range checking {
 -		for _, d := range file.diagnostics {
@@ -24879,8 +28156,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/cmd.go b/gopls/internal/lsp/cmd/cmd.go
 --- a/gopls/internal/lsp/cmd/cmd.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/cmd.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,640 +0,0 @@
++++ b/gopls/internal/lsp/cmd/cmd.go	1970-01-01 08:00:00
+@@ -1,801 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -24894,7 +28171,6 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
 -	"log"
 -	"os"
 -	"reflect"
@@ -24905,12 +28181,15 @@
 -	"time"
 -
 -	"golang.org/x/tools/gopls/internal/lsp"
+-	"golang.org/x/tools/gopls/internal/lsp/browser"
 -	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
+-	"golang.org/x/tools/gopls/internal/lsp/filecache"
 -	"golang.org/x/tools/gopls/internal/lsp/lsprpc"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/diff"
 -	"golang.org/x/tools/internal/jsonrpc2"
 -	"golang.org/x/tools/internal/tool"
 -	"golang.org/x/tools/internal/xcontext"
@@ -24956,6 +28235,26 @@
 -	// PrepareOptions is called to update the options when a new view is built.
 -	// It is primarily to allow the behavior of gopls to be modified by hooks.
 -	PrepareOptions func(*source.Options)
+-
+-	// editFlags holds flags that control how file edit operations
+-	// are applied, in particular when the server makes an ApplyEdits
+-	// downcall to the client. Present only for commands that apply edits.
+-	editFlags *EditFlags
+-}
+-
+-// EditFlags defines flags common to {fix,format,imports,rename}
+-// that control how edits are applied to the client's files.
+-//
+-// The type is exported for flag reflection.
+-//
+-// The -write, -diff, and -list flags are orthogonal but any
+-// of them suppresses the default behavior, which is to print
+-// the edited file contents.
+-type EditFlags struct {
+-	Write    bool `flag:"w,write" help:"write edited content to source files"`
+-	Preserve bool `flag:"preserve" help:"with -write, make copies of original files"`
+-	Diff     bool `flag:"d,diff" help:"display diffs instead of edited file content"`
+-	List     bool `flag:"l,list" help:"display names of edited files"`
 -}
 -
 -func (app *Application) verbose() bool {
@@ -25019,6 +28318,12 @@
 -	for _, c := range app.featureCommands() {
 -		fmt.Fprintf(w, "  %s\t%s\n", c.Name(), c.ShortHelp())
 -	}
+-	if app.verbose() {
+-		fmt.Fprint(w, "\t\nInternal Use Only\t\n")
+-		for _, c := range app.internalCommands() {
+-			fmt.Fprintf(w, "  %s\t%s\n", c.Name(), c.ShortHelp())
+-		}
+-	}
 -	fmt.Fprint(w, "\nflags:\n")
 -	printFlagDefaults(f)
 -}
@@ -25097,6 +28402,11 @@
 -// If no arguments are passed it will invoke the server sub command, as a
 -// temporary measure for compatibility.
 -func (app *Application) Run(ctx context.Context, args ...string) error {
+-	// In the category of "things we can do while waiting for the Go command":
+-	// Pre-initialize the filecache, which takes ~50ms to hash the gopls
+-	// executable, and immediately runs a gc.
+-	filecache.Start()
+-
 -	ctx = debug.WithInstance(ctx, app.wd, app.OCAgent)
 -	if len(args) == 0 {
 -		s := flag.NewFlagSet(app.Name(), flag.ExitOnError)
@@ -25119,6 +28429,7 @@
 -	var commands []tool.Application
 -	commands = append(commands, app.mainCommands()...)
 -	commands = append(commands, app.featureCommands()...)
+-	commands = append(commands, app.internalCommands()...)
 -	return commands
 -}
 -
@@ -25133,6 +28444,12 @@
 -	}
 -}
 -
+-func (app *Application) internalCommands() []tool.Application {
+-	return []tool.Application{
+-		&vulncheck{app: app},
+-	}
+-}
+-
 -func (app *Application) featureCommands() []tool.Application {
 -	return []tool.Application{
 -		&callHierarchy{app: app},
@@ -25151,10 +28468,11 @@
 -		&rename{app: app},
 -		&semtok{app: app},
 -		&signature{app: app},
+-		&stats{app: app},
 -		&suggestedFix{app: app},
 -		&symbols{app: app},
+-
 -		&workspaceSymbol{app: app},
--		&vulncheck{app: app},
 -	}
 -}
 -
@@ -25163,20 +28481,25 @@
 -	internalConnections = make(map[string]*connection)
 -)
 -
--func (app *Application) connect(ctx context.Context) (*connection, error) {
+-// connect creates and initializes a new in-process gopls session.
+-//
+-// If onProgress is set, it is called for each new progress notification.
+-func (app *Application) connect(ctx context.Context, onProgress func(*protocol.ProgressParams)) (*connection, error) {
 -	switch {
 -	case app.Remote == "":
--		connection := newConnection(app)
--		connection.Server = lsp.NewServer(cache.NewSession(ctx, cache.New(nil), app.options), connection.Client)
--		ctx = protocol.WithClient(ctx, connection.Client)
--		return connection, connection.initialize(ctx, app.options)
+-		client := newClient(app, onProgress)
+-		options := source.DefaultOptions(app.options)
+-		server := lsp.NewServer(cache.NewSession(ctx, cache.New(nil)), client, options)
+-		conn := newConnection(server, client)
+-		if err := conn.initialize(protocol.WithClient(ctx, client), app.options); err != nil {
+-			return nil, err
+-		}
+-		return conn, nil
+-
 -	case strings.HasPrefix(app.Remote, "internal@"):
 -		internalMu.Lock()
 -		defer internalMu.Unlock()
--		opts := source.DefaultOptions().Clone()
--		if app.options != nil {
--			app.options(opts)
--		}
+-		opts := source.DefaultOptions(app.options)
 -		key := fmt.Sprintf("%s %v %v %v", app.wd, opts.PreferredContentFormat, opts.HierarchicalDocumentSymbolSupport, opts.SymbolMatcher)
 -		if c := internalConnections[key]; c != nil {
 -			return c, nil
@@ -25194,29 +28517,20 @@
 -	}
 -}
 -
--// CloseTestConnections terminates shared connections used in command tests. It
--// should only be called from tests.
--func CloseTestConnections(ctx context.Context) {
--	for _, c := range internalConnections {
--		c.Shutdown(ctx)
--		c.Exit(ctx)
--	}
--}
--
 -func (app *Application) connectRemote(ctx context.Context, remote string) (*connection, error) {
--	connection := newConnection(app)
 -	conn, err := lsprpc.ConnectToRemote(ctx, remote)
 -	if err != nil {
 -		return nil, err
 -	}
 -	stream := jsonrpc2.NewHeaderStream(conn)
 -	cc := jsonrpc2.NewConn(stream)
--	connection.Server = protocol.ServerDispatcher(cc)
--	ctx = protocol.WithClient(ctx, connection.Client)
+-	server := protocol.ServerDispatcher(cc)
+-	client := newClient(app, nil)
+-	connection := newConnection(server, client)
+-	ctx = protocol.WithClient(ctx, connection.client)
 -	cc.Go(ctx,
 -		protocol.Handlers(
--			protocol.ClientHandler(connection.Client,
--				jsonrpc2.MethodNotFound)))
+-			protocol.ClientHandler(client, jsonrpc2.MethodNotFound)))
 -	return connection, connection.initialize(ctx, app.options)
 -}
 -
@@ -25228,14 +28542,11 @@
 -
 -func (c *connection) initialize(ctx context.Context, options func(*source.Options)) error {
 -	params := &protocol.ParamInitialize{}
--	params.RootURI = protocol.URIFromPath(c.Client.app.wd)
+-	params.RootURI = protocol.URIFromPath(c.client.app.wd)
 -	params.Capabilities.Workspace.Configuration = true
 -
 -	// Make sure to respect configured options when sending initialize request.
--	opts := source.DefaultOptions().Clone()
--	if options != nil {
--		options(opts)
--	}
+-	opts := source.DefaultOptions(options)
 -	// If you add an additional option here, you must update the map key in connect.
 -	params.Capabilities.TextDocument.Hover = &protocol.HoverClientCapabilities{
 -		ContentFormat: []protocol.MarkupKind{opts.PreferredContentFormat},
@@ -25247,6 +28558,13 @@
 -	params.Capabilities.TextDocument.SemanticTokens.Requests.Full.Value = true
 -	params.Capabilities.TextDocument.SemanticTokens.TokenTypes = lsp.SemanticTypes()
 -	params.Capabilities.TextDocument.SemanticTokens.TokenModifiers = lsp.SemanticModifiers()
+-
+-	// If the subcommand has registered a progress handler, report the progress
+-	// capability.
+-	if c.client.onProgress != nil {
+-		params.Capabilities.Window.WorkDoneProgress = true
+-	}
+-
 -	params.InitializationOptions = map[string]interface{}{
 -		"symbolMatcher": matcherString[opts.SymbolMatcher],
 -	}
@@ -25261,17 +28579,18 @@
 -
 -type connection struct {
 -	protocol.Server
--	Client *cmdClient
+-	client *cmdClient
 -}
 -
+-// cmdClient defines the protocol.Client interface behavior of the gopls CLI tool.
 -type cmdClient struct {
--	protocol.Server
--	app *Application
+-	app        *Application
+-	onProgress func(*protocol.ProgressParams)
 -
 -	diagnosticsMu   sync.Mutex
 -	diagnosticsDone chan struct{}
 -
--	filesMu sync.Mutex
+-	filesMu sync.Mutex // guards files map and each cmdFile.diagnostics
 -	files   map[span.URI]*cmdFile
 -}
 -
@@ -25279,16 +28598,21 @@
 -	uri         span.URI
 -	mapper      *protocol.Mapper
 -	err         error
--	open        bool
 -	diagnostics []protocol.Diagnostic
 -}
 -
--func newConnection(app *Application) *connection {
+-func newClient(app *Application, onProgress func(*protocol.ProgressParams)) *cmdClient {
+-	return &cmdClient{
+-		app:        app,
+-		onProgress: onProgress,
+-		files:      make(map[span.URI]*cmdFile),
+-	}
+-}
+-
+-func newConnection(server protocol.Server, client *cmdClient) *connection {
 -	return &connection{
--		Client: &cmdClient{
--			app:   app,
--			files: make(map[span.URI]*cmdFile),
--		},
+-		Server: server,
+-		client: client,
 -	}
 -}
 -
@@ -25379,7 +28703,87 @@
 -}
 -
 -func (c *cmdClient) ApplyEdit(ctx context.Context, p *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) {
--	return &protocol.ApplyWorkspaceEditResult{Applied: false, FailureReason: "not implemented"}, nil
+-	if err := c.applyWorkspaceEdit(&p.Edit); err != nil {
+-		return &protocol.ApplyWorkspaceEditResult{FailureReason: err.Error()}, nil
+-	}
+-	return &protocol.ApplyWorkspaceEditResult{Applied: true}, nil
+-}
+-
+-// applyWorkspaceEdit applies a complete WorkspaceEdit to the client's
+-// files, honoring the preferred edit mode specified by cli.app.editMode.
+-// (Used by rename and by ApplyEdit downcalls.)
+-func (cli *cmdClient) applyWorkspaceEdit(edit *protocol.WorkspaceEdit) error {
+-	var orderedURIs []string
+-	edits := map[span.URI][]protocol.TextEdit{}
+-	for _, c := range edit.DocumentChanges {
+-		if c.TextDocumentEdit != nil {
+-			uri := fileURI(c.TextDocumentEdit.TextDocument.URI)
+-			edits[uri] = append(edits[uri], c.TextDocumentEdit.Edits...)
+-			orderedURIs = append(orderedURIs, string(uri))
+-		}
+-		if c.RenameFile != nil {
+-			return fmt.Errorf("client does not support file renaming (%s -> %s)",
+-				c.RenameFile.OldURI,
+-				c.RenameFile.NewURI)
+-		}
+-	}
+-	sort.Strings(orderedURIs)
+-	for _, u := range orderedURIs {
+-		uri := span.URIFromURI(u)
+-		f := cli.openFile(uri)
+-		if f.err != nil {
+-			return f.err
+-		}
+-		if err := applyTextEdits(f.mapper, edits[uri], cli.app.editFlags); err != nil {
+-			return err
+-		}
+-	}
+-	return nil
+-}
+-
+-// applyTextEdits applies a list of edits to the mapper file content,
+-// using the preferred edit mode. It is a no-op if there are no edits.
+-func applyTextEdits(mapper *protocol.Mapper, edits []protocol.TextEdit, flags *EditFlags) error {
+-	if len(edits) == 0 {
+-		return nil
+-	}
+-	newContent, renameEdits, err := source.ApplyProtocolEdits(mapper, edits)
+-	if err != nil {
+-		return err
+-	}
+-
+-	filename := mapper.URI.Filename()
+-
+-	if flags.List {
+-		fmt.Println(filename)
+-	}
+-
+-	if flags.Write {
+-		if flags.Preserve {
+-			if err := os.Rename(filename, filename+".orig"); err != nil {
+-				return err
+-			}
+-		}
+-		if err := os.WriteFile(filename, newContent, 0644); err != nil {
+-			return err
+-		}
+-	}
+-
+-	if flags.Diff {
+-		unified, err := diff.ToUnified(filename+".orig", filename, string(mapper.Content), renameEdits)
+-		if err != nil {
+-			return err
+-		}
+-		fmt.Print(unified)
+-	}
+-
+-	// No flags: just print edited file content.
+-	// TODO(adonovan): how is this ever useful with multiple files?
+-	if !(flags.List || flags.Write || flags.Diff) {
+-		os.Stdout.Write(newContent)
+-	}
+-
+-	return nil
 -}
 -
 -func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishDiagnosticsParams) error {
@@ -25394,17 +28798,52 @@
 -	c.filesMu.Lock()
 -	defer c.filesMu.Unlock()
 -
--	file := c.getFile(ctx, fileURI(p.URI))
--	file.diagnostics = p.Diagnostics
+-	file := c.getFile(fileURI(p.URI))
+-	file.diagnostics = append(file.diagnostics, p.Diagnostics...)
+-
+-	// Perform a crude in-place deduplication.
+-	// TODO(golang/go#60122): replace the ad-hoc gopls/diagnoseFiles
+-	// non-standard request with support for textDocument/diagnostic,
+-	// so that we don't need to do this de-duplication.
+-	type key [6]interface{}
+-	seen := make(map[key]bool)
+-	out := file.diagnostics[:0]
+-	for _, d := range file.diagnostics {
+-		var codeHref string
+-		if desc := d.CodeDescription; desc != nil {
+-			codeHref = desc.Href
+-		}
+-		k := key{d.Range, d.Severity, d.Code, codeHref, d.Source, d.Message}
+-		if !seen[k] {
+-			seen[k] = true
+-			out = append(out, d)
+-		}
+-	}
+-	file.diagnostics = out
+-
 -	return nil
 -}
 -
--func (c *cmdClient) Progress(context.Context, *protocol.ProgressParams) error {
+-func (c *cmdClient) Progress(_ context.Context, params *protocol.ProgressParams) error {
+-	if c.onProgress != nil {
+-		c.onProgress(params)
+-	}
 -	return nil
 -}
 -
--func (c *cmdClient) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
--	return nil, nil
+-func (c *cmdClient) ShowDocument(ctx context.Context, params *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
+-	var success bool
+-	if params.External {
+-		// Open URI in external browser.
+-		success = browser.Open(string(params.URI))
+-	} else {
+-		// Open file in editor, optionally taking focus and selecting a range.
+-		// (cmdClient has no editor. Should it fork+exec $EDITOR?)
+-		log.Printf("Server requested that client editor open %q (takeFocus=%t, selection=%+v)",
+-			params.URI, params.TakeFocus, params.Selection)
+-		success = true
+-	}
+-	return &protocol.ShowDocumentResult{Success: success}, nil
 -}
 -
 -func (c *cmdClient) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
@@ -25427,7 +28866,7 @@
 -	return nil
 -}
 -
--func (c *cmdClient) getFile(ctx context.Context, uri span.URI) *cmdFile {
+-func (c *cmdClient) getFile(uri span.URI) *cmdFile {
 -	file, found := c.files[uri]
 -	if !found || file.err != nil {
 -		file = &cmdFile{
@@ -25436,7 +28875,7 @@
 -		c.files[uri] = file
 -	}
 -	if file.mapper == nil {
--		content, err := ioutil.ReadFile(uri.Filename())
+-		content, err := os.ReadFile(uri.Filename())
 -		if err != nil {
 -			file.err = fmt.Errorf("getFile: %v: %v", uri, err)
 -			return file
@@ -25446,22 +28885,19 @@
 -	return file
 -}
 -
--func (c *cmdClient) openFile(ctx context.Context, uri span.URI) *cmdFile {
+-func (c *cmdClient) openFile(uri span.URI) *cmdFile {
 -	c.filesMu.Lock()
 -	defer c.filesMu.Unlock()
--
--	file := c.getFile(ctx, uri)
--	if file.err != nil || file.open {
--		return file
--	}
--	file.open = true
--	return file
+-	return c.getFile(uri)
 -}
 -
--func (c *connection) openFile(ctx context.Context, uri span.URI) *cmdFile {
--	file := c.Client.openFile(ctx, uri)
+-// TODO(adonovan): provide convenience helpers to:
+-// - map a (URI, protocol.Range) to a MappedRange;
+-// - parse a command-line argument to a MappedRange.
+-func (c *connection) openFile(ctx context.Context, uri span.URI) (*cmdFile, error) {
+-	file := c.client.openFile(uri)
 -	if file.err != nil {
--		return file
+-		return nil, file.err
 -	}
 -
 -	p := &protocol.DidOpenTextDocumentParams{
@@ -25473,9 +28909,11 @@
 -		},
 -	}
 -	if err := c.Server.DidOpen(ctx, p); err != nil {
+-		// TODO(adonovan): is this assignment concurrency safe?
 -		file.err = fmt.Errorf("%v: %v", uri, err)
+-		return nil, file.err
 -	}
--	return file
+-	return file, nil
 -}
 -
 -func (c *connection) semanticTokens(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
@@ -25492,22 +28930,22 @@
 -	for _, file := range files {
 -		untypedFiles = append(untypedFiles, string(file))
 -	}
--	c.Client.diagnosticsMu.Lock()
--	defer c.Client.diagnosticsMu.Unlock()
+-	c.client.diagnosticsMu.Lock()
+-	defer c.client.diagnosticsMu.Unlock()
 -
--	c.Client.diagnosticsDone = make(chan struct{})
+-	c.client.diagnosticsDone = make(chan struct{})
 -	_, err := c.Server.NonstandardRequest(ctx, "gopls/diagnoseFiles", map[string]interface{}{"files": untypedFiles})
 -	if err != nil {
--		close(c.Client.diagnosticsDone)
+-		close(c.client.diagnosticsDone)
 -		return err
 -	}
 -
--	<-c.Client.diagnosticsDone
+-	<-c.client.diagnosticsDone
 -	return nil
 -}
 -
 -func (c *connection) terminate(ctx context.Context) {
--	if strings.HasPrefix(c.Client.app.Remote, "internal@") {
+-	if strings.HasPrefix(c.client.app.Remote, "internal@") {
 -		// internal connections need to be left alive for the next test
 -		return
 -	}
@@ -25523,8 +28961,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/definition.go b/gopls/internal/lsp/cmd/definition.go
 --- a/gopls/internal/lsp/cmd/definition.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/definition.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,132 +0,0 @@
++++ b/gopls/internal/lsp/cmd/definition.go	1970-01-01 08:00:00
+@@ -1,138 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -25601,15 +29039,15 @@
 -			o.PreferredContentFormat = protocol.Markdown
 -		}
 -	}
--	conn, err := d.app.connect(ctx)
+-	conn, err := d.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -	loc, err := file.mapper.SpanLocation(from)
 -	if err != nil {
@@ -25626,6 +29064,15 @@
 -	if len(locs) == 0 {
 -		return fmt.Errorf("%v: not an identifier", from)
 -	}
+-	file, err = conn.openFile(ctx, fileURI(locs[0].URI))
+-	if err != nil {
+-		return fmt.Errorf("%v: %v", from, err)
+-	}
+-	definition, err := file.mapper.LocationSpan(locs[0])
+-	if err != nil {
+-		return fmt.Errorf("%v: %v", from, err)
+-	}
+-
 -	q := protocol.HoverParams{
 -		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
 -	}
@@ -25633,18 +29080,11 @@
 -	if err != nil {
 -		return fmt.Errorf("%v: %v", from, err)
 -	}
--	if hover == nil {
--		return fmt.Errorf("%v: not an identifier", from)
+-	var description string
+-	if hover != nil {
+-		description = strings.TrimSpace(hover.Contents.Value)
 -	}
--	file = conn.openFile(ctx, fileURI(locs[0].URI))
--	if file.err != nil {
--		return fmt.Errorf("%v: %v", from, file.err)
--	}
--	definition, err := file.mapper.LocationSpan(locs[0])
--	if err != nil {
--		return fmt.Errorf("%v: %v", from, err)
--	}
--	description := strings.TrimSpace(hover.Contents.Value)
+-
 -	result := &Definition{
 -		Span:        definition,
 -		Description: description,
@@ -25654,13 +29094,17 @@
 -		enc.SetIndent("", "\t")
 -		return enc.Encode(result)
 -	}
--	fmt.Printf("%v: defined here as %s", result.Span, result.Description)
+-	fmt.Printf("%v", result.Span)
+-	if len(result.Description) > 0 {
+-		fmt.Printf(": defined here as %s", result.Description)
+-	}
+-	fmt.Printf("\n")
 -	return nil
 -}
 diff -urN a/gopls/internal/lsp/cmd/folding_range.go b/gopls/internal/lsp/cmd/folding_range.go
 --- a/gopls/internal/lsp/cmd/folding_range.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/folding_range.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,73 +0,0 @@
++++ b/gopls/internal/lsp/cmd/folding_range.go	1970-01-01 08:00:00
+@@ -1,72 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -25700,16 +29144,15 @@
 -		return tool.CommandLineErrorf("folding_ranges expects 1 argument (file)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	if _, err := conn.openFile(ctx, from.URI()); err != nil {
+-		return err
 -	}
 -
 -	p := protocol.FoldingRangeParams{
@@ -25736,8 +29179,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/format.go b/gopls/internal/lsp/cmd/format.go
 --- a/gopls/internal/lsp/cmd/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,110 +0,0 @@
++++ b/gopls/internal/lsp/cmd/format.go	1970-01-01 08:00:00
+@@ -1,76 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -25748,21 +29191,14 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
--	"os"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/diff"
 -)
 -
 -// format implements the format verb for gopls.
 -type format struct {
--	Diff  bool `flag:"d,diff" help:"display diffs instead of rewriting files"`
--	Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"`
--	List  bool `flag:"l,list" help:"list files whose formatting differs from gofmt's"`
--
+-	EditFlags
 -	app *Application
 -}
 -
@@ -25787,22 +29223,20 @@
 -// results to stdout.
 -func (c *format) Run(ctx context.Context, args ...string) error {
 -	if len(args) == 0 {
--		// no files, so no results
 -		return nil
 -	}
--	// now we ready to kick things off
--	conn, err := c.app.connect(ctx)
+-	c.app.editFlags = &c.EditFlags
+-	conn, err := c.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -	for _, arg := range args {
 -		spn := span.Parse(arg)
--		file := conn.openFile(ctx, spn.URI())
--		if file.err != nil {
--			return file.err
+-		file, err := conn.openFile(ctx, spn.URI())
+-		if err != nil {
+-			return err
 -		}
--		filename := spn.URI().Filename()
 -		loc, err := file.mapper.SpanLocation(spn)
 -		if err != nil {
 -			return err
@@ -25817,41 +29251,16 @@
 -		if err != nil {
 -			return fmt.Errorf("%v: %v", spn, err)
 -		}
--		formatted, sedits, err := source.ApplyProtocolEdits(file.mapper, edits)
--		if err != nil {
--			return fmt.Errorf("%v: %v", spn, err)
--		}
--		printIt := true
--		if c.List {
--			printIt = false
--			if len(edits) > 0 {
--				fmt.Println(filename)
--			}
--		}
--		if c.Write {
--			printIt = false
--			if len(edits) > 0 {
--				ioutil.WriteFile(filename, formatted, 0644)
--			}
--		}
--		if c.Diff {
--			printIt = false
--			unified, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits)
--			if err != nil {
--				return err
--			}
--			fmt.Print(unified)
--		}
--		if printIt {
--			os.Stdout.Write(formatted)
+-		if err := applyTextEdits(file.mapper, edits, c.app.editFlags); err != nil {
+-			return err
 -		}
 -	}
 -	return nil
 -}
 diff -urN a/gopls/internal/lsp/cmd/help_test.go b/gopls/internal/lsp/cmd/help_test.go
 --- a/gopls/internal/lsp/cmd/help_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/help_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,58 +0,0 @@
++++ b/gopls/internal/lsp/cmd/help_test.go	1970-01-01 08:00:00
+@@ -1,84 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -25862,7 +29271,7 @@
 -	"bytes"
 -	"context"
 -	"flag"
--	"io/ioutil"
+-	"os"
 -	"path/filepath"
 -	"testing"
 -
@@ -25895,12 +29304,12 @@
 -			helpFile := filepath.Join("usage", name+".hlp")
 -			got := buf.Bytes()
 -			if *updateHelpFiles {
--				if err := ioutil.WriteFile(helpFile, got, 0666); err != nil {
+-				if err := os.WriteFile(helpFile, got, 0666); err != nil {
 -					t.Errorf("Failed writing %v: %v", helpFile, err)
 -				}
 -				return
 -			}
--			want, err := ioutil.ReadFile(helpFile)
+-			want, err := os.ReadFile(helpFile)
 -			if err != nil {
 -				t.Fatalf("Missing help file %q", helpFile)
 -			}
@@ -25910,9 +29319,35 @@
 -		})
 -	}
 -}
+-
+-func TestVerboseHelp(t *testing.T) {
+-	testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code.
+-	app := cmd.New(appName, "", nil, nil)
+-	ctx := context.Background()
+-	var buf bytes.Buffer
+-	s := flag.NewFlagSet(appName, flag.ContinueOnError)
+-	s.SetOutput(&buf)
+-	tool.Run(ctx, s, app, []string{"-v", "-h"})
+-	got := buf.Bytes()
+-
+-	helpFile := filepath.Join("usage", "usage-v.hlp")
+-	if *updateHelpFiles {
+-		if err := os.WriteFile(helpFile, got, 0666); err != nil {
+-			t.Errorf("Failed writing %v: %v", helpFile, err)
+-		}
+-		return
+-	}
+-	want, err := os.ReadFile(helpFile)
+-	if err != nil {
+-		t.Fatalf("Missing help file %q", helpFile)
+-	}
+-	if diff := cmp.Diff(string(want), string(got)); diff != "" {
+-		t.Errorf("Help file %q did not match, run with -update-help-files to fix (-want +got)\n%s", helpFile, diff)
+-	}
+-}
 diff -urN a/gopls/internal/lsp/cmd/highlight.go b/gopls/internal/lsp/cmd/highlight.go
 --- a/gopls/internal/lsp/cmd/highlight.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/highlight.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/highlight.go	1970-01-01 08:00:00
 @@ -1,82 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -25955,16 +29390,16 @@
 -		return tool.CommandLineErrorf("highlight expects 1 argument (position)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -
 -	loc, err := file.mapper.SpanLocation(from)
@@ -25998,8 +29433,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/implementation.go b/gopls/internal/lsp/cmd/implementation.go
 --- a/gopls/internal/lsp/cmd/implementation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/implementation.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,84 +0,0 @@
++++ b/gopls/internal/lsp/cmd/implementation.go	1970-01-01 08:00:00
+@@ -1,87 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -26042,16 +29477,16 @@
 -		return tool.CommandLineErrorf("implementation expects 1 argument (position)")
 -	}
 -
--	conn, err := i.app.connect(ctx)
+-	conn, err := i.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -
 -	loc, err := file.mapper.SpanLocation(from)
@@ -26069,7 +29504,10 @@
 -
 -	var spans []string
 -	for _, impl := range implementations {
--		f := conn.openFile(ctx, fileURI(impl.URI))
+-		f, err := conn.openFile(ctx, fileURI(impl.URI))
+-		if err != nil {
+-			return err
+-		}
 -		span, err := f.mapper.LocationSpan(impl)
 -		if err != nil {
 -			return err
@@ -26086,8 +29524,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/imports.go b/gopls/internal/lsp/cmd/imports.go
 --- a/gopls/internal/lsp/cmd/imports.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/imports.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,105 +0,0 @@
++++ b/gopls/internal/lsp/cmd/imports.go	1970-01-01 08:00:00
+@@ -1,81 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -26098,21 +29536,15 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
--	"os"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/diff"
 -	"golang.org/x/tools/internal/tool"
 -)
 -
 -// imports implements the import verb for gopls.
 -type imports struct {
--	Diff  bool `flag:"d,diff" help:"display diffs instead of rewriting files"`
--	Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"`
--
+-	EditFlags
 -	app *Application
 -}
 -
@@ -26139,7 +29571,8 @@
 -	if len(args) != 1 {
 -		return tool.CommandLineErrorf("imports expects 1 argument")
 -	}
--	conn, err := t.app.connect(ctx)
+-	t.app.editFlags = &t.EditFlags
+-	conn, err := t.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -26147,9 +29580,9 @@
 -
 -	from := span.Parse(args[0])
 -	uri := from.URI()
--	file := conn.openFile(ctx, uri)
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, uri)
+-	if err != nil {
+-		return err
 -	}
 -	actions, err := conn.CodeAction(ctx, &protocol.CodeActionParams{
 -		TextDocument: protocol.TextDocumentIdentifier{
@@ -26172,31 +29605,12 @@
 -			}
 -		}
 -	}
--	newContent, sedits, err := source.ApplyProtocolEdits(file.mapper, edits)
--	if err != nil {
--		return fmt.Errorf("%v: %v", edits, err)
--	}
--	filename := file.uri.Filename()
--	switch {
--	case t.Write:
--		if len(edits) > 0 {
--			ioutil.WriteFile(filename, newContent, 0644)
--		}
--	case t.Diff:
--		unified, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits)
--		if err != nil {
--			return err
--		}
--		fmt.Print(unified)
--	default:
--		os.Stdout.Write(newContent)
--	}
--	return nil
+-	return applyTextEdits(file.mapper, edits, t.app.editFlags)
 -}
 diff -urN a/gopls/internal/lsp/cmd/info.go b/gopls/internal/lsp/cmd/info.go
 --- a/gopls/internal/lsp/cmd/info.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/info.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,246 +0,0 @@
++++ b/gopls/internal/lsp/cmd/info.go	1970-01-01 08:00:00
+@@ -1,311 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -26211,10 +29625,13 @@
 -	"fmt"
 -	"net/url"
 -	"os"
+-	"sort"
 -	"strings"
 -
+-	goplsbug "golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/browser"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
+-	"golang.org/x/tools/gopls/internal/lsp/filecache"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/internal/tool"
 -)
@@ -26327,10 +29744,50 @@
 -// Run collects some basic information and then prepares an issue ready to
 -// be reported.
 -func (b *bug) Run(ctx context.Context, args ...string) error {
--	buf := &bytes.Buffer{}
--	fmt.Fprint(buf, goplsBugHeader)
--	debug.PrintVersionInfo(ctx, buf, true, debug.Markdown)
--	body := buf.String()
+-	// This undocumented environment variable allows
+-	// the cmd integration test (and maintainers) to
+-	// trigger a call to bug.Report.
+-	if msg := os.Getenv("TEST_GOPLS_BUG"); msg != "" {
+-		filecache.Start() // register bug handler
+-		goplsbug.Report(msg)
+-		return nil
+-	}
+-
+-	// Enumerate bug reports, grouped and sorted.
+-	_, reports := filecache.BugReports()
+-	sort.Slice(reports, func(i, j int) bool {
+-		x, y := reports[i], reports[i]
+-		if x.Key != y.Key {
+-			return x.Key < y.Key // ascending key order
+-		}
+-		return y.AtTime.Before(x.AtTime) // most recent first
+-	})
+-	keyDenom := make(map[string]int) // key is "file:line"
+-	for _, report := range reports {
+-		keyDenom[report.Key]++
+-	}
+-
+-	// Privacy: the content of 'public' will be posted to GitHub
+-	// to populate an issue textarea. Even though the user must
+-	// submit the form to share the information with the world,
+-	// merely populating the form causes us to share the
+-	// information with GitHub itself.
+-	//
+-	// For that reason, we cannot write private information to
+-	// public, such as bug reports, which may quote source code.
+-	public := &bytes.Buffer{}
+-	fmt.Fprint(public, goplsBugHeader)
+-	if len(reports) > 0 {
+-		fmt.Fprintf(public, "#### Internal errors\n\n")
+-		fmt.Fprintf(public, "Gopls detected %d internal errors, %d distinct:\n",
+-			len(reports), len(keyDenom))
+-		for key, denom := range keyDenom {
+-			fmt.Fprintf(public, "- %s (%d)\n", key, denom)
+-		}
+-		fmt.Fprintf(public, "\nPlease copy the full information printed by `gopls bug` here, if you are comfortable sharing it.\n\n")
+-	}
+-	debug.PrintVersionInfo(ctx, public, true, debug.Markdown)
+-	body := public.String()
 -	title := strings.Join(args, " ")
 -	if !strings.HasPrefix(title, goplsBugPrefix) {
 -		title = goplsBugPrefix + title
@@ -26339,6 +29796,29 @@
 -		fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
 -		fmt.Print(body)
 -	}
+-
+-	// Print bug reports to stdout (not GitHub).
+-	keyNum := make(map[string]int)
+-	for _, report := range reports {
+-		fmt.Printf("-- %v -- \n", report.AtTime)
+-
+-		// Append seq number (e.g. " (1/2)") for repeated keys.
+-		var seq string
+-		if denom := keyDenom[report.Key]; denom > 1 {
+-			keyNum[report.Key]++
+-			seq = fmt.Sprintf(" (%d/%d)", keyNum[report.Key], denom)
+-		}
+-
+-		// Privacy:
+-		// - File and Stack may contain the name of the user that built gopls.
+-		// - Description may contain names of the user's packages/files/symbols.
+-		fmt.Printf("%s:%d: %s%s\n\n", report.File, report.Line, report.Description, seq)
+-		fmt.Printf("%s\n\n", report.Stack)
+-	}
+-	if len(reports) > 0 {
+-		fmt.Printf("Please copy the above information into the GitHub issue, if you are comfortable sharing it.\n")
+-	}
+-
 -	return nil
 -}
 -
@@ -26432,8 +29912,7 @@
 -`
 -
 -func (l *licenses) Run(ctx context.Context, args ...string) error {
--	opts := source.DefaultOptions()
--	l.app.options(opts)
+-	opts := source.DefaultOptions(l.app.options)
 -	txt := licensePreamble
 -	if opts.LicensesText == "" {
 -		txt += "(development gopls, license information not available)"
@@ -26445,7 +29924,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/links.go b/gopls/internal/lsp/cmd/links.go
 --- a/gopls/internal/lsp/cmd/links.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/links.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/links.go	1970-01-01 08:00:00
 @@ -1,77 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -26494,7 +29973,7 @@
 -	if len(args) != 1 {
 -		return tool.CommandLineErrorf("links expects 1 argument")
 -	}
--	conn, err := l.app.connect(ctx)
+-	conn, err := l.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -26502,9 +29981,9 @@
 -
 -	from := span.Parse(args[0])
 -	uri := from.URI()
--	file := conn.openFile(ctx, uri)
--	if file.err != nil {
--		return file.err
+-
+-	if _, err := conn.openFile(ctx, uri); err != nil {
+-		return err
 -	}
 -	results, err := conn.DocumentLink(ctx, &protocol.DocumentLinkParams{
 -		TextDocument: protocol.TextDocumentIdentifier{
@@ -26520,13 +29999,13 @@
 -		return enc.Encode(results)
 -	}
 -	for _, v := range results {
--		fmt.Println(v.Target)
+-		fmt.Println(*v.Target)
 -	}
 -	return nil
 -}
 diff -urN a/gopls/internal/lsp/cmd/prepare_rename.go b/gopls/internal/lsp/cmd/prepare_rename.go
 --- a/gopls/internal/lsp/cmd/prepare_rename.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/prepare_rename.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/prepare_rename.go	1970-01-01 08:00:00
 @@ -1,80 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -26574,16 +30053,16 @@
 -		return tool.CommandLineErrorf("prepare_rename expects 1 argument (file)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -	loc, err := file.mapper.SpanLocation(from)
 -	if err != nil {
@@ -26610,8 +30089,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/references.go b/gopls/internal/lsp/cmd/references.go
 --- a/gopls/internal/lsp/cmd/references.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/references.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,89 +0,0 @@
++++ b/gopls/internal/lsp/cmd/references.go	1970-01-01 08:00:00
+@@ -1,92 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -26658,16 +30137,16 @@
 -		return tool.CommandLineErrorf("references expects 1 argument (position)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -	loc, err := file.mapper.SpanLocation(from)
 -	if err != nil {
@@ -26685,7 +30164,10 @@
 -	}
 -	var spans []string
 -	for _, l := range locations {
--		f := conn.openFile(ctx, fileURI(l.URI))
+-		f, err := conn.openFile(ctx, fileURI(l.URI))
+-		if err != nil {
+-			return err
+-		}
 -		// convert location to span for user-friendly 1-indexed line
 -		// and column numbers
 -		span, err := f.mapper.LocationSpan(l)
@@ -26703,7 +30185,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/remote.go b/gopls/internal/lsp/cmd/remote.go
 --- a/gopls/internal/lsp/cmd/remote.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/remote.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/remote.go	1970-01-01 08:00:00
 @@ -1,164 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -26871,8 +30353,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/rename.go b/gopls/internal/lsp/cmd/rename.go
 --- a/gopls/internal/lsp/cmd/rename.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/rename.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,130 +0,0 @@
++++ b/gopls/internal/lsp/cmd/rename.go	1970-01-01 08:00:00
+@@ -1,74 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -26883,24 +30365,15 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
--	"os"
--	"path/filepath"
--	"sort"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/diff"
 -	"golang.org/x/tools/internal/tool"
 -)
 -
 -// rename implements the rename verb for gopls.
 -type rename struct {
--	Diff     bool `flag:"d,diff" help:"display diffs instead of rewriting files"`
--	Write    bool `flag:"w,write" help:"write result to (source) file instead of stdout"`
--	Preserve bool `flag:"preserve" help:"preserve original files"`
--
+-	EditFlags
 -	app *Application
 -}
 -
@@ -26929,16 +30402,17 @@
 -	if len(args) != 2 {
 -		return tool.CommandLineErrorf("definition expects 2 arguments (position, new name)")
 -	}
--	conn, err := r.app.connect(ctx)
+-	r.app.editFlags = &r.EditFlags
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -	loc, err := file.mapper.SpanLocation(from)
 -	if err != nil {
@@ -26953,60 +30427,12 @@
 -	if err != nil {
 -		return err
 -	}
--	var orderedURIs []string
--	edits := map[span.URI][]protocol.TextEdit{}
--	for _, c := range edit.DocumentChanges {
--		if c.TextDocumentEdit != nil {
--			uri := fileURI(c.TextDocumentEdit.TextDocument.URI)
--			edits[uri] = append(edits[uri], c.TextDocumentEdit.Edits...)
--			orderedURIs = append(orderedURIs, string(uri))
--		}
--	}
--	sort.Strings(orderedURIs)
--	changeCount := len(orderedURIs)
--
--	for _, u := range orderedURIs {
--		uri := span.URIFromURI(u)
--		cmdFile := conn.openFile(ctx, uri)
--		filename := cmdFile.uri.Filename()
--
--		newContent, renameEdits, err := source.ApplyProtocolEdits(cmdFile.mapper, edits[uri])
--		if err != nil {
--			return fmt.Errorf("%v: %v", edits, err)
--		}
--
--		switch {
--		case r.Write:
--			fmt.Fprintln(os.Stderr, filename)
--			if r.Preserve {
--				if err := os.Rename(filename, filename+".orig"); err != nil {
--					return fmt.Errorf("%v: %v", edits, err)
--				}
--			}
--			ioutil.WriteFile(filename, newContent, 0644)
--		case r.Diff:
--			unified, err := diff.ToUnified(filename+".orig", filename, string(cmdFile.mapper.Content), renameEdits)
--			if err != nil {
--				return err
--			}
--			fmt.Print(unified)
--		default:
--			if len(orderedURIs) > 1 {
--				fmt.Printf("%s:\n", filepath.Base(filename))
--			}
--			os.Stdout.Write(newContent)
--			if changeCount > 1 { // if this wasn't last change, print newline
--				fmt.Println()
--			}
--			changeCount -= 1
--		}
--	}
--	return nil
+-	return conn.client.applyWorkspaceEdit(edit)
 -}
 diff -urN a/gopls/internal/lsp/cmd/semantictokens.go b/gopls/internal/lsp/cmd/semantictokens.go
 --- a/gopls/internal/lsp/cmd/semantictokens.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/semantictokens.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,225 +0,0 @@
++++ b/gopls/internal/lsp/cmd/semantictokens.go	1970-01-01 08:00:00
+@@ -1,224 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -27020,7 +30446,6 @@
 -	"fmt"
 -	"go/parser"
 -	"go/token"
--	"io/ioutil"
 -	"log"
 -	"os"
 -	"unicode/utf8"
@@ -27085,18 +30510,18 @@
 -		origOptions(opts)
 -		opts.SemanticTokens = true
 -	}
--	conn, err := c.app.connect(ctx)
+-	conn, err := c.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -	uri := span.URIFromPath(args[0])
--	file := conn.openFile(ctx, uri)
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, uri)
+-	if err != nil {
+-		return err
 -	}
 -
--	buf, err := ioutil.ReadFile(args[0])
+-	buf, err := os.ReadFile(args[0])
 -	if err != nil {
 -		return err
 -	}
@@ -27171,7 +30596,7 @@
 -}
 -
 -func decorate(file string, result []uint32) error {
--	buf, err := ioutil.ReadFile(file)
+-	buf, err := os.ReadFile(file)
 -	if err != nil {
 -		return err
 -	}
@@ -27234,8 +30659,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/serve.go b/gopls/internal/lsp/cmd/serve.go
 --- a/gopls/internal/lsp/cmd/serve.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/serve.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,130 +0,0 @@
++++ b/gopls/internal/lsp/cmd/serve.go	1970-01-01 08:00:00
+@@ -1,146 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -27328,7 +30753,6 @@
 -		}
 -		defer closeLog()
 -		di.ServerAddress = s.Address
--		di.MonitorMemory(ctx)
 -		di.Serve(ctx, s.Debug)
 -	}
 -	var ss jsonrpc2.StreamServer
@@ -27348,6 +30772,23 @@
 -	}
 -	if s.Port != 0 {
 -		network = "tcp"
+-		// TODO(adonovan): should gopls ever be listening on network
+-		// sockets, or only local ones?
+-		//
+-		// Ian says this was added in anticipation of
+-		// something related to "VS Code remote" that turned
+-		// out to be unnecessary. So I propose we limit it to
+-		// localhost, if only so that we avoid the macOS
+-		// firewall prompt.
+-		//
+-		// Hana says: "s.Address is for the remote access (LSP)
+-		// and s.Port is for debugging purpose (according to
+-		// the Server type documentation). I am not sure why the
+-		// existing code here is mixing up and overwriting addr.
+-		// For debugging endpoint, I think localhost makes perfect sense."
+-		//
+-		// TODO(adonovan): disentangle Address and Port,
+-		// and use only localhost for the latter.
 -		addr = fmt.Sprintf(":%v", s.Port)
 -	}
 -	if addr != "" {
@@ -27368,7 +30809,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/signature.go b/gopls/internal/lsp/cmd/signature.go
 --- a/gopls/internal/lsp/cmd/signature.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/signature.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/signature.go	1970-01-01 08:00:00
 @@ -1,88 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -27411,16 +30852,16 @@
 -		return tool.CommandLineErrorf("signature expects 1 argument (position)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
 -	defer conn.terminate(ctx)
 -
 -	from := span.Parse(args[0])
--	file := conn.openFile(ctx, from.URI())
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, from.URI())
+-	if err != nil {
+-		return err
 -	}
 -
 -	loc, err := file.mapper.SpanLocation(from)
@@ -27458,9 +30899,284 @@
 -
 -	return nil
 -}
+diff -urN a/gopls/internal/lsp/cmd/stats.go b/gopls/internal/lsp/cmd/stats.go
+--- a/gopls/internal/lsp/cmd/stats.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cmd/stats.go	1970-01-01 08:00:00
+@@ -1,271 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package cmd
+-
+-import (
+-	"context"
+-	"encoding/json"
+-	"flag"
+-	"fmt"
+-	"go/token"
+-	"io/fs"
+-	"os"
+-	"path/filepath"
+-	"reflect"
+-	"runtime"
+-	"strings"
+-	"sync"
+-	"time"
+-
+-	goplsbug "golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/debug"
+-	"golang.org/x/tools/gopls/internal/lsp/filecache"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
+-)
+-
+-type stats struct {
+-	app *Application
+-
+-	Anon bool `flag:"anon" help:"hide any fields that may contain user names, file names, or source code"`
+-}
+-
+-func (s *stats) Name() string      { return "stats" }
+-func (r *stats) Parent() string    { return r.app.Name() }
+-func (s *stats) Usage() string     { return "" }
+-func (s *stats) ShortHelp() string { return "print workspace statistics" }
+-
+-func (s *stats) DetailedHelp(f *flag.FlagSet) {
+-	fmt.Fprint(f.Output(), `
+-Load the workspace for the current directory, and output a JSON summary of
+-workspace information relevant to performance. As a side effect, this command
+-populates the gopls file cache for the current workspace.
+-
+-By default, this command may include output that refers to the location or
+-content of user code. When the -anon flag is set, fields that may refer to user
+-code are hidden.
+-
+-Example:
+-  $ gopls stats -anon
+-`)
+-	printFlagDefaults(f)
+-}
+-
+-func (s *stats) Run(ctx context.Context, args ...string) error {
+-	if s.app.Remote != "" {
+-		// stats does not work with -remote.
+-		// Other sessions on the daemon may interfere with results.
+-		// Additionally, the type assertions in below only work if progress
+-		// notifications bypass jsonrpc2 serialization.
+-		return fmt.Errorf("the stats subcommand does not work with -remote")
+-	}
+-
+-	if !s.app.Verbose {
+-		event.SetExporter(nil) // don't log errors to stderr
+-	}
+-
+-	stats := GoplsStats{
+-		GOOS:         runtime.GOOS,
+-		GOARCH:       runtime.GOARCH,
+-		GOPLSCACHE:   os.Getenv("GOPLSCACHE"),
+-		GoVersion:    runtime.Version(),
+-		GoplsVersion: debug.Version(),
+-	}
+-
+-	opts := s.app.options
+-	s.app.options = func(o *source.Options) {
+-		if opts != nil {
+-			opts(o)
+-		}
+-		o.VerboseWorkDoneProgress = true
+-	}
+-	var (
+-		iwlMu    sync.Mutex
+-		iwlToken protocol.ProgressToken
+-		iwlDone  = make(chan struct{})
+-	)
+-
+-	onProgress := func(p *protocol.ProgressParams) {
+-		switch v := p.Value.(type) {
+-		case *protocol.WorkDoneProgressBegin:
+-			if v.Title == lsp.DiagnosticWorkTitle(lsp.FromInitialWorkspaceLoad) {
+-				iwlMu.Lock()
+-				iwlToken = p.Token
+-				iwlMu.Unlock()
+-			}
+-		case *protocol.WorkDoneProgressEnd:
+-			iwlMu.Lock()
+-			tok := iwlToken
+-			iwlMu.Unlock()
+-
+-			if p.Token == tok {
+-				close(iwlDone)
+-			}
+-		}
+-	}
+-
+-	// do executes a timed section of the stats command.
+-	do := func(name string, f func() error) (time.Duration, error) {
+-		start := time.Now()
+-		fmt.Fprintf(os.Stderr, "%-30s", name+"...")
+-		if err := f(); err != nil {
+-			return time.Since(start), err
+-		}
+-		d := time.Since(start)
+-		fmt.Fprintf(os.Stderr, "done (%v)\n", d)
+-		return d, nil
+-	}
+-
+-	var conn *connection
+-	iwlDuration, err := do("Initializing workspace", func() error {
+-		var err error
+-		conn, err = s.app.connect(ctx, onProgress)
+-		if err != nil {
+-			return err
+-		}
+-		select {
+-		case <-iwlDone:
+-		case <-ctx.Done():
+-			return ctx.Err()
+-		}
+-		return nil
+-	})
+-	stats.InitialWorkspaceLoadDuration = fmt.Sprint(iwlDuration)
+-	if err != nil {
+-		return err
+-	}
+-	defer conn.terminate(ctx)
+-
+-	// Gather bug reports produced by any process using
+-	// this executable and persisted in the cache.
+-	do("Gathering bug reports", func() error {
+-		stats.CacheDir, stats.BugReports = filecache.BugReports()
+-		if stats.BugReports == nil {
+-			stats.BugReports = []goplsbug.Bug{} // non-nil for JSON
+-		}
+-		return nil
+-	})
+-
+-	if _, err := do("Querying memstats", func() error {
+-		memStats, err := conn.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
+-			Command: command.MemStats.ID(),
+-		})
+-		if err != nil {
+-			return err
+-		}
+-		stats.MemStats = memStats.(command.MemStatsResult)
+-		return nil
+-	}); err != nil {
+-		return err
+-	}
+-
+-	if _, err := do("Querying workspace stats", func() error {
+-		wsStats, err := conn.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
+-			Command: command.WorkspaceStats.ID(),
+-		})
+-		if err != nil {
+-			return err
+-		}
+-		stats.WorkspaceStats = wsStats.(command.WorkspaceStatsResult)
+-		return nil
+-	}); err != nil {
+-		return err
+-	}
+-
+-	if _, err := do("Collecting directory info", func() error {
+-		var err error
+-		stats.DirStats, err = findDirStats(ctx)
+-		if err != nil {
+-			return err
+-		}
+-		return nil
+-	}); err != nil {
+-		return err
+-	}
+-
+-	// Filter JSON output to fields that are consistent with s.Anon.
+-	okFields := make(map[string]interface{})
+-	{
+-		v := reflect.ValueOf(stats)
+-		t := v.Type()
+-		for i := 0; i < t.NumField(); i++ {
+-			f := t.Field(i)
+-			if !token.IsExported(f.Name) {
+-				continue
+-			}
+-			if s.Anon && f.Tag.Get("anon") != "ok" {
+-				// Fields that can be served with -anon must be explicitly marked as OK.
+-				continue
+-			}
+-			vf := v.FieldByName(f.Name)
+-			okFields[f.Name] = vf.Interface()
+-		}
+-	}
+-	data, err := json.MarshalIndent(okFields, "", "  ")
+-	if err != nil {
+-		return err
+-	}
+-
+-	os.Stdout.Write(data)
+-	fmt.Println()
+-	return nil
+-}
+-
+-// GoplsStats holds information extracted from a gopls session in the current
+-// workspace.
+-//
+-// Fields that should be printed with the -anon flag should be explicitly
+-// marked as `anon:"ok"`. Only fields that cannot refer to user files or code
+-// should be marked as such.
+-type GoplsStats struct {
+-	GOOS, GOARCH                 string `anon:"ok"`
+-	GOPLSCACHE                   string
+-	GoVersion                    string `anon:"ok"`
+-	GoplsVersion                 string `anon:"ok"`
+-	InitialWorkspaceLoadDuration string `anon:"ok"` // in time.Duration string form
+-	CacheDir                     string
+-	BugReports                   []goplsbug.Bug
+-	MemStats                     command.MemStatsResult       `anon:"ok"`
+-	WorkspaceStats               command.WorkspaceStatsResult `anon:"ok"`
+-	DirStats                     dirStats                     `anon:"ok"`
+-}
+-
+-type dirStats struct {
+-	Files         int
+-	TestdataFiles int
+-	GoFiles       int
+-	ModFiles      int
+-	Dirs          int
+-}
+-
+-// findDirStats collects information about the current directory and its
+-// subdirectories.
+-func findDirStats(ctx context.Context) (dirStats, error) {
+-	var ds dirStats
+-	filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
+-		if err != nil {
+-			return err
+-		}
+-		if d.IsDir() {
+-			ds.Dirs++
+-		} else {
+-			ds.Files++
+-			slashed := filepath.ToSlash(path)
+-			switch {
+-			case strings.Contains(slashed, "/testdata/") || strings.HasPrefix(slashed, "testdata/"):
+-				ds.TestdataFiles++
+-			case strings.HasSuffix(path, ".go"):
+-				ds.GoFiles++
+-			case strings.HasSuffix(path, ".mod"):
+-				ds.ModFiles++
+-			}
+-		}
+-		return nil
+-	})
+-	return ds, nil
+-}
 diff -urN a/gopls/internal/lsp/cmd/subcommands.go b/gopls/internal/lsp/cmd/subcommands.go
 --- a/gopls/internal/lsp/cmd/subcommands.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/subcommands.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/subcommands.go	1970-01-01 08:00:00
 @@ -1,59 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -27523,8 +31239,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/suggested_fix.go b/gopls/internal/lsp/cmd/suggested_fix.go
 --- a/gopls/internal/lsp/cmd/suggested_fix.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/suggested_fix.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,167 +0,0 @@
++++ b/gopls/internal/lsp/cmd/suggested_fix.go	1970-01-01 08:00:00
+@@ -1,193 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -27535,21 +31251,21 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
--	"os"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/diff"
 -	"golang.org/x/tools/internal/tool"
 -)
 -
+-// TODO(adonovan): this command has a very poor user interface. It
+-// should have a way to query the available fixes for a file (without
+-// a span), enumerate the valid fix kinds, enable all fixes, and not
+-// require the pointless -all flag. See issue #60290.
+-
 -// suggestedFix implements the fix verb for gopls.
 -type suggestedFix struct {
--	Diff  bool `flag:"d,diff" help:"display diffs instead of rewriting files"`
--	Write bool `flag:"w,write" help:"write result to (source) file instead of stdout"`
--	All   bool `flag:"a,all" help:"apply all fixes, not just preferred fixes"`
+-	EditFlags
+-	All bool `flag:"a,all" help:"apply all fixes, not just preferred fixes"`
 -
 -	app *Application
 -}
@@ -27560,8 +31276,33 @@
 -func (s *suggestedFix) ShortHelp() string { return "apply suggested fixes" }
 -func (s *suggestedFix) DetailedHelp(f *flag.FlagSet) {
 -	fmt.Fprintf(f.Output(), `
--Example: apply suggested fixes for this file
--	$ gopls fix -w internal/lsp/cmd/check.go
+-Example: apply fixes to this file, rewriting it:
+-
+-	$ gopls fix -a -w internal/lsp/cmd/check.go
+-
+-The -a (-all) flag causes all fixes, not just preferred ones, to be
+-applied, but since no fixes are currently preferred, this flag is
+-essentially mandatory.
+-
+-Arguments after the filename are interpreted as LSP CodeAction kinds
+-to be applied; the default set is {"quickfix"}, but valid kinds include:
+-
+-	quickfix
+-	refactor
+-	refactor.extract
+-	refactor.inline
+-	refactor.rewrite
+-	source.organizeImports
+-	source.fixAll
+-
+-CodeAction kinds are hierarchical, so "refactor" includes
+-"refactor.inline". There is currently no way to enable or even
+-enumerate all kinds.
+-
+-Example: apply any "refactor.rewrite" fixes at the specific byte
+-offset within this file:
+-
+-	$ gopls fix -a internal/lsp/cmd/check.go:#43 refactor.rewrite
 -
 -fix-flags:
 -`)
@@ -27576,7 +31317,8 @@
 -	if len(args) < 1 {
 -		return tool.CommandLineErrorf("fix expects at least 1 argument")
 -	}
--	conn, err := s.app.connect(ctx)
+-	s.app.editFlags = &s.EditFlags
+-	conn, err := s.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -27584,17 +31326,25 @@
 -
 -	from := span.Parse(args[0])
 -	uri := from.URI()
--	file := conn.openFile(ctx, uri)
--	if file.err != nil {
--		return file.err
+-	file, err := conn.openFile(ctx, uri)
+-	if err != nil {
+-		return err
+-	}
+-	rng, err := file.mapper.SpanRange(from)
+-	if err != nil {
+-		return err
 -	}
 -
+-	// Get diagnostics.
 -	if err := conn.diagnoseFiles(ctx, []span.URI{uri}); err != nil {
 -		return err
 -	}
--	conn.Client.filesMu.Lock()
--	defer conn.Client.filesMu.Unlock()
+-	diagnostics := []protocol.Diagnostic{} // LSP wants non-nil slice
+-	conn.client.filesMu.Lock()
+-	diagnostics = append(diagnostics, file.diagnostics...)
+-	conn.client.filesMu.Unlock()
 -
+-	// Request code actions
 -	codeActionKinds := []protocol.CodeActionKind{protocol.QuickFix}
 -	if len(args) > 1 {
 -		codeActionKinds = []protocol.CodeActionKind{}
@@ -27602,18 +31352,13 @@
 -			codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k))
 -		}
 -	}
--
--	rng, err := file.mapper.SpanRange(from)
--	if err != nil {
--		return err
--	}
 -	p := protocol.CodeActionParams{
 -		TextDocument: protocol.TextDocumentIdentifier{
 -			URI: protocol.URIFromSpanURI(uri),
 -		},
 -		Context: protocol.CodeActionContext{
 -			Only:        codeActionKinds,
--			Diagnostics: file.diagnostics,
+-			Diagnostics: diagnostics,
 -		},
 -		Range: rng,
 -	}
@@ -27621,14 +31366,34 @@
 -	if err != nil {
 -		return fmt.Errorf("%v: %v", from, err)
 -	}
+-
+-	// Gather edits from matching code actions.
 -	var edits []protocol.TextEdit
 -	for _, a := range actions {
--		if a.Command != nil {
--			return fmt.Errorf("ExecuteCommand is not yet supported on the command line")
--		}
+-		// Without -all, apply only "preferred" fixes.
 -		if !a.IsPreferred && !s.All {
 -			continue
 -		}
+-
+-		// Execute any command.
+-		// This may cause the server to make
+-		// an ApplyEdit downcall to the client.
+-		if a.Command != nil {
+-			if _, err := conn.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
+-				Command:   a.Command.Command,
+-				Arguments: a.Command.Arguments,
+-			}); err != nil {
+-				return err
+-			}
+-			// The specification says that commands should
+-			// be executed _after_ edits are applied, not
+-			// instead of them, but we don't want to
+-			// duplicate edits.
+-			continue
+-		}
+-
+-		// Partially apply CodeAction.Edit, a WorkspaceEdit.
+-		// (See also conn.Client.applyWorkspaceEdit(a.Edit)).
 -		if !from.HasPosition() {
 -			for _, c := range a.Edit.DocumentChanges {
 -				if c.TextDocumentEdit != nil {
@@ -27639,14 +31404,11 @@
 -			}
 -			continue
 -		}
--		// If the span passed in has a position, then we need to find
--		// the codeaction that has the same range as the passed in span.
+-
+-		// The provided span has a position (not just offsets).
+-		// Find the code action that has the same range as it.
 -		for _, diag := range a.Diagnostics {
--			spn, err := file.mapper.RangeSpan(diag.Range)
--			if err != nil {
--				continue
--			}
--			if span.ComparePoint(from.Start(), spn.Start()) == 0 {
+-			if diag.Range.Start == rng.Start {
 -				for _, c := range a.Edit.DocumentChanges {
 -					if c.TextDocumentEdit != nil {
 -						if fileURI(c.TextDocumentEdit.TextDocument.URI) == uri {
@@ -27670,31 +31432,11 @@
 -		}
 -	}
 -
--	newContent, sedits, err := source.ApplyProtocolEdits(file.mapper, edits)
--	if err != nil {
--		return fmt.Errorf("%v: %v", edits, err)
--	}
--
--	filename := file.uri.Filename()
--	switch {
--	case s.Write:
--		if len(edits) > 0 {
--			ioutil.WriteFile(filename, newContent, 0644)
--		}
--	case s.Diff:
--		diffs, err := diff.ToUnified(filename+".orig", filename, string(file.mapper.Content), sedits)
--		if err != nil {
--			return err
--		}
--		fmt.Print(diffs)
--	default:
--		os.Stdout.Write(newContent)
--	}
--	return nil
+-	return applyTextEdits(file.mapper, edits, s.app.editFlags)
 -}
 diff -urN a/gopls/internal/lsp/cmd/symbols.go b/gopls/internal/lsp/cmd/symbols.go
 --- a/gopls/internal/lsp/cmd/symbols.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/symbols.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/symbols.go	1970-01-01 08:00:00
 @@ -1,116 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -27735,7 +31477,7 @@
 -		return tool.CommandLineErrorf("symbols expects 1 argument (position)")
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -27812,24 +31554,16 @@
 -		r.End.Character+1,
 -	)
 -}
-diff -urN a/gopls/internal/lsp/cmd/test/cmdtest.go b/gopls/internal/lsp/cmd/test/cmdtest.go
---- a/gopls/internal/lsp/cmd/test/cmdtest.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/test/cmdtest.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
+diff -urN a/gopls/internal/lsp/cmd/test/integration_test.go b/gopls/internal/lsp/cmd/test/integration_test.go
+--- a/gopls/internal/lsp/cmd/test/integration_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cmd/test/integration_test.go	1970-01-01 08:00:00
+@@ -1,1024 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
 -// Package cmdtest contains the test suite for the command line behavior of gopls.
 -package cmdtest
-diff -urN a/gopls/internal/lsp/cmd/test/integration_test.go b/gopls/internal/lsp/cmd/test/integration_test.go
---- a/gopls/internal/lsp/cmd/test/integration_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/test/integration_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,898 +0,0 @@
--// Copyright 2023 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--package cmdtest
 -
 -// This file defines integration tests of each gopls subcommand that
 -// fork+exec the command in a separate process.
@@ -27845,9 +31579,9 @@
 -//
 -// TODO(adonovan):
 -// - Use markers to represent positions in the input and in assertions.
--// - Coverage of cross-cutting things like cwd, enviro, span parsing, etc.
--// - Subcommands that accept -write and -diff flags should implement
--//   them consistently wrt the default behavior; factor their tests.
+-// - Coverage of cross-cutting things like cwd, environ, span parsing, etc.
+-// - Subcommands that accept -write and -diff flags implement them
+-//   consistently; factor their tests.
 -// - Add missing test for 'vulncheck' subcommand.
 -// - Add tests for client-only commands: serve, bug, help, api-json, licenses.
 -
@@ -27856,6 +31590,7 @@
 -	"context"
 -	"encoding/json"
 -	"fmt"
+-	"math/rand"
 -	"os"
 -	"path/filepath"
 -	"regexp"
@@ -27863,11 +31598,11 @@
 -	"testing"
 -
 -	exec "golang.org/x/sys/execabs"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/cmd"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/testenv"
 -	"golang.org/x/tools/internal/tool"
 -	"golang.org/x/tools/txtar"
@@ -27880,7 +31615,7 @@
 -	tree := writeTree(t, "")
 -
 -	// There's not much we can robustly assert about the actual version.
--	const want = debug.Version // e.g. "master"
+-	want := debug.Version() // e.g. "master"
 -
 -	// basic
 -	{
@@ -28221,7 +31956,7 @@
 -		res := gopls(t, tree, "imports", "a.go")
 -		res.checkExit(true)
 -		if res.stdout != want {
--			t.Errorf("format: got <<%s>>, want <<%s>>", res.stdout, want)
+-			t.Errorf("imports: got <<%s>>, want <<%s>>", res.stdout, want)
 -		}
 -	}
 -	// -diff: show a unified diff
@@ -28506,6 +32241,95 @@
 -	}
 -}
 -
+-func TestStats(t *testing.T) {
+-	t.Parallel()
+-
+-	tree := writeTree(t, `
+--- go.mod --
+-module example.com
+-go 1.18
+-
+--- a.go --
+-package a
+--- b/b.go --
+-package b
+--- testdata/foo.go --
+-package foo
+-`)
+-
+-	// Trigger a bug report with a distinctive string
+-	// and check that it was durably recorded.
+-	oops := fmt.Sprintf("oops-%d", rand.Int())
+-	{
+-		env := []string{"TEST_GOPLS_BUG=" + oops}
+-		res := goplsWithEnv(t, tree, env, "bug")
+-		res.checkExit(true)
+-	}
+-
+-	res := gopls(t, tree, "stats")
+-	res.checkExit(true)
+-
+-	var stats cmd.GoplsStats
+-	if err := json.Unmarshal([]byte(res.stdout), &stats); err != nil {
+-		t.Fatalf("failed to unmarshal JSON output of stats command: %v", err)
+-	}
+-
+-	// a few sanity checks
+-	checks := []struct {
+-		field string
+-		got   int
+-		want  int
+-	}{
+-		{
+-			"WorkspaceStats.Views[0].WorkspaceModules",
+-			stats.WorkspaceStats.Views[0].WorkspacePackages.Modules,
+-			1,
+-		},
+-		{
+-			"WorkspaceStats.Views[0].WorkspacePackages",
+-			stats.WorkspaceStats.Views[0].WorkspacePackages.Packages,
+-			2,
+-		},
+-		{"DirStats.Files", stats.DirStats.Files, 4},
+-		{"DirStats.GoFiles", stats.DirStats.GoFiles, 2},
+-		{"DirStats.ModFiles", stats.DirStats.ModFiles, 1},
+-		{"DirStats.TestdataFiles", stats.DirStats.TestdataFiles, 1},
+-	}
+-	for _, check := range checks {
+-		if check.got != check.want {
+-			t.Errorf("stats.%s = %d, want %d", check.field, check.got, check.want)
+-		}
+-	}
+-
+-	// Check that we got a BugReport with the expected message.
+-	{
+-		got := fmt.Sprint(stats.BugReports)
+-		wants := []string{
+-			"cmd/info.go", // File containing call to bug.Report
+-			oops,          // Description
+-		}
+-		for _, want := range wants {
+-			if !strings.Contains(got, want) {
+-				t.Errorf("BugReports does not contain %q. Got:<<%s>>", want, got)
+-				break
+-			}
+-		}
+-	}
+-
+-	// Check that -anon suppresses fields containing user information.
+-	{
+-		res2 := gopls(t, tree, "stats", "-anon")
+-		res2.checkExit(true)
+-		var stats2 cmd.GoplsStats
+-		if err := json.Unmarshal([]byte(res2.stdout), &stats2); err != nil {
+-			t.Fatalf("failed to unmarshal JSON output of stats command: %v", err)
+-		}
+-		if got := len(stats2.BugReports); got > 0 {
+-			t.Errorf("Got %d bug reports with -anon, want 0. Reports:%+v", got, stats2.BugReports)
+-		}
+-	}
+-}
+-
 -// TestFix tests the 'fix' subcommand (../suggested_fix.go).
 -func TestFix(t *testing.T) {
 -	t.Parallel()
@@ -28517,16 +32341,15 @@
 -
 --- a.go --
 -package a
--var _ error = T(0)
 -type T int
 -func f() (int, string) { return }
--`)
--	want := `
+-
+--- b.go --
 -package a
--var _ error = T(0)
--type T int
--func f() (int, string) { return 0, "" }
--`[1:]
+-import "io"
+-var _ io.Reader = C{}
+-type C struct{}
+-`)
 -
 -	// no arguments
 -	{
@@ -28534,20 +32357,45 @@
 -		res.checkExit(false)
 -		res.checkStderr("expects at least 1 argument")
 -	}
--	// success (-a enables fillreturns)
+-	// success with default kinds, {quickfix}.
+-	// -a is always required because no fix is currently "preferred" (!)
 -	{
 -		res := gopls(t, tree, "fix", "-a", "a.go")
 -		res.checkExit(true)
 -		got := res.stdout
+-		want := `
+-package a
+-type T int
+-func f() (int, string) { return 0, "" }
+-
+-`[1:]
 -		if got != want {
--			t.Errorf("fix: got <<%s>>, want <<%s>>", got, want)
+-			t.Errorf("fix: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
 -		}
 -	}
--	// TODO(adonovan): more tests:
--	// - -write, -diff: factor with imports, format, rename.
--	// - without -all flag
--	// - args[2:] is an optional list of protocol.CodeActionKind enum values.
--	// - a span argument with a range causes filtering.
+-	// success, with explicit CodeAction kind and diagnostics span.
+-	{
+-		res := gopls(t, tree, "fix", "-a", "b.go:#40", "quickfix")
+-		res.checkExit(true)
+-		got := res.stdout
+-		want := `
+-package a
+-
+-import "io"
+-
+-var _ io.Reader = C{}
+-
+-type C struct{}
+-
+-// Read implements io.Reader.
+-func (C) Read(p []byte) (n int, err error) {
+-	panic("unimplemented")
+-}
+-`[1:]
+-		if got != want {
+-			t.Errorf("fix: got <<%s>>, want <<%s>>\nstderr:\n%s", got, want, res.stderr)
+-		}
+-	}
 -}
 -
 -// TestWorkspaceSymbol tests the 'workspace_symbol' subcommand (../workspace_symbol.go).
@@ -28590,7 +32438,12 @@
 -
 -// This function is a stand-in for gopls.main in ../../../../main.go.
 -func goplsMain() {
--	bug.PanicOnBugs = true // (not in the production command)
+-	// Panic on bugs (unlike the production gopls command),
+-	// except in tests that inject calls to bug.Report.
+-	if os.Getenv("TEST_GOPLS_BUG") == "" {
+-		bug.PanicOnBugs = true
+-	}
+-
 -	tool.Main(context.Background(), cmd.New("gopls", "", nil, hooks.Options), os.Args[1:])
 -}
 -
@@ -28620,6 +32473,10 @@
 -
 -// gopls executes gopls in a child process.
 -func gopls(t *testing.T, dir string, args ...string) *result {
+-	return goplsWithEnv(t, dir, nil, args...)
+-}
+-
+-func goplsWithEnv(t *testing.T, dir string, env []string, args ...string) *result {
 -	testenv.NeedsTool(t, "go")
 -
 -	// Catch inadvertent use of dir=".", which would make
@@ -28628,16 +32485,17 @@
 -		t.Fatalf("dir is not absolute: %s", dir)
 -	}
 -
--	cmd := exec.Command(os.Args[0], args...)
--	cmd.Env = append(os.Environ(), "ENTRYPOINT=goplsMain")
--	cmd.Dir = dir
--	cmd.Stdout = new(bytes.Buffer)
--	cmd.Stderr = new(bytes.Buffer)
+-	goplsCmd := exec.Command(os.Args[0], args...)
+-	goplsCmd.Env = append(os.Environ(), "ENTRYPOINT=goplsMain")
+-	goplsCmd.Env = append(goplsCmd.Env, env...)
+-	goplsCmd.Dir = dir
+-	goplsCmd.Stdout = new(bytes.Buffer)
+-	goplsCmd.Stderr = new(bytes.Buffer)
 -
--	cmdErr := cmd.Run()
+-	cmdErr := goplsCmd.Run()
 -
--	stdout := strings.ReplaceAll(fmt.Sprint(cmd.Stdout), dir, ".")
--	stderr := strings.ReplaceAll(fmt.Sprint(cmd.Stderr), dir, ".")
+-	stdout := strings.ReplaceAll(fmt.Sprint(goplsCmd.Stdout), dir, ".")
+-	stderr := strings.ReplaceAll(fmt.Sprint(goplsCmd.Stderr), dir, ".")
 -	exitcode := 0
 -	if cmdErr != nil {
 -		if exitErr, ok := cmdErr.(*exec.ExitError); ok {
@@ -28726,7 +32584,7 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/usage/api-json.hlp b/gopls/internal/lsp/cmd/usage/api-json.hlp
 --- a/gopls/internal/lsp/cmd/usage/api-json.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/api-json.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/api-json.hlp	1970-01-01 08:00:00
 @@ -1,4 +0,0 @@
 -print json describing gopls API
 -
@@ -28734,7 +32592,7 @@
 -  gopls [flags] api-json
 diff -urN a/gopls/internal/lsp/cmd/usage/bug.hlp b/gopls/internal/lsp/cmd/usage/bug.hlp
 --- a/gopls/internal/lsp/cmd/usage/bug.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/bug.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/bug.hlp	1970-01-01 08:00:00
 @@ -1,4 +0,0 @@
 -report a bug in gopls
 -
@@ -28742,7 +32600,7 @@
 -  gopls [flags] bug
 diff -urN a/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp b/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp
 --- a/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/call_hierarchy.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -display selected identifier's call hierarchy
 -
@@ -28756,7 +32614,7 @@
 -	$ gopls call_hierarchy helper/helper.go:#53
 diff -urN a/gopls/internal/lsp/cmd/usage/check.hlp b/gopls/internal/lsp/cmd/usage/check.hlp
 --- a/gopls/internal/lsp/cmd/usage/check.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/check.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/check.hlp	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -show diagnostic results for the specified file
 -
@@ -28768,7 +32626,7 @@
 -	$ gopls check internal/lsp/cmd/check.go
 diff -urN a/gopls/internal/lsp/cmd/usage/definition.hlp b/gopls/internal/lsp/cmd/usage/definition.hlp
 --- a/gopls/internal/lsp/cmd/usage/definition.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/definition.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/definition.hlp	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -show declaration of selected identifier
 -
@@ -28787,26 +32645,55 @@
 -    	support markdown in responses
 diff -urN a/gopls/internal/lsp/cmd/usage/fix.hlp b/gopls/internal/lsp/cmd/usage/fix.hlp
 --- a/gopls/internal/lsp/cmd/usage/fix.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/fix.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,15 +0,0 @@
++++ b/gopls/internal/lsp/cmd/usage/fix.hlp	1970-01-01 08:00:00
+@@ -1,44 +0,0 @@
 -apply suggested fixes
 -
 -Usage:
 -  gopls [flags] fix [fix-flags] <filename>
 -
--Example: apply suggested fixes for this file
--	$ gopls fix -w internal/lsp/cmd/check.go
+-Example: apply fixes to this file, rewriting it:
+-
+-	$ gopls fix -a -w internal/lsp/cmd/check.go
+-
+-The -a (-all) flag causes all fixes, not just preferred ones, to be
+-applied, but since no fixes are currently preferred, this flag is
+-essentially mandatory.
+-
+-Arguments after the filename are interpreted as LSP CodeAction kinds
+-to be applied; the default set is {"quickfix"}, but valid kinds include:
+-
+-	quickfix
+-	refactor
+-	refactor.extract
+-	refactor.inline
+-	refactor.rewrite
+-	source.organizeImports
+-	source.fixAll
+-
+-CodeAction kinds are hierarchical, so "refactor" includes
+-"refactor.inline". There is currently no way to enable or even
+-enumerate all kinds.
+-
+-Example: apply any "refactor.rewrite" fixes at the specific byte
+-offset within this file:
+-
+-	$ gopls fix -a internal/lsp/cmd/check.go:#43 refactor.rewrite
 -
 -fix-flags:
 -  -a,-all
 -    	apply all fixes, not just preferred fixes
 -  -d,-diff
--    	display diffs instead of rewriting files
+-    	display diffs instead of edited file content
+-  -l,-list
+-    	display names of edited files
+-  -preserve
+-    	with -write, make copies of original files
 -  -w,-write
--    	write result to (source) file instead of stdout
+-    	write edited content to source files
 diff -urN a/gopls/internal/lsp/cmd/usage/folding_ranges.hlp b/gopls/internal/lsp/cmd/usage/folding_ranges.hlp
 --- a/gopls/internal/lsp/cmd/usage/folding_ranges.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/folding_ranges.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/folding_ranges.hlp	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -display selected file's folding ranges
 -
@@ -28818,8 +32705,8 @@
 -	$ gopls folding_ranges helper/helper.go
 diff -urN a/gopls/internal/lsp/cmd/usage/format.hlp b/gopls/internal/lsp/cmd/usage/format.hlp
 --- a/gopls/internal/lsp/cmd/usage/format.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/format.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
++++ b/gopls/internal/lsp/cmd/usage/format.hlp	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
 -format the code according to the go standard
 -
 -Usage:
@@ -28833,14 +32720,16 @@
 -
 -format-flags:
 -  -d,-diff
--    	display diffs instead of rewriting files
+-    	display diffs instead of edited file content
 -  -l,-list
--    	list files whose formatting differs from gofmt's
+-    	display names of edited files
+-  -preserve
+-    	with -write, make copies of original files
 -  -w,-write
--    	write result to (source) file instead of stdout
+-    	write edited content to source files
 diff -urN a/gopls/internal/lsp/cmd/usage/help.hlp b/gopls/internal/lsp/cmd/usage/help.hlp
 --- a/gopls/internal/lsp/cmd/usage/help.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/help.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/help.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -print usage information for subcommands
 -
@@ -28854,7 +32743,7 @@
 -$ gopls help remote sessions         # help on 'remote sessions' subcommand
 diff -urN a/gopls/internal/lsp/cmd/usage/highlight.hlp b/gopls/internal/lsp/cmd/usage/highlight.hlp
 --- a/gopls/internal/lsp/cmd/usage/highlight.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/highlight.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/highlight.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -display selected identifier's highlights
 -
@@ -28868,7 +32757,7 @@
 -	$ gopls highlight helper/helper.go:#53
 diff -urN a/gopls/internal/lsp/cmd/usage/implementation.hlp b/gopls/internal/lsp/cmd/usage/implementation.hlp
 --- a/gopls/internal/lsp/cmd/usage/implementation.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/implementation.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/implementation.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -display selected identifier's implementation
 -
@@ -28882,8 +32771,8 @@
 -	$ gopls implementation helper/helper.go:#53
 diff -urN a/gopls/internal/lsp/cmd/usage/imports.hlp b/gopls/internal/lsp/cmd/usage/imports.hlp
 --- a/gopls/internal/lsp/cmd/usage/imports.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/imports.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
++++ b/gopls/internal/lsp/cmd/usage/imports.hlp	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
 -updates import statements
 -
 -Usage:
@@ -28895,12 +32784,16 @@
 -
 -imports-flags:
 -  -d,-diff
--    	display diffs instead of rewriting files
+-    	display diffs instead of edited file content
+-  -l,-list
+-    	display names of edited files
+-  -preserve
+-    	with -write, make copies of original files
 -  -w,-write
--    	write result to (source) file instead of stdout
+-    	write edited content to source files
 diff -urN a/gopls/internal/lsp/cmd/usage/inspect.hlp b/gopls/internal/lsp/cmd/usage/inspect.hlp
 --- a/gopls/internal/lsp/cmd/usage/inspect.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/inspect.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/inspect.hlp	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -interact with the gopls daemon (deprecated: use 'remote')
 -
@@ -28912,7 +32805,7 @@
 -  debug     start the debug server
 diff -urN a/gopls/internal/lsp/cmd/usage/licenses.hlp b/gopls/internal/lsp/cmd/usage/licenses.hlp
 --- a/gopls/internal/lsp/cmd/usage/licenses.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/licenses.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/licenses.hlp	1970-01-01 08:00:00
 @@ -1,4 +0,0 @@
 -print licenses of included software
 -
@@ -28920,7 +32813,7 @@
 -  gopls [flags] licenses
 diff -urN a/gopls/internal/lsp/cmd/usage/links.hlp b/gopls/internal/lsp/cmd/usage/links.hlp
 --- a/gopls/internal/lsp/cmd/usage/links.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/links.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/links.hlp	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -list links in a file
 -
@@ -28936,7 +32829,7 @@
 -    	emit document links in JSON format
 diff -urN a/gopls/internal/lsp/cmd/usage/prepare_rename.hlp b/gopls/internal/lsp/cmd/usage/prepare_rename.hlp
 --- a/gopls/internal/lsp/cmd/usage/prepare_rename.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/prepare_rename.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/prepare_rename.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -test validity of a rename operation at location
 -
@@ -28950,7 +32843,7 @@
 -	$ gopls prepare_rename helper/helper.go:#53
 diff -urN a/gopls/internal/lsp/cmd/usage/references.hlp b/gopls/internal/lsp/cmd/usage/references.hlp
 --- a/gopls/internal/lsp/cmd/usage/references.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/references.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/references.hlp	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 -display selected identifier's references
 -
@@ -28968,7 +32861,7 @@
 -    	include the declaration of the specified identifier in the results
 diff -urN a/gopls/internal/lsp/cmd/usage/remote.hlp b/gopls/internal/lsp/cmd/usage/remote.hlp
 --- a/gopls/internal/lsp/cmd/usage/remote.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/remote.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/remote.hlp	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -interact with the gopls daemon
 -
@@ -28980,8 +32873,8 @@
 -  debug     start the debug server
 diff -urN a/gopls/internal/lsp/cmd/usage/rename.hlp b/gopls/internal/lsp/cmd/usage/rename.hlp
 --- a/gopls/internal/lsp/cmd/usage/rename.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/rename.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
++++ b/gopls/internal/lsp/cmd/usage/rename.hlp	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
 -rename selected identifier
 -
 -Usage:
@@ -28995,14 +32888,16 @@
 -
 -rename-flags:
 -  -d,-diff
--    	display diffs instead of rewriting files
+-    	display diffs instead of edited file content
+-  -l,-list
+-    	display names of edited files
 -  -preserve
--    	preserve original files
+-    	with -write, make copies of original files
 -  -w,-write
--    	write result to (source) file instead of stdout
+-    	write edited content to source files
 diff -urN a/gopls/internal/lsp/cmd/usage/semtok.hlp b/gopls/internal/lsp/cmd/usage/semtok.hlp
 --- a/gopls/internal/lsp/cmd/usage/semtok.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/semtok.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/semtok.hlp	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -show semantic tokens for the specified file
 -
@@ -29014,7 +32909,7 @@
 -	$ gopls semtok internal/lsp/cmd/semtok.go
 diff -urN a/gopls/internal/lsp/cmd/usage/serve.hlp b/gopls/internal/lsp/cmd/usage/serve.hlp
 --- a/gopls/internal/lsp/cmd/usage/serve.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/serve.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/serve.hlp	1970-01-01 08:00:00
 @@ -1,30 +0,0 @@
 -run a server for Go code using the Language Server Protocol
 -
@@ -29048,7 +32943,7 @@
 -    	print the full rpc trace in lsp inspector format
 diff -urN a/gopls/internal/lsp/cmd/usage/signature.hlp b/gopls/internal/lsp/cmd/usage/signature.hlp
 --- a/gopls/internal/lsp/cmd/usage/signature.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/signature.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/signature.hlp	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -display selected identifier's signature
 -
@@ -29060,9 +32955,30 @@
 -	$ # 1-indexed location (:line:column or :#offset) of the target identifier
 -	$ gopls signature helper/helper.go:8:6
 -	$ gopls signature helper/helper.go:#53
+diff -urN a/gopls/internal/lsp/cmd/usage/stats.hlp b/gopls/internal/lsp/cmd/usage/stats.hlp
+--- a/gopls/internal/lsp/cmd/usage/stats.hlp	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cmd/usage/stats.hlp	1970-01-01 08:00:00
+@@ -1,17 +0,0 @@
+-print workspace statistics
+-
+-Usage:
+-  gopls [flags] stats
+-
+-Load the workspace for the current directory, and output a JSON summary of
+-workspace information relevant to performance. As a side effect, this command
+-populates the gopls file cache for the current workspace.
+-
+-By default, this command may include output that refers to the location or
+-content of user code. When the -anon flag is set, fields that may refer to user
+-code are hidden.
+-
+-Example:
+-  $ gopls stats -anon
+-  -anon
+-    	hide any fields that may contain user names, file names, or source code
 diff -urN a/gopls/internal/lsp/cmd/usage/symbols.hlp b/gopls/internal/lsp/cmd/usage/symbols.hlp
 --- a/gopls/internal/lsp/cmd/usage/symbols.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/symbols.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/symbols.hlp	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -display selected file's symbols
 -
@@ -29071,10 +32987,10 @@
 -
 -Example:
 -	$ gopls symbols helper/helper.go
-diff -urN a/gopls/internal/lsp/cmd/usage/usage.hlp b/gopls/internal/lsp/cmd/usage/usage.hlp
---- a/gopls/internal/lsp/cmd/usage/usage.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/usage.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,77 +0,0 @@
+diff -urN a/gopls/internal/lsp/cmd/usage/usage-v.hlp b/gopls/internal/lsp/cmd/usage/usage-v.hlp
+--- a/gopls/internal/lsp/cmd/usage/usage-v.hlp	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cmd/usage/usage-v.hlp	1970-01-01 08:00:00
+@@ -1,82 +0,0 @@
 -
 -gopls is a Go language server.
 -
@@ -29112,10 +33028,13 @@
 -  rename            rename selected identifier
 -  semtok            show semantic tokens for the specified file
 -  signature         display selected identifier's signature
+-  stats             print workspace statistics
 -  fix               apply suggested fixes
 -  symbols           display selected file's symbols
 -  workspace_symbol  search symbols in workspace
--  vulncheck         run experimental vulncheck analysis (experimental: under development)
+-                    
+-Internal Use Only   
+-  vulncheck         run vulncheck analysis (internal-use only)
 -
 -flags:
 -  -debug=string
@@ -29132,6 +33051,91 @@
 -    	the address of the ocagent (e.g. http://localhost:55678), or off (default "off")
 -  -port=int
 -    	port on which to run gopls for debugging purposes
+-  -profile.alloc=string
+-    	write alloc profile to this file
+-  -profile.cpu=string
+-    	write CPU profile to this file
+-  -profile.mem=string
+-    	write memory profile to this file
+-  -profile.trace=string
+-    	write trace log to this file
+-  -remote=string
+-    	forward all commands to a remote lsp specified by this flag. With no special prefix, this is assumed to be a TCP address. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. If 'auto', or prefixed by 'auto;', the remote address is automatically resolved based on the executing environment.
+-  -remote.debug=string
+-    	when used with -remote=auto, the -debug value used to start the daemon
+-  -remote.listen.timeout=duration
+-    	when used with -remote=auto, the -listen.timeout value used to start the daemon (default 1m0s)
+-  -remote.logfile=string
+-    	when used with -remote=auto, the -logfile value used to start the daemon
+-  -rpc.trace
+-    	print the full rpc trace in lsp inspector format
+-  -v,-verbose
+-    	verbose output
+-  -vv,-veryverbose
+-    	very verbose output
+diff -urN a/gopls/internal/lsp/cmd/usage/usage.hlp b/gopls/internal/lsp/cmd/usage/usage.hlp
+--- a/gopls/internal/lsp/cmd/usage/usage.hlp	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/cmd/usage/usage.hlp	1970-01-01 08:00:00
+@@ -1,79 +0,0 @@
+-
+-gopls is a Go language server.
+-
+-It is typically used with an editor to provide language features. When no
+-command is specified, gopls will default to the 'serve' command. The language
+-features can also be accessed via the gopls command-line interface.
+-
+-Usage:
+-  gopls help [<subject>]
+-
+-Command:
+-
+-Main                
+-  serve             run a server for Go code using the Language Server Protocol
+-  version           print the gopls version information
+-  bug               report a bug in gopls
+-  help              print usage information for subcommands
+-  api-json          print json describing gopls API
+-  licenses          print licenses of included software
+-                    
+-Features            
+-  call_hierarchy    display selected identifier's call hierarchy
+-  check             show diagnostic results for the specified file
+-  definition        show declaration of selected identifier
+-  folding_ranges    display selected file's folding ranges
+-  format            format the code according to the go standard
+-  highlight         display selected identifier's highlights
+-  implementation    display selected identifier's implementation
+-  imports           updates import statements
+-  remote            interact with the gopls daemon
+-  inspect           interact with the gopls daemon (deprecated: use 'remote')
+-  links             list links in a file
+-  prepare_rename    test validity of a rename operation at location
+-  references        display selected identifier's references
+-  rename            rename selected identifier
+-  semtok            show semantic tokens for the specified file
+-  signature         display selected identifier's signature
+-  stats             print workspace statistics
+-  fix               apply suggested fixes
+-  symbols           display selected file's symbols
+-  workspace_symbol  search symbols in workspace
+-
+-flags:
+-  -debug=string
+-    	serve debug information on the supplied address
+-  -listen=string
+-    	address on which to listen for remote connections. If prefixed by 'unix;', the subsequent address is assumed to be a unix domain socket. Otherwise, TCP is used.
+-  -listen.timeout=duration
+-    	when used with -listen, shut down the server when there are no connected clients for this duration
+-  -logfile=string
+-    	filename to log to. if value is "auto", then logging to a default output file is enabled
+-  -mode=string
+-    	no effect
+-  -ocagent=string
+-    	the address of the ocagent (e.g. http://localhost:55678), or off (default "off")
+-  -port=int
+-    	port on which to run gopls for debugging purposes
+-  -profile.alloc=string
+-    	write alloc profile to this file
 -  -profile.cpu=string
 -    	write CPU profile to this file
 -  -profile.mem=string
@@ -29154,7 +33158,7 @@
 -    	very verbose output
 diff -urN a/gopls/internal/lsp/cmd/usage/version.hlp b/gopls/internal/lsp/cmd/usage/version.hlp
 --- a/gopls/internal/lsp/cmd/usage/version.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/version.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/version.hlp	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -print the gopls version information
 -
@@ -29164,14 +33168,14 @@
 -    	outputs in json format.
 diff -urN a/gopls/internal/lsp/cmd/usage/vulncheck.hlp b/gopls/internal/lsp/cmd/usage/vulncheck.hlp
 --- a/gopls/internal/lsp/cmd/usage/vulncheck.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/vulncheck.hlp	1970-01-01 00:00:00.000000000 +0000
-@@ -1,17 +0,0 @@
--run experimental vulncheck analysis (experimental: under development)
++++ b/gopls/internal/lsp/cmd/usage/vulncheck.hlp	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-run vulncheck analysis (internal-use only)
 -
 -Usage:
 -  gopls [flags] vulncheck
 -
--	WARNING: this command is experimental.
+-	WARNING: this command is for internal-use only.
 -
 -	By default, the command outputs a JSON-encoded
 -	golang.org/x/tools/gopls/internal/lsp/command.VulncheckResult
@@ -29179,13 +33183,9 @@
 -	Example:
 -	$ gopls vulncheck <packages>
 -
--  -config
--    	If true, the command reads a JSON-encoded package load configuration from stdin
--  -summary
--    	If true, outputs a JSON-encoded govulnchecklib.Summary JSON
 diff -urN a/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp b/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp
 --- a/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/cmd/usage/workspace_symbol.hlp	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -search symbols in workspace
 -
@@ -29198,12 +33198,12 @@
 -
 -workspace_symbol-flags:
 -  -matcher=string
--    	specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive.
--    	The default is caseInsensitive.
+-    	specifies the type of matcher: fuzzy, fastfuzzy, casesensitive, or caseinsensitive.
+-    	The default is caseinsensitive.
 diff -urN a/gopls/internal/lsp/cmd/vulncheck.go b/gopls/internal/lsp/cmd/vulncheck.go
 --- a/gopls/internal/lsp/cmd/vulncheck.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/vulncheck.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,84 +0,0 @@
++++ b/gopls/internal/lsp/cmd/vulncheck.go	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -29212,43 +33212,28 @@
 -
 -import (
 -	"context"
--	"encoding/json"
 -	"flag"
 -	"fmt"
 -	"os"
 -
--	"golang.org/x/tools/go/packages"
--	vulnchecklib "golang.org/x/tools/gopls/internal/vulncheck"
--	"golang.org/x/tools/internal/tool"
+-	"golang.org/x/tools/gopls/internal/vulncheck/scan"
 -)
 -
 -// vulncheck implements the vulncheck command.
+-// TODO(hakim): hide from the public.
 -type vulncheck struct {
--	Config    bool `flag:"config" help:"If true, the command reads a JSON-encoded package load configuration from stdin"`
--	AsSummary bool `flag:"summary" help:"If true, outputs a JSON-encoded govulnchecklib.Summary JSON"`
--	app       *Application
+-	app *Application
 -}
 -
--type pkgLoadConfig struct {
--	// BuildFlags is a list of command-line flags to be passed through to
--	// the build system's query tool.
--	BuildFlags []string
--
--	// If Tests is set, the loader includes related test packages.
--	Tests bool
--}
--
--// TODO(hyangah): document pkgLoadConfig
--
 -func (v *vulncheck) Name() string   { return "vulncheck" }
 -func (v *vulncheck) Parent() string { return v.app.Name() }
 -func (v *vulncheck) Usage() string  { return "" }
 -func (v *vulncheck) ShortHelp() string {
--	return "run experimental vulncheck analysis (experimental: under development)"
+-	return "run vulncheck analysis (internal-use only)"
 -}
 -func (v *vulncheck) DetailedHelp(f *flag.FlagSet) {
 -	fmt.Fprint(f.Output(), `
--	WARNING: this command is experimental.
+-	WARNING: this command is for internal-use only.
 -
 -	By default, the command outputs a JSON-encoded
 -	golang.org/x/tools/gopls/internal/lsp/command.VulncheckResult
@@ -29257,32 +33242,10 @@
 -	$ gopls vulncheck <packages>
 -
 -`)
--	printFlagDefaults(f)
 -}
 -
 -func (v *vulncheck) Run(ctx context.Context, args ...string) error {
--	if vulnchecklib.Main == nil {
--		return fmt.Errorf("vulncheck command is available only in gopls compiled with go1.18 or newer")
--	}
--
--	// TODO(hyangah): what's wrong with allowing multiple targets?
--	if len(args) > 1 {
--		return tool.CommandLineErrorf("vulncheck accepts at most one package pattern")
--	}
--	var cfg pkgLoadConfig
--	if v.Config {
--		if err := json.NewDecoder(os.Stdin).Decode(&cfg); err != nil {
--			return tool.CommandLineErrorf("failed to parse cfg: %v", err)
--		}
--	}
--	loadCfg := packages.Config{
--		Context:    ctx,
--		Tests:      cfg.Tests,
--		BuildFlags: cfg.BuildFlags,
--		// inherit the current process's cwd and env.
--	}
--
--	if err := vulnchecklib.Main(loadCfg, args...); err != nil {
+-	if err := scan.Main(ctx, args...); err != nil {
 -		fmt.Fprintln(os.Stderr, err)
 -		os.Exit(1)
 -	}
@@ -29290,8 +33253,8 @@
 -}
 diff -urN a/gopls/internal/lsp/cmd/workspace_symbol.go b/gopls/internal/lsp/cmd/workspace_symbol.go
 --- a/gopls/internal/lsp/cmd/workspace_symbol.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/cmd/workspace_symbol.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,85 +0,0 @@
++++ b/gopls/internal/lsp/cmd/workspace_symbol.go	1970-01-01 08:00:00
+@@ -1,89 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -29302,6 +33265,7 @@
 -	"context"
 -	"flag"
 -	"fmt"
+-	"strings"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
@@ -29310,7 +33274,7 @@
 -
 -// workspaceSymbol implements the workspace_symbol verb for gopls.
 -type workspaceSymbol struct {
--	Matcher string `flag:"matcher" help:"specifies the type of matcher: fuzzy, caseSensitive, or caseInsensitive.\nThe default is caseInsensitive."`
+-	Matcher string `flag:"matcher" help:"specifies the type of matcher: fuzzy, fastfuzzy, casesensitive, or caseinsensitive.\nThe default is caseinsensitive."`
 -
 -	app *Application
 -}
@@ -29340,10 +33304,10 @@
 -		if opts != nil {
 -			opts(o)
 -		}
--		switch r.Matcher {
+-		switch strings.ToLower(r.Matcher) {
 -		case "fuzzy":
 -			o.SymbolMatcher = source.SymbolFuzzy
--		case "caseSensitive":
+-		case "casesensitive":
 -			o.SymbolMatcher = source.SymbolCaseSensitive
 -		case "fastfuzzy":
 -			o.SymbolMatcher = source.SymbolFastFuzzy
@@ -29352,7 +33316,7 @@
 -		}
 -	}
 -
--	conn, err := r.app.connect(ctx)
+-	conn, err := r.app.connect(ctx, nil)
 -	if err != nil {
 -		return err
 -	}
@@ -29367,7 +33331,10 @@
 -		return err
 -	}
 -	for _, s := range symbols {
--		f := conn.openFile(ctx, fileURI(s.Location.URI))
+-		f, err := conn.openFile(ctx, fileURI(s.Location.URI))
+-		if err != nil {
+-			return err
+-		}
 -		span, err := f.mapper.LocationSpan(s.Location)
 -		if err != nil {
 -			return err
@@ -29379,8 +33346,8 @@
 -}
 diff -urN a/gopls/internal/lsp/code_action.go b/gopls/internal/lsp/code_action.go
 --- a/gopls/internal/lsp/code_action.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/code_action.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,481 +0,0 @@
++++ b/gopls/internal/lsp/code_action.go	1970-01-01 08:00:00
+@@ -1,655 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -29390,9 +33357,15 @@
 -import (
 -	"context"
 -	"fmt"
+-	"go/ast"
 -	"sort"
 -	"strings"
 -
+-	"golang.org/x/tools/go/ast/inspector"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct"
+-	"golang.org/x/tools/gopls/internal/lsp/analysis/infertypeargs"
+-	"golang.org/x/tools/gopls/internal/lsp/analysis/stubmethods"
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/mod"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
@@ -29404,6 +33377,9 @@
 -)
 -
 -func (s *Server) codeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.codeAction")
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
@@ -29412,224 +33388,268 @@
 -	uri := fh.URI()
 -
 -	// Determine the supported actions for this file kind.
--	kind := snapshot.View().FileKind(fh)
--	supportedCodeActions, ok := snapshot.View().Options().SupportedCodeActions[kind]
+-	kind := snapshot.FileKind(fh)
+-	supportedCodeActions, ok := snapshot.Options().SupportedCodeActions[kind]
 -	if !ok {
 -		return nil, fmt.Errorf("no supported code actions for %v file kind", kind)
 -	}
--
--	// The Only field of the context specifies which code actions the client wants.
--	// If Only is empty, assume that the client wants all of the non-explicit code actions.
--	var wanted map[protocol.CodeActionKind]bool
--
--	// Explicit Code Actions are opt-in and shouldn't be returned to the client unless
--	// requested using Only.
--	// TODO: Add other CodeLenses such as GoGenerate, RegenerateCgo, etc..
--	explicit := map[protocol.CodeActionKind]bool{
--		protocol.GoTest: true,
--	}
--
--	if len(params.Context.Only) == 0 {
--		wanted = supportedCodeActions
--	} else {
--		wanted = make(map[protocol.CodeActionKind]bool)
--		for _, only := range params.Context.Only {
--			for k, v := range supportedCodeActions {
--				if only == k || strings.HasPrefix(string(k), string(only)+".") {
--					wanted[k] = wanted[k] || v
--				}
--			}
--			wanted[only] = wanted[only] || explicit[only]
--		}
--	}
 -	if len(supportedCodeActions) == 0 {
 -		return nil, nil // not an error if there are none supported
 -	}
--	if len(wanted) == 0 {
+-
+-	// The Only field of the context specifies which code actions the client wants.
+-	// If Only is empty, assume that the client wants all of the non-explicit code actions.
+-	var want map[protocol.CodeActionKind]bool
+-	{
+-		// Explicit Code Actions are opt-in and shouldn't be returned to the client unless
+-		// requested using Only.
+-		// TODO: Add other CodeLenses such as GoGenerate, RegenerateCgo, etc..
+-		explicit := map[protocol.CodeActionKind]bool{
+-			protocol.GoTest: true,
+-		}
+-
+-		if len(params.Context.Only) == 0 {
+-			want = supportedCodeActions
+-		} else {
+-			want = make(map[protocol.CodeActionKind]bool)
+-			for _, only := range params.Context.Only {
+-				for k, v := range supportedCodeActions {
+-					if only == k || strings.HasPrefix(string(k), string(only)+".") {
+-						want[k] = want[k] || v
+-					}
+-				}
+-				want[only] = want[only] || explicit[only]
+-			}
+-		}
+-	}
+-	if len(want) == 0 {
 -		return nil, fmt.Errorf("no supported code action to execute for %s, wanted %v", uri, params.Context.Only)
 -	}
 -
--	var codeActions []protocol.CodeAction
 -	switch kind {
 -	case source.Mod:
--		if diagnostics := params.Context.Diagnostics; len(diagnostics) > 0 {
--			diags, err := mod.ModDiagnostics(ctx, snapshot, fh)
--			if source.IsNonFatalGoModError(err) {
--				return nil, nil
--			}
--			if err != nil {
--				return nil, err
--			}
--			udiags, err := mod.ModUpgradeDiagnostics(ctx, snapshot, fh)
--			if err != nil {
--				return nil, err
--			}
--			quickFixes, err := codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, append(diags, udiags...))
--			if err != nil {
--				return nil, err
--			}
--			codeActions = append(codeActions, quickFixes...)
+-		var actions []protocol.CodeAction
 -
--			vdiags, err := mod.ModVulnerabilityDiagnostics(ctx, snapshot, fh)
--			if err != nil {
--				return nil, err
--			}
--			// Group vulnerabilities by location and then limit which code actions we return
--			// for each location.
--			m := make(map[protocol.Range][]*source.Diagnostic)
--			for _, v := range vdiags {
--				m[v.Range] = append(m[v.Range], v)
--			}
--			for _, sdiags := range m {
--				quickFixes, err = codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, sdiags)
--				if err != nil {
--					return nil, err
--				}
--				quickFixes = mod.SelectUpgradeCodeActions(quickFixes)
--				codeActions = append(codeActions, quickFixes...)
--			}
+-		fixes, err := s.codeActionsMatchingDiagnostics(ctx, fh.URI(), snapshot, params.Context.Diagnostics, want)
+-		if err != nil {
+-			return nil, err
 -		}
+-
+-		// Group vulnerability fixes by their range, and select only the most
+-		// appropriate upgrades.
+-		//
+-		// TODO(rfindley): can this instead be accomplished on the diagnosis side,
+-		// so that code action handling remains uniform?
+-		vulnFixes := make(map[protocol.Range][]protocol.CodeAction)
+-	searchFixes:
+-		for _, fix := range fixes {
+-			for _, diag := range fix.Diagnostics {
+-				if diag.Source == string(source.Govulncheck) || diag.Source == string(source.Vulncheck) {
+-					vulnFixes[diag.Range] = append(vulnFixes[diag.Range], fix)
+-					continue searchFixes
+-				}
+-			}
+-			actions = append(actions, fix)
+-		}
+-
+-		for _, fixes := range vulnFixes {
+-			fixes = mod.SelectUpgradeCodeActions(fixes)
+-			actions = append(actions, fixes...)
+-		}
+-
+-		return actions, nil
+-
 -	case source.Go:
+-		diagnostics := params.Context.Diagnostics
+-
 -		// Don't suggest fixes for generated files, since they are generally
 -		// not useful and some editors may apply them automatically on save.
 -		if source.IsGenerated(ctx, snapshot, uri) {
 -			return nil, nil
 -		}
--		diagnostics := params.Context.Diagnostics
 -
--		// First, process any missing imports and pair them with the
--		// diagnostics they fix.
--		if wantQuickFixes := wanted[protocol.QuickFix] && len(diagnostics) > 0; wantQuickFixes || wanted[protocol.SourceOrganizeImports] {
--			importEdits, importEditsPerFix, err := source.AllImportsFixes(ctx, snapshot, fh)
+-		actions, err := s.codeActionsMatchingDiagnostics(ctx, uri, snapshot, diagnostics, want)
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		// Only compute quick fixes if there are any diagnostics to fix.
+-		wantQuickFixes := want[protocol.QuickFix] && len(diagnostics) > 0
+-
+-		// Code actions requiring syntax information alone.
+-		if wantQuickFixes || want[protocol.SourceOrganizeImports] || want[protocol.RefactorExtract] {
+-			pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull)
 -			if err != nil {
--				event.Error(ctx, "imports fixes", err, tag.File.Of(fh.URI().Filename()))
+-				return nil, err
 -			}
--			// Separate this into a set of codeActions per diagnostic, where
--			// each action is the addition, removal, or renaming of one import.
--			if wantQuickFixes {
--				for _, importFix := range importEditsPerFix {
--					fixes := importDiagnostics(importFix.Fix, diagnostics)
--					if len(fixes) == 0 {
--						continue
+-
+-			// Process any missing imports and pair them with the diagnostics they
+-			// fix.
+-			if wantQuickFixes || want[protocol.SourceOrganizeImports] {
+-				importEdits, importEditsPerFix, err := source.AllImportsFixes(ctx, snapshot, pgf)
+-				if err != nil {
+-					event.Error(ctx, "imports fixes", err, tag.File.Of(fh.URI().Filename()))
+-					importEdits = nil
+-					importEditsPerFix = nil
+-				}
+-
+-				// Separate this into a set of codeActions per diagnostic, where
+-				// each action is the addition, removal, or renaming of one import.
+-				if wantQuickFixes {
+-					for _, importFix := range importEditsPerFix {
+-						fixed := fixedByImportFix(importFix.Fix, diagnostics)
+-						if len(fixed) == 0 {
+-							continue
+-						}
+-						actions = append(actions, protocol.CodeAction{
+-							Title: importFixTitle(importFix.Fix),
+-							Kind:  protocol.QuickFix,
+-							Edit: &protocol.WorkspaceEdit{
+-								DocumentChanges: documentChanges(fh, importFix.Edits),
+-							},
+-							Diagnostics: fixed,
+-						})
 -					}
--					codeActions = append(codeActions, protocol.CodeAction{
--						Title: importFixTitle(importFix.Fix),
--						Kind:  protocol.QuickFix,
+-				}
+-
+-				// Send all of the import edits as one code action if the file is
+-				// being organized.
+-				if want[protocol.SourceOrganizeImports] && len(importEdits) > 0 {
+-					actions = append(actions, protocol.CodeAction{
+-						Title: "Organize Imports",
+-						Kind:  protocol.SourceOrganizeImports,
 -						Edit: &protocol.WorkspaceEdit{
--							DocumentChanges: documentChanges(fh, importFix.Edits),
+-							DocumentChanges: documentChanges(fh, importEdits),
 -						},
--						Diagnostics: fixes,
 -					})
 -				}
 -			}
 -
--			// Send all of the import edits as one code action if the file is
--			// being organized.
--			if wanted[protocol.SourceOrganizeImports] && len(importEdits) > 0 {
--				codeActions = append(codeActions, protocol.CodeAction{
--					Title: "Organize Imports",
--					Kind:  protocol.SourceOrganizeImports,
--					Edit: &protocol.WorkspaceEdit{
--						DocumentChanges: documentChanges(fh, importEdits),
--					},
--				})
+-			if want[protocol.RefactorExtract] {
+-				extractions, err := refactorExtract(ctx, snapshot, pgf, params.Range)
+-				if err != nil {
+-					return nil, err
+-				}
+-				actions = append(actions, extractions...)
 -			}
 -		}
--		if ctx.Err() != nil {
--			return nil, ctx.Err()
--		}
 -
--		// Type-check the package and also run analysis,
--		// then combine their diagnostics.
--		pkg, _, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage)
--		if err != nil {
--			return nil, err
--		}
--		pkgDiags, err := pkg.DiagnosticsForFile(ctx, snapshot, uri)
--		if err != nil {
--			return nil, err
--		}
--		analysisDiags, err := source.Analyze(ctx, snapshot, pkg.Metadata().ID, true)
--		if err != nil {
--			return nil, err
--		}
--		var fileDiags []*source.Diagnostic
--		source.CombineDiagnostics(pkgDiags, analysisDiags[uri], &fileDiags, &fileDiags)
--
--		// Split diagnostics into fixes, which must match incoming diagnostics,
--		// and non-fixes, which must match the requested range. Build actions
--		// for all of them.
--		var fixDiags, nonFixDiags []*source.Diagnostic
--		for _, d := range fileDiags {
--			if len(d.SuggestedFixes) == 0 {
--				continue
--			}
--			var isFix bool
--			for _, fix := range d.SuggestedFixes {
--				if fix.ActionKind == protocol.QuickFix || fix.ActionKind == protocol.SourceFixAll {
--					isFix = true
--					break
+-		var stubMethodsDiagnostics []protocol.Diagnostic
+-		if wantQuickFixes && snapshot.Options().IsAnalyzerEnabled(stubmethods.Analyzer.Name) {
+-			for _, pd := range diagnostics {
+-				if stubmethods.MatchesMessage(pd.Message) {
+-					stubMethodsDiagnostics = append(stubMethodsDiagnostics, pd)
 -				}
 -			}
--			if isFix {
--				fixDiags = append(fixDiags, d)
--			} else {
--				nonFixDiags = append(nonFixDiags, d)
--			}
 -		}
 -
--		fixActions, err := codeActionsMatchingDiagnostics(ctx, snapshot, diagnostics, fixDiags)
--		if err != nil {
--			return nil, err
--		}
--		codeActions = append(codeActions, fixActions...)
--
--		for _, nonfix := range nonFixDiags {
--			// For now, only show diagnostics for matching lines. Maybe we should
--			// alter this behavior in the future, depending on the user experience.
--			if !protocol.Intersect(nonfix.Range, params.Range) {
--				continue
--			}
--			actions, err := codeActionsForDiagnostic(ctx, snapshot, nonfix, nil)
+-		// Code actions requiring type information.
+-		if len(stubMethodsDiagnostics) > 0 ||
+-			want[protocol.RefactorRewrite] ||
+-			want[protocol.RefactorInline] ||
+-			want[protocol.GoTest] {
+-			pkg, pgf, err := source.NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -			if err != nil {
 -				return nil, err
 -			}
--			codeActions = append(codeActions, actions...)
+-			for _, pd := range stubMethodsDiagnostics {
+-				start, end, err := pgf.RangePos(pd.Range)
+-				if err != nil {
+-					return nil, err
+-				}
+-				action, ok, err := func() (_ protocol.CodeAction, _ bool, rerr error) {
+-					// golang/go#61693: code actions were refactored to run outside of the
+-					// analysis framework, but as a result they lost their panic recovery.
+-					//
+-					// Stubmethods "should never fail"", but put back the panic recovery as a
+-					// defensive measure.
+-					defer func() {
+-						if r := recover(); r != nil {
+-							rerr = bug.Errorf("stubmethods panicked: %v", r)
+-						}
+-					}()
+-					d, ok := stubmethods.DiagnosticForError(pkg.FileSet(), pgf.File, start, end, pd.Message, pkg.GetTypesInfo())
+-					if !ok {
+-						return protocol.CodeAction{}, false, nil
+-					}
+-					cmd, err := command.NewApplyFixCommand(d.Message, command.ApplyFixArgs{
+-						URI:   protocol.URIFromSpanURI(pgf.URI),
+-						Fix:   source.StubMethods,
+-						Range: pd.Range,
+-					})
+-					if err != nil {
+-						return protocol.CodeAction{}, false, err
+-					}
+-					return protocol.CodeAction{
+-						Title:       d.Message,
+-						Kind:        protocol.QuickFix,
+-						Command:     &cmd,
+-						Diagnostics: []protocol.Diagnostic{pd},
+-					}, true, nil
+-				}()
+-				if err != nil {
+-					return nil, err
+-				}
+-				if ok {
+-					actions = append(actions, action)
+-				}
+-			}
+-
+-			if want[protocol.RefactorRewrite] {
+-				rewrites, err := refactorRewrite(ctx, snapshot, pkg, pgf, fh, params.Range)
+-				if err != nil {
+-					return nil, err
+-				}
+-				actions = append(actions, rewrites...)
+-			}
+-
+-			if want[protocol.RefactorInline] {
+-				rewrites, err := refactorInline(ctx, snapshot, pkg, pgf, fh, params.Range)
+-				if err != nil {
+-					return nil, err
+-				}
+-				actions = append(actions, rewrites...)
+-			}
+-
+-			if want[protocol.GoTest] {
+-				fixes, err := goTest(ctx, snapshot, pkg, pgf, params.Range)
+-				if err != nil {
+-					return nil, err
+-				}
+-				actions = append(actions, fixes...)
+-			}
 -		}
 -
--		if wanted[protocol.RefactorExtract] {
--			fixes, err := extractionFixes(ctx, snapshot, uri, params.Range)
--			if err != nil {
--				return nil, err
--			}
--			codeActions = append(codeActions, fixes...)
--		}
--
--		if wanted[protocol.GoTest] {
--			fixes, err := goTest(ctx, snapshot, uri, params.Range)
--			if err != nil {
--				return nil, err
--			}
--			codeActions = append(codeActions, fixes...)
--		}
+-		return actions, nil
 -
 -	default:
 -		// Unsupported file kind for a code action.
 -		return nil, nil
 -	}
+-}
 -
--	var filtered []protocol.CodeAction
--	for _, action := range codeActions {
--		if wanted[action.Kind] {
--			filtered = append(filtered, action)
+-func (s *Server) findMatchingDiagnostics(uri span.URI, pd protocol.Diagnostic) []*source.Diagnostic {
+-	s.diagnosticsMu.Lock()
+-	defer s.diagnosticsMu.Unlock()
+-
+-	var sds []*source.Diagnostic
+-	for _, report := range s.diagnostics[uri].reports {
+-		for _, sd := range report.diags {
+-			sameDiagnostic := (pd.Message == strings.TrimSpace(sd.Message) && // extra space may have been trimmed when converting to protocol.Diagnostic
+-				protocol.CompareRange(pd.Range, sd.Range) == 0 &&
+-				pd.Source == string(sd.Source))
+-
+-			if sameDiagnostic {
+-				sds = append(sds, sd)
+-			}
 -		}
 -	}
--	return filtered, nil
+-	return sds
 -}
 -
 -func (s *Server) getSupportedCodeActions() []protocol.CodeActionKind {
 -	allCodeActionKinds := make(map[protocol.CodeActionKind]struct{})
--	for _, kinds := range s.session.Options().SupportedCodeActions {
+-	for _, kinds := range s.Options().SupportedCodeActions {
 -		for kind := range kinds {
 -			allCodeActionKinds[kind] = struct{}{}
 -		}
@@ -29657,7 +33677,10 @@
 -	return str
 -}
 -
--func importDiagnostics(fix *imports.ImportFix, diagnostics []protocol.Diagnostic) (results []protocol.Diagnostic) {
+-// fixedByImportFix filters the provided slice of diagnostics to those that
+-// would be fixed by the provided imports fix.
+-func fixedByImportFix(fix *imports.ImportFix, diagnostics []protocol.Diagnostic) []protocol.Diagnostic {
+-	var results []protocol.Diagnostic
 -	for _, diagnostic := range diagnostics {
 -		switch {
 -		// "undeclared name: X" may be an unresolved import.
@@ -29691,23 +33714,16 @@
 -	return results
 -}
 -
--func extractionFixes(ctx context.Context, snapshot source.Snapshot, uri span.URI, rng protocol.Range) ([]protocol.CodeAction, error) {
+-func refactorExtract(ctx context.Context, snapshot source.Snapshot, pgf *source.ParsedGoFile, rng protocol.Range) ([]protocol.CodeAction, error) {
 -	if rng.Start == rng.End {
 -		return nil, nil
 -	}
--	fh, err := snapshot.GetFile(ctx, uri)
--	if err != nil {
--		return nil, err
--	}
--	pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull)
--	if err != nil {
--		return nil, fmt.Errorf("getting file for Identifier: %w", err)
--	}
+-
 -	start, end, err := pgf.RangePos(rng)
 -	if err != nil {
 -		return nil, err
 -	}
--	puri := protocol.URIFromSpanURI(uri)
+-	puri := protocol.URIFromSpanURI(pgf.URI)
 -	var commands []protocol.Command
 -	if _, ok, methodOk, _ := source.CanExtractFunction(pgf.Tok, start, end, pgf.Src, pgf.File); ok {
 -		cmd, err := command.NewApplyFixCommand("Extract function", command.ApplyFixArgs{
@@ -29753,6 +33769,126 @@
 -	return actions, nil
 -}
 -
+-func refactorRewrite(ctx context.Context, snapshot source.Snapshot, pkg source.Package, pgf *source.ParsedGoFile, fh source.FileHandle, rng protocol.Range) (_ []protocol.CodeAction, rerr error) {
+-	// golang/go#61693: code actions were refactored to run outside of the
+-	// analysis framework, but as a result they lost their panic recovery.
+-	//
+-	// These code actions should never fail, but put back the panic recovery as a
+-	// defensive measure.
+-	defer func() {
+-		if r := recover(); r != nil {
+-			rerr = bug.Errorf("refactor.rewrite code actions panicked: %v", r)
+-		}
+-	}()
+-	start, end, err := pgf.RangePos(rng)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	var commands []protocol.Command
+-	if _, ok, _ := source.CanInvertIfCondition(pgf.File, start, end); ok {
+-		cmd, err := command.NewApplyFixCommand("Invert if condition", command.ApplyFixArgs{
+-			URI:   protocol.URIFromSpanURI(pgf.URI),
+-			Fix:   source.InvertIfCondition,
+-			Range: rng,
+-		})
+-		if err != nil {
+-			return nil, err
+-		}
+-		commands = append(commands, cmd)
+-	}
+-
+-	// N.B.: an inspector only pays for itself after ~5 passes, which means we're
+-	// currently not getting a good deal on this inspection.
+-	//
+-	// TODO: Consider removing the inspection after convenienceAnalyzers are removed.
+-	inspect := inspector.New([]*ast.File{pgf.File})
+-	if snapshot.Options().IsAnalyzerEnabled(fillstruct.Analyzer.Name) {
+-		for _, d := range fillstruct.DiagnoseFillableStructs(inspect, start, end, pkg.GetTypes(), pkg.GetTypesInfo()) {
+-			rng, err := pgf.Mapper.PosRange(pgf.Tok, d.Pos, d.End)
+-			if err != nil {
+-				return nil, err
+-			}
+-			cmd, err := command.NewApplyFixCommand(d.Message, command.ApplyFixArgs{
+-				URI:   protocol.URIFromSpanURI(pgf.URI),
+-				Fix:   source.FillStruct,
+-				Range: rng,
+-			})
+-			if err != nil {
+-				return nil, err
+-			}
+-			commands = append(commands, cmd)
+-		}
+-	}
+-
+-	var actions []protocol.CodeAction
+-	for i := range commands {
+-		actions = append(actions, protocol.CodeAction{
+-			Title:   commands[i].Title,
+-			Kind:    protocol.RefactorRewrite,
+-			Command: &commands[i],
+-		})
+-	}
+-
+-	if snapshot.Options().IsAnalyzerEnabled(infertypeargs.Analyzer.Name) {
+-		for _, d := range infertypeargs.DiagnoseInferableTypeArgs(pkg.FileSet(), inspect, start, end, pkg.GetTypes(), pkg.GetTypesInfo()) {
+-			if len(d.SuggestedFixes) != 1 {
+-				panic(fmt.Sprintf("unexpected number of suggested fixes from infertypeargs: %v", len(d.SuggestedFixes)))
+-			}
+-			fix := d.SuggestedFixes[0]
+-			var edits []protocol.TextEdit
+-			for _, analysisEdit := range fix.TextEdits {
+-				rng, err := pgf.Mapper.PosRange(pgf.Tok, analysisEdit.Pos, analysisEdit.End)
+-				if err != nil {
+-					return nil, err
+-				}
+-				edits = append(edits, protocol.TextEdit{
+-					Range:   rng,
+-					NewText: string(analysisEdit.NewText),
+-				})
+-			}
+-			actions = append(actions, protocol.CodeAction{
+-				Title: "Simplify type arguments",
+-				Kind:  protocol.RefactorRewrite,
+-				Edit: &protocol.WorkspaceEdit{
+-					DocumentChanges: documentChanges(fh, edits),
+-				},
+-			})
+-		}
+-	}
+-
+-	return actions, nil
+-}
+-
+-// refactorInline returns inline actions available at the specified range.
+-func refactorInline(ctx context.Context, snapshot source.Snapshot, pkg source.Package, pgf *source.ParsedGoFile, fh source.FileHandle, rng protocol.Range) ([]protocol.CodeAction, error) {
+-	var commands []protocol.Command
+-
+-	// If range is within call expression, offer inline action.
+-	if _, fn, err := source.EnclosingStaticCall(pkg, pgf, rng); err == nil {
+-		cmd, err := command.NewApplyFixCommand(fmt.Sprintf("Inline call to %s", fn.Name()), command.ApplyFixArgs{
+-			URI:   protocol.URIFromSpanURI(pgf.URI),
+-			Fix:   source.InlineCall,
+-			Range: rng,
+-		})
+-		if err != nil {
+-			return nil, err
+-		}
+-		commands = append(commands, cmd)
+-	}
+-
+-	// Convert commands to actions.
+-	var actions []protocol.CodeAction
+-	for i := range commands {
+-		actions = append(actions, protocol.CodeAction{
+-			Title:   commands[i].Title,
+-			Kind:    protocol.RefactorInline,
+-			Command: &commands[i],
+-		})
+-	}
+-	return actions, nil
+-}
+-
 -func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol.DocumentChanges {
 -	return []protocol.DocumentChanges{
 -		{
@@ -29763,41 +33899,55 @@
 -						URI: protocol.URIFromSpanURI(fh.URI()),
 -					},
 -				},
--				Edits: edits,
+-				Edits: nonNilSliceTextEdit(edits),
 -			},
 -		},
 -	}
 -}
 -
--func codeActionsMatchingDiagnostics(ctx context.Context, snapshot source.Snapshot, pdiags []protocol.Diagnostic, sdiags []*source.Diagnostic) ([]protocol.CodeAction, error) {
+-// codeActionsMatchingDiagnostics fetches code actions for the provided
+-// diagnostics, by first attempting to unmarshal code actions directly from the
+-// bundled protocol.Diagnostic.Data field, and failing that by falling back on
+-// fetching a matching source.Diagnostic from the set of stored diagnostics for
+-// this file.
+-func (s *Server) codeActionsMatchingDiagnostics(ctx context.Context, uri span.URI, snapshot source.Snapshot, pds []protocol.Diagnostic, want map[protocol.CodeActionKind]bool) ([]protocol.CodeAction, error) {
 -	var actions []protocol.CodeAction
--	for _, sd := range sdiags {
--		var diag *protocol.Diagnostic
--		for _, pd := range pdiags {
--			if sameDiagnostic(pd, sd) {
--				diag = &pd
--				break
+-	var unbundled []protocol.Diagnostic // diagnostics without bundled code actions in their Data field
+-	for _, pd := range pds {
+-		bundled := source.BundledQuickFixes(pd)
+-		if len(bundled) > 0 {
+-			for _, fix := range bundled {
+-				if want[fix.Kind] {
+-					actions = append(actions, fix)
+-				}
 -			}
+-		} else {
+-			// No bundled actions: keep searching for a match.
+-			unbundled = append(unbundled, pd)
 -		}
--		if diag == nil {
--			continue
--		}
--		diagActions, err := codeActionsForDiagnostic(ctx, snapshot, sd, diag)
--		if err != nil {
--			return nil, err
--		}
--		actions = append(actions, diagActions...)
+-	}
 -
+-	for _, pd := range unbundled {
+-		for _, sd := range s.findMatchingDiagnostics(uri, pd) {
+-			diagActions, err := codeActionsForDiagnostic(ctx, snapshot, sd, &pd, want)
+-			if err != nil {
+-				return nil, err
+-			}
+-			actions = append(actions, diagActions...)
+-		}
 -	}
 -	return actions, nil
 -}
 -
--func codeActionsForDiagnostic(ctx context.Context, snapshot source.Snapshot, sd *source.Diagnostic, pd *protocol.Diagnostic) ([]protocol.CodeAction, error) {
+-func codeActionsForDiagnostic(ctx context.Context, snapshot source.Snapshot, sd *source.Diagnostic, pd *protocol.Diagnostic, want map[protocol.CodeActionKind]bool) ([]protocol.CodeAction, error) {
 -	var actions []protocol.CodeAction
 -	for _, fix := range sd.SuggestedFixes {
--		var changes []protocol.DocumentChanges
+-		if !want[fix.ActionKind] {
+-			continue
+-		}
+-		changes := []protocol.DocumentChanges{} // must be a slice
 -		for uri, edits := range fix.Edits {
--			fh, err := snapshot.GetFile(ctx, uri)
+-			fh, err := snapshot.ReadFile(ctx, uri)
 -			if err != nil {
 -				return nil, err
 -			}
@@ -29811,25 +33961,14 @@
 -			},
 -			Command: fix.Command,
 -		}
--		if pd != nil {
--			action.Diagnostics = []protocol.Diagnostic{*pd}
--		}
+-		action.Diagnostics = []protocol.Diagnostic{*pd}
 -		actions = append(actions, action)
 -	}
 -	return actions, nil
 -}
 -
--func sameDiagnostic(pd protocol.Diagnostic, sd *source.Diagnostic) bool {
--	return pd.Message == strings.TrimSpace(sd.Message) && // extra space may have been trimmed when converting to protocol.Diagnostic
--		protocol.CompareRange(pd.Range, sd.Range) == 0 && pd.Source == string(sd.Source)
--}
--
--func goTest(ctx context.Context, snapshot source.Snapshot, uri span.URI, rng protocol.Range) ([]protocol.CodeAction, error) {
--	fh, err := snapshot.GetFile(ctx, uri)
--	if err != nil {
--		return nil, err
--	}
--	fns, err := source.TestsAndBenchmarks(ctx, snapshot, fh)
+-func goTest(ctx context.Context, snapshot source.Snapshot, pkg source.Package, pgf *source.ParsedGoFile, rng protocol.Range) ([]protocol.CodeAction, error) {
+-	fns, err := source.TestsAndBenchmarks(ctx, snapshot, pkg, pgf)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -29852,7 +33991,7 @@
 -		return nil, nil
 -	}
 -
--	cmd, err := command.NewTestCommand("Run tests and benchmarks", protocol.URIFromSpanURI(uri), tests, benchmarks)
+-	cmd, err := command.NewTestCommand("Run tests and benchmarks", protocol.URIFromSpanURI(pgf.URI), tests, benchmarks)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -29862,10 +34001,12 @@
 -		Command: &cmd,
 -	}}, nil
 -}
+-
+-type unit = struct{}
 diff -urN a/gopls/internal/lsp/code_lens.go b/gopls/internal/lsp/code_lens.go
 --- a/gopls/internal/lsp/code_lens.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/code_lens.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,57 +0,0 @@
++++ b/gopls/internal/lsp/code_lens.go	1970-01-01 08:00:00
+@@ -1,61 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -29882,16 +34023,20 @@
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) codeLens(ctx context.Context, params *protocol.CodeLensParams) ([]protocol.CodeLens, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.codeLens", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
 -	var lenses map[command.Command]source.LensFunc
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Mod:
 -		lenses = mod.LensFuncs()
 -	case source.Go:
@@ -29902,7 +34047,7 @@
 -	}
 -	var result []protocol.CodeLens
 -	for cmd, lf := range lenses {
--		if !snapshot.View().Options().Codelenses[string(cmd)] {
+-		if !snapshot.Options().Codelenses[string(cmd)] {
 -			continue
 -		}
 -		added, err := lf(ctx, snapshot, fh)
@@ -29925,8 +34070,8 @@
 -}
 diff -urN a/gopls/internal/lsp/command/command_gen.go b/gopls/internal/lsp/command/command_gen.go
 --- a/gopls/internal/lsp/command/command_gen.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/command_gen.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,509 +0,0 @@
++++ b/gopls/internal/lsp/command/command_gen.go	1970-01-01 08:00:00
+@@ -1,621 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -29936,10 +34081,10 @@
 -//go:build !generate
 -// +build !generate
 -
--package command
--
 -// Code generated by generate.go. DO NOT EDIT.
 -
+-package command
+-
 -import (
 -	"context"
 -	"fmt"
@@ -29948,35 +34093,42 @@
 -)
 -
 -const (
--	AddDependency         Command = "add_dependency"
--	AddImport             Command = "add_import"
--	ApplyFix              Command = "apply_fix"
--	CheckUpgrades         Command = "check_upgrades"
--	EditGoDirective       Command = "edit_go_directive"
--	FetchVulncheckResult  Command = "fetch_vulncheck_result"
--	GCDetails             Command = "gc_details"
--	Generate              Command = "generate"
--	GoGetPackage          Command = "go_get_package"
--	ListImports           Command = "list_imports"
--	ListKnownPackages     Command = "list_known_packages"
--	MemStats              Command = "mem_stats"
--	RegenerateCgo         Command = "regenerate_cgo"
--	RemoveDependency      Command = "remove_dependency"
--	ResetGoModDiagnostics Command = "reset_go_mod_diagnostics"
--	RunGovulncheck        Command = "run_govulncheck"
--	RunTests              Command = "run_tests"
--	StartDebugging        Command = "start_debugging"
--	Test                  Command = "test"
--	Tidy                  Command = "tidy"
--	ToggleGCDetails       Command = "toggle_gc_details"
--	UpdateGoSum           Command = "update_go_sum"
--	UpgradeDependency     Command = "upgrade_dependency"
--	Vendor                Command = "vendor"
+-	AddDependency           Command = "add_dependency"
+-	AddImport               Command = "add_import"
+-	AddTelemetryCounters    Command = "add_telemetry_counters"
+-	ApplyFix                Command = "apply_fix"
+-	CheckUpgrades           Command = "check_upgrades"
+-	EditGoDirective         Command = "edit_go_directive"
+-	FetchVulncheckResult    Command = "fetch_vulncheck_result"
+-	GCDetails               Command = "gc_details"
+-	Generate                Command = "generate"
+-	GoGetPackage            Command = "go_get_package"
+-	ListImports             Command = "list_imports"
+-	ListKnownPackages       Command = "list_known_packages"
+-	MaybePromptForTelemetry Command = "maybe_prompt_for_telemetry"
+-	MemStats                Command = "mem_stats"
+-	RegenerateCgo           Command = "regenerate_cgo"
+-	RemoveDependency        Command = "remove_dependency"
+-	ResetGoModDiagnostics   Command = "reset_go_mod_diagnostics"
+-	RunGoWorkCommand        Command = "run_go_work_command"
+-	RunGovulncheck          Command = "run_govulncheck"
+-	RunTests                Command = "run_tests"
+-	StartDebugging          Command = "start_debugging"
+-	StartProfile            Command = "start_profile"
+-	StopProfile             Command = "stop_profile"
+-	Test                    Command = "test"
+-	Tidy                    Command = "tidy"
+-	ToggleGCDetails         Command = "toggle_gc_details"
+-	UpdateGoSum             Command = "update_go_sum"
+-	UpgradeDependency       Command = "upgrade_dependency"
+-	Vendor                  Command = "vendor"
+-	WorkspaceStats          Command = "workspace_stats"
 -)
 -
 -var Commands = []Command{
 -	AddDependency,
 -	AddImport,
+-	AddTelemetryCounters,
 -	ApplyFix,
 -	CheckUpgrades,
 -	EditGoDirective,
@@ -29986,19 +34138,24 @@
 -	GoGetPackage,
 -	ListImports,
 -	ListKnownPackages,
+-	MaybePromptForTelemetry,
 -	MemStats,
 -	RegenerateCgo,
 -	RemoveDependency,
 -	ResetGoModDiagnostics,
+-	RunGoWorkCommand,
 -	RunGovulncheck,
 -	RunTests,
 -	StartDebugging,
+-	StartProfile,
+-	StopProfile,
 -	Test,
 -	Tidy,
 -	ToggleGCDetails,
 -	UpdateGoSum,
 -	UpgradeDependency,
 -	Vendor,
+-	WorkspaceStats,
 -}
 -
 -func Dispatch(ctx context.Context, params *protocol.ExecuteCommandParams, s Interface) (interface{}, error) {
@@ -30015,6 +34172,12 @@
 -			return nil, err
 -		}
 -		return nil, s.AddImport(ctx, a0)
+-	case "gopls.add_telemetry_counters":
+-		var a0 AddTelemetryCountersArgs
+-		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+-			return nil, err
+-		}
+-		return nil, s.AddTelemetryCounters(ctx, a0)
 -	case "gopls.apply_fix":
 -		var a0 ApplyFixArgs
 -		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
@@ -30069,6 +34232,8 @@
 -			return nil, err
 -		}
 -		return s.ListKnownPackages(ctx, a0)
+-	case "gopls.maybe_prompt_for_telemetry":
+-		return nil, s.MaybePromptForTelemetry(ctx)
 -	case "gopls.mem_stats":
 -		return s.MemStats(ctx)
 -	case "gopls.regenerate_cgo":
@@ -30089,6 +34254,12 @@
 -			return nil, err
 -		}
 -		return nil, s.ResetGoModDiagnostics(ctx, a0)
+-	case "gopls.run_go_work_command":
+-		var a0 RunGoWorkArgs
+-		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+-			return nil, err
+-		}
+-		return nil, s.RunGoWorkCommand(ctx, a0)
 -	case "gopls.run_govulncheck":
 -		var a0 VulncheckArgs
 -		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
@@ -30107,6 +34278,18 @@
 -			return nil, err
 -		}
 -		return s.StartDebugging(ctx, a0)
+-	case "gopls.start_profile":
+-		var a0 StartProfileArgs
+-		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+-			return nil, err
+-		}
+-		return s.StartProfile(ctx, a0)
+-	case "gopls.stop_profile":
+-		var a0 StopProfileArgs
+-		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+-			return nil, err
+-		}
+-		return s.StopProfile(ctx, a0)
 -	case "gopls.test":
 -		var a0 protocol.DocumentURI
 -		var a1 []string
@@ -30145,6 +34328,8 @@
 -			return nil, err
 -		}
 -		return nil, s.Vendor(ctx, a0)
+-	case "gopls.workspace_stats":
+-		return s.WorkspaceStats(ctx)
 -	}
 -	return nil, fmt.Errorf("unsupported command %q", params.Command)
 -}
@@ -30173,6 +34358,18 @@
 -	}, nil
 -}
 -
+-func NewAddTelemetryCountersCommand(title string, a0 AddTelemetryCountersArgs) (protocol.Command, error) {
+-	args, err := MarshalArgs(a0)
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.add_telemetry_counters",
+-		Arguments: args,
+-	}, nil
+-}
+-
 -func NewApplyFixCommand(title string, a0 ApplyFixArgs) (protocol.Command, error) {
 -	args, err := MarshalArgs(a0)
 -	if err != nil {
@@ -30281,6 +34478,18 @@
 -	}, nil
 -}
 -
+-func NewMaybePromptForTelemetryCommand(title string) (protocol.Command, error) {
+-	args, err := MarshalArgs()
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.maybe_prompt_for_telemetry",
+-		Arguments: args,
+-	}, nil
+-}
+-
 -func NewMemStatsCommand(title string) (protocol.Command, error) {
 -	args, err := MarshalArgs()
 -	if err != nil {
@@ -30329,6 +34538,18 @@
 -	}, nil
 -}
 -
+-func NewRunGoWorkCommandCommand(title string, a0 RunGoWorkArgs) (protocol.Command, error) {
+-	args, err := MarshalArgs(a0)
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.run_go_work_command",
+-		Arguments: args,
+-	}, nil
+-}
+-
 -func NewRunGovulncheckCommand(title string, a0 VulncheckArgs) (protocol.Command, error) {
 -	args, err := MarshalArgs(a0)
 -	if err != nil {
@@ -30365,6 +34586,30 @@
 -	}, nil
 -}
 -
+-func NewStartProfileCommand(title string, a0 StartProfileArgs) (protocol.Command, error) {
+-	args, err := MarshalArgs(a0)
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.start_profile",
+-		Arguments: args,
+-	}, nil
+-}
+-
+-func NewStopProfileCommand(title string, a0 StopProfileArgs) (protocol.Command, error) {
+-	args, err := MarshalArgs(a0)
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.stop_profile",
+-		Arguments: args,
+-	}, nil
+-}
+-
 -func NewTestCommand(title string, a0 protocol.DocumentURI, a1 []string, a2 []string) (protocol.Command, error) {
 -	args, err := MarshalArgs(a0, a1, a2)
 -	if err != nil {
@@ -30436,9 +34681,21 @@
 -		Arguments: args,
 -	}, nil
 -}
+-
+-func NewWorkspaceStatsCommand(title string) (protocol.Command, error) {
+-	args, err := MarshalArgs()
+-	if err != nil {
+-		return protocol.Command{}, err
+-	}
+-	return protocol.Command{
+-		Title:     title,
+-		Command:   "gopls.workspace_stats",
+-		Arguments: args,
+-	}, nil
+-}
 diff -urN a/gopls/internal/lsp/command/commandmeta/meta.go b/gopls/internal/lsp/command/commandmeta/meta.go
 --- a/gopls/internal/lsp/command/commandmeta/meta.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/commandmeta/meta.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/command/commandmeta/meta.go	1970-01-01 08:00:00
 @@ -1,259 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -30701,7 +34958,7 @@
 -}
 diff -urN a/gopls/internal/lsp/command/gen/gen.go b/gopls/internal/lsp/command/gen/gen.go
 --- a/gopls/internal/lsp/command/gen/gen.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/gen/gen.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/command/gen/gen.go	1970-01-01 08:00:00
 @@ -1,155 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -30717,8 +34974,8 @@
 -	"go/types"
 -	"text/template"
 -
--	"golang.org/x/tools/internal/imports"
 -	"golang.org/x/tools/gopls/internal/lsp/command/commandmeta"
+-	"golang.org/x/tools/internal/imports"
 -)
 -
 -const src = `// Copyright 2021 The Go Authors. All rights reserved.
@@ -30730,10 +34987,10 @@
 -//go:build !generate
 -// +build !generate
 -
--package command
--
 -// Code generated by generate.go. DO NOT EDIT.
 -
+-package command
+-
 -import (
 -	{{range $k, $v := .Imports -}}
 -	"{{$k}}"
@@ -30860,7 +35117,7 @@
 -}
 diff -urN a/gopls/internal/lsp/command/generate.go b/gopls/internal/lsp/command/generate.go
 --- a/gopls/internal/lsp/command/generate.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/generate.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/command/generate.go	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -30889,8 +35146,8 @@
 -}
 diff -urN a/gopls/internal/lsp/command/interface.go b/gopls/internal/lsp/command/interface.go
 --- a/gopls/internal/lsp/command/interface.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/interface.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,410 +0,0 @@
++++ b/gopls/internal/lsp/command/interface.go	1970-01-01 08:00:00
+@@ -1,521 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -30910,8 +35167,8 @@
 -import (
 -	"context"
 -
--	"golang.org/x/tools/gopls/internal/govulncheck"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
 -)
 -
 -// Interface defines the interface gopls exposes for the
@@ -30930,6 +35187,7 @@
 -	//
 -	// Applies a fix to a region of source code.
 -	ApplyFix(context.Context, ApplyFixArgs) error
+-
 -	// Test: Run test(s) (legacy)
 -	//
 -	// Runs `go test` for a specific set of test or benchmark functions.
@@ -31038,7 +35296,22 @@
 -	// address.
 -	StartDebugging(context.Context, DebuggingArgs) (DebuggingResult, error)
 -
--	// RunGovulncheck: Run govulncheck.
+-	// StartProfile: start capturing a profile of gopls' execution.
+-	//
+-	// Start a new pprof profile. Before using the resulting file, profiling must
+-	// be stopped with a corresponding call to StopProfile.
+-	//
+-	// This command is intended for internal use only, by the gopls benchmark
+-	// runner.
+-	StartProfile(context.Context, StartProfileArgs) (StartProfileResult, error)
+-
+-	// StopProfile: stop an ongoing profile.
+-	//
+-	// This command is intended for internal use only, by the gopls benchmark
+-	// runner.
+-	StopProfile(context.Context, StopProfileArgs) (StopProfileResult, error)
+-
+-	// RunGovulncheck: Run vulncheck.
 -	//
 -	// Run vulnerability check (`govulncheck`).
 -	RunGovulncheck(context.Context, VulncheckArgs) (RunVulncheckResult, error)
@@ -31046,7 +35319,7 @@
 -	// FetchVulncheckResult: Get known vulncheck result
 -	//
 -	// Fetch the result of latest vulnerability check (`govulncheck`).
--	FetchVulncheckResult(context.Context, URIArg) (map[protocol.DocumentURI]*govulncheck.Result, error)
+-	FetchVulncheckResult(context.Context, URIArg) (map[protocol.DocumentURI]*vulncheck.Result, error)
 -
 -	// MemStats: fetch memory statistics
 -	//
@@ -31055,6 +35328,29 @@
 -	//
 -	// This command is used for benchmarking, and may change in the future.
 -	MemStats(context.Context) (MemStatsResult, error)
+-
+-	// WorkspaceStats: fetch workspace statistics
+-	//
+-	// Query statistics about workspace builds, modules, packages, and files.
+-	//
+-	// This command is intended for internal use only, by the gopls stats
+-	// command.
+-	WorkspaceStats(context.Context) (WorkspaceStatsResult, error)
+-
+-	// RunGoWorkCommand: run `go work [args...]`, and apply the resulting go.work
+-	// edits to the current go.work file.
+-	RunGoWorkCommand(context.Context, RunGoWorkArgs) error
+-
+-	// AddTelemetryCounters: update the given telemetry counters.
+-	//
+-	// Gopls will prepend "fwd/" to all the counters updated using this command
+-	// to avoid conflicts with other counters gopls collects.
+-	AddTelemetryCounters(context.Context, AddTelemetryCountersArgs) error
+-
+-	// MaybePromptForTelemetry: checks for the right conditions, and then prompts
+-	// the user to ask if they want to enable Go telemetry uploading. If the user
+-	// responds 'Yes', the telemetry mode is set to "on".
+-	MaybePromptForTelemetry(context.Context) error
 -}
 -
 -type RunTestsArgs struct {
@@ -31117,7 +35413,10 @@
 -	// The go.mod file URI.
 -	URI protocol.DocumentURI
 -	// The module path to remove.
--	ModulePath     string
+-	ModulePath string
+-	// If the module is tidied apart from the one unused diagnostic, we can
+-	// run `go get module@none`, and then run `go mod tidy`. Otherwise, we
+-	// must make textual edits.
 -	OnlyDiagnostic bool
 -}
 -
@@ -31205,6 +35504,30 @@
 -	URLs []string
 -}
 -
+-// StartProfileArgs holds the arguments to the StartProfile command.
+-//
+-// It is a placeholder for future compatibility.
+-type StartProfileArgs struct {
+-}
+-
+-// StartProfileResult holds the result of the StartProfile command.
+-//
+-// It is a placeholder for future compatibility.
+-type StartProfileResult struct {
+-}
+-
+-// StopProfileArgs holds the arguments to the StopProfile command.
+-//
+-// It is a placeholder for future compatibility.
+-type StopProfileArgs struct {
+-}
+-
+-// StopProfileResult holds the result to the StopProfile command.
+-type StopProfileResult struct {
+-	// File is the profile file name.
+-	File string
+-}
+-
 -type ResetGoModDiagnosticsArgs struct {
 -	URIArg
 -
@@ -31298,13 +35621,58 @@
 -
 -// MemStatsResult holds selected fields from runtime.MemStats.
 -type MemStatsResult struct {
--	HeapAlloc uint64
--	HeapInUse uint64
+-	HeapAlloc  uint64
+-	HeapInUse  uint64
+-	TotalAlloc uint64
+-}
+-
+-// WorkspaceStatsResult returns information about the size and shape of the
+-// workspace.
+-type WorkspaceStatsResult struct {
+-	Files FileStats   // file stats for the cache
+-	Views []ViewStats // stats for each view in the session
+-}
+-
+-// FileStats holds information about a set of files.
+-type FileStats struct {
+-	Total   int // total number of files
+-	Largest int // number of bytes in the largest file
+-	Errs    int // number of files that could not be read
+-}
+-
+-// ViewStats holds information about a single View in the session.
+-type ViewStats struct {
+-	GoCommandVersion  string       // version of the Go command resolved for this view
+-	AllPackages       PackageStats // package info for all packages (incl. dependencies)
+-	WorkspacePackages PackageStats // package info for workspace packages
+-	Diagnostics       int          // total number of diagnostics in the workspace
+-}
+-
+-// PackageStats holds information about a collection of packages.
+-type PackageStats struct {
+-	Packages        int // total number of packages
+-	LargestPackage  int // number of files in the largest package
+-	CompiledGoFiles int // total number of compiled Go files across all packages
+-	Modules         int // total number of unique modules
+-}
+-
+-type RunGoWorkArgs struct {
+-	ViewID    string   // ID of the view to run the command from
+-	InitFirst bool     // Whether to run `go work init` first
+-	Args      []string // Args to pass to `go work`
+-}
+-
+-// AddTelemetryCountersArgs holds the arguments to the AddCounters command
+-// that updates the telemetry counters.
+-type AddTelemetryCountersArgs struct {
+-	// Names and Values must have the same length.
+-	Names  []string // Name of counters.
+-	Values []int64  // Values added to the corresponding counters. Must be non-negative.
 -}
 diff -urN a/gopls/internal/lsp/command/interface_test.go b/gopls/internal/lsp/command/interface_test.go
 --- a/gopls/internal/lsp/command/interface_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/interface_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
++++ b/gopls/internal/lsp/command/interface_test.go	1970-01-01 08:00:00
+@@ -1,32 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -31312,7 +35680,7 @@
 -package command_test
 -
 -import (
--	"io/ioutil"
+-	"os"
 -	"testing"
 -
 -	"github.com/google/go-cmp/cmp"
@@ -31321,9 +35689,10 @@
 -)
 -
 -func TestGenerated(t *testing.T) {
--	testenv.NeedsGoBuild(t) // This is a lie. We actually need the source code.
+-	testenv.NeedsGoPackages(t)
+-	testenv.NeedsLocalXTools(t)
 -
--	onDisk, err := ioutil.ReadFile("command_gen.go")
+-	onDisk, err := os.ReadFile("command_gen.go")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -31338,8 +35707,8 @@
 -}
 diff -urN a/gopls/internal/lsp/command/util.go b/gopls/internal/lsp/command/util.go
 --- a/gopls/internal/lsp/command/util.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command/util.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,63 +0,0 @@
++++ b/gopls/internal/lsp/command/util.go	1970-01-01 08:00:00
+@@ -1,64 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -31358,6 +35727,7 @@
 -
 -type Command string
 -
+-// ID returns the command identifier to use in the executeCommand request.
 -func (c Command) ID() string {
 -	return ID(string(c))
 -}
@@ -31405,8 +35775,8 @@
 -}
 diff -urN a/gopls/internal/lsp/command.go b/gopls/internal/lsp/command.go
 --- a/gopls/internal/lsp/command.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/command.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,964 +0,0 @@
++++ b/gopls/internal/lsp/command.go	1970-01-01 08:00:00
+@@ -1,1212 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -31420,33 +35790,38 @@
 -	"errors"
 -	"fmt"
 -	"io"
--	"io/ioutil"
 -	"os"
--	"os/exec"
 -	"path/filepath"
 -	"runtime"
+-	"runtime/pprof"
 -	"sort"
 -	"strings"
--	"time"
 -
 -	"golang.org/x/mod/modfile"
 -	"golang.org/x/tools/go/ast/astutil"
--	"golang.org/x/tools/gopls/internal/govulncheck"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
 -	"golang.org/x/tools/gopls/internal/lsp/progress"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/telemetry"
 -	"golang.org/x/tools/gopls/internal/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/scan"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/gocommand"
+-	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/xcontext"
 -)
 -
 -func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCommandParams) (interface{}, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.executeCommand")
+-	defer done()
+-
 -	var found bool
--	for _, name := range s.session.Options().SupportedCommands {
+-	for _, name := range s.Options().SupportedCommands {
 -		if name == params.Command {
 -			found = true
 -			break
@@ -31468,11 +35843,26 @@
 -	params *protocol.ExecuteCommandParams
 -}
 -
+-func (h *commandHandler) MaybePromptForTelemetry(ctx context.Context) error {
+-	go h.s.maybePromptForTelemetry(ctx, true)
+-	return nil
+-}
+-
+-func (*commandHandler) AddTelemetryCounters(_ context.Context, args command.AddTelemetryCountersArgs) error {
+-	if len(args.Names) != len(args.Values) {
+-		return fmt.Errorf("Names and Values must have the same length")
+-	}
+-	// invalid counter update requests will be silently dropped. (no audience)
+-	telemetry.AddForwardedCounters(args.Names, args.Values)
+-	return nil
+-}
+-
 -// commandConfig configures common command set-up and execution.
 -type commandConfig struct {
 -	async       bool                 // whether to run the command asynchronously. Async commands can only return errors.
 -	requireSave bool                 // whether all files must be saved for the command to work
 -	progress    string               // title to use for progress reporting. If empty, no progress will be reported.
+-	forView     string               // view to resolve to a snapshot; incompatible with forURI
 -	forURI      protocol.DocumentURI // URI to resolve to a snapshot. If unset, snapshot will be nil.
 -}
 -
@@ -31498,7 +35888,7 @@
 -	if cfg.requireSave {
 -		var unsaved []string
 -		for _, overlay := range c.s.session.Overlays() {
--			if !overlay.Saved() {
+-			if !overlay.SameContentsOnDisk() {
 -				unsaved = append(unsaved, overlay.URI().Filename())
 -			}
 -		}
@@ -31507,6 +35897,9 @@
 -		}
 -	}
 -	var deps commandDeps
+-	if cfg.forURI != "" && cfg.forView != "" {
+-		return bug.Errorf("internal error: forURI=%q, forView=%q", cfg.forURI, cfg.forView)
+-	}
 -	if cfg.forURI != "" {
 -		var ok bool
 -		var release func()
@@ -31518,6 +35911,17 @@
 -			}
 -			return fmt.Errorf("invalid file URL: %v", cfg.forURI)
 -		}
+-	} else if cfg.forView != "" {
+-		view, err := c.s.session.View(cfg.forView)
+-		if err != nil {
+-			return err
+-		}
+-		var release func()
+-		deps.snapshot, release, err = view.Snapshot()
+-		if err != nil {
+-			return err
+-		}
+-		defer release()
 -	}
 -	ctx, cancel := context.WithCancel(xcontext.Detach(ctx))
 -	if cfg.progress != "" {
@@ -31564,7 +35968,7 @@
 -		if err != nil {
 -			return err
 -		}
--		var changes []protocol.DocumentChanges
+-		changes := []protocol.DocumentChanges{} // must be a slice
 -		for _, edit := range edits {
 -			edit := edit
 -			changes = append(changes, protocol.DocumentChanges{
@@ -31609,7 +36013,7 @@
 -		}
 -		deps.snapshot.View().RegisterModuleUpgrades(args.URI.SpanURI(), upgrades)
 -		// Re-diagnose the snapshot to publish the new module diagnostics.
--		c.s.diagnoseSnapshot(deps.snapshot, nil, false)
+-		c.s.diagnoseSnapshot(deps.snapshot, nil, false, 0)
 -		return nil
 -	})
 -}
@@ -31640,7 +36044,7 @@
 -		}
 -
 -		// Re-diagnose the snapshot to remove the diagnostics.
--		c.s.diagnoseSnapshot(deps.snapshot, nil, false)
+-		c.s.diagnoseSnapshot(deps.snapshot, nil, false, 0)
 -		return nil
 -	})
 -}
@@ -31748,10 +36152,9 @@
 -		progress: "Removing dependency",
 -		forURI:   args.URI,
 -	}, func(ctx context.Context, deps commandDeps) error {
--		// If the module is tidied apart from the one unused diagnostic, we can
--		// run `go get module@none`, and then run `go mod tidy`. Otherwise, we
--		// must make textual edits.
--		// TODO(rstambler): In Go 1.17+, we will be able to use the go command
+-		// See the documentation for OnlyDiagnostic.
+-		//
+-		// TODO(rfindley): In Go 1.17+, we will be able to use the go command
 -		// without checking if the module is tidy.
 -		if args.OnlyDiagnostic {
 -			return c.s.runGoModUpdateCommands(ctx, deps.snapshot, args.URI.SpanURI(), func(invoke func(...string) (*bytes.Buffer, error)) error {
@@ -31781,7 +36184,7 @@
 -									URI: protocol.URIFromSpanURI(deps.fh.URI()),
 -								},
 -							},
--							Edits: edits,
+-							Edits: nonNilSliceTextEdit(edits),
 -						},
 -					},
 -				},
@@ -31815,7 +36218,7 @@
 -		return nil, err
 -	}
 -	// Calculate the edits to be made due to the change.
--	diff := snapshot.View().Options().ComputeEdits(string(pm.Mapper.Content), string(newContent))
+-	diff := snapshot.Options().ComputeEdits(string(pm.Mapper.Content), string(newContent))
 -	return source.ToProtocolEdits(pm.Mapper, diff)
 -}
 -
@@ -31843,15 +36246,11 @@
 -
 -func (c *commandHandler) runTests(ctx context.Context, snapshot source.Snapshot, work *progress.WorkDone, uri protocol.DocumentURI, tests, benchmarks []string) error {
 -	// TODO: fix the error reporting when this runs async.
--	metas, err := snapshot.MetadataForFile(ctx, uri.SpanURI())
+-	meta, err := source.NarrowestMetadataForFile(ctx, snapshot, uri.SpanURI())
 -	if err != nil {
 -		return err
 -	}
--	metas = source.RemoveIntermediateTestVariants(metas)
--	if len(metas) == 0 {
--		return fmt.Errorf("package could not be found for file: %s", uri.SpanURI().Filename())
--	}
--	pkgPath := string(metas[0].ForTest)
+-	pkgPath := string(meta.ForTest)
 -
 -	// create output
 -	buf := &bytes.Buffer{}
@@ -31984,48 +36383,35 @@
 -	}
 -	modURI := snapshot.GoModForFile(uri)
 -	sumURI := span.URIFromPath(strings.TrimSuffix(modURI.Filename(), ".mod") + ".sum")
--	modEdits, err := applyFileEdits(ctx, snapshot, modURI, newModBytes)
+-	modEdits, err := collectFileEdits(ctx, snapshot, modURI, newModBytes)
 -	if err != nil {
 -		return err
 -	}
--	sumEdits, err := applyFileEdits(ctx, snapshot, sumURI, newSumBytes)
+-	sumEdits, err := collectFileEdits(ctx, snapshot, sumURI, newSumBytes)
 -	if err != nil {
 -		return err
 -	}
--	changes := append(sumEdits, modEdits...)
--	if len(changes) == 0 {
--		return nil
--	}
--	var documentChanges []protocol.DocumentChanges
--	for _, change := range changes {
--		change := change
--		documentChanges = append(documentChanges, protocol.DocumentChanges{
--			TextDocumentEdit: &change,
--		})
--	}
--	response, err := s.client.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
--		Edit: protocol.WorkspaceEdit{
--			DocumentChanges: documentChanges,
--		},
--	})
--	if err != nil {
--		return err
--	}
--	if !response.Applied {
--		return fmt.Errorf("edits not applied because of %s", response.FailureReason)
--	}
--	return nil
+-	return applyFileEdits(ctx, s.client, append(sumEdits, modEdits...))
 -}
 -
--func applyFileEdits(ctx context.Context, snapshot source.Snapshot, uri span.URI, newContent []byte) ([]protocol.TextDocumentEdit, error) {
--	fh, err := snapshot.GetFile(ctx, uri)
+-// collectFileEdits collects any file edits required to transform the snapshot
+-// file specified by uri to the provided new content.
+-//
+-// If the file is not open, collectFileEdits simply writes the new content to
+-// disk.
+-//
+-// TODO(rfindley): fix this API asymmetry. It should be up to the caller to
+-// write the file or apply the edits.
+-func collectFileEdits(ctx context.Context, snapshot source.Snapshot, uri span.URI, newContent []byte) ([]protocol.TextDocumentEdit, error) {
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
--	oldContent, err := fh.Read()
+-	oldContent, err := fh.Content()
 -	if err != nil && !os.IsNotExist(err) {
 -		return nil, err
 -	}
+-
 -	if bytes.Equal(oldContent, newContent) {
 -		return nil, nil
 -	}
@@ -32034,12 +36420,12 @@
 -	// file and leave it unsaved. We would rather apply the changes directly,
 -	// especially to go.sum, which should be mostly invisible to the user.
 -	if !snapshot.IsOpen(uri) {
--		err := ioutil.WriteFile(uri.Filename(), newContent, 0666)
+-		err := os.WriteFile(uri.Filename(), newContent, 0666)
 -		return nil, err
 -	}
 -
 -	m := protocol.NewMapper(fh.URI(), oldContent)
--	diff := snapshot.View().Options().ComputeEdits(string(oldContent), string(newContent))
+-	diff := snapshot.Options().ComputeEdits(string(oldContent), string(newContent))
 -	edits, err := source.ToProtocolEdits(m, diff)
 -	if err != nil {
 -		return nil, err
@@ -32055,6 +36441,31 @@
 -	}}, nil
 -}
 -
+-func applyFileEdits(ctx context.Context, cli protocol.Client, edits []protocol.TextDocumentEdit) error {
+-	if len(edits) == 0 {
+-		return nil
+-	}
+-	documentChanges := []protocol.DocumentChanges{} // must be a slice
+-	for _, change := range edits {
+-		change := change
+-		documentChanges = append(documentChanges, protocol.DocumentChanges{
+-			TextDocumentEdit: &change,
+-		})
+-	}
+-	response, err := cli.ApplyEdit(ctx, &protocol.ApplyWorkspaceEditParams{
+-		Edit: protocol.WorkspaceEdit{
+-			DocumentChanges: documentChanges,
+-		},
+-	})
+-	if err != nil {
+-		return err
+-	}
+-	if !response.Applied {
+-		return fmt.Errorf("edits not applied because of %s", response.FailureReason)
+-	}
+-	return nil
+-}
+-
 -func runGoGetModule(invoke func(...string) (*bytes.Buffer, error), addRequire bool, args []string) error {
 -	if addRequire {
 -		if err := addModuleRequire(invoke, args); err != nil {
@@ -32109,20 +36520,19 @@
 -		progress:    "Toggling GC Details",
 -		forURI:      args.URI,
 -	}, func(ctx context.Context, deps commandDeps) error {
--		metas, err := deps.snapshot.MetadataForFile(ctx, deps.fh.URI())
+-		meta, err := source.NarrowestMetadataForFile(ctx, deps.snapshot, deps.fh.URI())
 -		if err != nil {
 -			return err
 -		}
--		id := metas[0].ID // 0 => narrowest package
 -		c.s.gcOptimizationDetailsMu.Lock()
--		if _, ok := c.s.gcOptimizationDetails[id]; ok {
--			delete(c.s.gcOptimizationDetails, id)
+-		if _, ok := c.s.gcOptimizationDetails[meta.ID]; ok {
+-			delete(c.s.gcOptimizationDetails, meta.ID)
 -			c.s.clearDiagnosticSource(gcDetailsSource)
 -		} else {
--			c.s.gcOptimizationDetails[id] = struct{}{}
+-			c.s.gcOptimizationDetails[meta.ID] = struct{}{}
 -		}
 -		c.s.gcOptimizationDetailsMu.Unlock()
--		c.s.diagnoseSnapshot(deps.snapshot, nil, false)
+-		c.s.diagnoseSnapshot(deps.snapshot, nil, false, 0)
 -		return nil
 -	})
 -}
@@ -32147,7 +36557,7 @@
 -	err := c.run(ctx, commandConfig{
 -		forURI: args.URI,
 -	}, func(ctx context.Context, deps commandDeps) error {
--		fh, err := deps.snapshot.GetFile(ctx, args.URI.SpanURI())
+-		fh, err := deps.snapshot.ReadFile(ctx, args.URI.SpanURI())
 -		if err != nil {
 -			return err
 -		}
@@ -32155,7 +36565,7 @@
 -		if err != nil {
 -			return err
 -		}
--		fset := source.FileSetFor(pgf.Tok)
+-		fset := tokeninternal.FileSetFor(pgf.Tok)
 -		for _, group := range astutil.Imports(fset, pgf.File) {
 -			for _, imp := range group {
 -				if imp.Path == nil {
@@ -32171,14 +36581,11 @@
 -				})
 -			}
 -		}
--		metas, err := deps.snapshot.MetadataForFile(ctx, args.URI.SpanURI())
+-		meta, err := source.NarrowestMetadataForFile(ctx, deps.snapshot, args.URI.SpanURI())
 -		if err != nil {
 -			return err // e.g. cancelled
 -		}
--		if len(metas) == 0 {
--			return fmt.Errorf("no package containing %v", args.URI.SpanURI())
--		}
--		for pkgPath := range metas[0].DepsByPkgPath { // 0 => narrowest package
+-		for pkgPath := range meta.DepsByPkgPath {
 -			result.PackageImports = append(result.PackageImports,
 -				command.PackageImport{Path: string(pkgPath)})
 -		}
@@ -32224,6 +36631,49 @@
 -		return result, fmt.Errorf("starting debug server: %w", err)
 -	}
 -	result.URLs = []string{"http://" + listenedAddr}
+-	openClientBrowser(ctx, c.s.client, result.URLs[0])
+-	return result, nil
+-}
+-
+-func (c *commandHandler) StartProfile(ctx context.Context, args command.StartProfileArgs) (result command.StartProfileResult, _ error) {
+-	file, err := os.CreateTemp("", "gopls-profile-*")
+-	if err != nil {
+-		return result, fmt.Errorf("creating temp profile file: %v", err)
+-	}
+-
+-	c.s.ongoingProfileMu.Lock()
+-	defer c.s.ongoingProfileMu.Unlock()
+-
+-	if c.s.ongoingProfile != nil {
+-		file.Close() // ignore error
+-		return result, fmt.Errorf("profile already started (for %q)", c.s.ongoingProfile.Name())
+-	}
+-
+-	if err := pprof.StartCPUProfile(file); err != nil {
+-		file.Close() // ignore error
+-		return result, fmt.Errorf("starting profile: %v", err)
+-	}
+-
+-	c.s.ongoingProfile = file
+-	return result, nil
+-}
+-
+-func (c *commandHandler) StopProfile(ctx context.Context, args command.StopProfileArgs) (result command.StopProfileResult, _ error) {
+-	c.s.ongoingProfileMu.Lock()
+-	defer c.s.ongoingProfileMu.Unlock()
+-
+-	prof := c.s.ongoingProfile
+-	c.s.ongoingProfile = nil
+-
+-	if prof == nil {
+-		return result, fmt.Errorf("no ongoing profile")
+-	}
+-
+-	pprof.StopCPUProfile()
+-	if err := prof.Close(); err != nil {
+-		return result, fmt.Errorf("closing profile file: %v", err)
+-	}
+-	result.File = prof.Name()
 -	return result, nil
 -}
 -
@@ -32238,10 +36688,10 @@
 -	Tests bool
 -}
 -
--func (c *commandHandler) FetchVulncheckResult(ctx context.Context, arg command.URIArg) (map[protocol.DocumentURI]*govulncheck.Result, error) {
--	ret := map[protocol.DocumentURI]*govulncheck.Result{}
+-func (c *commandHandler) FetchVulncheckResult(ctx context.Context, arg command.URIArg) (map[protocol.DocumentURI]*vulncheck.Result, error) {
+-	ret := map[protocol.DocumentURI]*vulncheck.Result{}
 -	err := c.run(ctx, commandConfig{forURI: arg.URI}, func(ctx context.Context, deps commandDeps) error {
--		if deps.snapshot.View().Options().Vulncheck == source.ModeVulncheckImports {
+-		if deps.snapshot.Options().Vulncheck == source.ModeVulncheckImports {
 -			for _, modfile := range deps.snapshot.ModFiles() {
 -				res, err := deps.snapshot.ModVuln(ctx, modfile)
 -				if err != nil {
@@ -32278,60 +36728,22 @@
 -	}, func(ctx context.Context, deps commandDeps) error {
 -		tokenChan <- deps.work.Token()
 -
--		view := deps.snapshot.View()
--		opts := view.Options()
--		// quickly test if gopls is compiled to support govulncheck
--		// by checking vulncheck.Main. Alternatively, we can continue and
--		// let the `gopls vulncheck` command fail. This is lighter-weight.
--		if vulncheck.Main == nil {
--			return errors.New("vulncheck feature is not available")
--		}
+-		workDoneWriter := progress.NewWorkDoneWriter(ctx, deps.work)
+-		dir := filepath.Dir(args.URI.SpanURI().Filename())
+-		pattern := args.Pattern
 -
--		cmd := exec.CommandContext(ctx, os.Args[0], "vulncheck", "-config", args.Pattern)
--		cmd.Dir = filepath.Dir(args.URI.SpanURI().Filename())
--
--		var viewEnv []string
--		if e := opts.EnvSlice(); e != nil {
--			viewEnv = append(os.Environ(), e...)
--		}
--		cmd.Env = viewEnv
--
--		// stdin: gopls vulncheck expects JSON-encoded configuration from STDIN when -config flag is set.
--		var stdin bytes.Buffer
--		cmd.Stdin = &stdin
--
--		if err := json.NewEncoder(&stdin).Encode(pkgLoadConfig{
--			BuildFlags: opts.BuildFlags,
--			// TODO(hyangah): add `tests` flag in command.VulncheckArgs
--		}); err != nil {
--			return fmt.Errorf("failed to pass package load config: %v", err)
--		}
--
--		// stderr: stream gopls vulncheck's STDERR as progress reports
--		er := progress.NewEventWriter(ctx, "vulncheck")
--		stderr := io.MultiWriter(er, progress.NewWorkDoneWriter(ctx, deps.work))
--		cmd.Stderr = stderr
--		// TODO: can we stream stdout?
--		stdout, err := cmd.Output()
+-		result, err := scan.RunGovulncheck(ctx, pattern, deps.snapshot, dir, workDoneWriter)
 -		if err != nil {
--			return fmt.Errorf("failed to run govulncheck: %v", err)
+-			return err
 -		}
 -
--		var result govulncheck.Result
--		if err := json.Unmarshal(stdout, &result); err != nil {
--			// TODO: for easy debugging, log the failed stdout somewhere?
--			return fmt.Errorf("failed to parse govulncheck output: %v", err)
--		}
--		result.Mode = govulncheck.ModeGovulncheck
--		result.AsOf = time.Now()
--		deps.snapshot.View().SetVulnerabilities(args.URI.SpanURI(), &result)
+-		deps.snapshot.View().SetVulnerabilities(args.URI.SpanURI(), result)
+-		c.s.diagnoseSnapshot(deps.snapshot, nil, false, 0)
 -
--		c.s.diagnoseSnapshot(deps.snapshot, nil, false)
--		vulns := result.Vulns
--		affecting := make([]string, 0, len(vulns))
--		for _, v := range vulns {
--			if v.IsCalled() {
--				affecting = append(affecting, v.OSV.ID)
+-		affecting := make(map[string]bool, len(result.Entries))
+-		for _, finding := range result.Findings {
+-			if len(finding.Trace) > 1 { // at least 2 frames if callstack exists (vulnerability, entry)
+-				affecting[finding.OSV] = true
 -			}
 -		}
 -		if len(affecting) == 0 {
@@ -32340,10 +36752,14 @@
 -				Message: "No vulnerabilities found",
 -			})
 -		}
--		sort.Strings(affecting)
+-		affectingOSVs := make([]string, 0, len(affecting))
+-		for id := range affecting {
+-			affectingOSVs = append(affectingOSVs, id)
+-		}
+-		sort.Strings(affectingOSVs)
 -		return c.s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
 -			Type:    protocol.Warning,
--			Message: fmt.Sprintf("Found %v", strings.Join(affecting, ", ")),
+-			Message: fmt.Sprintf("Found %v", strings.Join(affectingOSVs, ", ")),
 -		})
 -	})
 -	if err != nil {
@@ -32367,14 +36783,216 @@
 -	var m runtime.MemStats
 -	runtime.ReadMemStats(&m)
 -	return command.MemStatsResult{
--		HeapAlloc: m.HeapAlloc,
--		HeapInUse: m.HeapInuse,
+-		HeapAlloc:  m.HeapAlloc,
+-		HeapInUse:  m.HeapInuse,
+-		TotalAlloc: m.TotalAlloc,
 -	}, nil
 -}
+-
+-// WorkspaceStats implements the WorkspaceStats command, reporting information
+-// about the current state of the loaded workspace for the current session.
+-func (c *commandHandler) WorkspaceStats(ctx context.Context) (command.WorkspaceStatsResult, error) {
+-	var res command.WorkspaceStatsResult
+-	res.Files.Total, res.Files.Largest, res.Files.Errs = c.s.session.Cache().FileStats()
+-
+-	for _, view := range c.s.session.Views() {
+-		vs, err := collectViewStats(ctx, view)
+-		if err != nil {
+-			return res, err
+-		}
+-		res.Views = append(res.Views, vs)
+-	}
+-	return res, nil
+-}
+-
+-func collectViewStats(ctx context.Context, view *cache.View) (command.ViewStats, error) {
+-	s, release, err := view.Snapshot()
+-	if err != nil {
+-		return command.ViewStats{}, err
+-	}
+-	defer release()
+-
+-	allMD, err := s.AllMetadata(ctx)
+-	if err != nil {
+-		return command.ViewStats{}, err
+-	}
+-	allPackages := collectPackageStats(allMD)
+-
+-	wsMD, err := s.WorkspaceMetadata(ctx)
+-	if err != nil {
+-		return command.ViewStats{}, err
+-	}
+-	workspacePackages := collectPackageStats(wsMD)
+-
+-	var ids []source.PackageID
+-	for _, m := range wsMD {
+-		ids = append(ids, m.ID)
+-	}
+-
+-	diags, err := s.PackageDiagnostics(ctx, ids...)
+-	if err != nil {
+-		return command.ViewStats{}, err
+-	}
+-
+-	ndiags := 0
+-	for _, d := range diags {
+-		ndiags += len(d)
+-	}
+-
+-	return command.ViewStats{
+-		GoCommandVersion:  view.GoVersionString(),
+-		AllPackages:       allPackages,
+-		WorkspacePackages: workspacePackages,
+-		Diagnostics:       ndiags,
+-	}, nil
+-}
+-
+-func collectPackageStats(md []*source.Metadata) command.PackageStats {
+-	var stats command.PackageStats
+-	stats.Packages = len(md)
+-	modules := make(map[string]bool)
+-
+-	for _, m := range md {
+-		n := len(m.CompiledGoFiles)
+-		stats.CompiledGoFiles += n
+-		if n > stats.LargestPackage {
+-			stats.LargestPackage = n
+-		}
+-		if m.Module != nil {
+-			modules[m.Module.Path] = true
+-		}
+-	}
+-	stats.Modules = len(modules)
+-
+-	return stats
+-}
+-
+-// RunGoWorkCommand invokes `go work <args>` with the provided arguments.
+-//
+-// args.InitFirst controls whether to first run `go work init`. This allows a
+-// single command to both create and recursively populate a go.work file -- as
+-// of writing there is no `go work init -r`.
+-//
+-// Some thought went into implementing this command. Unlike the go.mod commands
+-// above, this command simply invokes the go command and relies on the client
+-// to notify gopls of file changes via didChangeWatchedFile notifications.
+-// We could instead run these commands with GOWORK set to a temp file, but that
+-// poses the following problems:
+-//   - directory locations in the resulting temp go.work file will be computed
+-//     relative to the directory containing that go.work. If the go.work is in a
+-//     tempdir, the directories will need to be translated to/from that dir.
+-//   - it would be simpler to use a temp go.work file in the workspace
+-//     directory, or whichever directory contains the real go.work file, but
+-//     that sets a bad precedent of writing to a user-owned directory. We
+-//     shouldn't start doing that.
+-//   - Sending workspace edits to create a go.work file would require using
+-//     the CreateFile resource operation, which would need to be tested in every
+-//     client as we haven't used it before. We don't have time for that right
+-//     now.
+-//
+-// Therefore, we simply require that the current go.work file is saved (if it
+-// exists), and delegate to the go command.
+-func (c *commandHandler) RunGoWorkCommand(ctx context.Context, args command.RunGoWorkArgs) error {
+-	return c.run(ctx, commandConfig{
+-		progress: "Running go work command",
+-		forView:  args.ViewID,
+-	}, func(ctx context.Context, deps commandDeps) (runErr error) {
+-		snapshot := deps.snapshot
+-		view := snapshot.View().(*cache.View)
+-		viewDir := view.Folder().Filename()
+-
+-		// If the user has explicitly set GOWORK=off, we should warn them
+-		// explicitly and avoid potentially misleading errors below.
+-		goworkURI, off := view.GOWORK()
+-		if off {
+-			return fmt.Errorf("cannot modify go.work files when GOWORK=off")
+-		}
+-		gowork := goworkURI.Filename()
+-
+-		if goworkURI != "" {
+-			fh, err := snapshot.ReadFile(ctx, goworkURI)
+-			if err != nil {
+-				return fmt.Errorf("reading current go.work file: %v", err)
+-			}
+-			if !fh.SameContentsOnDisk() {
+-				return fmt.Errorf("must save workspace file %s before running go work commands", goworkURI)
+-			}
+-		} else {
+-			if !args.InitFirst {
+-				// If go.work does not exist, we should have detected that and asked
+-				// for InitFirst.
+-				return bug.Errorf("internal error: cannot run go work command: required go.work file not found")
+-			}
+-			gowork = filepath.Join(viewDir, "go.work")
+-			if err := c.invokeGoWork(ctx, viewDir, gowork, []string{"init"}); err != nil {
+-				return fmt.Errorf("running `go work init`: %v", err)
+-			}
+-		}
+-
+-		return c.invokeGoWork(ctx, viewDir, gowork, args.Args)
+-	})
+-}
+-
+-func (c *commandHandler) invokeGoWork(ctx context.Context, viewDir, gowork string, args []string) error {
+-	inv := gocommand.Invocation{
+-		Verb:       "work",
+-		Args:       args,
+-		WorkingDir: viewDir,
+-		Env:        append(os.Environ(), fmt.Sprintf("GOWORK=%s", gowork)),
+-	}
+-	if _, err := c.s.session.GoCommandRunner().Run(ctx, inv); err != nil {
+-		return fmt.Errorf("running go work command: %v", err)
+-	}
+-	return nil
+-}
+-
+-// openClientBrowser causes the LSP client to open the specified URL
+-// in an external browser.
+-func openClientBrowser(ctx context.Context, cli protocol.Client, url protocol.URI) {
+-	showDocumentImpl(ctx, cli, url, nil)
+-}
+-
+-// openClientEditor causes the LSP client to open the specified document
+-// and select the indicated range.
+-func openClientEditor(ctx context.Context, cli protocol.Client, loc protocol.Location) {
+-	showDocumentImpl(ctx, cli, protocol.URI(loc.URI), &loc.Range)
+-}
+-
+-func showDocumentImpl(ctx context.Context, cli protocol.Client, url protocol.URI, rangeOpt *protocol.Range) {
+-	// In principle we shouldn't send a showDocument request to a
+-	// client that doesn't support it, as reported by
+-	// ShowDocumentClientCapabilities. But even clients that do
+-	// support it may defer the real work of opening the document
+-	// asynchronously, to avoid deadlocks due to rentrancy.
+-	//
+-	// For example: client sends request to server; server sends
+-	// showDocument to client; client opens editor; editor causes
+-	// new RPC to be sent to server, which is still busy with
+-	// previous request. (This happens in eglot.)
+-	//
+-	// So we can't rely on the success/failure information.
+-	// That's the reason this function doesn't return an error.
+-
+-	// "External" means run the system-wide handler (e.g. open(1)
+-	// on macOS or xdg-open(1) on Linux) for this URL, ignoring
+-	// TakeFocus and Selection. Note that this may still end up
+-	// opening the same editor (e.g. VSCode) for a file: URL.
+-	res, err := cli.ShowDocument(ctx, &protocol.ShowDocumentParams{
+-		URI:       url,
+-		External:  rangeOpt == nil,
+-		TakeFocus: true,
+-		Selection: rangeOpt, // optional
+-	})
+-	if err != nil {
+-		event.Error(ctx, "client.showDocument: %v", err)
+-	} else if res != nil && !res.Success {
+-		event.Log(ctx, fmt.Sprintf("client declined to open document %v", url))
+-	}
+-}
 diff -urN a/gopls/internal/lsp/completion.go b/gopls/internal/lsp/completion.go
 --- a/gopls/internal/lsp/completion.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/completion.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,140 +0,0 @@
++++ b/gopls/internal/lsp/completion.go	1970-01-01 08:00:00
+@@ -1,149 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -32391,11 +37009,20 @@
 -	"golang.org/x/tools/gopls/internal/lsp/source/completion"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
 -	"golang.org/x/tools/gopls/internal/lsp/work"
+-	"golang.org/x/tools/gopls/internal/telemetry"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
 -)
 -
--func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
+-func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (_ *protocol.CompletionList, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("completion")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
+-	ctx, done := event.Start(ctx, "lsp.Server.completion", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
@@ -32403,7 +37030,7 @@
 -	}
 -	var candidates []completion.CompletionItem
 -	var surrounding *completion.Selection
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Go:
 -		candidates, surrounding, err = completion.Completion(ctx, snapshot, fh, params.Position, params.Context)
 -	case source.Mod:
@@ -32439,7 +37066,7 @@
 -
 -	// When using deep completions/fuzzy matching, report results as incomplete so
 -	// client fetches updated completions after every key stroke.
--	options := snapshot.View().Options()
+-	options := snapshot.Options()
 -	incompleteResults := options.DeepCompletion || options.Matcher == source.Fuzzy
 -
 -	items := toProtocolCompletionItems(candidates, rng, options)
@@ -32508,7 +37135,7 @@
 -
 -			Preselect:     i == 0,
 -			Documentation: doc,
--			Tags:          candidate.Tags,
+-			Tags:          nonNilSliceCompletionItemTag(candidate.Tags),
 -			Deprecated:    candidate.Deprecated,
 -		}
 -		items = append(items, item)
@@ -32517,8 +37144,8 @@
 -}
 diff -urN a/gopls/internal/lsp/completion_test.go b/gopls/internal/lsp/completion_test.go
 --- a/gopls/internal/lsp/completion_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/completion_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,176 +0,0 @@
++++ b/gopls/internal/lsp/completion_test.go	1970-01-01 08:00:00
+@@ -1,173 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -32570,15 +37197,6 @@
 -	}
 -}
 -
--func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
--	got := r.callCompletion(t, src, func(opts *source.Options) {})
--	got = tests.FilterBuiltins(src, got)
--	want := expected(t, test, items)
--	if diff := tests.CheckCompletionOrder(want, got, false); diff != "" {
--		t.Errorf("%s", diff)
--	}
--}
--
 -func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
 -	got := r.callCompletion(t, src, func(opts *source.Options) {
 -		opts.DeepCompletion = true
@@ -32639,6 +37257,7 @@
 -			Label:  item.Label,
 -			Kind:   item.Kind,
 -			Detail: item.Detail,
+-			Tags:   []protocol.CompletionItemTag{}, // must be a slice
 -			Documentation: &protocol.Or_CompletionItem_documentation{
 -				Value: item.Documentation,
 -			},
@@ -32664,20 +37283,8 @@
 -
 -func (r *runner) callCompletion(t *testing.T, src span.Span, options func(*source.Options)) []protocol.CompletionItem {
 -	t.Helper()
--
--	view, err := r.server.session.ViewOf(src.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	original := view.Options()
--	modified := view.Options().Clone()
--	options(modified)
--	view, err = r.server.session.SetViewOptions(r.ctx, view, modified)
--	if err != nil {
--		t.Error(err)
--		return nil
--	}
--	defer r.server.session.SetViewOptions(r.ctx, view, original)
+-	cleanup := r.toggleOptions(t, src.URI(), options)
+-	defer cleanup()
 -
 -	list, err := r.server.Completion(r.ctx, &protocol.CompletionParams{
 -		TextDocumentPositionParams: protocol.TextDocumentPositionParams{
@@ -32695,226 +37302,27 @@
 -	}
 -	return list.Items
 -}
-diff -urN a/gopls/internal/lsp/debounce.go b/gopls/internal/lsp/debounce.go
---- a/gopls/internal/lsp/debounce.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debounce.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,71 +0,0 @@
--// Copyright 2020 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
 -
--package lsp
--
--import (
--	"sync"
--	"time"
--)
--
--type debounceEvent struct {
--	order uint64
--	done  chan struct{}
--}
--
--type debouncer struct {
--	mu     sync.Mutex
--	events map[string]*debounceEvent
--}
--
--func newDebouncer() *debouncer {
--	return &debouncer{
--		events: make(map[string]*debounceEvent),
+-func (r *runner) toggleOptions(t *testing.T, uri span.URI, options func(*source.Options)) (reset func()) {
+-	view, err := r.server.session.ViewOf(uri)
+-	if err != nil {
+-		t.Fatal(err)
 -	}
--}
+-	folder := view.Folder()
 -
--// debounce returns a channel that receives a boolean reporting whether,
--// by the time the delay channel receives a value, this call is (or will be)
--// the most recent call with the highest order number for its key.
--func (d *debouncer) debounce(key string, order uint64, delay <-chan time.Time) <-chan bool {
--	okc := make(chan bool, 1)
--
--	d.mu.Lock()
--	if prev, ok := d.events[key]; ok {
--		if prev.order > order {
--			// If we have a logical ordering of events (as is the case for snapshots),
--			// don't overwrite a later event with an earlier event.
--			d.mu.Unlock()
--			okc <- false
--			return okc
--		}
--		close(prev.done)
+-	modified := r.server.Options().Clone()
+-	options(modified)
+-	if err = r.server.session.SetFolderOptions(r.ctx, folder, modified); err != nil {
+-		t.Fatal(err)
 -	}
--	done := make(chan struct{})
--	next := &debounceEvent{
--		order: order,
--		done:  done,
+-	return func() {
+-		r.server.session.SetFolderOptions(r.ctx, folder, r.server.Options())
 -	}
--	d.events[key] = next
--	d.mu.Unlock()
--
--	go func() {
--		ok := false
--		select {
--		case <-delay:
--			d.mu.Lock()
--			if d.events[key] == next {
--				ok = true
--				delete(d.events, key)
--			} else {
--				// The event was superseded before we acquired d.mu.
--			}
--			d.mu.Unlock()
--		case <-done:
--		}
--		okc <- ok
--	}()
--
--	return okc
--}
-diff -urN a/gopls/internal/lsp/debounce_test.go b/gopls/internal/lsp/debounce_test.go
---- a/gopls/internal/lsp/debounce_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debounce_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,81 +0,0 @@
--// Copyright 2020 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package lsp
--
--import (
--	"testing"
--	"time"
--)
--
--func TestDebouncer(t *testing.T) {
--	t.Parallel()
--
--	type event struct {
--		key       string
--		order     uint64
--		wantFired bool
--	}
--	tests := []struct {
--		label  string
--		events []*event
--	}{
--		{
--			label: "overridden",
--			events: []*event{
--				{key: "a", order: 1, wantFired: false},
--				{key: "a", order: 2, wantFired: true},
--			},
--		},
--		{
--			label: "distinct labels",
--			events: []*event{
--				{key: "a", order: 1, wantFired: true},
--				{key: "b", order: 2, wantFired: true},
--			},
--		},
--		{
--			label: "reverse order",
--			events: []*event{
--				{key: "a", order: 2, wantFired: true},
--				{key: "a", order: 1, wantFired: false},
--			},
--		},
--		{
--			label: "multiple overrides",
--			events: []*event{
--				{key: "a", order: 1, wantFired: false},
--				{key: "a", order: 2, wantFired: false},
--				{key: "a", order: 3, wantFired: false},
--				{key: "a", order: 4, wantFired: false},
--				{key: "a", order: 5, wantFired: true},
--			},
--		},
--	}
--	for _, test := range tests {
--		test := test
--		t.Run(test.label, func(t *testing.T) {
--			d := newDebouncer()
--
--			delays := make([]chan time.Time, len(test.events))
--			okcs := make([]<-chan bool, len(test.events))
--
--			// Register the events in deterministic order, synchronously.
--			for i, e := range test.events {
--				delays[i] = make(chan time.Time, 1)
--				okcs[i] = d.debounce(e.key, e.order, delays[i])
--			}
--
--			// Now see which event fired.
--			for i, okc := range okcs {
--				event := test.events[i]
--				delays[i] <- time.Now()
--				fired := <-okc
--				if fired != event.wantFired {
--					t.Errorf("[key: %q, order: %d]: fired = %t, want %t", event.key, event.order, fired, event.wantFired)
--				}
--			}
--		})
--	}
--}
-diff -urN a/gopls/internal/lsp/debug/buildinfo_go1.12.go b/gopls/internal/lsp/debug/buildinfo_go1.12.go
---- a/gopls/internal/lsp/debug/buildinfo_go1.12.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/buildinfo_go1.12.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,29 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build !go1.18
--// +build !go1.18
--
--package debug
--
--import (
--	"runtime"
--	"runtime/debug"
--)
--
--type BuildInfo struct {
--	debug.BuildInfo
--	GoVersion string // Version of Go that produced this binary
--}
--
--func readBuildInfo() (*BuildInfo, bool) {
--	rinfo, ok := debug.ReadBuildInfo()
--	if !ok {
--		return nil, false
--	}
--	return &BuildInfo{
--		GoVersion: runtime.Version(),
--		BuildInfo: *rinfo,
--	}, true
--}
-diff -urN a/gopls/internal/lsp/debug/buildinfo_go1.18.go b/gopls/internal/lsp/debug/buildinfo_go1.18.go
---- a/gopls/internal/lsp/debug/buildinfo_go1.18.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/buildinfo_go1.18.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,19 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:build go1.18
--// +build go1.18
--
--package debug
--
--import (
--	"runtime/debug"
--)
--
--type BuildInfo debug.BuildInfo
--
--func readBuildInfo() (*BuildInfo, bool) {
--	info, ok := debug.ReadBuildInfo()
--	return (*BuildInfo)(info), ok
 -}
 diff -urN a/gopls/internal/lsp/debug/info.go b/gopls/internal/lsp/debug/info.go
 --- a/gopls/internal/lsp/debug/info.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/info.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,254 +0,0 @@
++++ b/gopls/internal/lsp/debug/info.go	1970-01-01 08:00:00
+@@ -1,258 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -32927,6 +37335,7 @@
 -	"encoding/json"
 -	"fmt"
 -	"io"
+-	"os"
 -	"reflect"
 -	"runtime"
 -	"runtime/debug"
@@ -32946,12 +37355,19 @@
 -)
 -
 -// Version is a manually-updated mechanism for tracking versions.
--const Version = "master"
+-func Version() string {
+-	if info, ok := debug.ReadBuildInfo(); ok {
+-		if info.Main.Version != "" {
+-			return info.Main.Version
+-		}
+-	}
+-	return "(unknown)"
+-}
 -
 -// ServerVersion is the format used by gopls to report its version to the
 -// client. This format is structured so that the client can parse it easily.
 -type ServerVersion struct {
--	*BuildInfo
+-	*debug.BuildInfo
 -	Version string
 -}
 -
@@ -32959,23 +37375,18 @@
 -// built in module mode, we return a GOPATH-specific message with the
 -// hardcoded version.
 -func VersionInfo() *ServerVersion {
--	if info, ok := readBuildInfo(); ok {
--		return getVersion(info)
+-	if info, ok := debug.ReadBuildInfo(); ok {
+-		return &ServerVersion{
+-			Version:   Version(),
+-			BuildInfo: info,
+-		}
 -	}
--	buildInfo := &BuildInfo{}
--	// go1.17 or earlier, part of s.BuildInfo are embedded fields.
--	buildInfo.Path = "gopls, built in GOPATH mode"
--	buildInfo.GoVersion = runtime.Version()
 -	return &ServerVersion{
--		Version:   Version,
--		BuildInfo: buildInfo,
--	}
--}
--
--func getVersion(info *BuildInfo) *ServerVersion {
--	return &ServerVersion{
--		Version:   Version,
--		BuildInfo: info,
+-		Version: Version(),
+-		BuildInfo: &debug.BuildInfo{
+-			Path:      "gopls, built in GOPATH mode",
+-			GoVersion: runtime.Version(),
+-		},
 -	}
 -}
 -
@@ -32984,6 +37395,7 @@
 -	section(w, HTML, "Server Instance", func() {
 -		fmt.Fprintf(w, "Start time: %v\n", i.StartTime)
 -		fmt.Fprintf(w, "LogFile: %s\n", i.Logfile)
+-		fmt.Fprintf(w, "pid: %d\n", os.Getpid())
 -		fmt.Fprintf(w, "Working directory: %s\n", i.Workdir)
 -		fmt.Fprintf(w, "Address: %s\n", i.ServerAddress)
 -		fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress())
@@ -33040,7 +37452,7 @@
 -}
 -
 -func printBuildInfo(w io.Writer, info *ServerVersion, verbose bool, mode PrintMode) {
--	fmt.Fprintf(w, "%v %v\n", info.Path, Version)
+-	fmt.Fprintf(w, "%v %v\n", info.Path, Version())
 -	printModuleInfo(w, info.Main, mode)
 -	if !verbose {
 -		return
@@ -33171,8 +37583,8 @@
 -}
 diff -urN a/gopls/internal/lsp/debug/info_test.go b/gopls/internal/lsp/debug/info_test.go
 --- a/gopls/internal/lsp/debug/info_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/info_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,47 +0,0 @@
++++ b/gopls/internal/lsp/debug/info_test.go	1970-01-01 08:00:00
+@@ -1,48 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -33202,7 +37614,7 @@
 -	if g, w := got.GoVersion, runtime.Version(); g != w {
 -		t.Errorf("go version = %v, want %v", g, w)
 -	}
--	if g, w := got.Version, Version; g != w {
+-	if g, w := got.Version, Version(); g != w {
 -		t.Errorf("gopls version = %v, want %v", g, w)
 -	}
 -	// Other fields of BuildInfo may not be available during test.
@@ -33216,13 +37628,14 @@
 -	res := buf.Bytes()
 -
 -	// Other fields of BuildInfo may not be available during test.
--	if !bytes.Contains(res, []byte(Version)) || !bytes.Contains(res, []byte(runtime.Version())) {
--		t.Errorf("plaintext output = %q,\nwant (version: %v, go: %v)", res, Version, runtime.Version())
+-	wantGoplsVersion, wantGoVersion := Version(), runtime.Version()
+-	if !bytes.Contains(res, []byte(wantGoplsVersion)) || !bytes.Contains(res, []byte(wantGoVersion)) {
+-		t.Errorf("plaintext output = %q,\nwant (version: %v, go: %v)", res, wantGoplsVersion, wantGoVersion)
 -	}
 -}
 diff -urN a/gopls/internal/lsp/debug/log/log.go b/gopls/internal/lsp/debug/log/log.go
 --- a/gopls/internal/lsp/debug/log/log.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/log/log.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/debug/log/log.go	1970-01-01 08:00:00
 @@ -1,43 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -33269,7 +37682,7 @@
 -}
 diff -urN a/gopls/internal/lsp/debug/metrics.go b/gopls/internal/lsp/debug/metrics.go
 --- a/gopls/internal/lsp/debug/metrics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/metrics.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/debug/metrics.go	1970-01-01 08:00:00
 @@ -1,58 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -33331,7 +37744,7 @@
 -}
 diff -urN a/gopls/internal/lsp/debug/rpc.go b/gopls/internal/lsp/debug/rpc.go
 --- a/gopls/internal/lsp/debug/rpc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/rpc.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/debug/rpc.go	1970-01-01 08:00:00
 @@ -1,239 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -33574,8 +37987,8 @@
 -}
 diff -urN a/gopls/internal/lsp/debug/serve.go b/gopls/internal/lsp/debug/serve.go
 --- a/gopls/internal/lsp/debug/serve.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/serve.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,909 +0,0 @@
++++ b/gopls/internal/lsp/debug/serve.go	1970-01-01 08:00:00
+@@ -1,864 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -33583,7 +37996,6 @@
 -package debug
 -
 -import (
--	"archive/zip"
 -	"bytes"
 -	"context"
 -	"errors"
@@ -33598,16 +38010,15 @@
 -	"path"
 -	"path/filepath"
 -	"runtime"
--	rpprof "runtime/pprof"
 -	"strconv"
 -	"strings"
 -	"sync"
 -	"time"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/debug/log"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/core"
 -	"golang.org/x/tools/internal/event/export"
@@ -33685,6 +38096,13 @@
 -	return nil
 -}
 -
+-// Analysis returns the global Analysis template value.
+-func (st *State) Analysis() (_ analysisTmpl) { return }
+-
+-type analysisTmpl struct{}
+-
+-func (analysisTmpl) AnalyzerRunTimes() []cache.LabelDuration { return cache.AnalyzerRunTimes() }
+-
 -// Sessions returns the set of Session objects currently being served.
 -func (st *State) Sessions() []*cache.Session {
 -	var sessions []*cache.Session
@@ -33858,6 +38276,10 @@
 -	return i.State.Cache(path.Base(r.URL.Path))
 -}
 -
+-func (i *Instance) getAnalysis(r *http.Request) interface{} {
+-	return i.State.Analysis()
+-}
+-
 -func (i *Instance) getSession(r *http.Request) interface{} {
 -	return i.State.Session(path.Base(r.URL.Path))
 -}
@@ -34030,6 +38452,7 @@
 -		if i.traces != nil {
 -			mux.HandleFunc("/trace/", render(TraceTmpl, i.traces.getData))
 -		}
+-		mux.HandleFunc("/analysis/", render(AnalysisTmpl, i.getAnalysis))
 -		mux.HandleFunc("/cache/", render(CacheTmpl, i.getCache))
 -		mux.HandleFunc("/session/", render(SessionTmpl, i.getSession))
 -		mux.HandleFunc("/view/", render(ViewTmpl, i.getView))
@@ -34040,14 +38463,14 @@
 -		mux.HandleFunc("/memory", render(MemoryTmpl, getMemory))
 -
 -		// Internal debugging helpers.
--		mux.HandleFunc("/_dogc", func(w http.ResponseWriter, r *http.Request) {
+-		mux.HandleFunc("/gc", func(w http.ResponseWriter, r *http.Request) {
 -			runtime.GC()
 -			runtime.GC()
 -			runtime.GC()
--			http.Error(w, "OK", 200)
+-			http.Redirect(w, r, "/memory", http.StatusTemporaryRedirect)
 -		})
 -		mux.HandleFunc("/_makeabug", func(w http.ResponseWriter, r *http.Request) {
--			bug.Report("bug here", nil)
+-			bug.Report("bug here")
 -			http.Error(w, "made a bug", http.StatusOK)
 -		})
 -
@@ -34072,65 +38495,6 @@
 -	return i.listenedDebugAddress
 -}
 -
--// MonitorMemory starts recording memory statistics each second.
--func (i *Instance) MonitorMemory(ctx context.Context) {
--	tick := time.NewTicker(time.Second)
--	nextThresholdGiB := uint64(1)
--	go func() {
--		for {
--			<-tick.C
--			var mem runtime.MemStats
--			runtime.ReadMemStats(&mem)
--			if mem.HeapAlloc < nextThresholdGiB*1<<30 {
--				continue
--			}
--			if err := i.writeMemoryDebug(nextThresholdGiB, true); err != nil {
--				event.Error(ctx, "writing memory debug info", err)
--			}
--			if err := i.writeMemoryDebug(nextThresholdGiB, false); err != nil {
--				event.Error(ctx, "writing memory debug info", err)
--			}
--			event.Log(ctx, fmt.Sprintf("Wrote memory usage debug info to %v", os.TempDir()))
--			nextThresholdGiB++
--		}
--	}()
--}
--
--func (i *Instance) writeMemoryDebug(threshold uint64, withNames bool) error {
--	suffix := "withnames"
--	if !withNames {
--		suffix = "nonames"
--	}
--
--	filename := fmt.Sprintf("gopls.%d-%dGiB-%s.zip", os.Getpid(), threshold, suffix)
--	zipf, err := os.OpenFile(filepath.Join(os.TempDir(), filename), os.O_CREATE|os.O_RDWR, 0644)
--	if err != nil {
--		return err
--	}
--	zipw := zip.NewWriter(zipf)
--
--	f, err := zipw.Create("heap.pb.gz")
--	if err != nil {
--		return err
--	}
--	if err := rpprof.Lookup("heap").WriteTo(f, 0); err != nil {
--		return err
--	}
--
--	f, err = zipw.Create("goroutines.txt")
--	if err != nil {
--		return err
--	}
--	if err := rpprof.Lookup("goroutine").WriteTo(f, 1); err != nil {
--		return err
--	}
--
--	if err := zipw.Close(); err != nil {
--		return err
--	}
--	return zipf.Close()
--}
--
 -func makeGlobalExporter(stderr io.Writer) event.Exporter {
 -	p := export.Printer{}
 -	var pMu sync.Mutex
@@ -34275,10 +38639,10 @@
 -td.value {
 -  text-align: right;
 -}
--ul.events {
--	list-style-type: none;
+-ul.spans {
+-	font-family: monospace;
+-	font-size:   85%;
 -}
--
 -</style>
 -{{block "head" .}}{{end}}
 -</head>
@@ -34286,9 +38650,11 @@
 -<a href="/">Main</a>
 -<a href="/info">Info</a>
 -<a href="/memory">Memory</a>
+-<a href="/debug/pprof">Profiling</a>
 -<a href="/metrics">Metrics</a>
 -<a href="/rpc">RPC</a>
 -<a href="/trace">Trace</a>
+-<a href="/analysis">Analysis</a>
 -<hr>
 -<h1>{{template "title" .}}</h1>
 -{{block "body" .}}
@@ -34326,9 +38692,10 @@
 -		}
 -		return s
 -	},
--	"options": func(s *cache.Session) []sessionOption {
--		return showOptions(s.Options())
--	},
+-	// TODO(rfindley): re-enable option inspection.
+-	// "options": func(s *cache.Session) []sessionOption {
+-	// 	return showOptions(s.Options())
+-	// },
 -})
 -
 -var MainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
@@ -34355,9 +38722,10 @@
 -`))
 -
 -var MemoryTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
--{{define "title"}}GoPls memory usage{{end}}
+-{{define "title"}}Gopls memory usage{{end}}
 -{{define "head"}}<meta http-equiv="refresh" content="5">{{end}}
 -{{define "body"}}
+-<form action="/gc"><input type="submit" value="Run garbage collector"/></form>
 -<h2>Stats</h2>
 -<table>
 -<tr><td class="label">Allocated bytes</td><td class="value">{{fuint64 .HeapAlloc}}</td></tr>
@@ -34399,6 +38767,14 @@
 -{{end}}
 -`))
 -
+-var AnalysisTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
+-{{define "title"}}Analysis{{end}}
+-{{define "body"}}
+-<h2>Analyzer.Run times</h2>
+-<ul>{{range .AnalyzerRunTimes}}<li>{{.Duration}} {{.Label}}</li>{{end}}</ul>
+-{{end}}
+-`))
+-
 -var ClientTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
 -{{define "title"}}Client {{.Session.ID}}{{end}}
 -{{define "body"}}
@@ -34453,12 +38829,6 @@
 -<li>
 -<a href="/file/{{$session.ID}}/{{.FileIdentity.Hash}}">{{.FileIdentity.URI}}</a>
 -</li>{{end}}</ul>
--<h2>Options</h2>
--{{range options .}}
--<p><b>{{.Name}}</b> {{.Type}}</p>
--<p><i>default:</i> {{.Default}}</p>
--{{if ne .Default .Current}}<p><i>current:</i> {{.Current}}</p>{{end}}
--{{end}}
 -{{end}}
 -`))
 -
@@ -34467,8 +38837,6 @@
 -{{define "body"}}
 -Name: <b>{{.Name}}</b><br>
 -Folder: <b>{{.Folder}}</b><br>
--<h2>Environment</h2>
--<ul>{{range .Options.Env}}<li>{{.}}</li>{{end}}</ul>
 -{{end}}
 -`))
 -
@@ -34482,13 +38850,13 @@
 -	Kind: <b>{{.Kind}}</b><br>
 -{{end}}
 -<h3>Contents</h3>
--<pre>{{fcontent .Read}}</pre>
+-<pre>{{fcontent .Content}}</pre>
 -{{end}}
 -`))
 diff -urN a/gopls/internal/lsp/debug/trace.go b/gopls/internal/lsp/debug/trace.go
 --- a/gopls/internal/lsp/debug/trace.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/debug/trace.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,233 +0,0 @@
++++ b/gopls/internal/lsp/debug/trace.go	1970-01-01 08:00:00
+@@ -1,320 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -34513,60 +38881,117 @@
 -	"golang.org/x/tools/internal/event/label"
 -)
 -
+-// TraceTmpl extends BaseTemplate and renders a TraceResults, e.g. from getData().
 -var TraceTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
 -{{define "title"}}Trace Information{{end}}
 -{{define "body"}}
 -	{{range .Traces}}<a href="/trace/{{.Name}}">{{.Name}}</a> last: {{.Last.Duration}}, longest: {{.Longest.Duration}}<br>{{end}}
 -	{{if .Selected}}
 -		<H2>{{.Selected.Name}}</H2>
--		{{if .Selected.Last}}<H3>Last</H3><ul>{{template "details" .Selected.Last}}</ul>{{end}}
--		{{if .Selected.Longest}}<H3>Longest</H3><ul>{{template "details" .Selected.Longest}}</ul>{{end}}
+-		{{if .Selected.Last}}<H3>Last</H3><ul class='spans'>{{template "completeSpan" .Selected.Last}}</ul>{{end}}
+-		{{if .Selected.Longest}}<H3>Longest</H3><ul class='spans'>{{template "completeSpan" .Selected.Longest}}</ul>{{end}}
+-	{{end}}
+-
+-        <H2>Recent spans (oldest first)</H2>
+-        <p>
+-        A finite number of recent span start/end times are shown below.
+-        The nesting represents the children of a parent span (and the log events within a span).
+-        A span may appear twice: chronologically at toplevel, and nested within its parent.
+-        </p>
+-	<ul class='spans'>{{range .Recent}}{{template "spanStartEnd" .}}{{end}}</ul>
+-{{end}}
+-{{define "spanStartEnd"}}
+-	{{if .Start}}
+-		<li>{{.Span.Header .Start}}</li>
+-	{{else}}
+-		{{template "completeSpan" .Span}}
 -	{{end}}
 -{{end}}
--{{define "details"}}
--	<li>{{.Offset}} {{.Name}} {{.Duration}} {{.Tags}}</li>
--	{{if .Events}}<ul class=events>{{range .Events}}<li>{{.Offset}} {{.Tags}}</li>{{end}}</ul>{{end}}
--	{{if .Children}}<ul>{{range .Children}}{{template "details" .}}{{end}}</ul>{{end}}
+-{{define "completeSpan"}}
+-	<li>{{.Header false}}</li>
+-	{{if .Events}}<ul>{{range .Events}}<li>{{.Header}}</li>{{end}}</ul>{{end}}
+-	{{if .ChildStartEnd}}<ul>{{range .ChildStartEnd}}{{template "spanStartEnd" .}}{{end}}</ul>{{end}}
 -{{end}}
 -`))
 -
 -type traces struct {
--	mu         sync.Mutex
--	sets       map[string]*traceSet
--	unfinished map[export.SpanContext]*traceData
+-	mu              sync.Mutex
+-	sets            map[string]*traceSet
+-	unfinished      map[export.SpanContext]*traceSpan
+-	recent          []spanStartEnd
+-	recentEvictions int
 -}
 -
+-// A spanStartEnd records the start or end of a span.
+-// If Start, the span may be unfinished, so some fields (e.g. Finish)
+-// may be unset and others (e.g. Events) may be being actively populated.
+-type spanStartEnd struct {
+-	Start bool
+-	Span  *traceSpan
+-}
+-
+-func (ev spanStartEnd) Time() time.Time {
+-	if ev.Start {
+-		return ev.Span.Start
+-	} else {
+-		return ev.Span.Finish
+-	}
+-}
+-
+-// A TraceResults is the subject for the /trace HTML template.
 -type TraceResults struct { // exported for testing
 -	Traces   []*traceSet
 -	Selected *traceSet
+-	Recent   []spanStartEnd
 -}
 -
+-// A traceSet holds two representative spans of a given span name.
 -type traceSet struct {
 -	Name    string
--	Last    *traceData
--	Longest *traceData
+-	Last    *traceSpan
+-	Longest *traceSpan
 -}
 -
--type traceData struct {
--	TraceID  export.TraceID
--	SpanID   export.SpanID
--	ParentID export.SpanID
--	Name     string
--	Start    time.Time
--	Finish   time.Time
--	Offset   time.Duration
--	Duration time.Duration
--	Tags     string
--	Events   []traceEvent
--	Children []*traceData
+-// A traceSpan holds information about a single span.
+-type traceSpan struct {
+-	TraceID       export.TraceID
+-	SpanID        export.SpanID
+-	ParentID      export.SpanID
+-	Name          string
+-	Start         time.Time
+-	Finish        time.Time     // set at end
+-	Duration      time.Duration // set at end
+-	Tags          string
+-	Events        []traceEvent   // set at end
+-	ChildStartEnd []spanStartEnd // populated while active
+-
+-	parent *traceSpan
+-}
+-
+-const timeFormat = "15:04:05.000"
+-
+-// Header renders the time, name, tags, and (if !start),
+-// duration of a span start or end event.
+-func (span *traceSpan) Header(start bool) string {
+-	if start {
+-		return fmt.Sprintf("%s start %s %s",
+-			span.Start.Format(timeFormat), span.Name, span.Tags)
+-	} else {
+-		return fmt.Sprintf("%s end %s (+%s) %s",
+-			span.Finish.Format(timeFormat), span.Name, span.Duration, span.Tags)
+-	}
 -}
 -
 -type traceEvent struct {
 -	Time   time.Time
--	Offset time.Duration
+-	Offset time.Duration // relative to start of span
 -	Tags   string
 -}
 -
+-func (ev traceEvent) Header() string {
+-	return fmt.Sprintf("%s event (+%s) %s", ev.Time.Format(timeFormat), ev.Offset, ev.Tags)
+-}
+-
 -func StdTrace(exporter event.Exporter) event.Exporter {
 -	return func(ctx context.Context, ev core.Event, lm label.Map) context.Context {
 -		span := export.GetSpan(ctx)
@@ -34619,7 +39044,7 @@
 -	case event.IsStart(ev):
 -		// Just starting: add it to the unfinished map.
 -		// Allocate before the critical section.
--		td := &traceData{
+-		td := &traceSpan{
 -			TraceID:  span.ID.TraceID,
 -			SpanID:   span.ID.SpanID,
 -			ParentID: span.ParentID,
@@ -34630,22 +39055,23 @@
 -
 -		t.mu.Lock()
 -		defer t.mu.Unlock()
+-
+-		t.addRecentLocked(td, true) // add start event
+-
 -		if t.sets == nil {
 -			t.sets = make(map[string]*traceSet)
--			t.unfinished = make(map[export.SpanContext]*traceData)
+-			t.unfinished = make(map[export.SpanContext]*traceSpan)
 -		}
 -		t.unfinished[span.ID] = td
--		// and wire up parents if we have them
--		if !span.ParentID.IsValid() {
--			return ctx
+-
+-		// Wire up parents if we have them.
+-		if span.ParentID.IsValid() {
+-			parentID := export.SpanContext{TraceID: span.ID.TraceID, SpanID: span.ParentID}
+-			if parent, ok := t.unfinished[parentID]; ok {
+-				td.parent = parent
+-				parent.ChildStartEnd = append(parent.ChildStartEnd, spanStartEnd{true, td})
+-			}
 -		}
--		parentID := export.SpanContext{TraceID: span.ID.TraceID, SpanID: span.ParentID}
--		parent, found := t.unfinished[parentID]
--		if !found {
--			// trace had an invalid parent, so it cannot itself be valid
--			return ctx
--		}
--		parent.Children = append(parent.Children, td)
 -
 -	case event.IsEnd(ev):
 -		// Finishing: must be already in the map.
@@ -34666,10 +39092,10 @@
 -			return ctx // if this happens we are in a bad place
 -		}
 -		delete(t.unfinished, span.ID)
--
 -		td.Finish = span.Finish().At()
 -		td.Duration = span.Finish().At().Sub(span.Start().At())
 -		td.Events = tdEvents
+-		t.addRecentLocked(td, false) // add end event
 -
 -		set, ok := t.sets[span.Name]
 -		if !ok {
@@ -34680,43 +39106,72 @@
 -		if set.Longest == nil || set.Last.Duration > set.Longest.Duration {
 -			set.Longest = set.Last
 -		}
--		if !td.ParentID.IsValid() {
+-		if td.parent != nil {
+-			td.parent.ChildStartEnd = append(td.parent.ChildStartEnd, spanStartEnd{false, td})
+-		} else {
 -			fillOffsets(td, td.Start)
 -		}
 -	}
 -	return ctx
 -}
 -
--func (t *traces) getData(req *http.Request) interface{} {
--	if len(t.sets) == 0 {
--		return nil
+-// addRecentLocked appends a start or end event to the "recent" log,
+-// evicting an old entry if necessary.
+-func (t *traces) addRecentLocked(span *traceSpan, start bool) {
+-	t.recent = append(t.recent, spanStartEnd{Start: start, Span: span})
+-
+-	const maxRecent = 100 // number of log entries before eviction
+-	for len(t.recent) > maxRecent {
+-		t.recent[0] = spanStartEnd{} // aid GC
+-		t.recent = t.recent[1:]
+-		t.recentEvictions++
+-
+-		// Using a slice as a FIFO queue leads to unbounded growth
+-		// as Go's GC cannot collect the ever-growing unused prefix.
+-		// So, compact it periodically.
+-		if t.recentEvictions%maxRecent == 0 {
+-			t.recent = append([]spanStartEnd(nil), t.recent...)
+-		}
 -	}
--	data := TraceResults{}
--	data.Traces = make([]*traceSet, 0, len(t.sets))
--	for _, set := range t.sets {
--		data.Traces = append(data.Traces, set)
--	}
--	sort.Slice(data.Traces, func(i, j int) bool { return data.Traces[i].Name < data.Traces[j].Name })
--	if bits := strings.SplitN(req.URL.Path, "/trace/", 2); len(bits) > 1 {
--		data.Selected = t.sets[bits[1]]
--	}
--	return data
 -}
 -
--func fillOffsets(td *traceData, start time.Time) {
--	td.Offset = td.Start.Sub(start)
+-// getData returns the TraceResults rendered by TraceTmpl for the /trace[/name] endpoint.
+-func (t *traces) getData(req *http.Request) interface{} {
+-	// TODO(adonovan): the HTTP request doesn't acquire the mutex
+-	// for t or for each span! Audit and fix.
+-
+-	// Sort last/longest sets by name.
+-	traces := make([]*traceSet, 0, len(t.sets))
+-	for _, set := range t.sets {
+-		traces = append(traces, set)
+-	}
+-	sort.Slice(traces, func(i, j int) bool {
+-		return traces[i].Name < traces[j].Name
+-	})
+-
+-	return TraceResults{
+-		Traces:   traces,
+-		Selected: t.sets[strings.TrimPrefix(req.URL.Path, "/trace/")], // may be nil
+-		Recent:   t.recent,
+-	}
+-}
+-
+-func fillOffsets(td *traceSpan, start time.Time) {
 -	for i := range td.Events {
 -		td.Events[i].Offset = td.Events[i].Time.Sub(start)
 -	}
--	for _, child := range td.Children {
--		fillOffsets(child, start)
+-	for _, child := range td.ChildStartEnd {
+-		if !child.Start {
+-			fillOffsets(child.Span, start)
+-		}
 -	}
 -}
 -
 -func renderLabels(labels label.List) string {
 -	buf := &bytes.Buffer{}
 -	for index := 0; labels.Valid(index); index++ {
--		if l := labels.Label(index); l.Valid() {
+-		// The 'start' label duplicates the span name, so discard it.
+-		if l := labels.Label(index); l.Valid() && l.Key().Name() != "start" {
 -			fmt.Fprintf(buf, "%v ", l)
 -		}
 -	}
@@ -34724,8 +39179,8 @@
 -}
 diff -urN a/gopls/internal/lsp/definition.go b/gopls/internal/lsp/definition.go
 --- a/gopls/internal/lsp/definition.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/definition.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,52 +0,0 @@
++++ b/gopls/internal/lsp/definition.go	1970-01-01 08:00:00
+@@ -1,60 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -34734,30 +39189,35 @@
 -
 -import (
 -	"context"
--	"errors"
 -	"fmt"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
--func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) ([]protocol.Location, error) {
+-func (s *Server) definition(ctx context.Context, params *protocol.DefinitionParams) (_ []protocol.Location, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("definition")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
+-	ctx, done := event.Start(ctx, "lsp.Server.definition", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	// TODO(rfindley): definition requests should be multiplexed across all views.
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	switch kind := snapshot.View().FileKind(fh); kind {
+-	switch kind := snapshot.FileKind(fh); kind {
 -	case source.Tmpl:
 -		return template.Definition(snapshot, fh, params.Position)
 -	case source.Go:
--		// Partial support for jumping from linkname directive (position at 2nd argument).
--		locations, err := source.LinknameDefinition(ctx, snapshot, fh, params.Position)
--		if !errors.Is(err, source.ErrNoLinkname) {
--			return locations, err
--		}
 -		return source.Definition(ctx, snapshot, fh, params.Position)
 -	default:
 -		return nil, fmt.Errorf("can't find definitions for file type %s", kind)
@@ -34765,13 +39225,16 @@
 -}
 -
 -func (s *Server) typeDefinition(ctx context.Context, params *protocol.TypeDefinitionParams) ([]protocol.Location, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.typeDefinition", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	// TODO(rfindley): type definition requests should be multiplexed across all views.
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	switch kind := snapshot.View().FileKind(fh); kind {
+-	switch kind := snapshot.FileKind(fh); kind {
 -	case source.Go:
 -		return source.TypeDefinition(ctx, snapshot, fh, params.Position)
 -	default:
@@ -34780,8 +39243,8 @@
 -}
 diff -urN a/gopls/internal/lsp/diagnostics.go b/gopls/internal/lsp/diagnostics.go
 --- a/gopls/internal/lsp/diagnostics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/diagnostics.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,764 +0,0 @@
++++ b/gopls/internal/lsp/diagnostics.go	1970-01-01 08:00:00
+@@ -1,862 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -34795,12 +39258,12 @@
 -	"fmt"
 -	"os"
 -	"path/filepath"
+-	"sort"
 -	"strings"
 -	"sync"
 -	"time"
 -
--	"golang.org/x/sync/errgroup"
--	"golang.org/x/tools/gopls/internal/lsp/debug/log"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/mod"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
@@ -34809,14 +39272,23 @@
 -	"golang.org/x/tools/gopls/internal/span"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
--	"golang.org/x/tools/internal/xcontext"
 -)
 -
+-// TODO(rfindley): simplify this very complicated logic for publishing
+-// diagnostics. While doing so, ensure that we can test subtle logic such as
+-// for multi-pass diagnostics.
+-
 -// diagnosticSource differentiates different sources of diagnostics.
+-//
+-// Diagnostics from the same source overwrite each other, whereas diagnostics
+-// from different sources do not. Conceptually, the server state is a mapping
+-// from diagnostics source to a set of diagnostics, and each storeDiagnostics
+-// operation updates one entry of that mapping.
 -type diagnosticSource int
 -
 -const (
--	modSource diagnosticSource = iota
+-	modParseSource diagnosticSource = iota
+-	modTidySource
 -	gcDetailsSource
 -	analysisSource
 -	typeCheckSource
@@ -34863,13 +39335,15 @@
 -	mustPublish bool
 -
 -	// The last stored diagnostics for each diagnostic source.
--	reports map[diagnosticSource]diagnosticReport
+-	reports map[diagnosticSource]*diagnosticReport
 -}
 -
 -func (d diagnosticSource) String() string {
 -	switch d {
--	case modSource:
--		return "FromSource"
+-	case modParseSource:
+-		return "FromModParse"
+-	case modTidySource:
+-		return "FromModTidy"
 -	case gcDetailsSource:
 -		return "FromGCDetails"
 -	case analysisSource:
@@ -34890,46 +39364,69 @@
 -}
 -
 -// hashDiagnostics computes a hash to identify diags.
+-//
+-// hashDiagnostics mutates its argument (via sorting).
 -func hashDiagnostics(diags ...*source.Diagnostic) string {
+-	if len(diags) == 0 {
+-		return emptyDiagnosticsHash
+-	}
+-	return computeDiagnosticHash(diags...)
+-}
+-
+-// opt: pre-computed hash for empty diagnostics
+-var emptyDiagnosticsHash = computeDiagnosticHash()
+-
+-// computeDiagnosticHash should only be called from hashDiagnostics.
+-//
+-// TODO(rfindley): this should use source.Hash.
+-func computeDiagnosticHash(diags ...*source.Diagnostic) string {
 -	source.SortDiagnostics(diags)
 -	h := sha256.New()
 -	for _, d := range diags {
 -		for _, t := range d.Tags {
--			fmt.Fprintf(h, "%s", t)
+-			fmt.Fprintf(h, "tag: %s\n", t)
 -		}
 -		for _, r := range d.Related {
--			fmt.Fprintf(h, "%s%s%s", r.Location.URI.SpanURI(), r.Message, r.Location.Range)
+-			fmt.Fprintf(h, "related: %s %s %s\n", r.Location.URI.SpanURI(), r.Message, r.Location.Range)
 -		}
--		fmt.Fprintf(h, "%s%s%s%s", d.Message, d.Range, d.Severity, d.Source)
+-		fmt.Fprintf(h, "code: %s\n", d.Code)
+-		fmt.Fprintf(h, "codeHref: %s\n", d.CodeHref)
+-		fmt.Fprintf(h, "message: %s\n", d.Message)
+-		fmt.Fprintf(h, "range: %s\n", d.Range)
+-		fmt.Fprintf(h, "severity: %s\n", d.Severity)
+-		fmt.Fprintf(h, "source: %s\n", d.Source)
+-		if d.BundledFixes != nil {
+-			fmt.Fprintf(h, "fixes: %s\n", *d.BundledFixes)
+-		}
 -	}
 -	return fmt.Sprintf("%x", h.Sum(nil))
 -}
 -
--func (s *Server) diagnoseDetached(snapshot source.Snapshot) {
--	ctx := snapshot.BackgroundContext()
--	ctx = xcontext.Detach(ctx)
--	s.diagnose(ctx, snapshot, false)
--	s.publishDiagnostics(ctx, true, snapshot)
--}
--
 -func (s *Server) diagnoseSnapshots(snapshots map[source.Snapshot][]span.URI, onDisk bool) {
 -	var diagnosticWG sync.WaitGroup
 -	for snapshot, uris := range snapshots {
 -		diagnosticWG.Add(1)
 -		go func(snapshot source.Snapshot, uris []span.URI) {
 -			defer diagnosticWG.Done()
--			s.diagnoseSnapshot(snapshot, uris, onDisk)
+-			s.diagnoseSnapshot(snapshot, uris, onDisk, snapshot.Options().DiagnosticsDelay)
 -		}(snapshot, uris)
 -	}
 -	diagnosticWG.Wait()
 -}
 -
--func (s *Server) diagnoseSnapshot(snapshot source.Snapshot, changedURIs []span.URI, onDisk bool) {
+-// diagnoseSnapshot computes and publishes diagnostics for the given snapshot.
+-//
+-// If delay is non-zero, computing diagnostics does not start until after this
+-// delay has expired, to allow work to be cancelled by subsequent changes.
+-//
+-// If changedURIs is non-empty, it is a set of recently changed files that
+-// should be diagnosed immediately, and onDisk reports whether these file
+-// changes came from a change to on-disk files.
+-func (s *Server) diagnoseSnapshot(snapshot source.Snapshot, changedURIs []span.URI, onDisk bool, delay time.Duration) {
 -	ctx := snapshot.BackgroundContext()
 -	ctx, done := event.Start(ctx, "Server.diagnoseSnapshot", source.SnapshotLabels(snapshot)...)
 -	defer done()
 -
--	delay := snapshot.View().Options().DiagnosticsDelay
 -	if delay > 0 {
 -		// 2-phase diagnostics.
 -		//
@@ -34937,25 +39434,36 @@
 -		// does not analyze) packages directly affected by
 -		// file modifications.
 -		//
--		// The second phase runs analysis on the entire snapshot,
--		// and is debounced by the configured delay.
+-		// The second phase runs after the delay, and does everything.
+-		//
+-		// We wait a brief delay before the first phase, to allow higher priority
+-		// work such as autocompletion to acquire the type checking mutex (though
+-		// typically both diagnosing changed files and performing autocompletion
+-		// will be doing the same work: recomputing active packages).
+-		const minDelay = 20 * time.Millisecond
+-		select {
+-		case <-time.After(minDelay):
+-		case <-ctx.Done():
+-			return
+-		}
+-
 -		s.diagnoseChangedFiles(ctx, snapshot, changedURIs, onDisk)
 -		s.publishDiagnostics(ctx, false, snapshot)
 -
--		// We debounce diagnostics separately for each view, using the snapshot
--		// local ID as logical ordering.
--		//
--		// TODO(rfindley): it would be cleaner to simply put the diagnostic
--		// debouncer on the view, and remove the "key" argument to debouncing.
--		if ok := <-s.diagDebouncer.debounce(snapshot.View().Name(), snapshot.SequenceID(), time.After(delay)); ok {
--			s.diagnose(ctx, snapshot, false)
--			s.publishDiagnostics(ctx, true, snapshot)
+-		if delay < minDelay {
+-			delay = 0
+-		} else {
+-			delay -= minDelay
 -		}
--		return
+-
+-		select {
+-		case <-time.After(delay):
+-		case <-ctx.Done():
+-			return
+-		}
 -	}
 -
--	// Ignore possible workspace configuration warnings in the normal flow.
--	s.diagnose(ctx, snapshot, false)
+-	s.diagnose(ctx, snapshot, analyzeOpenPackages)
 -	s.publishDiagnostics(ctx, true, snapshot)
 -}
 -
@@ -34963,11 +39471,7 @@
 -	ctx, done := event.Start(ctx, "Server.diagnoseChangedFiles", source.SnapshotLabels(snapshot)...)
 -	defer done()
 -
--	// TODO(adonovan): safety: refactor so that group.Go is called
--	// in a second loop, so that if we should later add an early
--	// return to the first loop, we don't leak goroutines.
--	var group errgroup.Group
--	seen := make(map[*source.Metadata]bool)
+-	toDiagnose := make(map[source.PackageID]*source.Metadata)
 -	for _, uri := range uris {
 -		// If the change is only on-disk and the file is not open, don't
 -		// directly request its package. It may not be a workspace package.
@@ -34981,45 +39485,50 @@
 -		}
 -
 -		// Don't request type-checking for builtin.go: it's not a real package.
--		if snapshot.IsBuiltin(ctx, uri) {
+-		if snapshot.IsBuiltin(uri) {
+-			continue
+-		}
+-
+-		// Don't diagnose files that are ignored by `go list` (e.g. testdata).
+-		if snapshot.IgnoredFile(uri) {
 -			continue
 -		}
 -
 -		// Find all packages that include this file and diagnose them in parallel.
--		metas, err := snapshot.MetadataForFile(ctx, uri)
+-		meta, err := source.NarrowestMetadataForFile(ctx, snapshot, uri)
 -		if err != nil {
+-			if ctx.Err() != nil {
+-				return
+-			}
 -			// TODO(findleyr): we should probably do something with the error here,
 -			// but as of now this can fail repeatedly if load fails, so can be too
 -			// noisy to log (and we'll handle things later in the slow pass).
 -			continue
 -		}
--		for _, m := range metas {
--			if m.IsIntermediateTestVariant() {
--				continue
--			}
--			if !seen[m] {
--				seen[m] = true
--				m := m
--				group.Go(func() error {
--					s.diagnosePkg(ctx, snapshot, m, false)
--					return nil // error result is ignored
--				})
--			}
--		}
+-		toDiagnose[meta.ID] = meta
 -	}
--	group.Wait() // ignore error
+-	s.diagnosePkgs(ctx, snapshot, toDiagnose, nil)
 -}
 -
+-// analysisMode parameterizes analysis behavior of a call to diagnosePkgs.
+-type analysisMode int
+-
+-const (
+-	analyzeNothing      analysisMode = iota // don't run any analysis
+-	analyzeOpenPackages                     // run analysis on packages with open files
+-	analyzeEverything                       // run analysis on all packages
+-)
+-
 -// diagnose is a helper function for running diagnostics with a given context.
 -// Do not call it directly. forceAnalysis is only true for testing purposes.
--func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAnalysis bool) {
+-func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, analyze analysisMode) {
 -	ctx, done := event.Start(ctx, "Server.diagnose", source.SnapshotLabels(snapshot)...)
 -	defer done()
 -
 -	// Wait for a free diagnostics slot.
 -	// TODO(adonovan): opt: shouldn't it be the analysis implementation's
 -	// job to de-dup and limit resource consumption? In any case this
--	// this function spends most its time waiting for awaitLoaded, at
+-	// function spends most its time waiting for awaitLoaded, at
 -	// least initially.
 -	select {
 -	case <-ctx.Done():
@@ -35044,45 +39553,42 @@
 -		}
 -	}
 -
--	// Diagnose go.mod upgrades.
--	upgradeReports, upgradeErr := mod.UpgradeDiagnostics(ctx, snapshot)
--	if ctx.Err() != nil {
--		log.Trace.Log(ctx, "diagnose cancelled")
--		return
--	}
--	store(modCheckUpgradesSource, "diagnosing go.mod upgrades", upgradeReports, upgradeErr, true)
+-	// Diagnostics below are organized by increasing specificity:
+-	//  go.work > mod > mod upgrade > mod vuln > package, etc.
 -
 -	// Diagnose go.work file.
 -	workReports, workErr := work.Diagnostics(ctx, snapshot)
 -	if ctx.Err() != nil {
--		log.Trace.Log(ctx, "diagnose cancelled")
 -		return
 -	}
 -	store(workSource, "diagnosing go.work file", workReports, workErr, true)
 -
 -	// Diagnose go.mod file.
--	// (This step demands type checking of all active packages:
--	// the bottleneck in the startup sequence for a big workspace.)
 -	modReports, modErr := mod.Diagnostics(ctx, snapshot)
 -	if ctx.Err() != nil {
--		log.Trace.Log(ctx, "diagnose cancelled")
 -		return
 -	}
--	store(modSource, "diagnosing go.mod file", modReports, modErr, true)
+-	store(modParseSource, "diagnosing go.mod file", modReports, modErr, true)
+-
+-	// Diagnose go.mod upgrades.
+-	upgradeReports, upgradeErr := mod.UpgradeDiagnostics(ctx, snapshot)
+-	if ctx.Err() != nil {
+-		return
+-	}
+-	store(modCheckUpgradesSource, "diagnosing go.mod upgrades", upgradeReports, upgradeErr, true)
 -
 -	// Diagnose vulnerabilities.
 -	vulnReports, vulnErr := mod.VulnerabilityDiagnostics(ctx, snapshot)
 -	if ctx.Err() != nil {
--		log.Trace.Log(ctx, "diagnose cancelled")
 -		return
 -	}
 -	store(modVulncheckSource, "diagnosing vulnerabilities", vulnReports, vulnErr, false)
 -
--	activeMetas, activeErr := snapshot.ActiveMetadata(ctx)
--	if s.shouldIgnoreError(ctx, snapshot, activeErr) {
+-	workspace, err := snapshot.WorkspaceMetadata(ctx)
+-	if s.shouldIgnoreError(ctx, snapshot, err) {
 -		return
 -	}
--	criticalErr := snapshot.GetCriticalError(ctx)
+-	criticalErr := snapshot.CriticalError(ctx)
 -	if ctx.Err() != nil { // must check ctx after GetCriticalError
 -		return
 -	}
@@ -35101,103 +39607,200 @@
 -
 -	// If there are no workspace packages, there is nothing to diagnose and
 -	// there are no orphaned files.
--	if len(activeMetas) == 0 {
+-	if len(workspace) == 0 {
 -		return
 -	}
 -
--	// Run go/analysis diagnosis of packages in parallel.
--	// TODO(adonovan): opt: it may be more efficient to
--	// have diagnosePkg take a set of packages.
+-	var wg sync.WaitGroup // for potentially slow operations below
+-
+-	// Maybe run go mod tidy (if it has been invalidated).
 -	//
--	// TODO(adonovan): opt: since the new analysis driver does its
--	// own type checking, we could strength-reduce pkg to
--	// PackageID and get this step started as soon as the set of
--	// active package IDs are known, without waiting for them to load.
+-	// Since go mod tidy can be slow, we run it concurrently to diagnostics.
+-	wg.Add(1)
+-	go func() {
+-		defer wg.Done()
+-		modTidyReports, err := mod.TidyDiagnostics(ctx, snapshot)
+-		store(modTidySource, "running go mod tidy", modTidyReports, err, true)
+-	}()
+-
+-	// Run type checking and go/analysis diagnosis of packages in parallel.
 -	var (
--		wg   sync.WaitGroup
--		seen = map[span.URI]struct{}{}
+-		seen       = map[span.URI]struct{}{}
+-		toDiagnose = make(map[source.PackageID]*source.Metadata)
+-		toAnalyze  = make(map[source.PackageID]unit)
 -	)
--	for _, m := range activeMetas {
+-	for _, m := range workspace {
+-		var hasNonIgnored, hasOpenFile bool
 -		for _, uri := range m.CompiledGoFiles {
 -			seen[uri] = struct{}{}
+-			if !hasNonIgnored && !snapshot.IgnoredFile(uri) {
+-				hasNonIgnored = true
+-			}
+-			if !hasOpenFile && snapshot.IsOpen(uri) {
+-				hasOpenFile = true
+-			}
 -		}
--
--		wg.Add(1)
--		go func(m *source.Metadata) {
--			defer wg.Done()
--			s.diagnosePkg(ctx, snapshot, m, forceAnalysis)
--		}(m)
+-		if hasNonIgnored {
+-			toDiagnose[m.ID] = m
+-			if analyze == analyzeEverything || analyze == analyzeOpenPackages && hasOpenFile {
+-				toAnalyze[m.ID] = unit{}
+-			}
+-		}
 -	}
+-
+-	wg.Add(1)
+-	go func() {
+-		s.diagnosePkgs(ctx, snapshot, toDiagnose, toAnalyze)
+-		wg.Done()
+-	}()
+-
 -	wg.Wait()
 -
 -	// Orphaned files.
 -	// Confirm that every opened file belongs to a package (if any exist in
 -	// the workspace). Otherwise, add a diagnostic to the file.
--	for _, o := range s.session.Overlays() {
--		if _, ok := seen[o.URI()]; ok {
--			continue
+-	if diags, err := snapshot.OrphanedFileDiagnostics(ctx); err == nil {
+-		for uri, diag := range diags {
+-			s.storeDiagnostics(snapshot, uri, orphanedSource, []*source.Diagnostic{diag}, true)
 -		}
--		diagnostic := s.checkForOrphanedFile(ctx, snapshot, o)
--		if diagnostic == nil {
--			continue
+-	} else {
+-		if ctx.Err() == nil {
+-			event.Error(ctx, "computing orphaned file diagnostics", err, source.SnapshotLabels(snapshot)...)
 -		}
--		s.storeDiagnostics(snapshot, o.URI(), orphanedSource, []*source.Diagnostic{diagnostic}, true)
 -	}
 -}
 -
--func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, m *source.Metadata, alwaysAnalyze bool) {
--	ctx, done := event.Start(ctx, "Server.diagnosePkg", append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...)
+-// diagnosePkgs type checks packages in toDiagnose, and analyzes packages in
+-// toAnalyze, merging their diagnostics. Packages in toAnalyze must be a subset
+-// of the packages in toDiagnose.
+-//
+-// It also implements gc_details diagnostics.
+-//
+-// TODO(rfindley): revisit handling of analysis gc_details. It may be possible
+-// to merge this function with Server.diagnose, thereby avoiding the two layers
+-// of concurrent dispatch: as of writing we concurrently run TidyDiagnostics
+-// and diagnosePkgs, and diagnosePkgs concurrently runs PackageDiagnostics and
+-// analysis.
+-func (s *Server) diagnosePkgs(ctx context.Context, snapshot source.Snapshot, toDiagnose map[source.PackageID]*source.Metadata, toAnalyze map[source.PackageID]unit) {
+-	ctx, done := event.Start(ctx, "Server.diagnosePkgs", source.SnapshotLabels(snapshot)...)
 -	defer done()
--	enableDiagnostics := false
--	includeAnalysis := alwaysAnalyze // only run analyses for packages with open files
--	for _, uri := range m.CompiledGoFiles {
--		enableDiagnostics = enableDiagnostics || !snapshot.IgnoredFile(uri)
--		includeAnalysis = includeAnalysis || snapshot.IsOpen(uri)
--	}
--	// Don't show any diagnostics on ignored files.
--	if !enableDiagnostics {
--		return
--	}
 -
--	diags, err := snapshot.PackageDiagnostics(ctx, m.ID)
--	if err != nil {
--		event.Error(ctx, "warning: diagnostics failed", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...)
--		return
--	}
+-	// Analyze and type-check concurrently, since they are independent
+-	// operations.
+-	var (
+-		wg            sync.WaitGroup
+-		pkgDiags      map[span.URI][]*source.Diagnostic
+-		analysisDiags = make(map[span.URI][]*source.Diagnostic)
+-	)
+-
+-	// Collect package diagnostics.
+-	wg.Add(1)
+-	go func() {
+-		defer wg.Done()
+-		var ids []source.PackageID
+-		for id := range toDiagnose {
+-			ids = append(ids, id)
+-		}
+-		var err error
+-		pkgDiags, err = snapshot.PackageDiagnostics(ctx, ids...)
+-		if err != nil {
+-			event.Error(ctx, "warning: diagnostics failed", err, source.SnapshotLabels(snapshot)...)
+-		}
+-	}()
 -
 -	// Get diagnostics from analysis framework.
 -	// This includes type-error analyzers, which suggest fixes to compiler errors.
--	var analysisDiags map[span.URI][]*source.Diagnostic
--	if includeAnalysis {
--		diags, err := source.Analyze(ctx, snapshot, m.ID, false)
+-	wg.Add(1)
+-	go func() {
+-		defer wg.Done()
+-		diags, err := source.Analyze(ctx, snapshot, toAnalyze, s.progress)
 -		if err != nil {
--			event.Error(ctx, "warning: analyzing package", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...)
+-			var tagStr string // sorted comma-separated list of package IDs
+-			{
+-				// TODO(adonovan): replace with a generic map[S]any -> string
+-				// function in the tag package, and use  maps.Keys + slices.Sort.
+-				keys := make([]string, 0, len(toDiagnose))
+-				for id := range toDiagnose {
+-					keys = append(keys, string(id))
+-				}
+-				sort.Strings(keys)
+-				tagStr = strings.Join(keys, ",")
+-			}
+-			event.Error(ctx, "warning: analyzing package", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(tagStr))...)
 -			return
 -		}
--		analysisDiags = diags
--	}
+-		for uri, diags := range diags {
+-			analysisDiags[uri] = append(analysisDiags[uri], diags...)
+-		}
+-	}()
 -
--	// For each file, update the server's diagnostics state.
--	for _, uri := range m.CompiledGoFiles {
--		// builtin.go exists only for documentation purposes and
--		// is not valid Go code. Don't report distracting errors.
--		if snapshot.IsBuiltin(ctx, uri) {
+-	wg.Wait()
+-
+-	// TODO(rfindley): remove the guards against snapshot.IsBuiltin, after the
+-	// gopls@v0.12.0 release. Packages should not be producing diagnostics for
+-	// the builtin file: I do not know why this logic existed previously.
+-
+-	// Merge analysis diagnostics with package diagnostics, and store the
+-	// resulting analysis diagnostics.
+-	for uri, adiags := range analysisDiags {
+-		if snapshot.IsBuiltin(uri) {
+-			bug.Reportf("go/analysis reported diagnostics for the builtin file: %v", adiags)
 -			continue
 -		}
--
--		pkgDiags := diags[uri]
--		var tdiags, adiags []*source.Diagnostic
--		source.CombineDiagnostics(pkgDiags, analysisDiags[uri], &tdiags, &adiags)
--		s.storeDiagnostics(snapshot, uri, typeCheckSource, tdiags, true)
--		s.storeDiagnostics(snapshot, uri, analysisSource, adiags, true)
+-		tdiags := pkgDiags[uri]
+-		var tdiags2, adiags2 []*source.Diagnostic
+-		source.CombineDiagnostics(tdiags, adiags, &tdiags2, &adiags2)
+-		pkgDiags[uri] = tdiags2
+-		s.storeDiagnostics(snapshot, uri, analysisSource, adiags2, true)
 -	}
 -
--	// If gc optimization details are requested, add them to the
--	// diagnostic reports.
+-	// golang/go#59587: guarantee that we store type-checking diagnostics for every compiled
+-	// package file.
+-	//
+-	// Without explicitly storing empty diagnostics, the eager diagnostics
+-	// publication for changed files will not publish anything for files with
+-	// empty diagnostics.
+-	storedPkgDiags := make(map[span.URI]bool)
+-	for _, m := range toDiagnose {
+-		for _, uri := range m.CompiledGoFiles {
+-			s.storeDiagnostics(snapshot, uri, typeCheckSource, pkgDiags[uri], true)
+-			storedPkgDiags[uri] = true
+-		}
+-	}
+-	// Store the package diagnostics.
+-	for uri, diags := range pkgDiags {
+-		if storedPkgDiags[uri] {
+-			continue
+-		}
+-		// builtin.go exists only for documentation purposes, and is not valid Go code.
+-		// Don't report distracting errors
+-		if snapshot.IsBuiltin(uri) {
+-			bug.Reportf("type checking reported diagnostics for the builtin file: %v", diags)
+-			continue
+-		}
+-		s.storeDiagnostics(snapshot, uri, typeCheckSource, diags, true)
+-	}
+-
+-	// Process requested gc_details diagnostics.
+-	//
+-	// TODO(rfindley): this could be improved:
+-	//   1. This should memoize its results if the package has not changed.
+-	//   2. This should not even run gc_details if the package contains unsaved
+-	//      files.
+-	//   3. See note below about using FindFile.
+-	var toGCDetail map[source.PackageID]*source.Metadata
 -	s.gcOptimizationDetailsMu.Lock()
--	_, enableGCDetails := s.gcOptimizationDetails[m.ID]
+-	for id := range s.gcOptimizationDetails {
+-		if m, ok := toDiagnose[id]; ok {
+-			if toGCDetail == nil {
+-				toGCDetail = make(map[source.PackageID]*source.Metadata)
+-			}
+-			toGCDetail[id] = m
+-		}
+-	}
 -	s.gcOptimizationDetailsMu.Unlock()
--	if enableGCDetails {
+-
+-	for _, m := range toGCDetail {
 -		gcReports, err := source.GCOptimizationDetails(ctx, snapshot, m)
 -		if err != nil {
 -			event.Error(ctx, "warning: gc details", err, append(source.SnapshotLabels(snapshot), tag.Package.Of(string(m.ID)))...)
@@ -35211,10 +39814,13 @@
 -		// diagnostics does not race with storing the results here.
 -		if enableGCDetails {
 -			for uri, diags := range gcReports {
+-				// TODO(rfindley): remove the use of FindFile here, and use ReadFile
+-				// instead. Isn't it enough to know that the package came from the
+-				// snapshot? Any reports should apply to the snapshot.
 -				fh := snapshot.FindFile(uri)
 -				// Don't publish gc details for unsaved buffers, since the underlying
 -				// logic operates on the file on disk.
--				if fh == nil || !fh.Saved() {
+-				if fh == nil || !fh.SameContentsOnDisk() {
 -					continue
 -				}
 -				s.storeDiagnostics(snapshot, uri, gcDetailsSource, diags, true)
@@ -35236,7 +39842,7 @@
 -	if s.diagnostics[uri] == nil {
 -		s.diagnostics[uri] = &fileReports{
 -			publishedHash: hashDiagnostics(), // Hash for 0 diagnostics.
--			reports:       map[diagnosticSource]diagnosticReport{},
+-			reports:       map[diagnosticSource]*diagnosticReport{},
 -		}
 -	}
 -	s.diagnostics[uri].mustPublish = true
@@ -35245,6 +39851,8 @@
 -// storeDiagnostics stores results from a single diagnostic source. If merge is
 -// true, it merges results into any existing results for this snapshot.
 -//
+-// Mutates (sorts) diags.
+-//
 -// TODO(hyangah): investigate whether we can unconditionally overwrite previous report.diags
 -// with the new diags and eliminate the need for the `merge` flag.
 -func (s *Server) storeDiagnostics(snapshot source.Snapshot, uri span.URI, dsource diagnosticSource, diags []*source.Diagnostic, merge bool) {
@@ -35260,10 +39868,14 @@
 -	if s.diagnostics[uri] == nil {
 -		s.diagnostics[uri] = &fileReports{
 -			publishedHash: hashDiagnostics(), // Hash for 0 diagnostics.
--			reports:       map[diagnosticSource]diagnosticReport{},
+-			reports:       map[diagnosticSource]*diagnosticReport{},
 -		}
 -	}
 -	report := s.diagnostics[uri].reports[dsource]
+-	if report == nil {
+-		report = new(diagnosticReport)
+-		s.diagnostics[uri].reports[dsource] = report
+-	}
 -	// Don't set obsolete diagnostics.
 -	if report.snapshotID > snapshot.GlobalID() {
 -		return
@@ -35275,7 +39887,6 @@
 -	for _, d := range diags {
 -		report.diags[hashDiagnostics(d)] = d
 -	}
--	s.diagnostics[uri].reports[dsource] = report
 -}
 -
 -// clearDiagnosticSource clears all diagnostics for a given source type. It is
@@ -35303,7 +39914,7 @@
 -	if err != nil {
 -		event.Error(ctx, "errors loading workspace", err.MainError, source.SnapshotLabels(snapshot)...)
 -		for _, d := range err.Diagnostics {
--			s.storeDiagnostics(snapshot, d.URI, modSource, []*source.Diagnostic{d}, true)
+-			s.storeDiagnostics(snapshot, d.URI, modParseSource, []*source.Diagnostic{d}, true)
 -		}
 -		errMsg = strings.ReplaceAll(err.MainError.Error(), "\n", " ")
 -	}
@@ -35325,66 +39936,6 @@
 -	}
 -}
 -
--// checkForOrphanedFile checks that the given URIs can be mapped to packages.
--// If they cannot and the workspace is not otherwise unloaded, it also surfaces
--// a warning, suggesting that the user check the file for build tags.
--func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) *source.Diagnostic {
--	// TODO(rfindley): this function may fail to produce a diagnostic for a
--	// variety of reasons, some of which should probably not be ignored. For
--	// example, should this function be tolerant of the case where fh does not
--	// exist, or does not have a package name?
--	//
--	// It would be better to panic or report a bug in several of the cases below,
--	// so that we can move toward guaranteeing we show the user a meaningful
--	// error whenever it makes sense.
--	if snapshot.View().FileKind(fh) != source.Go {
--		return nil
--	}
--	// builtin files won't have a package, but they are never orphaned.
--	if snapshot.IsBuiltin(ctx, fh.URI()) {
--		return nil
--	}
--
--	// This call has the effect of inserting fh into snapshot.files,
--	// where for better or worse (actually: just worse) it influences
--	// the sets of open, known, and orphaned files.
--	snapshot.GetFile(ctx, fh.URI())
--
--	metas, _ := snapshot.MetadataForFile(ctx, fh.URI())
--	if len(metas) > 0 || ctx.Err() != nil {
--		return nil // no package, or cancelled
--	}
--	// Inv: file does not belong to a package we know about.
--	pgf, err := snapshot.ParseGo(ctx, fh, source.ParseHeader)
--	if err != nil {
--		return nil
--	}
--	if !pgf.File.Name.Pos().IsValid() {
--		return nil
--	}
--	rng, err := pgf.NodeRange(pgf.File.Name)
--	if err != nil {
--		return nil
--	}
--	// If the file no longer has a name ending in .go, this diagnostic is wrong
--	if filepath.Ext(fh.URI().Filename()) != ".go" {
--		return nil
--	}
--	// TODO(rstambler): We should be able to parse the build tags in the
--	// file and show a more specific error message. For now, put the diagnostic
--	// on the package declaration.
--	return &source.Diagnostic{
--		URI:      fh.URI(),
--		Range:    rng,
--		Severity: protocol.SeverityWarning,
--		Source:   source.ListError,
--		Message: fmt.Sprintf(`No packages found for open file %s: %v.
--If this file contains build tags, try adding "-tags=<build tag>" to your gopls "buildFlags" configuration (see (https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string).
--Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).
--`, fh.URI().Filename(), err),
--	}
--}
--
 -// publishDiagnostics collects and publishes any unpublished diagnostic reports.
 -func (s *Server) publishDiagnostics(ctx context.Context, final bool, snapshot source.Snapshot) {
 -	ctx, done := event.Start(ctx, "Server.publishDiagnostics", source.SnapshotLabels(snapshot)...)
@@ -35422,6 +39973,7 @@
 -				diags = append(diags, d)
 -				reportDiags = append(reportDiags, d)
 -			}
+-
 -			hash := hashDiagnostics(reportDiags...)
 -			if hash != report.publishedHash {
 -				anyReportsChanged = true
@@ -35435,7 +39987,6 @@
 -			continue
 -		}
 -
--		source.SortDiagnostics(diags)
 -		hash := hashDiagnostics(diags...)
 -		if hash == r.publishedHash && !r.mustPublish {
 -			// Update snapshotID to be the latest snapshot for which this diagnostic
@@ -35455,15 +40006,22 @@
 -			r.publishedHash = hash
 -			r.mustPublish = false // diagnostics have been successfully published
 -			r.publishedSnapshotID = snapshot.GlobalID()
--			for dsource, hash := range reportHashes {
--				report := r.reports[dsource]
--				report.publishedHash = hash
--				r.reports[dsource] = report
+-			// When we publish diagnostics for a file, we must update the
+-			// publishedHash for every report, not just the reports that were
+-			// published. Eliding a report is equivalent to publishing empty
+-			// diagnostics.
+-			for dsource, report := range r.reports {
+-				if hash, ok := reportHashes[dsource]; ok {
+-					report.publishedHash = hash
+-				} else {
+-					// The report was not (yet) stored for this snapshot. Record that we
+-					// published no diagnostics from this source.
+-					report.publishedHash = hashDiagnostics()
+-				}
 -			}
 -		} else {
 -			if ctx.Err() != nil {
 -				// Publish may have failed due to a cancelled context.
--				log.Trace.Log(ctx, "publish cancelled")
 -				return
 -			}
 -			event.Error(ctx, "publishReports: failed to deliver diagnostic", err, tag.URI.Of(uri))
@@ -35480,8 +40038,9 @@
 -			Range:              diag.Range,
 -			Severity:           diag.Severity,
 -			Source:             string(diag.Source),
--			Tags:               diag.Tags,
+-			Tags:               emptySliceDiagnosticTag(diag.Tags),
 -			RelatedInformation: diag.Related,
+-			Data:               diag.BundledFixes,
 -		}
 -		if diag.Code != "" {
 -			pdiag.Code = diag.Code
@@ -35502,6 +40061,8 @@
 -		return true
 -	}
 -	// If the folder has no Go code in it, we shouldn't spam the user with a warning.
+-	// TODO(rfindley): surely it is not correct to walk the folder here just to
+-	// suppress diagnostics, every time we compute diagnostics.
 -	var hasGo bool
 -	_ = filepath.Walk(snapshot.View().Folder().Filename(), func(path string, info os.FileInfo, err error) error {
 -		if err != nil {
@@ -35537,7 +40098,7 @@
 -	return ans
 -}
 -
--func auxStr(v *source.Diagnostic, d diagnosticReport, typ diagnosticSource) string {
+-func auxStr(v *source.Diagnostic, d *diagnosticReport, typ diagnosticSource) string {
 -	// Tags? RelatedInformation?
 -	msg := fmt.Sprintf("(%s)%q(source:%q,code:%q,severity:%s,snapshot:%d,type:%s)",
 -		v.Range, v.Message, v.Source, v.Code, v.Severity, d.snapshotID, typ)
@@ -35548,8 +40109,8 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/client.go b/gopls/internal/lsp/fake/client.go
 --- a/gopls/internal/lsp/fake/client.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/client.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,187 +0,0 @@
++++ b/gopls/internal/lsp/fake/client.go	1970-01-01 08:00:00
+@@ -1,193 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -35566,7 +40127,7 @@
 -)
 -
 -// ClientHooks are a set of optional hooks called during handling of
--// the corresponding client method (see protocol.Client for the the
+-// the corresponding client method (see protocol.Client for the
 -// LSP server-to-client RPCs) in order to make test expectations
 -// awaitable.
 -type ClientHooks struct {
@@ -35574,6 +40135,7 @@
 -	OnDiagnostics            func(context.Context, *protocol.PublishDiagnosticsParams) error
 -	OnWorkDoneProgressCreate func(context.Context, *protocol.WorkDoneProgressCreateParams) error
 -	OnProgress               func(context.Context, *protocol.ProgressParams) error
+-	OnShowDocument           func(context.Context, *protocol.ShowDocumentParams) error
 -	OnShowMessage            func(context.Context, *protocol.ShowMessageParams) error
 -	OnShowMessageRequest     func(context.Context, *protocol.ShowMessageRequestParams) error
 -	OnRegisterCapability     func(context.Context, *protocol.RegistrationParams) error
@@ -35614,10 +40176,10 @@
 -			return nil, err
 -		}
 -	}
--	if len(params.Actions) == 0 || len(params.Actions) > 1 {
--		return nil, fmt.Errorf("fake editor cannot handle multiple action items")
+-	if c.editor.config.MessageResponder != nil {
+-		return c.editor.config.MessageResponder(params)
 -	}
--	return &params.Actions[0], nil
+-	return nil, nil // don't choose, which is effectively dismissing the message
 -}
 -
 -func (c *Client) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error {
@@ -35646,9 +40208,8 @@
 -	results := make([]interface{}, len(p.Items))
 -	for i, item := range p.Items {
 -		if item.Section == "gopls" {
--			c.editor.mu.Lock()
--			results[i] = c.editor.settingsLocked()
--			c.editor.mu.Unlock()
+-			config := c.editor.Config()
+-			results[i] = makeSettings(c.editor.sandbox, config)
 -		}
 -	}
 -	return results, nil
@@ -35715,7 +40276,13 @@
 -	return nil
 -}
 -
--func (c *Client) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
+-func (c *Client) ShowDocument(ctx context.Context, params *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
+-	if c.hooks.OnShowDocument != nil {
+-		if err := c.hooks.OnShowDocument(ctx, params); err != nil {
+-			return nil, err
+-		}
+-		return &protocol.ShowDocumentResult{Success: true}, nil
+-	}
 -	return nil, nil
 -}
 -
@@ -35739,7 +40306,7 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/doc.go b/gopls/internal/lsp/fake/doc.go
 --- a/gopls/internal/lsp/fake/doc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/doc.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/doc.go	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -35762,7 +40329,7 @@
 -package fake
 diff -urN a/gopls/internal/lsp/fake/edit.go b/gopls/internal/lsp/fake/edit.go
 --- a/gopls/internal/lsp/fake/edit.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/edit.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/edit.go	1970-01-01 08:00:00
 @@ -1,51 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -35815,10 +40382,110 @@
 -	}
 -	return patched, nil
 -}
+diff -urN a/gopls/internal/lsp/fake/edit_test.go b/gopls/internal/lsp/fake/edit_test.go
+--- a/gopls/internal/lsp/fake/edit_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/fake/edit_test.go	1970-01-01 08:00:00
+@@ -1,96 +0,0 @@
+-// Copyright 2020 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package fake
+-
+-import (
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
+-
+-func TestApplyEdits(t *testing.T) {
+-	tests := []struct {
+-		label   string
+-		content string
+-		edits   []protocol.TextEdit
+-		want    string
+-		wantErr bool
+-	}{
+-		{
+-			label: "empty content",
+-		},
+-		{
+-			label:   "empty edit",
+-			content: "hello",
+-			edits:   []protocol.TextEdit{},
+-			want:    "hello",
+-		},
+-		{
+-			label:   "unicode edit",
+-			content: "hello, 日本語",
+-			edits: []protocol.TextEdit{
+-				NewEdit(0, 7, 0, 10, "world"),
+-			},
+-			want: "hello, world",
+-		},
+-		{
+-			label:   "range edit",
+-			content: "ABC\nDEF\nGHI\nJKL",
+-			edits: []protocol.TextEdit{
+-				NewEdit(1, 1, 2, 3, "12\n345"),
+-			},
+-			want: "ABC\nD12\n345\nJKL",
+-		},
+-		{
+-			label:   "regression test for issue #57627",
+-			content: "go 1.18\nuse moda/a",
+-			edits: []protocol.TextEdit{
+-				NewEdit(1, 0, 1, 0, "\n"),
+-				NewEdit(2, 0, 2, 0, "\n"),
+-			},
+-			want: "go 1.18\n\nuse moda/a\n",
+-		},
+-		{
+-			label:   "end before start",
+-			content: "ABC\nDEF\nGHI\nJKL",
+-			edits: []protocol.TextEdit{
+-				NewEdit(2, 3, 1, 1, "12\n345"),
+-			},
+-			wantErr: true,
+-		},
+-		{
+-			label:   "out of bounds line",
+-			content: "ABC\nDEF\nGHI\nJKL",
+-			edits: []protocol.TextEdit{
+-				NewEdit(1, 1, 4, 3, "12\n345"),
+-			},
+-			wantErr: true,
+-		},
+-		{
+-			label:   "out of bounds column",
+-			content: "ABC\nDEF\nGHI\nJKL",
+-			edits: []protocol.TextEdit{
+-				NewEdit(1, 4, 2, 3, "12\n345"),
+-			},
+-			wantErr: true,
+-		},
+-	}
+-
+-	for _, test := range tests {
+-		test := test
+-		t.Run(test.label, func(t *testing.T) {
+-			got, err := applyEdits(protocol.NewMapper("", []byte(test.content)), test.edits, false)
+-			if (err != nil) != test.wantErr {
+-				t.Errorf("got err %v, want error: %t", err, test.wantErr)
+-			}
+-			if err != nil {
+-				return
+-			}
+-			if got := string(got); got != test.want {
+-				t.Errorf("got %q, want %q", got, test.want)
+-			}
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/lsp/fake/editor.go b/gopls/internal/lsp/fake/editor.go
 --- a/gopls/internal/lsp/fake/editor.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/editor.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1464 +0,0 @@
++++ b/gopls/internal/lsp/fake/editor.go	1970-01-01 08:00:00
+@@ -1,1494 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -35828,6 +40495,7 @@
 -import (
 -	"bytes"
 -	"context"
+-	"encoding/json"
 -	"errors"
 -	"fmt"
 -	"os"
@@ -35858,7 +40526,6 @@
 -	serverConn jsonrpc2.Conn
 -	client     *Client
 -	sandbox    *Sandbox
--	defaultEnv map[string]string
 -
 -	// TODO(adonovan): buffers should be keyed by protocol.DocumentURI.
 -	mu                 sync.Mutex
@@ -35877,7 +40544,7 @@
 -
 -// CallCounts tracks the number of protocol notifications of different types.
 -type CallCounts struct {
--	DidOpen, DidChange, DidSave, DidChangeWatchedFiles, DidClose uint64
+-	DidOpen, DidChange, DidSave, DidChangeWatchedFiles, DidClose, DidChangeConfiguration uint64
 -}
 -
 -// buffer holds information about an open buffer in the editor.
@@ -35896,8 +40563,14 @@
 -// source.UserOptions, but we use a separate type here so that we expose only
 -// that configuration which we support.
 -//
--// The zero value for EditorConfig should correspond to its defaults.
+-// The zero value for EditorConfig is the default configuration.
 -type EditorConfig struct {
+-	// ClientName sets the clientInfo.name for the LSP session (in the initialize request).
+-	//
+-	// Since this can only be set during initialization, changing this field via
+-	// Editor.ChangeConfiguration has no effect.
+-	ClientName string
+-
 -	// Env holds environment variables to apply on top of the default editor
 -	// environment. When applying these variables, the special string
 -	// $SANDBOX_WORKDIR is replaced by the absolute path to the sandbox working
@@ -35925,15 +40598,25 @@
 -
 -	// Settings holds user-provided configuration for the LSP server.
 -	Settings map[string]interface{}
+-
+-	// CapabilitiesJSON holds JSON client capabilities to overlay over the
+-	// editor's default client capabilities.
+-	//
+-	// Specifically, this JSON string will be unmarshalled into the editor's
+-	// client capabilities struct, before sending to the server.
+-	CapabilitiesJSON []byte
+-
+-	// If non-nil, MessageResponder is used to respond to ShowMessageRequest
+-	// messages.
+-	MessageResponder func(params *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error)
 -}
 -
 -// NewEditor creates a new Editor.
 -func NewEditor(sandbox *Sandbox, config EditorConfig) *Editor {
 -	return &Editor{
--		buffers:    make(map[string]buffer),
--		sandbox:    sandbox,
--		defaultEnv: sandbox.GoEnv(),
--		config:     config,
+-		buffers: make(map[string]buffer),
+-		sandbox: sandbox,
+-		config:  config,
 -	}
 -}
 -
@@ -36019,19 +40702,17 @@
 -	return e.client
 -}
 -
--// settingsLocked builds the settings map for use in LSP settings RPCs.
--//
--// e.mu must be held while calling this function.
--func (e *Editor) settingsLocked() map[string]interface{} {
+-// makeSettings builds the settings map for use in LSP settings RPCs.
+-func makeSettings(sandbox *Sandbox, config EditorConfig) map[string]interface{} {
 -	env := make(map[string]string)
--	for k, v := range e.defaultEnv {
+-	for k, v := range sandbox.GoEnv() {
 -		env[k] = v
 -	}
--	for k, v := range e.config.Env {
+-	for k, v := range config.Env {
 -		env[k] = v
 -	}
 -	for k, v := range env {
--		v = strings.ReplaceAll(v, "$SANDBOX_WORKDIR", e.sandbox.Workdir.RootURI().SpanURI().Filename())
+-		v = strings.ReplaceAll(v, "$SANDBOX_WORKDIR", sandbox.Workdir.RootURI().SpanURI().Filename())
 -		env[k] = v
 -	}
 -
@@ -36042,16 +40723,12 @@
 -		// asynchronous operations being completed (such as diagnosing a snapshot).
 -		"verboseWorkDoneProgress": true,
 -
--		// Set a generous completion budget, so that tests don't flake because
+-		// Set an unlimited completion budget, so that tests don't flake because
 -		// completions are too slow.
--		"completionBudget": "10s",
--
--		// Shorten the diagnostic delay to speed up test execution (else we'd add
--		// the default delay to each assertion about diagnostics)
--		"diagnosticsDelay": "10ms",
+-		"completionBudget": "0s",
 -	}
 -
--	for k, v := range e.config.Settings {
+-	for k, v := range config.Settings {
 -		if k == "env" {
 -			panic("must not provide env via the EditorConfig.Settings field: use the EditorConfig.Env field instead")
 -		}
@@ -36062,23 +40739,23 @@
 -}
 -
 -func (e *Editor) initialize(ctx context.Context) error {
+-	config := e.Config()
+-
 -	params := &protocol.ParamInitialize{}
--	params.ClientInfo = &protocol.Msg_XInitializeParams_clientInfo{}
--	params.ClientInfo.Name = "fakeclient"
--	params.ClientInfo.Version = "v1.0.0"
--	e.mu.Lock()
--	params.WorkspaceFolders = e.makeWorkspaceFoldersLocked()
--	params.InitializationOptions = e.settingsLocked()
--	e.mu.Unlock()
--	params.Capabilities.Workspace.Configuration = true
--	params.Capabilities.Window.WorkDoneProgress = true
+-	if e.config.ClientName != "" {
+-		params.ClientInfo = &protocol.Msg_XInitializeParams_clientInfo{}
+-		params.ClientInfo.Name = e.config.ClientName
+-		params.ClientInfo.Version = "v1.0.0"
+-	}
+-	params.InitializationOptions = makeSettings(e.sandbox, config)
+-	params.WorkspaceFolders = makeWorkspaceFolders(e.sandbox, config.WorkspaceFolders)
 -
--	// TODO: set client capabilities
+-	// Set various client capabilities that are sought by gopls.
+-	params.Capabilities.Workspace.Configuration = true // support workspace/configuration
+-	params.Capabilities.Window.WorkDoneProgress = true // support window/workDoneProgress
 -	params.Capabilities.TextDocument.Completion.CompletionItem.TagSupport.ValueSet = []protocol.CompletionItemTag{protocol.ComplDeprecated}
--
 -	params.Capabilities.TextDocument.Completion.CompletionItem.SnippetSupport = true
 -	params.Capabilities.TextDocument.SemanticTokens.Requests.Full.Value = true
--	// copied from lsp/semantic.go to avoid import cycle in tests
 -	params.Capabilities.TextDocument.SemanticTokens.TokenTypes = []string{
 -		"namespace", "type", "class", "enum", "interface",
 -		"struct", "typeParameter", "parameter", "variable", "property", "enumMember",
@@ -36089,17 +40766,25 @@
 -		"declaration", "definition", "readonly", "static",
 -		"deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary",
 -	}
--
--	// This is a bit of a hack, since the fake editor doesn't actually support
--	// watching changed files that match a specific glob pattern. However, the
--	// editor does send didChangeWatchedFiles notifications, so set this to
--	// true.
+-	// The LSP tests have historically enabled this flag,
+-	// but really we should test both ways for older editors.
+-	params.Capabilities.TextDocument.DocumentSymbol.HierarchicalDocumentSymbolSupport = true
+-	// Glob pattern watching is enabled.
 -	params.Capabilities.Workspace.DidChangeWatchedFiles.DynamicRegistration = true
+-	// "rename" operations are used for package renaming.
+-	//
+-	// TODO(rfindley): add support for other resource operations (create, delete, ...)
 -	params.Capabilities.Workspace.WorkspaceEdit = &protocol.WorkspaceEditClientCapabilities{
 -		ResourceOperations: []protocol.ResourceOperationKind{
 -			"rename",
 -		},
 -	}
+-	// Apply capabilities overlay.
+-	if config.CapabilitiesJSON != nil {
+-		if err := json.Unmarshal(config.CapabilitiesJSON, &params.Capabilities); err != nil {
+-			return fmt.Errorf("unmarshalling EditorConfig.CapabilitiesJSON: %v", err)
+-		}
+-	}
 -
 -	trace := protocol.TraceValues("messages")
 -	params.Trace = &trace
@@ -36121,18 +40806,25 @@
 -	return nil
 -}
 -
--// makeWorkspaceFoldersLocked creates a slice of workspace folders to use for
+-// HasCommand reports whether the connected server supports the command with the given ID.
+-func (e *Editor) HasCommand(id string) bool {
+-	for _, command := range e.serverCapabilities.ExecuteCommandProvider.Commands {
+-		if command == id {
+-			return true
+-		}
+-	}
+-	return false
+-}
+-
+-// makeWorkspaceFolders creates a slice of workspace folders to use for
 -// this editing session, based on the editor configuration.
--//
--// e.mu must be held while calling this function.
--func (e *Editor) makeWorkspaceFoldersLocked() (folders []protocol.WorkspaceFolder) {
--	paths := e.config.WorkspaceFolders
+-func makeWorkspaceFolders(sandbox *Sandbox, paths []string) (folders []protocol.WorkspaceFolder) {
 -	if len(paths) == 0 {
--		paths = append(paths, string(e.sandbox.Workdir.RelativeTo))
+-		paths = []string{string(sandbox.Workdir.RelativeTo)}
 -	}
 -
 -	for _, path := range paths {
--		uri := string(e.sandbox.Workdir.URI(path))
+-		uri := string(sandbox.Workdir.URI(path))
 -		folders = append(folders, protocol.WorkspaceFolder{
 -			URI:  uri,
 -			Name: filepath.Base(uri),
@@ -36594,10 +41286,7 @@
 -
 -// GoToDefinition jumps to the definition of the symbol at the given position
 -// in an open buffer. It returns the location of the resulting jump.
--//
--// TODO(rfindley): rename to "Definition", to be consistent with LSP
--// terminology.
--func (e *Editor) GoToDefinition(ctx context.Context, loc protocol.Location) (protocol.Location, error) {
+-func (e *Editor) Definition(ctx context.Context, loc protocol.Location) (protocol.Location, error) {
 -	if err := e.checkBufferLocation(loc); err != nil {
 -		return protocol.Location{}, err
 -	}
@@ -36612,9 +41301,9 @@
 -	return e.extractFirstLocation(ctx, resp)
 -}
 -
--// GoToTypeDefinition jumps to the type definition of the symbol at the given location
--// in an open buffer.
--func (e *Editor) GoToTypeDefinition(ctx context.Context, loc protocol.Location) (protocol.Location, error) {
+-// TypeDefinition jumps to the type definition of the symbol at the given
+-// location in an open buffer.
+-func (e *Editor) TypeDefinition(ctx context.Context, loc protocol.Location) (protocol.Location, error) {
 -	if err := e.checkBufferLocation(loc); err != nil {
 -		return protocol.Location{}, err
 -	}
@@ -37150,19 +41839,26 @@
 -	return e.config
 -}
 -
+-func (e *Editor) SetConfig(cfg EditorConfig) {
+-	e.mu.Lock()
+-	e.config = cfg
+-	e.mu.Unlock()
+-}
+-
 -// ChangeConfiguration sets the new editor configuration, and if applicable
 -// sends a didChangeConfiguration notification.
 -//
 -// An error is returned if the change notification failed to send.
 -func (e *Editor) ChangeConfiguration(ctx context.Context, newConfig EditorConfig) error {
--	e.mu.Lock()
--	e.config = newConfig
--	e.mu.Unlock() // don't hold e.mu during server calls
+-	e.SetConfig(newConfig)
 -	if e.Server != nil {
 -		var params protocol.DidChangeConfigurationParams // empty: gopls ignores the Settings field
 -		if err := e.Server.DidChangeConfiguration(ctx, &params); err != nil {
 -			return err
 -		}
+-		e.callsMu.Lock()
+-		e.calls.DidChangeConfiguration++
+-		e.callsMu.Unlock()
 -	}
 -	return nil
 -}
@@ -37172,12 +41868,13 @@
 -//
 -// The given folders must all be unique.
 -func (e *Editor) ChangeWorkspaceFolders(ctx context.Context, folders []string) error {
+-	config := e.Config()
+-
 -	// capture existing folders so that we can compute the change.
--	e.mu.Lock()
--	oldFolders := e.makeWorkspaceFoldersLocked()
--	e.config.WorkspaceFolders = folders
--	newFolders := e.makeWorkspaceFoldersLocked()
--	e.mu.Unlock()
+-	oldFolders := makeWorkspaceFolders(e.sandbox, config.WorkspaceFolders)
+-	newFolders := makeWorkspaceFolders(e.sandbox, folders)
+-	config.WorkspaceFolders = folders
+-	e.SetConfig(config)
 -
 -	if e.Server == nil {
 -		return nil
@@ -37285,7 +41982,7 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/editor_test.go b/gopls/internal/lsp/fake/editor_test.go
 --- a/gopls/internal/lsp/fake/editor_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/editor_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/editor_test.go	1970-01-01 08:00:00
 @@ -1,61 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -37348,109 +42045,9 @@
 -		t.Errorf("got text %q, want %q", got, want)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/fake/edit_test.go b/gopls/internal/lsp/fake/edit_test.go
---- a/gopls/internal/lsp/fake/edit_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/edit_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,96 +0,0 @@
--// Copyright 2020 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package fake
--
--import (
--	"testing"
--
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
--)
--
--func TestApplyEdits(t *testing.T) {
--	tests := []struct {
--		label   string
--		content string
--		edits   []protocol.TextEdit
--		want    string
--		wantErr bool
--	}{
--		{
--			label: "empty content",
--		},
--		{
--			label:   "empty edit",
--			content: "hello",
--			edits:   []protocol.TextEdit{},
--			want:    "hello",
--		},
--		{
--			label:   "unicode edit",
--			content: "hello, 日本語",
--			edits: []protocol.TextEdit{
--				NewEdit(0, 7, 0, 10, "world"),
--			},
--			want: "hello, world",
--		},
--		{
--			label:   "range edit",
--			content: "ABC\nDEF\nGHI\nJKL",
--			edits: []protocol.TextEdit{
--				NewEdit(1, 1, 2, 3, "12\n345"),
--			},
--			want: "ABC\nD12\n345\nJKL",
--		},
--		{
--			label:   "regression test for issue #57627",
--			content: "go 1.18\nuse moda/a",
--			edits: []protocol.TextEdit{
--				NewEdit(1, 0, 1, 0, "\n"),
--				NewEdit(2, 0, 2, 0, "\n"),
--			},
--			want: "go 1.18\n\nuse moda/a\n",
--		},
--		{
--			label:   "end before start",
--			content: "ABC\nDEF\nGHI\nJKL",
--			edits: []protocol.TextEdit{
--				NewEdit(2, 3, 1, 1, "12\n345"),
--			},
--			wantErr: true,
--		},
--		{
--			label:   "out of bounds line",
--			content: "ABC\nDEF\nGHI\nJKL",
--			edits: []protocol.TextEdit{
--				NewEdit(1, 1, 4, 3, "12\n345"),
--			},
--			wantErr: true,
--		},
--		{
--			label:   "out of bounds column",
--			content: "ABC\nDEF\nGHI\nJKL",
--			edits: []protocol.TextEdit{
--				NewEdit(1, 4, 2, 3, "12\n345"),
--			},
--			wantErr: true,
--		},
--	}
--
--	for _, test := range tests {
--		test := test
--		t.Run(test.label, func(t *testing.T) {
--			got, err := applyEdits(protocol.NewMapper("", []byte(test.content)), test.edits, false)
--			if (err != nil) != test.wantErr {
--				t.Errorf("got err %v, want error: %t", err, test.wantErr)
--			}
--			if err != nil {
--				return
--			}
--			if got := string(got); got != test.want {
--				t.Errorf("got %q, want %q", got, test.want)
--			}
--		})
--	}
--}
 diff -urN a/gopls/internal/lsp/fake/proxy.go b/gopls/internal/lsp/fake/proxy.go
 --- a/gopls/internal/lsp/fake/proxy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/proxy.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/proxy.go	1970-01-01 08:00:00
 @@ -1,35 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -37489,7 +42086,7 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/sandbox.go b/gopls/internal/lsp/fake/sandbox.go
 --- a/gopls/internal/lsp/fake/sandbox.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/sandbox.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/sandbox.go	1970-01-01 08:00:00
 @@ -1,299 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -37501,7 +42098,6 @@
 -	"context"
 -	"errors"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"strings"
@@ -37585,7 +42181,7 @@
 -
 -	rootDir := config.RootDir
 -	if rootDir == "" {
--		rootDir, err = ioutil.TempDir(config.RootDir, "gopls-sandbox-")
+-		rootDir, err = os.MkdirTemp(config.RootDir, "gopls-sandbox-")
 -		if err != nil {
 -			return nil, fmt.Errorf("creating temporary workdir: %v", err)
 -		}
@@ -37643,7 +42239,7 @@
 -// is the responsibility of the caller to call os.RemoveAll on the returned
 -// file path when it is no longer needed.
 -func Tempdir(files map[string][]byte) (string, error) {
--	dir, err := ioutil.TempDir("", "gopls-tempdir-")
+-	dir, err := os.MkdirTemp("", "gopls-tempdir-")
 -	if err != nil {
 -		return "", err
 -	}
@@ -37747,10 +42343,11 @@
 -// RunGoCommand executes a go command in the sandbox. If checkForFileChanges is
 -// true, the sandbox scans the working directory and emits file change events
 -// for any file changes it finds.
--func (sb *Sandbox) RunGoCommand(ctx context.Context, dir, verb string, args []string, checkForFileChanges bool) error {
+-func (sb *Sandbox) RunGoCommand(ctx context.Context, dir, verb string, args, env []string, checkForFileChanges bool) error {
 -	inv := sb.goCommandInvocation()
 -	inv.Verb = verb
 -	inv.Args = args
+-	inv.Env = append(inv.Env, env...)
 -	if dir != "" {
 -		inv.WorkingDir = sb.Workdir.AbsPath(dir)
 -	}
@@ -37759,7 +42356,7 @@
 -		return fmt.Errorf("go command failed (stdout: %s) (stderr: %s): %v", stdout.String(), stderr.String(), err)
 -	}
 -	// Since running a go command may result in changes to workspace files,
--	// check if we need to send any any "watched" file events.
+-	// check if we need to send any "watched" file events.
 -	//
 -	// TODO(rFindley): this side-effect can impact the usability of the sandbox
 -	//                 for benchmarks. Consider refactoring.
@@ -37782,7 +42379,7 @@
 -func (sb *Sandbox) Close() error {
 -	var goCleanErr error
 -	if sb.gopath != "" {
--		goCleanErr = sb.RunGoCommand(context.Background(), "", "clean", []string{"-modcache"}, false)
+-		goCleanErr = sb.RunGoCommand(context.Background(), "", "clean", []string{"-modcache"}, nil, false)
 -	}
 -	err := robustio.RemoveAll(sb.rootdir)
 -	if err != nil || goCleanErr != nil {
@@ -37792,8 +42389,8 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/workdir.go b/gopls/internal/lsp/fake/workdir.go
 --- a/gopls/internal/lsp/fake/workdir.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/workdir.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,438 +0,0 @@
++++ b/gopls/internal/lsp/fake/workdir.go	1970-01-01 08:00:00
+@@ -1,430 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -37806,7 +42403,6 @@
 -	"crypto/sha256"
 -	"fmt"
 -	"io/fs"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"runtime"
@@ -37853,7 +42449,7 @@
 -	}
 -	backoff := 1 * time.Millisecond
 -	for {
--		err := ioutil.WriteFile(fp, []byte(content), 0644)
+-		err := os.WriteFile(fp, []byte(content), 0644)
 -		if err != nil {
 -			// This lock file violation is not handled by the robustio package, as it
 -			// indicates a real race condition that could be avoided.
@@ -37916,7 +42512,7 @@
 -// fileID identifies a file version on disk.
 -type fileID struct {
 -	mtime time.Time
--	hash  string // empty if mtime is old enough to be reliabe; otherwise a file digest
+-	hash  string // empty if mtime is old enough to be reliable; otherwise a file digest
 -}
 -
 -func hashFile(data []byte) string {
@@ -37956,7 +42552,7 @@
 -func (w *Workdir) ReadFile(path string) ([]byte, error) {
 -	backoff := 1 * time.Millisecond
 -	for {
--		b, err := ioutil.ReadFile(w.AbsPath(path))
+-		b, err := os.ReadFile(w.AbsPath(path))
 -		if err != nil {
 -			if runtime.GOOS == "plan9" && strings.HasSuffix(err.Error(), " exclusive use file already open") {
 -				// Plan 9 enforces exclusive access to locked files.
@@ -38015,13 +42611,6 @@
 -	return w.WriteFiles(ctx, map[string]string{path: content})
 -}
 -
--func (w *Workdir) fileEvent(path string, changeType protocol.FileChangeType) protocol.FileEvent {
--	return protocol.FileEvent{
--		URI:  w.URI(path),
--		Type: changeType,
--	}
--}
--
 -// RenameFile performs an on disk-renaming of the workdir-relative oldPath to
 -// workdir-relative newPath, and notifies watchers of the changes.
 -//
@@ -38166,14 +42755,14 @@
 -			return nil
 -		}
 -
--		// Opt: avoid reading the file if mtime is sufficently old to be reliable.
+-		// Opt: avoid reading the file if mtime is sufficiently old to be reliable.
 -		//
 -		// If mtime is recent, it may not sufficiently identify the file contents:
 -		// a subsequent write could result in the same mtime. For these cases, we
 -		// must read the file contents.
 -		id := fileID{mtime: info.ModTime()}
 -		if time.Since(info.ModTime()) < 2*time.Second {
--			data, err := ioutil.ReadFile(fp)
+-			data, err := os.ReadFile(fp)
 -			if err != nil {
 -				return err
 -			}
@@ -38200,7 +42789,7 @@
 -				// In this case, read the content to check whether the file actually
 -				// changed.
 -				if oldID.mtime.Equal(id.mtime) && oldID.hash != "" && id.hash == "" {
--					data, err := ioutil.ReadFile(fp)
+-					data, err := os.ReadFile(fp)
 -					if err != nil {
 -						return err
 -					}
@@ -38234,8 +42823,8 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/workdir_test.go b/gopls/internal/lsp/fake/workdir_test.go
 --- a/gopls/internal/lsp/fake/workdir_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/workdir_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,220 +0,0 @@
++++ b/gopls/internal/lsp/fake/workdir_test.go	1970-01-01 08:00:00
+@@ -1,219 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -38244,7 +42833,6 @@
 -
 -import (
 -	"context"
--	"io/ioutil"
 -	"os"
 -	"sync"
 -	"testing"
@@ -38270,7 +42858,7 @@
 -func newWorkdir(t *testing.T, txt string) (*Workdir, *eventBuffer, func()) {
 -	t.Helper()
 -
--	tmpdir, err := ioutil.TempDir("", "goplstest-workdir-")
+-	tmpdir, err := os.MkdirTemp("", "goplstest-workdir-")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -38458,7 +43046,7 @@
 -}
 diff -urN a/gopls/internal/lsp/fake/workdir_windows.go b/gopls/internal/lsp/fake/workdir_windows.go
 --- a/gopls/internal/lsp/fake/workdir_windows.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/fake/workdir_windows.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/fake/workdir_windows.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -38483,8 +43071,8 @@
 -}
 diff -urN a/gopls/internal/lsp/filecache/filecache.go b/gopls/internal/lsp/filecache/filecache.go
 --- a/gopls/internal/lsp/filecache/filecache.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/filecache/filecache.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,369 +0,0 @@
++++ b/gopls/internal/lsp/filecache/filecache.go	1970-01-01 08:00:00
+@@ -1,608 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -38510,60 +43098,114 @@
 -import (
 -	"bytes"
 -	"crypto/sha256"
--	"encoding/binary"
+-	"encoding/hex"
+-	"encoding/json"
 -	"errors"
 -	"fmt"
 -	"io"
+-	"io/fs"
 -	"log"
 -	"os"
 -	"path/filepath"
 -	"sort"
+-	"strings"
 -	"sync"
 -	"sync/atomic"
 -	"time"
 -
--	"golang.org/x/tools/internal/lockedfile"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/lru"
 -)
 -
--// Get retrieves from the cache and returns a newly allocated
--// copy of the value most recently supplied to Set(kind, key),
--// possibly by another process.
+-// Start causes the filecache to initialize and start garbage gollection.
+-//
+-// Start is automatically called by the first call to Get, but may be called
+-// explicitly to pre-initialize the cache.
+-func Start() {
+-	go getCacheDir()
+-}
+-
+-// As an optimization, use a 100MB in-memory LRU cache in front of filecache
+-// operations. This reduces I/O for operations such as diagnostics or
+-// implementations that repeatedly access the same cache entries.
+-var memCache = lru.New(100 * 1e6)
+-
+-type memKey struct {
+-	kind string
+-	key  [32]byte
+-}
+-
+-// Get retrieves from the cache and returns the value most recently
+-// supplied to Set(kind, key), possibly by another process.
 -// Get returns ErrNotFound if the value was not found.
+-//
+-// Callers should not modify the returned array.
 -func Get(kind string, key [32]byte) ([]byte, error) {
--	name := filename(kind, key)
--	data, err := lockedfile.Read(name)
+-	// First consult the read-through memory cache.
+-	// Note that memory cache hits do not update the times
+-	// used for LRU eviction of the file-based cache.
+-	if value := memCache.Get(memKey{kind, key}); value != nil {
+-		return value.([]byte), nil
+-	}
+-
+-	iolimit <- struct{}{}        // acquire a token
+-	defer func() { <-iolimit }() // release a token
+-
+-	// Read the index file, which provides the name of the CAS file.
+-	indexName, err := filename(kind, key)
+-	if err != nil {
+-		return nil, err
+-	}
+-	indexData, err := os.ReadFile(indexName)
 -	if err != nil {
 -		if errors.Is(err, os.ErrNotExist) {
 -			return nil, ErrNotFound
 -		}
 -		return nil, err
 -	}
--
--	// Verify that the Write was complete
--	// by checking the recorded length.
--	if len(data) < 8 {
--		return nil, ErrNotFound // cache entry is incomplete
+-	var valueHash [32]byte
+-	if copy(valueHash[:], indexData) != len(valueHash) {
+-		return nil, ErrNotFound // index entry has wrong length
 -	}
--	if length := binary.LittleEndian.Uint64(data); int(length) != len(data)-8 {
--		return nil, ErrNotFound // cache entry is incomplete (or too long!)
--	}
--	data = data[8:]
 -
--	// Update file time for use by LRU eviction.
--	// (This turns every read into a write operation.
--	// If this is a performance problem, we should
--	// touch the files aynchronously.)
+-	// Read the CAS file and check its contents match.
+-	//
+-	// This ensures integrity in all cases (corrupt or truncated
+-	// file, short read, I/O error, wrong length, etc) except an
+-	// engineered hash collision, which is infeasible.
+-	casName, err := filename(casKind, valueHash)
+-	if err != nil {
+-		return nil, err
+-	}
+-	value, _ := os.ReadFile(casName) // ignore error
+-	if sha256.Sum256(value) != valueHash {
+-		return nil, ErrNotFound // CAS file is missing or has wrong contents
+-	}
+-
+-	// Update file times used by LRU eviction.
+-	//
+-	// Because this turns a read into a write operation,
+-	// we follow the approach used in the go command's
+-	// cache and update the access time only if the
+-	// existing timestamp is older than one hour.
 -	//
 -	// (Traditionally the access time would be updated
 -	// automatically, but for efficiency most POSIX systems have
 -	// for many years set the noatime mount option to avoid every
 -	// open or read operation entailing a metadata write.)
 -	now := time.Now()
--	if err := os.Chtimes(name, now, now); err != nil {
--		return nil, fmt.Errorf("failed to update access time: %w", err)
+-	touch := func(filename string) {
+-		st, err := os.Stat(filename)
+-		if err == nil && now.Sub(st.ModTime()) > time.Hour {
+-			os.Chtimes(filename, now, now) // ignore error
+-		}
 -	}
+-	touch(indexName)
+-	touch(casName)
 -
--	return data, nil
+-	memCache.Set(memKey{kind, key}, value, len(value))
+-
+-	return value, nil
 -}
 -
 -// ErrNotFound is the distinguished error
@@ -38572,37 +43214,97 @@
 -
 -// Set updates the value in the cache.
 -func Set(kind string, key [32]byte, value []byte) error {
--	name := filename(kind, key)
--	if err := os.MkdirAll(filepath.Dir(name), 0700); err != nil {
--		return err
+-	memCache.Set(memKey{kind, key}, value, len(value))
+-
+-	// Set the active event to wake up the GC.
+-	select {
+-	case active <- struct{}{}:
+-	default:
 -	}
 -
--	// In the unlikely event of a short write (e.g. ENOSPC)
--	// followed by process termination (e.g. a power cut), we
--	// don't want a reader to see a short file, so we record
--	// the expected length first and verify it in Get.
--	var length [8]byte
--	binary.LittleEndian.PutUint64(length[:], uint64(len(value)))
--	header := bytes.NewReader(length[:])
--	payload := bytes.NewReader(value)
+-	iolimit <- struct{}{}        // acquire a token
+-	defer func() { <-iolimit }() // release a token
 -
--	// Windows doesn't support atomic rename--we tried MoveFile,
--	// MoveFileEx, ReplaceFileEx, and SetFileInformationByHandle
--	// of RenameFileInfo, all to no avail--so instead we use
--	// advisory file locking, which is only about 2x slower even
--	// on POSIX platforms with atomic rename.
--	return lockedfile.Write(name, io.MultiReader(header, payload), 0600)
+-	// First, add the value to the content-
+-	// addressable store (CAS), if not present.
+-	hash := sha256.Sum256(value)
+-	casName, err := filename(casKind, hash)
+-	if err != nil {
+-		return err
+-	}
+-	// Does CAS file exist and have correct (complete) content?
+-	// TODO(adonovan): opt: use mmap for this check.
+-	if prev, _ := os.ReadFile(casName); !bytes.Equal(prev, value) {
+-		if err := os.MkdirAll(filepath.Dir(casName), 0700); err != nil {
+-			return err
+-		}
+-		// Avoiding O_TRUNC here is merely an optimization to avoid
+-		// cache misses when two threads race to write the same file.
+-		if err := writeFileNoTrunc(casName, value, 0600); err != nil {
+-			os.Remove(casName) // ignore error
+-			return err         // e.g. disk full
+-		}
+-	}
+-
+-	// Now write an index entry that refers to the CAS file.
+-	indexName, err := filename(kind, key)
+-	if err != nil {
+-		return err
+-	}
+-	if err := os.MkdirAll(filepath.Dir(indexName), 0700); err != nil {
+-		return err
+-	}
+-	if err := writeFileNoTrunc(indexName, hash[:], 0600); err != nil {
+-		os.Remove(indexName) // ignore error
+-		return err           // e.g. disk full
+-	}
+-
+-	return nil
 -}
 -
+-// The active 1-channel is a selectable resettable event
+-// indicating recent cache activity.
+-var active = make(chan struct{}, 1)
+-
+-// writeFileNoTrunc is like os.WriteFile but doesn't truncate until
+-// after the write, so that racing writes of the same data are idempotent.
+-func writeFileNoTrunc(filename string, data []byte, perm os.FileMode) error {
+-	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, perm)
+-	if err != nil {
+-		return err
+-	}
+-	_, err = f.Write(data)
+-	if err == nil {
+-		err = f.Truncate(int64(len(data)))
+-	}
+-	if closeErr := f.Close(); err == nil {
+-		err = closeErr
+-	}
+-	return err
+-}
+-
+-// reserved kind strings
+-const (
+-	casKind = "cas" // content-addressable store files
+-	bugKind = "bug" // gopls bug reports
+-)
+-
+-var iolimit = make(chan struct{}, 128) // counting semaphore to limit I/O concurrency in Set.
+-
 -var budget int64 = 1e9 // 1GB
 -
--// SetBudget sets a soft limit on disk usage of the cache (in bytes)
--// and returns the previous value. Supplying a negative value queries
--// the current value without changing it.
+-// SetBudget sets a soft limit on disk usage of regular files in the
+-// cache (in bytes) and returns the previous value. Supplying a
+-// negative value queries the current value without changing it.
 -//
 -// If two gopls processes have different budgets, the one with the
 -// lower budget will collect garbage more actively, but both will
 -// observe the effect.
+-//
+-// Even in the steady state, the storage usage reported by the 'du'
+-// command may exceed the budget by as much as a factor of 3 due to
+-// the overheads of directories and the effects of block quantization,
+-// which are especially pronounced for the small index files.
 -func SetBudget(new int64) (old int64) {
 -	if new < 0 {
 -		return atomic.LoadInt64(&budget)
@@ -38612,22 +43314,62 @@
 -
 -// --- implementation ----
 -
--// filename returns the cache entry of the specified kind and key.
+-// filename returns the name of the cache file of the specified kind and key.
 -//
--// A typical cache entry is a file name such as:
+-// A typical cache file has a name such as:
 -//
--//	$HOME/Library/Caches / gopls / VVVVVVVV / kind / KK / KKKK...KKKK
+-//	$HOME/Library/Caches / gopls / VVVVVVVV / KK / KKKK...KKKK - kind
 -//
 -// The portions separated by spaces are as follows:
 -// - The user's preferred cache directory; the default value varies by OS.
 -// - The constant "gopls".
 -// - The "version", 32 bits of the digest of the gopls executable.
--// - The kind or purpose of this cache subtree (e.g. "analysis").
 -// - The first 8 bits of the key, to avoid huge directories.
 -// - The full 256 bits of the key.
+-// - The kind or purpose of this cache file (e.g. "analysis").
 -//
--// Once a file is written its contents are never modified, though it
--// may be atomically replaced or removed.
+-// The kind establishes a namespace for the keys. It is represented as
+-// a suffix, not a segment, as this significantly reduces the number
+-// of directories created, and thus the storage overhead.
+-//
+-// Previous iterations of the design aimed for the invariant that once
+-// a file is written, its contents are never modified, though it may
+-// be atomically replaced or removed. However, not all platforms have
+-// an atomic rename operation (our first approach), and file locking
+-// (our second) is a notoriously fickle mechanism.
+-//
+-// The current design instead exploits a trick from the cache
+-// implementation used by the go command: writes of small files are in
+-// practice atomic (all or nothing) on all platforms.
+-// (See GOROOT/src/cmd/go/internal/cache/cache.go.)
+-//
+-// Russ Cox notes: "all file systems use an rwlock around every file
+-// system block, including data blocks, so any writes or reads within
+-// the same block are going to be handled atomically by the FS
+-// implementation without any need to request file locking explicitly.
+-// And since the files are so small, there's only one block. (A block
+-// is at minimum 512 bytes, usually much more.)" And: "all modern file
+-// systems protect against [partial writes due to power loss] with
+-// journals."
+-//
+-// We use a two-level scheme consisting of an index and a
+-// content-addressable store (CAS). A single cache entry consists of
+-// two files. The value of a cache entry is written into the file at
+-// filename("cas", sha256(value)). Since the value may be arbitrarily
+-// large, this write is not atomic. That means we must check the
+-// integrity of the contents read back from the CAS to make sure they
+-// hash to the expected key. If the CAS file is incomplete or
+-// inconsistent, we proceed as if it were missing.
+-//
+-// Once the CAS file has been written, we write a small fixed-size
+-// index file at filename(kind, key), using the values supplied by the
+-// caller. The index file contains the hash that identifies the value
+-// file in the CAS. (We could add extra metadata to this file, up to
+-// 512B, the minimum size of a disk block, if later desired, so long
+-// as the total size remains fixed.) Because the index file is small,
+-// concurrent writes to it are atomic in practice, even though this is
+-// not guaranteed by any OS. The fixed size ensures that readers can't
+-// see a palimpsest when a short new file overwrites a longer old one.
 -//
 -// New versions of gopls are free to reorganize the contents of the
 -// version directory as needs evolve.  But all versions of gopls must
@@ -38636,10 +43378,15 @@
 -// In particular, each gopls process attempts to garbage collect
 -// the entire gopls directory so that newer binaries can clean up
 -// after older ones: in the development cycle especially, new
--// new versions may be created frequently.
--func filename(kind string, key [32]byte) string {
--	hex := fmt.Sprintf("%x", key)
--	return filepath.Join(getCacheDir(), kind, hex[:2], hex)
+-// versions may be created frequently.
+-func filename(kind string, key [32]byte) (string, error) {
+-	base := fmt.Sprintf("%x-%s", key, kind)
+-	dir, err := getCacheDir()
+-	if err != nil {
+-		return "", err
+-	}
+-	// Keep the BugReports function consistent with this one.
+-	return filepath.Join(dir, base[:2], base), nil
 -}
 -
 -// getCacheDir returns the persistent cache directory of all processes
@@ -38648,7 +43395,7 @@
 -// It must incorporate the hash of the executable so that we needn't
 -// worry about incompatible changes to the file format or changes to
 -// the algorithm that produced the index.
--func getCacheDir() string {
+-func getCacheDir() (string, error) {
 -	cacheDirOnce.Do(func() {
 -		// Use user's preferred cache directory.
 -		userDir := os.Getenv("GOPLSCACHE")
@@ -38681,21 +43428,22 @@
 -		// Compute the hash of this executable (~20ms) and create a subdirectory.
 -		hash, err := hashExecutable()
 -		if err != nil {
--			log.Fatalf("can't hash gopls executable: %v", err)
+-			cacheDirErr = fmt.Errorf("can't hash gopls executable: %v", err)
 -		}
 -		// Use only 32 bits of the digest to avoid unwieldy filenames.
 -		// It's not an adversarial situation.
 -		cacheDir = filepath.Join(goplsDir, fmt.Sprintf("%x", hash[:4]))
 -		if err := os.MkdirAll(cacheDir, 0700); err != nil {
--			log.Fatalf("can't create cache: %v", err)
+-			cacheDirErr = fmt.Errorf("can't create cache: %v", err)
 -		}
 -	})
--	return cacheDir
+-	return cacheDir, cacheDirErr
 -}
 -
 -var (
 -	cacheDirOnce sync.Once
--	cacheDir     string // only accessed by getCacheDir
+-	cacheDir     string
+-	cacheDirErr  error
 -)
 -
 -func hashExecutable() (hash [32]byte, err error) {
@@ -38724,13 +43472,25 @@
 -// process, possibly running a different version of gopls, possibly
 -// running concurrently.
 -func gc(goplsDir string) {
--	const period = 1 * time.Minute // period between collections
+-	// period between collections
+-	//
+-	// Originally the period was always 1 minute, but this
+-	// consumed 15% of a CPU core when idle (#61049).
+-	//
+-	// The reason for running collections even when idle is so
+-	// that long lived gopls sessions eventually clean up the
+-	// caches created by defunct executables.
+-	const (
+-		minPeriod = 5 * time.Minute // when active
+-		maxPeriod = 6 * time.Hour   // when idle
+-	)
+-
 -	// Sleep statDelay*batchSize between stats to smooth out I/O.
 -	//
 -	// The constants below were chosen using the following heuristics:
 -	//  - 1GB of filecache is on the order of ~100-200k files, in which case
--	//    100μs delay per file introduces 10-20s of additional walk time, less
--	//    than the 1m gc period.
+-	//    100μs delay per file introduces 10-20s of additional walk time,
+-	//    less than the minPeriod.
 -	//  - Processing batches of stats at once is much more efficient than
 -	//    sleeping after every stat (due to OS optimizations).
 -	const statDelay = 100 * time.Microsecond // average delay between stats, to smooth out I/O
@@ -38756,8 +43516,9 @@
 -	for {
 -		// Enumerate all files in the cache.
 -		type item struct {
--			path string
--			stat os.FileInfo
+-			path  string
+-			mtime time.Time
+-			size  int64
 -		}
 -		var files []item
 -		start := time.Now()
@@ -38783,7 +43544,7 @@
 -					}
 -					os.Remove(path) // ignore error
 -				} else {
--					files = append(files, item{path, stat})
+-					files = append(files, item{path, stat.ModTime(), stat.Size()})
 -					total += stat.Size()
 -					if debug && len(files)%1000 == 0 {
 -						log.Printf("filecache: checked %d files in %v", len(files), time.Since(start))
@@ -38798,7 +43559,7 @@
 -
 -		// Sort oldest files first.
 -		sort.Slice(files, func(i, j int) bool {
--			return files[i].stat.ModTime().Before(files[j].stat.ModTime())
+-			return files[i].mtime.Before(files[j].mtime)
 -		})
 -
 -		// Delete oldest files until we're under budget.
@@ -38808,15 +43569,17 @@
 -				break
 -			}
 -			if debug {
--				age := time.Since(file.stat.ModTime())
+-				age := time.Since(file.mtime)
 -				log.Printf("budget: deleting stale file %s (%dB, age %v)",
--					file.path, file.stat.Size(), age)
+-					file.path, file.size, age)
 -			}
 -			os.Remove(file.path) // ignore error
--			total -= file.stat.Size()
+-			total -= file.size
 -		}
+-		files = nil // release memory before sleep
 -
--		time.Sleep(period)
+-		// Wait unconditionally for the minimum period.
+-		time.Sleep(minPeriod)
 -
 -		// Once only, delete all directories.
 -		// This will succeed only for the empty ones,
@@ -38852,12 +43615,76 @@
 -				log.Printf("deleted %d empty directories", deleted)
 -			}
 -		}
+-
+-		// Wait up to the max period,
+-		// or for Set activity in this process.
+-		select {
+-		case <-active:
+-		case <-time.After(maxPeriod):
+-		}
 -	}
 -}
+-
+-func init() {
+-	// Register a handler to durably record this process's first
+-	// assertion failure in the cache so that we can ask users to
+-	// share this information via the stats command.
+-	bug.Handle(func(bug bug.Bug) {
+-		// Wait for cache init (bugs in tests happen early).
+-		_, _ = getCacheDir()
+-
+-		data, err := json.Marshal(bug)
+-		if err != nil {
+-			panic(fmt.Sprintf("error marshalling bug %+v: %v", bug, err))
+-		}
+-
+-		key := sha256.Sum256(data)
+-		_ = Set(bugKind, key, data)
+-	})
+-}
+-
+-// BugReports returns a new unordered array of the contents
+-// of all cached bug reports produced by this executable.
+-// It also returns the location of the cache directory
+-// used by this process (or "" on initialization error).
+-func BugReports() (string, []bug.Bug) {
+-	// To test this logic, run:
+-	// $ TEST_GOPLS_BUG=oops gopls bug     # trigger a bug
+-	// $ gopls stats                       # list the bugs
+-
+-	dir, err := getCacheDir()
+-	if err != nil {
+-		return "", nil // ignore initialization errors
+-	}
+-	var result []bug.Bug
+-	_ = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
+-		if err != nil {
+-			return nil // ignore readdir/stat errors
+-		}
+-		// Parse the key from each "XXXX-bug" cache file name.
+-		if !info.IsDir() && strings.HasSuffix(path, bugKind) {
+-			var key [32]byte
+-			n, err := hex.Decode(key[:], []byte(filepath.Base(path)[:len(key)*2]))
+-			if err != nil || n != len(key) {
+-				return nil // ignore malformed file names
+-			}
+-			content, err := Get(bugKind, key)
+-			if err == nil { // ignore read errors
+-				var b bug.Bug
+-				if err := json.Unmarshal(content, &b); err != nil {
+-					log.Printf("error marshalling bug %q: %v", string(content), err)
+-				}
+-				result = append(result, b)
+-			}
+-		}
+-		return nil
+-	})
+-	return dir, result
+-}
 diff -urN a/gopls/internal/lsp/filecache/filecache_test.go b/gopls/internal/lsp/filecache/filecache_test.go
 --- a/gopls/internal/lsp/filecache/filecache_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/filecache/filecache_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,215 +0,0 @@
++++ b/gopls/internal/lsp/filecache/filecache_test.go	1970-01-01 08:00:00
+@@ -1,265 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -38878,10 +43705,12 @@
 -	"os"
 -	"os/exec"
 -	"strconv"
+-	"strings"
 -	"testing"
 -
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/gopls/internal/lsp/filecache"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -func TestBasics(t *testing.T) {
@@ -38891,6 +43720,10 @@
 -
 -	// Get of a never-seen key returns not found.
 -	if _, err := filecache.Get(kind, key); err != filecache.ErrNotFound {
+-		if strings.Contains(err.Error(), "operation not supported") ||
+-			strings.Contains(err.Error(), "not implemented") {
+-			t.Skipf("skipping: %v", err)
+-		}
 -		t.Errorf("Get of random key returned err=%q, want not found", err)
 -	}
 -
@@ -38914,6 +43747,9 @@
 -
 -// TestConcurrency exercises concurrent access to the same entry.
 -func TestConcurrency(t *testing.T) {
+-	if os.Getenv("GO_BUILDER_NAME") == "plan9-arm" {
+-		t.Skip(`skipping on plan9-arm builder due to golang/go#58748: failing with 'mount rpc error'`)
+-	}
 -	const kind = "TestConcurrency"
 -	key := uniqueKey()
 -	const N = 100 // concurrency level
@@ -38956,6 +43792,10 @@
 -		group.Go(func() error { return get(false) })
 -	}
 -	if err := group.Wait(); err != nil {
+-		if strings.Contains(err.Error(), "operation not supported") ||
+-			strings.Contains(err.Error(), "not implemented") {
+-			t.Skipf("skipping: %v", err)
+-		}
 -		t.Fatal(err)
 -	}
 -
@@ -38975,12 +43815,17 @@
 -// It calls Set(A) in the parent, { Get(A); Set(B) } in the child
 -// process, then Get(B) in the parent.
 -func TestIPC(t *testing.T) {
+-	testenv.NeedsExec(t)
+-
 -	keyA := uniqueKey()
 -	keyB := uniqueKey()
 -	value := []byte(testIPCValueA)
 -
 -	// Set keyA.
 -	if err := filecache.Set(testIPCKind, keyA, value); err != nil {
+-		if strings.Contains(err.Error(), "operation not supported") {
+-			t.Skipf("skipping: %v", err)
+-		}
 -		t.Fatalf("Set: %v", err)
 -	}
 -
@@ -39060,6 +43905,7 @@
 -		b.Fatal(err)
 -	}
 -	b.ResetTimer()
+-	b.SetBytes(int64(len(value)))
 -
 -	var group errgroup.Group
 -	group.SetLimit(50)
@@ -39073,10 +43919,41 @@
 -		b.Fatal(err)
 -	}
 -}
+-
+-// These two benchmarks are asymmetric: the one for Get imposes a
+-// modest bound on concurrency (50) whereas the one for Set imposes a
+-// much higher concurrency (1000) to test the implementation's
+-// self-imposed bound.
+-
+-func BenchmarkUncontendedSet(b *testing.B) {
+-	const kind = "BenchmarkUncontendedSet"
+-	key := uniqueKey()
+-	var value [8192]byte
+-
+-	const P = 1000 // parallelism
+-	b.SetBytes(P * int64(len(value)))
+-
+-	for i := 0; i < b.N; i++ {
+-		// Perform P concurrent calls to Set. All must succeed.
+-		var group errgroup.Group
+-		for range [P]bool{} {
+-			group.Go(func() error {
+-				return filecache.Set(kind, key, value[:])
+-			})
+-		}
+-		if err := group.Wait(); err != nil {
+-			if strings.Contains(err.Error(), "operation not supported") ||
+-				strings.Contains(err.Error(), "not implemented") {
+-				b.Skipf("skipping: %v", err)
+-			}
+-			b.Fatal(err)
+-		}
+-	}
+-}
 diff -urN a/gopls/internal/lsp/folding_range.go b/gopls/internal/lsp/folding_range.go
 --- a/gopls/internal/lsp/folding_range.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/folding_range.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,41 +0,0 @@
++++ b/gopls/internal/lsp/folding_range.go	1970-01-01 08:00:00
+@@ -1,46 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -39088,16 +43965,21 @@
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) foldingRange(ctx context.Context, params *protocol.FoldingRangeParams) ([]protocol.FoldingRange, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.foldingRange", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
 -
--	ranges, err := source.FoldingRange(ctx, snapshot, fh, snapshot.View().Options().LineFoldingOnly)
+-	ranges, err := source.FoldingRange(ctx, snapshot, fh, snapshot.Options().LineFoldingOnly)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -39120,8 +44002,8 @@
 -}
 diff -urN a/gopls/internal/lsp/format.go b/gopls/internal/lsp/format.go
 --- a/gopls/internal/lsp/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
++++ b/gopls/internal/lsp/format.go	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -39135,15 +44017,20 @@
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/work"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.formatting", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Mod:
 -		return mod.Format(ctx, snapshot, fh)
 -	case source.Go:
@@ -39153,10 +44040,576 @@
 -	}
 -	return nil, nil
 -}
+diff -urN a/gopls/internal/lsp/frob/frob.go b/gopls/internal/lsp/frob/frob.go
+--- a/gopls/internal/lsp/frob/frob.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/frob/frob.go	1970-01-01 08:00:00
+@@ -1,439 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Package frob is a fast restricted object encoder/decoder in the
+-// spirit of encoding/gob.
+-//
+-// As with gob, types that recursively contain functions, channels,
+-// and unsafe.Pointers cannot be encoded, but frob has these
+-// additional restrictions:
+-//
+-//   - Interface values are not supported; this avoids the need for
+-//     the encoding to describe types.
+-//
+-//   - Types that recursively contain private struct fields are not
+-//     permitted.
+-//
+-//   - The encoding is unspecified and subject to change, so the encoder
+-//     and decoder must exactly agree on their implementation and on the
+-//     definitions of the target types.
+-//
+-//   - Lengths (of arrays, slices, and maps) are currently assumed to
+-//     fit in 32 bits.
+-//
+-//   - There is no error handling. All errors are reported by panicking.
+-//
+-//   - Values are serialized as trees, not graphs, so shared subgraphs
+-//     are encoded repeatedly.
+-//
+-//   - No attempt is made to detect cyclic data structures.
+-package frob
+-
+-import (
+-	"encoding/binary"
+-	"fmt"
+-	"math"
+-	"reflect"
+-	"sync"
+-)
+-
+-// A Codec[T] is an immutable encoder and decoder for values of type T.
+-type Codec[T any] struct{ frob *frob }
+-
+-// CodecFor[T] returns a codec for values of type T.
+-// It panics if type T is unsuitable.
+-func CodecFor[T any]() Codec[T] {
+-	frobsMu.Lock()
+-	defer frobsMu.Unlock()
+-	return Codec[T]{frobFor(reflect.TypeOf((*T)(nil)).Elem())}
+-}
+-
+-func (codec Codec[T]) Encode(v T) []byte          { return codec.frob.Encode(v) }
+-func (codec Codec[T]) Decode(data []byte, ptr *T) { codec.frob.Decode(data, ptr) }
+-
+-var (
+-	frobsMu sync.Mutex
+-	frobs   = make(map[reflect.Type]*frob)
+-)
+-
+-// A frob is an encoder/decoder for a specific type.
+-type frob struct {
+-	t     reflect.Type
+-	kind  reflect.Kind
+-	elems []*frob // elem (array/slice/ptr), key+value (map), fields (struct)
+-}
+-
+-// frobFor returns the frob for a particular type.
+-// Precondition: caller holds frobsMu.
+-func frobFor(t reflect.Type) *frob {
+-	fr, ok := frobs[t]
+-	if !ok {
+-		fr = &frob{t: t, kind: t.Kind()}
+-		frobs[t] = fr
+-
+-		switch fr.kind {
+-		case reflect.Bool,
+-			reflect.Int,
+-			reflect.Int8,
+-			reflect.Int16,
+-			reflect.Int32,
+-			reflect.Int64,
+-			reflect.Uint,
+-			reflect.Uint8,
+-			reflect.Uint16,
+-			reflect.Uint32,
+-			reflect.Uint64,
+-			reflect.Uintptr,
+-			reflect.Float32,
+-			reflect.Float64,
+-			reflect.Complex64,
+-			reflect.Complex128,
+-			reflect.String:
+-
+-		case reflect.Array,
+-			reflect.Slice,
+-			reflect.Ptr: // TODO(adonovan): after go1.18, use Pointer
+-			fr.addElem(fr.t.Elem())
+-
+-		case reflect.Map:
+-			fr.addElem(fr.t.Key())
+-			fr.addElem(fr.t.Elem())
+-
+-		case reflect.Struct:
+-			for i := 0; i < fr.t.NumField(); i++ {
+-				field := fr.t.Field(i)
+-				if field.PkgPath != "" {
+-					panic(fmt.Sprintf("unexported field %v", field))
+-				}
+-				fr.addElem(field.Type)
+-			}
+-
+-		default:
+-			// chan, func, interface, unsafe.Pointer
+-			panic(fmt.Sprintf("type %v is not supported by frob", fr.t))
+-		}
+-	}
+-	return fr
+-}
+-
+-func (fr *frob) addElem(t reflect.Type) {
+-	fr.elems = append(fr.elems, frobFor(t))
+-}
+-
+-const magic = "frob"
+-
+-func (fr *frob) Encode(v any) []byte {
+-	rv := reflect.ValueOf(v)
+-	if rv.Type() != fr.t {
+-		panic(fmt.Sprintf("got %v, want %v", rv.Type(), fr.t))
+-	}
+-	w := &writer{}
+-	w.bytes([]byte(magic))
+-	fr.encode(w, rv)
+-	if uint64(len(w.data))>>32 != 0 {
+-		panic("too large") // includes all cases where len doesn't fit in 32 bits
+-	}
+-	return w.data
+-}
+-
+-// encode appends the encoding of value v, whose type must be fr.t.
+-func (fr *frob) encode(out *writer, v reflect.Value) {
+-	switch fr.kind {
+-	case reflect.Bool:
+-		var b byte
+-		if v.Bool() {
+-			b = 1
+-		}
+-		out.uint8(b)
+-	case reflect.Int:
+-		out.uint64(uint64(v.Int()))
+-	case reflect.Int8:
+-		out.uint8(uint8(v.Int()))
+-	case reflect.Int16:
+-		out.uint16(uint16(v.Int()))
+-	case reflect.Int32:
+-		out.uint32(uint32(v.Int()))
+-	case reflect.Int64:
+-		out.uint64(uint64(v.Int()))
+-	case reflect.Uint:
+-		out.uint64(v.Uint())
+-	case reflect.Uint8:
+-		out.uint8(uint8(v.Uint()))
+-	case reflect.Uint16:
+-		out.uint16(uint16(v.Uint()))
+-	case reflect.Uint32:
+-		out.uint32(uint32(v.Uint()))
+-	case reflect.Uint64:
+-		out.uint64(v.Uint())
+-	case reflect.Uintptr:
+-		out.uint64(uint64(v.Uint()))
+-	case reflect.Float32:
+-		out.uint32(math.Float32bits(float32(v.Float())))
+-	case reflect.Float64:
+-		out.uint64(math.Float64bits(v.Float()))
+-	case reflect.Complex64:
+-		z := complex64(v.Complex())
+-		out.uint32(uint32(math.Float32bits(real(z))))
+-		out.uint32(uint32(math.Float32bits(imag(z))))
+-	case reflect.Complex128:
+-		z := v.Complex()
+-		out.uint64(math.Float64bits(real(z)))
+-		out.uint64(math.Float64bits(imag(z)))
+-
+-	case reflect.Array:
+-		len := v.Type().Len()
+-		elem := fr.elems[0]
+-		for i := 0; i < len; i++ {
+-			elem.encode(out, v.Index(i))
+-		}
+-
+-	case reflect.Slice:
+-		len := v.Len()
+-		out.uint32(uint32(len))
+-		if len > 0 {
+-			elem := fr.elems[0]
+-			if elem.kind == reflect.Uint8 {
+-				// []byte fast path
+-				out.bytes(v.Bytes())
+-			} else {
+-				for i := 0; i < len; i++ {
+-					elem.encode(out, v.Index(i))
+-				}
+-			}
+-		}
+-
+-	case reflect.Map:
+-		len := v.Len()
+-		out.uint32(uint32(len))
+-		if len > 0 {
+-			kfrob, vfrob := fr.elems[0], fr.elems[1]
+-			for iter := v.MapRange(); iter.Next(); {
+-				kfrob.encode(out, iter.Key())
+-				vfrob.encode(out, iter.Value())
+-			}
+-		}
+-
+-	case reflect.Ptr: // TODO(adonovan): after go1.18, use Pointer
+-		if v.IsNil() {
+-			out.uint8(0)
+-		} else {
+-			out.uint8(1)
+-			fr.elems[0].encode(out, v.Elem())
+-		}
+-
+-	case reflect.String:
+-		len := v.Len()
+-		out.uint32(uint32(len))
+-		if len > 0 {
+-			out.data = append(out.data, v.String()...)
+-		}
+-
+-	case reflect.Struct:
+-		for i, elem := range fr.elems {
+-			elem.encode(out, v.Field(i))
+-		}
+-
+-	default:
+-		panic(fr.t)
+-	}
+-}
+-
+-func (fr *frob) Decode(data []byte, ptr any) {
+-	rv := reflect.ValueOf(ptr).Elem()
+-	if rv.Type() != fr.t {
+-		panic(fmt.Sprintf("got %v, want %v", rv.Type(), fr.t))
+-	}
+-	rd := &reader{data}
+-	if string(rd.bytes(4)) != magic {
+-		panic("not a frob-encoded message")
+-	}
+-	fr.decode(rd, rv)
+-	if len(rd.data) > 0 {
+-		panic("surplus bytes")
+-	}
+-}
+-
+-// decode reads from in, decodes a value, and sets addr to it.
+-// addr must be a zero-initialized addressable variable of type fr.t.
+-func (fr *frob) decode(in *reader, addr reflect.Value) {
+-	switch fr.kind {
+-	case reflect.Bool:
+-		addr.SetBool(in.uint8() != 0)
+-	case reflect.Int:
+-		addr.SetInt(int64(in.uint64()))
+-	case reflect.Int8:
+-		addr.SetInt(int64(in.uint8()))
+-	case reflect.Int16:
+-		addr.SetInt(int64(in.uint16()))
+-	case reflect.Int32:
+-		addr.SetInt(int64(in.uint32()))
+-	case reflect.Int64:
+-		addr.SetInt(int64(in.uint64()))
+-	case reflect.Uint:
+-		addr.SetUint(in.uint64())
+-	case reflect.Uint8:
+-		addr.SetUint(uint64(in.uint8()))
+-	case reflect.Uint16:
+-		addr.SetUint(uint64(in.uint16()))
+-	case reflect.Uint32:
+-		addr.SetUint(uint64(in.uint32()))
+-	case reflect.Uint64:
+-		addr.SetUint(in.uint64())
+-	case reflect.Uintptr:
+-		addr.SetUint(in.uint64())
+-	case reflect.Float32:
+-		addr.SetFloat(float64(math.Float32frombits(in.uint32())))
+-	case reflect.Float64:
+-		addr.SetFloat(math.Float64frombits(in.uint64()))
+-	case reflect.Complex64:
+-		addr.SetComplex(complex128(complex(
+-			math.Float32frombits(in.uint32()),
+-			math.Float32frombits(in.uint32()),
+-		)))
+-	case reflect.Complex128:
+-		addr.SetComplex(complex(
+-			math.Float64frombits(in.uint64()),
+-			math.Float64frombits(in.uint64()),
+-		))
+-
+-	case reflect.Array:
+-		len := fr.t.Len()
+-		for i := 0; i < len; i++ {
+-			fr.elems[0].decode(in, addr.Index(i))
+-		}
+-
+-	case reflect.Slice:
+-		len := int(in.uint32())
+-		if len > 0 {
+-			elem := fr.elems[0]
+-			if elem.kind == reflect.Uint8 {
+-				// []byte fast path
+-				// (Not addr.SetBytes: we must make a copy.)
+-				addr.Set(reflect.AppendSlice(addr, reflect.ValueOf(in.bytes(len))))
+-			} else {
+-				addr.Set(reflect.MakeSlice(fr.t, len, len))
+-				for i := 0; i < len; i++ {
+-					elem.decode(in, addr.Index(i))
+-				}
+-			}
+-		}
+-
+-	case reflect.Map:
+-		len := int(in.uint32())
+-		if len > 0 {
+-			m := reflect.MakeMapWithSize(fr.t, len)
+-			addr.Set(m)
+-			kfrob, vfrob := fr.elems[0], fr.elems[1]
+-			k := reflect.New(kfrob.t).Elem()
+-			v := reflect.New(vfrob.t).Elem()
+-			kzero := reflect.Zero(kfrob.t)
+-			vzero := reflect.Zero(vfrob.t)
+-			for i := 0; i < len; i++ {
+-				// TODO(adonovan): use SetZero from go1.20.
+-				// k.SetZero()
+-				// v.SetZero()
+-				k.Set(kzero)
+-				v.Set(vzero)
+-				kfrob.decode(in, k)
+-				vfrob.decode(in, v)
+-				m.SetMapIndex(k, v)
+-			}
+-		}
+-
+-	case reflect.Ptr: // TODO(adonovan): after go1.18, use Pointer
+-		isNil := in.uint8() == 0
+-		if !isNil {
+-			ptr := reflect.New(fr.elems[0].t)
+-			addr.Set(ptr)
+-			fr.elems[0].decode(in, ptr.Elem())
+-		}
+-
+-	case reflect.String:
+-		len := int(in.uint32())
+-		if len > 0 {
+-			addr.SetString(string(in.bytes(len)))
+-		}
+-
+-	case reflect.Struct:
+-		for i, elem := range fr.elems {
+-			elem.decode(in, addr.Field(i))
+-		}
+-
+-	default:
+-		panic(fr.t)
+-	}
+-}
+-
+-var le = binary.LittleEndian
+-
+-type reader struct{ data []byte }
+-
+-func (r *reader) uint8() uint8 {
+-	v := r.data[0]
+-	r.data = r.data[1:]
+-	return v
+-}
+-
+-func (r *reader) uint16() uint16 {
+-	v := le.Uint16(r.data)
+-	r.data = r.data[2:]
+-	return v
+-}
+-
+-func (r *reader) uint32() uint32 {
+-	v := le.Uint32(r.data)
+-	r.data = r.data[4:]
+-	return v
+-}
+-
+-func (r *reader) uint64() uint64 {
+-	v := le.Uint64(r.data)
+-	r.data = r.data[8:]
+-	return v
+-}
+-
+-func (r *reader) bytes(n int) []byte {
+-	v := r.data[:n]
+-	r.data = r.data[n:]
+-	return v
+-}
+-
+-type writer struct{ data []byte }
+-
+-func (w *writer) uint8(v uint8)   { w.data = append(w.data, v) }
+-func (w *writer) uint16(v uint16) { w.data = appendUint16(w.data, v) }
+-func (w *writer) uint32(v uint32) { w.data = appendUint32(w.data, v) }
+-func (w *writer) uint64(v uint64) { w.data = appendUint64(w.data, v) }
+-func (w *writer) bytes(v []byte)  { w.data = append(w.data, v...) }
+-
+-// TODO(adonovan): delete these as in go1.19 they are methods on LittleEndian:
+-
+-func appendUint16(b []byte, v uint16) []byte {
+-	return append(b,
+-		byte(v),
+-		byte(v>>8),
+-	)
+-}
+-
+-func appendUint32(b []byte, v uint32) []byte {
+-	return append(b,
+-		byte(v),
+-		byte(v>>8),
+-		byte(v>>16),
+-		byte(v>>24),
+-	)
+-}
+-
+-func appendUint64(b []byte, v uint64) []byte {
+-	return append(b,
+-		byte(v),
+-		byte(v>>8),
+-		byte(v>>16),
+-		byte(v>>24),
+-		byte(v>>32),
+-		byte(v>>40),
+-		byte(v>>48),
+-		byte(v>>56),
+-	)
+-}
+diff -urN a/gopls/internal/lsp/frob/frob_test.go b/gopls/internal/lsp/frob/frob_test.go
+--- a/gopls/internal/lsp/frob/frob_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/frob/frob_test.go	1970-01-01 08:00:00
+@@ -1,119 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package frob_test
+-
+-import (
+-	"math"
+-	"reflect"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/frob"
+-)
+-
+-func TestBasics(t *testing.T) {
+-	type Basics struct {
+-		A []*string
+-		B [2]int
+-		C *Basics
+-		D map[string]int
+-		E []byte
+-		F []string
+-	}
+-	codec := frob.CodecFor[Basics]()
+-
+-	s1, s2 := "hello", "world"
+-	x := Basics{
+-		A: []*string{&s1, nil, &s2},
+-		B: [...]int{1, 2},
+-		C: &Basics{
+-			B: [...]int{3, 4},
+-			D: map[string]int{"one": 1},
+-		},
+-		E: []byte("hello"),
+-		F: []string{s1, s2},
+-	}
+-	var y Basics
+-	codec.Decode(codec.Encode(x), &y)
+-	if !reflect.DeepEqual(x, y) {
+-		t.Fatalf("bad roundtrip: got %#v, want %#v", y, x)
+-	}
+-}
+-
+-func TestInts(t *testing.T) {
+-	type Ints struct {
+-		U    uint
+-		U8   uint8
+-		U16  uint16
+-		U32  uint32
+-		U64  uint64
+-		UP   uintptr
+-		I    int
+-		I8   int8
+-		I16  int16
+-		I32  int32
+-		I64  int64
+-		F32  float32
+-		F64  float64
+-		C64  complex64
+-		C128 complex128
+-	}
+-	codec := frob.CodecFor[Ints]()
+-
+-	// maxima
+-	max1 := Ints{
+-		U:    math.MaxUint,
+-		U8:   math.MaxUint8,
+-		U16:  math.MaxUint16,
+-		U32:  math.MaxUint32,
+-		U64:  math.MaxUint64,
+-		UP:   math.MaxUint,
+-		I:    math.MaxInt,
+-		I8:   math.MaxInt8,
+-		I16:  math.MaxInt16,
+-		I32:  math.MaxInt32,
+-		I64:  math.MaxInt64,
+-		F32:  math.MaxFloat32,
+-		F64:  math.MaxFloat64,
+-		C64:  complex(math.MaxFloat32, math.MaxFloat32),
+-		C128: complex(math.MaxFloat64, math.MaxFloat64),
+-	}
+-	var max2 Ints
+-	codec.Decode(codec.Encode(max1), &max2)
+-	if !reflect.DeepEqual(max1, max2) {
+-		t.Fatalf("max: bad roundtrip: got %#v, want %#v", max2, max1)
+-	}
+-
+-	// minima
+-	min1 := Ints{
+-		I:    math.MinInt,
+-		I8:   math.MinInt8,
+-		I16:  math.MinInt16,
+-		I32:  math.MinInt32,
+-		I64:  math.MinInt64,
+-		F32:  -math.MaxFloat32,
+-		F64:  -math.MaxFloat32,
+-		C64:  complex(-math.MaxFloat32, -math.MaxFloat32),
+-		C128: complex(-math.MaxFloat64, -math.MaxFloat64),
+-	}
+-	var min2 Ints
+-	codec.Decode(codec.Encode(min1), &min2)
+-	if !reflect.DeepEqual(min1, min2) {
+-		t.Fatalf("min: bad roundtrip: got %#v, want %#v", min2, min1)
+-	}
+-
+-	// negatives (other than MinInt), to exercise conversions
+-	neg1 := Ints{
+-		I:   -1,
+-		I8:  -1,
+-		I16: -1,
+-		I32: -1,
+-		I64: -1,
+-	}
+-	var neg2 Ints
+-	codec.Decode(codec.Encode(neg1), &neg2)
+-	if !reflect.DeepEqual(neg1, neg2) {
+-		t.Fatalf("neg: bad roundtrip: got %#v, want %#v", neg2, neg1)
+-	}
+-}
 diff -urN a/gopls/internal/lsp/general.go b/gopls/internal/lsp/general.go
 --- a/gopls/internal/lsp/general.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/general.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,619 +0,0 @@
++++ b/gopls/internal/lsp/general.go	1970-01-01 08:00:00
+@@ -1,707 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -39167,6 +44620,7 @@
 -	"context"
 -	"encoding/json"
 -	"fmt"
+-	"go/build"
 -	"log"
 -	"os"
 -	"path"
@@ -39175,16 +44629,22 @@
 -	"strings"
 -	"sync"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/gopls/internal/telemetry"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/jsonrpc2"
 -)
 -
 -func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.initialize")
+-	defer done()
+-
+-	telemetry.RecordClientInfo(params)
+-
 -	s.stateMu.Lock()
 -	if s.state >= serverInitializing {
 -		defer s.stateMu.Unlock()
@@ -39209,27 +44669,29 @@
 -	}
 -	s.progress.SetSupportsWorkDoneProgress(params.Capabilities.Window.WorkDoneProgress)
 -
--	options := s.session.Options()
--	defer func() { s.session.SetOptions(options) }()
+-	options := s.Options().Clone()
+-	// TODO(rfindley): remove the error return from handleOptionResults, and
+-	// eliminate this defer.
+-	defer func() { s.SetOptions(options) }()
 -
 -	if err := s.handleOptionResults(ctx, source.SetOptions(options, params.InitializationOptions)); err != nil {
 -		return nil, err
 -	}
--	options.ForClientCapabilities(params.Capabilities)
+-	options.ForClientCapabilities(params.ClientInfo, params.Capabilities)
 -
 -	if options.ShowBugReports {
 -		// Report the next bug that occurs on the server.
--		bugCh := bug.Notify()
--		go func() {
--			b := <-bugCh
+-		bug.Handle(func(b bug.Bug) {
 -			msg := &protocol.ShowMessageParams{
 -				Type:    protocol.Error,
 -				Message: fmt.Sprintf("A bug occurred on the server: %s\nLocation:%s", b.Description, b.Key),
 -			}
--			if err := s.eventuallyShowMessage(context.Background(), msg); err != nil {
--				log.Printf("error showing bug: %v", err)
--			}
--		}()
+-			go func() {
+-				if err := s.eventuallyShowMessage(context.Background(), msg); err != nil {
+-					log.Printf("error showing bug: %v", err)
+-				}
+-			}()
+-		})
 -	}
 -
 -	folders := params.WorkspaceFolders
@@ -39308,7 +44770,7 @@
 -			DocumentSymbolProvider:     &protocol.Or_ServerCapabilities_documentSymbolProvider{Value: true},
 -			WorkspaceSymbolProvider:    &protocol.Or_ServerCapabilities_workspaceSymbolProvider{Value: true},
 -			ExecuteCommandProvider: &protocol.ExecuteCommandOptions{
--				Commands: options.SupportedCommands,
+-				Commands: nonNilSliceString(options.SupportedCommands),
 -			},
 -			FoldingRangeProvider:      &protocol.Or_ServerCapabilities_foldingRangeProvider{Value: true},
 -			HoverProvider:             &protocol.Or_ServerCapabilities_hoverProvider{Value: true},
@@ -39322,8 +44784,8 @@
 -				Range: &protocol.Or_SemanticTokensOptions_range{Value: true},
 -				Full:  &protocol.Or_SemanticTokensOptions_full{Value: true},
 -				Legend: protocol.SemanticTokensLegend{
--					TokenTypes:     s.session.Options().SemanticTypes,
--					TokenModifiers: s.session.Options().SemanticMods,
+-					TokenTypes:     nonNilSliceString(s.Options().SemanticTypes),
+-					TokenModifiers: nonNilSliceString(s.Options().SemanticMods),
 -				},
 -			},
 -			SignatureHelpProvider: &protocol.SignatureHelpOptions{
@@ -39351,6 +44813,9 @@
 -}
 -
 -func (s *Server) initialized(ctx context.Context, params *protocol.InitializedParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.initialized")
+-	defer done()
+-
 -	s.stateMu.Lock()
 -	if s.state >= serverInitialized {
 -		defer s.stateMu.Unlock()
@@ -39364,9 +44829,7 @@
 -	}
 -	s.notifications = nil
 -
--	options := s.session.Options()
--	defer func() { s.session.SetOptions(options) }()
--
+-	options := s.Options()
 -	if err := s.addFolders(ctx, s.pendingFolders); err != nil {
 -		return err
 -	}
@@ -39387,19 +44850,26 @@
 -			return err
 -		}
 -	}
+-
+-	// Ask (maybe) about enabling telemetry. Do this asynchronously, as it's OK
+-	// for users to ignore or dismiss the question.
+-	go s.maybePromptForTelemetry(ctx, options.TelemetryPrompt)
+-
 -	return nil
 -}
 -
 -// GoVersionTable maps Go versions to the gopls version in which support will
 -// be deprecated, and the final gopls version supporting them without warnings.
--// Keep this in sync with gopls/README.md
+-// Keep this in sync with gopls/README.md.
 -//
 -// Must be sorted in ascending order of Go version.
 -//
 -// Mutable for testing.
 -var GoVersionTable = []GoVersionSupport{
 -	{12, "", "v0.7.5"},
--	{15, "v0.11.0", "v0.9.5"},
+-	{15, "", "v0.9.5"},
+-	{16, "v0.13.0", "v0.11.0"},
+-	{17, "v0.13.0", "v0.11.0"},
 -}
 -
 -// GoVersionSupport holds information about end-of-life Go version support.
@@ -39415,11 +44885,13 @@
 -	return GoVersionTable[len(GoVersionTable)-1].GoVersion + 1
 -}
 -
--// versionMessage returns the warning/error message to display if the user is
--// on the given Go version, if any. The goVersion variable is the X in Go 1.X.
+-// versionMessage returns the warning/error message to display if the user has
+-// the given Go version, if any. The goVersion variable is the X in Go 1.X. If
+-// fromBuild is set, the Go version is the version used to build gopls.
+-// Otherwise, it is the go command version.
 -//
 -// If goVersion is invalid (< 0), it returns "", 0.
--func versionMessage(goVersion int) (string, protocol.MessageType) {
+-func versionMessage(goVersion int, fromBuild bool) (string, protocol.MessageType) {
 -	if goVersion < 0 {
 -		return "", 0
 -	}
@@ -39429,7 +44901,11 @@
 -			var msgBuilder strings.Builder
 -
 -			mType := protocol.Error
--			fmt.Fprintf(&msgBuilder, "Found Go version 1.%d", goVersion)
+-			if fromBuild {
+-				fmt.Fprintf(&msgBuilder, "Gopls was built with Go version 1.%d", goVersion)
+-			} else {
+-				fmt.Fprintf(&msgBuilder, "Found Go version 1.%d", goVersion)
+-			}
 -			if v.DeprecatedVersion != "" {
 -				// not deprecated yet, just a warning
 -				fmt.Fprintf(&msgBuilder, ", which will be unsupported by gopls %s. ", v.DeprecatedVersion)
@@ -39452,15 +44928,16 @@
 -//
 -// It should be called after views change.
 -func (s *Server) checkViewGoVersions() {
--	oldestVersion := -1
+-	oldestVersion, fromBuild := go1Point(), true
 -	for _, view := range s.session.Views() {
 -		viewVersion := view.GoVersion()
 -		if oldestVersion == -1 || viewVersion < oldestVersion {
--			oldestVersion = viewVersion
+-			oldestVersion, fromBuild = viewVersion, false
 -		}
+-		telemetry.RecordViewGoVersion(viewVersion)
 -	}
 -
--	if msg, mType := versionMessage(oldestVersion); msg != "" {
+-	if msg, mType := versionMessage(oldestVersion, fromBuild); msg != "" {
 -		s.eventuallyShowMessage(context.Background(), &protocol.ShowMessageParams{
 -			Type:    mType,
 -			Message: msg,
@@ -39468,12 +44945,27 @@
 -	}
 -}
 -
+-// go1Point returns the x in Go 1.x. If an error occurs extracting the go
+-// version, it returns -1.
+-//
+-// Copied from the testenv package.
+-func go1Point() int {
+-	for i := len(build.Default.ReleaseTags) - 1; i >= 0; i-- {
+-		var version int
+-		if _, err := fmt.Sscanf(build.Default.ReleaseTags[i], "go1.%d", &version); err != nil {
+-			continue
+-		}
+-		return version
+-	}
+-	return -1
+-}
+-
 -func (s *Server) addFolders(ctx context.Context, folders []protocol.WorkspaceFolder) error {
 -	originalViews := len(s.session.Views())
 -	viewErrors := make(map[span.URI]error)
 -
 -	var ndiagnose sync.WaitGroup // number of unfinished diagnose calls
--	if s.session.Options().VerboseWorkDoneProgress {
+-	if s.Options().VerboseWorkDoneProgress {
 -		work := s.progress.Start(ctx, DiagnosticWorkTitle(FromInitialWorkspaceLoad), "Calculating diagnostics for initial workspace load...", nil, nil)
 -		defer func() {
 -			go func() {
@@ -39515,7 +45007,7 @@
 -		// Diagnose the newly created view asynchronously.
 -		ndiagnose.Add(1)
 -		go func() {
--			s.diagnoseDetached(snapshot)
+-			s.diagnoseSnapshot(snapshot, nil, false, 0)
 -			<-initialized
 -			release()
 -			ndiagnose.Done()
@@ -39598,14 +45090,13 @@
 -
 -// registerWatchedDirectoriesLocked sends the workspace/didChangeWatchedFiles
 -// registrations to the client and updates s.watchedDirectories.
+-// The caller must not subsequently mutate patterns.
 -func (s *Server) registerWatchedDirectoriesLocked(ctx context.Context, patterns map[string]struct{}) error {
--	if !s.session.Options().DynamicWatchedFilesSupported {
+-	if !s.Options().DynamicWatchedFilesSupported {
 -		return nil
 -	}
--	for k := range s.watchedGlobPatterns {
--		delete(s.watchedGlobPatterns, k)
--	}
--	var watchers []protocol.FileSystemWatcher
+-	s.watchedGlobPatterns = patterns
+-	watchers := make([]protocol.FileSystemWatcher, 0, len(patterns)) // must be a slice
 -	val := protocol.WatchChange | protocol.WatchDelete | protocol.WatchCreate
 -	for pattern := range patterns {
 -		watchers = append(watchers, protocol.FileSystemWatcher{
@@ -39626,16 +45117,30 @@
 -		return err
 -	}
 -	s.watchRegistrationCount++
--
--	for k, v := range patterns {
--		s.watchedGlobPatterns[k] = v
--	}
 -	return nil
 -}
 -
--func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, o *source.Options) error {
--	if !s.session.Options().ConfigurationSupported {
--		return nil
+-// Options returns the current server options.
+-//
+-// The caller must not modify the result.
+-func (s *Server) Options() *source.Options {
+-	s.optionsMu.Lock()
+-	defer s.optionsMu.Unlock()
+-	return s.options
+-}
+-
+-// SetOptions sets the current server options.
+-//
+-// The caller must not subsequently modify the options.
+-func (s *Server) SetOptions(opts *source.Options) {
+-	s.optionsMu.Lock()
+-	defer s.optionsMu.Unlock()
+-	s.options = opts
+-}
+-
+-func (s *Server) fetchFolderOptions(ctx context.Context, folder span.URI) (*source.Options, error) {
+-	if opts := s.Options(); !opts.ConfigurationSupported {
+-		return opts, nil
 -	}
 -	configs, err := s.client.Configuration(ctx, &protocol.ParamConfiguration{
 -		Items: []protocol.ConfigurationItem{{
@@ -39645,14 +45150,16 @@
 -	},
 -	)
 -	if err != nil {
--		return fmt.Errorf("failed to get workspace configuration from client (%s): %v", folder, err)
+-		return nil, fmt.Errorf("failed to get workspace configuration from client (%s): %v", folder, err)
 -	}
+-
+-	folderOpts := s.Options().Clone()
 -	for _, config := range configs {
--		if err := s.handleOptionResults(ctx, source.SetOptions(o, config)); err != nil {
--			return err
+-		if err := s.handleOptionResults(ctx, source.SetOptions(folderOpts, config)); err != nil {
+-			return nil, err
 -		}
 -	}
--	return nil
+-	return folderOpts, nil
 -}
 -
 -func (s *Server) eventuallyShowMessage(ctx context.Context, msg *protocol.ShowMessageParams) error {
@@ -39728,12 +45235,12 @@
 -	if err != nil {
 -		return nil, nil, false, func() {}, err
 -	}
--	fh, err := snapshot.GetFile(ctx, uri)
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		release()
 -		return nil, nil, false, func() {}, err
 -	}
--	if expectKind != source.UnknownKind && view.FileKind(fh) != expectKind {
+-	if expectKind != source.UnknownKind && snapshot.FileKind(fh) != expectKind {
 -		// Wrong kind of file. Nothing to do.
 -		release()
 -		return nil, nil, false, func() {}, nil
@@ -39744,6 +45251,9 @@
 -// shutdown implements the 'shutdown' LSP handler. It releases resources
 -// associated with the server and waits for all ongoing work to complete.
 -func (s *Server) shutdown(ctx context.Context) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.shutdown")
+-	defer done()
+-
 -	s.stateMu.Lock()
 -	defer s.stateMu.Unlock()
 -	if s.state < serverInitialized {
@@ -39763,6 +45273,9 @@
 -}
 -
 -func (s *Server) exit(ctx context.Context) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.exit")
+-	defer done()
+-
 -	s.stateMu.Lock()
 -	defer s.stateMu.Unlock()
 -
@@ -39772,14 +45285,42 @@
 -		// TODO: We should be able to do better than this.
 -		os.Exit(1)
 -	}
--	// we don't terminate the process on a normal exit, we just allow it to
+-	// We don't terminate the process on a normal exit, we just allow it to
 -	// close naturally if needed after the connection is closed.
 -	return nil
 -}
+-
+-// TODO: when we can assume go1.18, replace with generic
+-// (after retiring support for go1.17)
+-func nonNilSliceString(x []string) []string {
+-	if x == nil {
+-		return []string{}
+-	}
+-	return x
+-}
+-func nonNilSliceTextEdit(x []protocol.TextEdit) []protocol.TextEdit {
+-	if x == nil {
+-		return []protocol.TextEdit{}
+-	}
+-
+-	return x
+-}
+-func nonNilSliceCompletionItemTag(x []protocol.CompletionItemTag) []protocol.CompletionItemTag {
+-	if x == nil {
+-		return []protocol.CompletionItemTag{}
+-	}
+-	return x
+-}
+-func emptySliceDiagnosticTag(x []protocol.DiagnosticTag) []protocol.DiagnosticTag {
+-	if x == nil {
+-		return []protocol.DiagnosticTag{}
+-	}
+-	return x
+-}
 diff -urN a/gopls/internal/lsp/general_test.go b/gopls/internal/lsp/general_test.go
 --- a/gopls/internal/lsp/general_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/general_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,44 +0,0 @@
++++ b/gopls/internal/lsp/general_test.go	1970-01-01 08:00:00
+@@ -1,48 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -39796,18 +45337,22 @@
 -func TestVersionMessage(t *testing.T) {
 -	tests := []struct {
 -		goVersion    int
+-		fromBuild    bool
 -		wantContains []string // string fragments that we expect to see
 -		wantType     protocol.MessageType
 -	}{
--		{-1, nil, 0},
--		{12, []string{"1.12", "not supported", "upgrade to Go 1.16", "install gopls v0.7.5"}, protocol.Error},
--		{13, []string{"1.13", "will be unsupported by gopls v0.11.0", "upgrade to Go 1.16", "install gopls v0.9.5"}, protocol.Warning},
--		{15, []string{"1.15", "will be unsupported by gopls v0.11.0", "upgrade to Go 1.16", "install gopls v0.9.5"}, protocol.Warning},
--		{16, nil, 0},
+-		{-1, false, nil, 0},
+-		{12, false, []string{"1.12", "not supported", "upgrade to Go 1.18", "install gopls v0.7.5"}, protocol.Error},
+-		{13, false, []string{"1.13", "not supported", "upgrade to Go 1.18", "install gopls v0.9.5"}, protocol.Error},
+-		{15, false, []string{"1.15", "not supported", "upgrade to Go 1.18", "install gopls v0.9.5"}, protocol.Error},
+-		{15, true, []string{"Gopls was built with Go version 1.15", "not supported", "upgrade to Go 1.18", "install gopls v0.9.5"}, protocol.Error},
+-		{16, false, []string{"1.16", "will be unsupported by gopls v0.13.0", "upgrade to Go 1.18", "install gopls v0.11.0"}, protocol.Warning},
+-		{17, false, []string{"1.17", "will be unsupported by gopls v0.13.0", "upgrade to Go 1.18", "install gopls v0.11.0"}, protocol.Warning},
+-		{17, true, []string{"Gopls was built with Go version 1.17", "will be unsupported by gopls v0.13.0", "upgrade to Go 1.18", "install gopls v0.11.0"}, protocol.Warning},
 -	}
 -
 -	for _, test := range tests {
--		gotMsg, gotType := versionMessage(test.goVersion)
+-		gotMsg, gotType := versionMessage(test.goVersion, test.fromBuild)
 -
 -		if len(test.wantContains) == 0 && gotMsg != "" {
 -			t.Errorf("versionMessage(%d) = %q, want \"\"", test.goVersion, gotMsg)
@@ -39826,7 +45371,7 @@
 -}
 diff -urN a/gopls/internal/lsp/glob/glob.go b/gopls/internal/lsp/glob/glob.go
 --- a/gopls/internal/lsp/glob/glob.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/glob/glob.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/glob/glob.go	1970-01-01 08:00:00
 @@ -1,349 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -40179,7 +45724,7 @@
 -}
 diff -urN a/gopls/internal/lsp/glob/glob_test.go b/gopls/internal/lsp/glob/glob_test.go
 --- a/gopls/internal/lsp/glob/glob_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/glob/glob_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/glob/glob_test.go	1970-01-01 08:00:00
 @@ -1,118 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -40299,9 +45844,48 @@
 -		}
 -	}
 -}
+diff -urN a/gopls/internal/lsp/helper/README.md b/gopls/internal/lsp/helper/README.md
+--- a/gopls/internal/lsp/helper/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/helper/README.md	1970-01-01 08:00:00
+@@ -1,35 +0,0 @@
+-# Generate server_gen.go
+-
+-`helper` generates the file `../server_gen.go` (in package
+-`internal/lsp`) which contains stub declarations of server methods.
+-
+-To invoke it, run `go generate` in the `gopls/internal/lsp` directory.
+-
+-It is derived from `gopls/internal/lsp/protocol/tsserver.go`, which
+-itself is generated from the protocol downloaded from VSCode, so be
+-sure to run `go generate` in the protocol first. Or run `go generate
+-./...` twice in the gopls directory.
+-
+-It decides what stubs are needed and their signatures
+-by looking at the `Server` interface (`-t` flag). These all look somewhat like
+-`Resolve(context.Context, *CompletionItem) (*CompletionItem, error)`.
+-
+-It then parses the `lsp` directory (`-u` flag) to see if there is a corresponding
+-implementation function (which in this case would be named `resolve`). If so
+-it discovers the parameter names needed, and generates (in `server_gen.go`) code
+-like
+-
+-``` go
+-func (s *Server) resolve(ctx context.Context, params *protocol.CompletionItem) (*protocol.CompletionItem, error) {
+-    return s.resolve(ctx, params)
+-}
+-```
+-
+-If `resolve` is not defined (and it is not), then the body of the generated function is
+-
+-```go
+-    return nil, notImplemented("resolve")
+-```
+-
+-So to add a capability currently not implemented, just define it somewhere in `lsp`.
+-In this case, just define `func (s *Server) resolve(...)` and re-generate `server_gen.go`.
 diff -urN a/gopls/internal/lsp/helper/helper.go b/gopls/internal/lsp/helper/helper.go
 --- a/gopls/internal/lsp/helper/helper.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/helper/helper.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/helper/helper.go	1970-01-01 08:00:00
 @@ -1,264 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -40567,49 +46151,10 @@
 -		return fmt.Sprintf("%T", x)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/helper/README.md b/gopls/internal/lsp/helper/README.md
---- a/gopls/internal/lsp/helper/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/helper/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,35 +0,0 @@
--# Generate server_gen.go
--
--`helper` generates the file `../server_gen.go` (in package
--`internal/lsp`) which contains stub declarations of server methods.
--
--To invoke it, run `go generate` in the `gopls/internal/lsp` directory.
--
--It is derived from `gopls/internal/lsp/protocol/tsserver.go`, which
--itself is generated from the protocol downloaded from VSCode, so be
--sure to run `go generate` in the protocol first. Or run `go generate
--./...` twice in the gopls directory.
--
--It decides what stubs are needed and their signatures
--by looking at the `Server` interface (`-t` flag). These all look somewhat like
--`Resolve(context.Context, *CompletionItem) (*CompletionItem, error)`.
--
--It then parses the `lsp` directory (`-u` flag) to see if there is a corresponding
--implementation function (which in this case would be named `resolve`). If so
--it discovers the parameter names needed, and generates (in `server_gen.go`) code
--like
--
--``` go
--func (s *Server) resolve(ctx context.Context, params *protocol.CompletionItem) (*protocol.CompletionItem, error) {
--    return s.resolve(ctx, params)
--}
--```
--
--If `resolve` is not defined (and it is not), then the body of the generated function is
--
--```go
--    return nil, notImplemented("resolve")
--```
--
--So to add a capability currently not implemented, just define it somewhere in `lsp`.
--In this case, just define `func (s *Server) resolve(...)` and re-generate `server_gen.go`.
 diff -urN a/gopls/internal/lsp/highlight.go b/gopls/internal/lsp/highlight.go
 --- a/gopls/internal/lsp/highlight.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/highlight.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,45 +0,0 @@
++++ b/gopls/internal/lsp/highlight.go	1970-01-01 08:00:00
+@@ -1,48 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -40619,27 +46164,30 @@
 -import (
 -	"context"
 -
--	"golang.org/x/tools/internal/event"
--	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) documentHighlight(ctx context.Context, params *protocol.DocumentHighlightParams) ([]protocol.DocumentHighlight, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.documentHighlight", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
 -
--	if snapshot.View().FileKind(fh) == source.Tmpl {
+-	if snapshot.FileKind(fh) == source.Tmpl {
 -		return template.Highlight(ctx, snapshot, fh, params.Position)
 -	}
 -
 -	rngs, err := source.Highlight(ctx, snapshot, fh, params.Position)
 -	if err != nil {
--		event.Error(ctx, "no highlight", err, tag.URI.Of(params.TextDocument.URI))
+-		event.Error(ctx, "no highlight", err)
 -	}
 -	return toProtocolHighlight(rngs), nil
 -}
@@ -40657,8 +46205,8 @@
 -}
 diff -urN a/gopls/internal/lsp/hover.go b/gopls/internal/lsp/hover.go
 --- a/gopls/internal/lsp/hover.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/hover.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,34 +0,0 @@
++++ b/gopls/internal/lsp/hover.go	1970-01-01 08:00:00
+@@ -1,45 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -40673,15 +46221,26 @@
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
 -	"golang.org/x/tools/gopls/internal/lsp/work"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
--func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
+-func (s *Server) hover(ctx context.Context, params *protocol.HoverParams) (_ *protocol.Hover, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("hover")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
+-	ctx, done := event.Start(ctx, "lsp.Server.hover", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Mod:
 -		return mod.Hover(ctx, snapshot, fh, params.Position)
 -	case source.Go:
@@ -40695,8 +46254,8 @@
 -}
 diff -urN a/gopls/internal/lsp/implementation.go b/gopls/internal/lsp/implementation.go
 --- a/gopls/internal/lsp/implementation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/implementation.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
++++ b/gopls/internal/lsp/implementation.go	1970-01-01 08:00:00
+@@ -1,32 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -40708,9 +46267,20 @@
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
--func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) ([]protocol.Location, error) {
+-func (s *Server) implementation(ctx context.Context, params *protocol.ImplementationParams) (_ []protocol.Location, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("implementation")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
+-	ctx, done := event.Start(ctx, "lsp.Server.implementation", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -40720,8 +46290,8 @@
 -}
 diff -urN a/gopls/internal/lsp/inlay_hint.go b/gopls/internal/lsp/inlay_hint.go
 --- a/gopls/internal/lsp/inlay_hint.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/inlay_hint.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
++++ b/gopls/internal/lsp/inlay_hint.go	1970-01-01 08:00:00
+@@ -1,33 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -40731,22 +46301,34 @@
 -import (
 -	"context"
 -
+-	"golang.org/x/tools/gopls/internal/lsp/mod"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
--	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
+-	ctx, done := event.Start(ctx, "lsp.Server.inlayHint", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
+-	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	return source.InlayHint(ctx, snapshot, fh, params.Range)
+-	switch snapshot.FileKind(fh) {
+-	case source.Mod:
+-		return mod.InlayHint(ctx, snapshot, fh, params.Range)
+-	case source.Go:
+-		return source.InlayHint(ctx, snapshot, fh, params.Range)
+-	}
+-	return nil, nil
 -}
 diff -urN a/gopls/internal/lsp/link.go b/gopls/internal/lsp/link.go
 --- a/gopls/internal/lsp/link.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/link.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,278 +0,0 @@
++++ b/gopls/internal/lsp/link.go	1970-01-01 08:00:00
+@@ -1,280 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -40773,12 +46355,15 @@
 -)
 -
 -func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) (links []protocol.DocumentLink, err error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.documentLink")
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Mod:
 -		links, err = modLinks(ctx, snapshot, fh)
 -	case source.Go:
@@ -40815,7 +46400,7 @@
 -		}
 -		// Shift the start position to the location of the
 -		// dependency within the require statement.
--		target := source.BuildLink(snapshot.View().Options().LinkTarget, "mod/"+req.Mod.String(), "")
+-		target := source.BuildLink(snapshot.Options().LinkTarget, "mod/"+req.Mod.String(), "")
 -		l, err := toProtocolLink(pm.Mapper, target, start+i, start+i+len(dep))
 -		if err != nil {
 -			return nil, err
@@ -40828,7 +46413,7 @@
 -	}
 -
 -	// Get all the links that are contained in the comments of the file.
--	urlRegexp := snapshot.View().Options().URLRegexp
+-	urlRegexp := snapshot.Options().URLRegexp
 -	for _, expr := range pm.File.Syntax.Stmt {
 -		comments := expr.Comment()
 -		if comments == nil {
@@ -40849,7 +46434,6 @@
 -
 -// goLinks returns the set of hyperlink annotations for the specified Go file.
 -func goLinks(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentLink, error) {
--	view := snapshot.View()
 -
 -	pgf, err := snapshot.ParseGo(ctx, fh, source.ParseFull)
 -	if err != nil {
@@ -40859,14 +46443,14 @@
 -	var links []protocol.DocumentLink
 -
 -	// Create links for import specs.
--	if view.Options().ImportShortcut.ShowLinks() {
+-	if snapshot.Options().ImportShortcut.ShowLinks() {
 -
 -		// If links are to pkg.go.dev, append module version suffixes.
 -		// This requires the import map from the package metadata. Ignore errors.
 -		var depsByImpPath map[source.ImportPath]source.PackageID
--		if strings.ToLower(view.Options().LinkTarget) == "pkg.go.dev" {
--			if metas, _ := snapshot.MetadataForFile(ctx, fh.URI()); len(metas) > 0 {
--				depsByImpPath = metas[0].DepsByImpPath // 0 => narrowest package
+-		if strings.ToLower(snapshot.Options().LinkTarget) == "pkg.go.dev" {
+-			if meta, err := source.NarrowestMetadataForFile(ctx, snapshot, fh.URI()); err == nil {
+-				depsByImpPath = meta.DepsByImpPath
 -			}
 -		}
 -
@@ -40876,7 +46460,7 @@
 -				continue // bad import
 -			}
 -			// See golang/go#36998: don't link to modules matching GOPRIVATE.
--			if view.IsGoPrivatePath(string(importPath)) {
+-			if snapshot.View().IsGoPrivatePath(string(importPath)) {
 -				continue
 -			}
 -
@@ -40891,7 +46475,7 @@
 -			if err != nil {
 -				return nil, err
 -			}
--			targetURL := source.BuildLink(view.Options().LinkTarget, urlPath, "")
+-			targetURL := source.BuildLink(snapshot.Options().LinkTarget, urlPath, "")
 -			// Account for the quotation marks in the positions.
 -			l, err := toProtocolLink(pgf.Mapper, targetURL, start+len(`"`), end-len(`"`))
 -			if err != nil {
@@ -40901,7 +46485,7 @@
 -		}
 -	}
 -
--	urlRegexp := snapshot.View().Options().URLRegexp
+-	urlRegexp := snapshot.Options().URLRegexp
 -
 -	// Gather links found in string literals.
 -	var str []*ast.BasicLit
@@ -41022,12 +46606,1134 @@
 -	}
 -	return protocol.DocumentLink{
 -		Range:  rng,
--		Target: targetURL,
+-		Target: &targetURL,
 -	}, nil
 -}
+diff -urN a/gopls/internal/lsp/lru/lru.go b/gopls/internal/lsp/lru/lru.go
+--- a/gopls/internal/lsp/lru/lru.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/lru/lru.go	1970-01-01 08:00:00
+@@ -1,151 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// The lru package implements a fixed-size in-memory LRU cache.
+-package lru
+-
+-import (
+-	"container/heap"
+-	"fmt"
+-	"sync"
+-)
+-
+-// A Cache is a fixed-size in-memory LRU cache.
+-type Cache struct {
+-	capacity int
+-
+-	mu    sync.Mutex
+-	used  int            // used capacity, in user-specified units
+-	m     map[any]*entry // k/v lookup
+-	lru   queue          // min-atime priority queue of *entry
+-	clock int64          // clock time, incremented whenever the cache is updated
+-}
+-
+-type entry struct {
+-	key   any
+-	value any
+-	size  int   // caller-specified size
+-	atime int64 // last access / set time
+-	index int   // index of entry in the heap slice
+-}
+-
+-// New creates a new Cache with the given capacity, which must be positive.
+-//
+-// The cache capacity uses arbitrary units, which are specified during the Set
+-// operation.
+-func New(capacity int) *Cache {
+-	if capacity == 0 {
+-		panic("zero capacity")
+-	}
+-
+-	return &Cache{
+-		capacity: capacity,
+-		m:        make(map[any]*entry),
+-	}
+-}
+-
+-// Get retrieves the value for the specified key, or nil if the key is not
+-// found.
+-//
+-// If the key is found, its access time is updated.
+-func (c *Cache) Get(key any) any {
+-	c.mu.Lock()
+-	defer c.mu.Unlock()
+-
+-	c.clock++ // every access updates the clock
+-
+-	if e, ok := c.m[key]; ok { // cache hit
+-		e.atime = c.clock
+-		heap.Fix(&c.lru, e.index)
+-		return e.value
+-	}
+-
+-	return nil
+-}
+-
+-// Set stores a value for the specified key, using its given size to update the
+-// current cache size, evicting old entries as necessary to fit in the cache
+-// capacity.
+-//
+-// Size must be a non-negative value. If size is larger than the cache
+-// capacity, the value is not stored and the cache is not modified.
+-func (c *Cache) Set(key, value any, size int) {
+-	if size < 0 {
+-		panic(fmt.Sprintf("size must be non-negative, got %d", size))
+-	}
+-	if size > c.capacity {
+-		return // uncacheable
+-	}
+-
+-	c.mu.Lock()
+-	defer c.mu.Unlock()
+-
+-	c.clock++
+-
+-	// Remove the existing cache entry for key, if it exists.
+-	e, ok := c.m[key]
+-	if ok {
+-		c.used -= e.size
+-		heap.Remove(&c.lru, e.index)
+-		delete(c.m, key)
+-	}
+-
+-	// Evict entries until the new value will fit.
+-	newUsed := c.used + size
+-	if newUsed < 0 {
+-		return // integer overflow; return silently
+-	}
+-	c.used = newUsed
+-	for c.used > c.capacity {
+-		// evict oldest entry
+-		e = heap.Pop(&c.lru).(*entry)
+-		c.used -= e.size
+-		delete(c.m, e.key)
+-	}
+-
+-	// Store the new value.
+-	// Opt: e is evicted, so it can be reused to reduce allocation.
+-	if e == nil {
+-		e = new(entry)
+-	}
+-	e.key = key
+-	e.value = value
+-	e.size = size
+-	e.atime = c.clock
+-	c.m[e.key] = e
+-	heap.Push(&c.lru, e)
+-
+-	if len(c.m) != len(c.lru) {
+-		panic("map and LRU are inconsistent")
+-	}
+-}
+-
+-// -- priority queue boilerplate --
+-
+-// queue is a min-atime priority queue of cache entries.
+-type queue []*entry
+-
+-func (q queue) Len() int { return len(q) }
+-
+-func (q queue) Less(i, j int) bool { return q[i].atime < q[j].atime }
+-
+-func (q queue) Swap(i, j int) {
+-	q[i], q[j] = q[j], q[i]
+-	q[i].index = i
+-	q[j].index = j
+-}
+-
+-func (q *queue) Push(x any) {
+-	e := x.(*entry)
+-	e.index = len(*q)
+-	*q = append(*q, e)
+-}
+-
+-func (q *queue) Pop() any {
+-	last := len(*q) - 1
+-	e := (*q)[last]
+-	(*q)[last] = nil // aid GC
+-	*q = (*q)[:last]
+-	return e
+-}
+diff -urN a/gopls/internal/lsp/lru/lru_fuzz_test.go b/gopls/internal/lsp/lru/lru_fuzz_test.go
+--- a/gopls/internal/lsp/lru/lru_fuzz_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/lru/lru_fuzz_test.go	1970-01-01 08:00:00
+@@ -1,41 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.18
+-// +build go1.18
+-
+-package lru_test
+-
+-import (
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/lru"
+-)
+-
+-// Simple fuzzing test for consistency.
+-func FuzzCache(f *testing.F) {
+-	type op struct {
+-		set        bool
+-		key, value byte
+-	}
+-	f.Fuzz(func(t *testing.T, data []byte) {
+-		var ops []op
+-		for len(data) >= 3 {
+-			ops = append(ops, op{data[0]%2 == 0, data[1], data[2]})
+-			data = data[3:]
+-		}
+-		cache := lru.New(100)
+-		var reference [256]byte
+-		for _, op := range ops {
+-			if op.set {
+-				reference[op.key] = op.value
+-				cache.Set(op.key, op.value, 1)
+-			} else {
+-				if v := cache.Get(op.key); v != nil && v != reference[op.key] {
+-					t.Fatalf("cache.Get(%d) = %d, want %d", op.key, v, reference[op.key])
+-				}
+-			}
+-		}
+-	})
+-}
+diff -urN a/gopls/internal/lsp/lru/lru_test.go b/gopls/internal/lsp/lru/lru_test.go
+--- a/gopls/internal/lsp/lru/lru_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/lru/lru_test.go	1970-01-01 08:00:00
+@@ -1,154 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package lru_test
+-
+-import (
+-	"bytes"
+-	cryptorand "crypto/rand"
+-	"fmt"
+-	"log"
+-	mathrand "math/rand"
+-	"strings"
+-	"testing"
+-
+-	"golang.org/x/sync/errgroup"
+-	"golang.org/x/tools/gopls/internal/lsp/lru"
+-)
+-
+-func TestCache(t *testing.T) {
+-	type get struct {
+-		key  string
+-		want any
+-	}
+-	type set struct {
+-		key, value string
+-	}
+-
+-	tests := []struct {
+-		label string
+-		steps []any
+-	}{
+-		{"empty cache", []any{
+-			get{"a", nil},
+-			get{"b", nil},
+-		}},
+-		{"zero-length string", []any{
+-			set{"a", ""},
+-			get{"a", ""},
+-		}},
+-		{"under capacity", []any{
+-			set{"a", "123"},
+-			set{"b", "456"},
+-			get{"a", "123"},
+-			get{"b", "456"},
+-		}},
+-		{"over capacity", []any{
+-			set{"a", "123"},
+-			set{"b", "456"},
+-			set{"c", "78901"},
+-			get{"a", nil},
+-			get{"b", "456"},
+-			get{"c", "78901"},
+-		}},
+-		{"access ordering", []any{
+-			set{"a", "123"},
+-			set{"b", "456"},
+-			get{"a", "123"},
+-			set{"c", "78901"},
+-			get{"a", "123"},
+-			get{"b", nil},
+-			get{"c", "78901"},
+-		}},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(test.label, func(t *testing.T) {
+-			c := lru.New(10)
+-			for i, step := range test.steps {
+-				switch step := step.(type) {
+-				case get:
+-					if got := c.Get(step.key); got != step.want {
+-						t.Errorf("#%d: c.Get(%q) = %q, want %q", i, step.key, got, step.want)
+-					}
+-				case set:
+-					c.Set(step.key, step.value, len(step.value))
+-				}
+-			}
+-		})
+-	}
+-}
+-
+-// TestConcurrency exercises concurrent access to the same entry.
+-//
+-// It is a copy of TestConcurrency from the filecache package.
+-func TestConcurrency(t *testing.T) {
+-	key := uniqueKey()
+-	const N = 100 // concurrency level
+-
+-	// Construct N distinct values, each larger
+-	// than a typical 4KB OS file buffer page.
+-	var values [N][8192]byte
+-	for i := range values {
+-		if _, err := mathrand.Read(values[i][:]); err != nil {
+-			t.Fatalf("rand: %v", err)
+-		}
+-	}
+-
+-	cache := lru.New(100 * 1e6) // 100MB cache
+-
+-	// get calls Get and verifies that the cache entry
+-	// matches one of the values passed to Set.
+-	get := func(mustBeFound bool) error {
+-		got := cache.Get(key)
+-		if got == nil {
+-			if !mustBeFound {
+-				return nil
+-			}
+-			return fmt.Errorf("Get did not return a value")
+-		}
+-		gotBytes := got.([]byte)
+-		for _, want := range values {
+-			if bytes.Equal(want[:], gotBytes) {
+-				return nil // a match
+-			}
+-		}
+-		return fmt.Errorf("Get returned a value that was never Set")
+-	}
+-
+-	// Perform N concurrent calls to Set and Get.
+-	// All sets must succeed.
+-	// All gets must return nothing, or one of the Set values;
+-	// there is no third possibility.
+-	var group errgroup.Group
+-	for i := range values {
+-		i := i
+-		v := values[i][:]
+-		group.Go(func() error {
+-			cache.Set(key, v, len(v))
+-			return nil
+-		})
+-		group.Go(func() error { return get(false) })
+-	}
+-	if err := group.Wait(); err != nil {
+-		if strings.Contains(err.Error(), "operation not supported") ||
+-			strings.Contains(err.Error(), "not implemented") {
+-			t.Skipf("skipping: %v", err)
+-		}
+-		t.Fatal(err)
+-	}
+-
+-	// A final Get must report one of the values that was Set.
+-	if err := get(true); err != nil {
+-		t.Fatalf("final Get failed: %v", err)
+-	}
+-}
+-
+-// uniqueKey returns a key that has never been used before.
+-func uniqueKey() (key [32]byte) {
+-	if _, err := cryptorand.Read(key[:]); err != nil {
+-		log.Fatalf("rand: %v", err)
+-	}
+-	return
+-}
+diff -urN a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go
+--- a/gopls/internal/lsp/lsp_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/lsp_test.go	1970-01-01 08:00:00
+@@ -1,760 +0,0 @@
+-// Copyright 2018 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package lsp
+-
+-import (
+-	"bytes"
+-	"context"
+-	"fmt"
+-	"os"
+-	"path/filepath"
+-	"sort"
+-	"strings"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/debug"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/lsp/tests"
+-	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-func TestMain(m *testing.M) {
+-	bug.PanicOnBugs = true
+-	testenv.ExitIfSmallMachine()
+-
+-	os.Exit(m.Run())
+-}
+-
+-// TestLSP runs the marker tests in files beneath testdata/ using
+-// implementations of each of the marker operations that make LSP RPCs to a
+-// gopls server.
+-func TestLSP(t *testing.T) {
+-	tests.RunTests(t, "testdata", true, testLSP)
+-}
+-
+-func testLSP(t *testing.T, datum *tests.Data) {
+-	ctx := tests.Context(t)
+-
+-	// Setting a debug instance suppresses logging to stderr, but ensures that we
+-	// still e.g. convert events into runtime/trace/instrumentation.
+-	//
+-	// Previously, we called event.SetExporter(nil), which turns off all
+-	// instrumentation.
+-	ctx = debug.WithInstance(ctx, "", "off")
+-
+-	session := cache.NewSession(ctx, cache.New(nil))
+-	options := source.DefaultOptions(tests.DefaultOptions)
+-	options.SetEnvSlice(datum.Config.Env)
+-	view, snapshot, release, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	defer session.RemoveView(view)
+-
+-	// Only run the -modfile specific tests in module mode with Go 1.14 or above.
+-	datum.ModfileFlagAvailable = len(snapshot.ModFiles()) > 0 && testenv.Go1Point() >= 14
+-	release()
+-
+-	// Open all files for performance reasons, because gopls only
+-	// keeps active packages (those with open files) in memory.
+-	//
+-	// In practice clients will only send document-oriented requests for open
+-	// files.
+-	var modifications []source.FileModification
+-	for _, module := range datum.Exported.Modules {
+-		for name := range module.Files {
+-			filename := datum.Exported.File(module.Name, name)
+-			if filepath.Ext(filename) != ".go" {
+-				continue
+-			}
+-			content, err := datum.Exported.FileContents(filename)
+-			if err != nil {
+-				t.Fatal(err)
+-			}
+-			modifications = append(modifications, source.FileModification{
+-				URI:        span.URIFromPath(filename),
+-				Action:     source.Open,
+-				Version:    -1,
+-				Text:       content,
+-				LanguageID: "go",
+-			})
+-		}
+-	}
+-	for filename, content := range datum.Config.Overlay {
+-		if filepath.Ext(filename) != ".go" {
+-			continue
+-		}
+-		modifications = append(modifications, source.FileModification{
+-			URI:        span.URIFromPath(filename),
+-			Action:     source.Open,
+-			Version:    -1,
+-			Text:       content,
+-			LanguageID: "go",
+-		})
+-	}
+-	if err := session.ModifyFiles(ctx, modifications); err != nil {
+-		t.Fatal(err)
+-	}
+-	r := &runner{
+-		data:     datum,
+-		ctx:      ctx,
+-		editRecv: make(chan map[span.URI][]byte, 1),
+-	}
+-
+-	r.server = NewServer(session, testClient{runner: r}, options)
+-	tests.Run(t, r, datum)
+-}
+-
+-// runner implements tests.Tests by making LSP RPCs to a gopls server.
+-type runner struct {
+-	server      *Server
+-	data        *tests.Data
+-	diagnostics map[span.URI][]*source.Diagnostic
+-	ctx         context.Context
+-	editRecv    chan map[span.URI][]byte
+-}
+-
+-// testClient stubs any client functions that may be called by LSP functions.
+-type testClient struct {
+-	protocol.Client
+-	runner *runner
+-}
+-
+-func (c testClient) Close() error {
+-	return nil
+-}
+-
+-// Trivially implement PublishDiagnostics so that we can call
+-// server.publishReports below to de-dup sent diagnostics.
+-func (c testClient) PublishDiagnostics(context.Context, *protocol.PublishDiagnosticsParams) error {
+-	return nil
+-}
+-
+-func (c testClient) ShowMessage(context.Context, *protocol.ShowMessageParams) error {
+-	return nil
+-}
+-
+-func (c testClient) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) {
+-	res, err := applyTextDocumentEdits(c.runner, params.Edit.DocumentChanges)
+-	if err != nil {
+-		return nil, err
+-	}
+-	c.runner.editRecv <- res
+-	return &protocol.ApplyWorkspaceEditResult{Applied: true}, nil
+-}
+-
+-func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) {
+-	mapper, err := r.data.Mapper(spn.URI())
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	loc, err := mapper.SpanLocation(spn)
+-	if err != nil {
+-		t.Fatalf("failed for %v: %v", spn, err)
+-	}
+-
+-	params := &protocol.CallHierarchyPrepareParams{
+-		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
+-	}
+-
+-	items, err := r.server.PrepareCallHierarchy(r.ctx, params)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	if len(items) == 0 {
+-		t.Fatalf("expected call hierarchy item to be returned for identifier at %v\n", loc.Range)
+-	}
+-
+-	callLocation := protocol.Location{
+-		URI:   items[0].URI,
+-		Range: items[0].Range,
+-	}
+-	if callLocation != loc {
+-		t.Fatalf("expected server.PrepareCallHierarchy to return identifier at %v but got %v\n", loc, callLocation)
+-	}
+-
+-	incomingCalls, err := r.server.IncomingCalls(r.ctx, &protocol.CallHierarchyIncomingCallsParams{Item: items[0]})
+-	if err != nil {
+-		t.Error(err)
+-	}
+-	var incomingCallItems []protocol.CallHierarchyItem
+-	for _, item := range incomingCalls {
+-		incomingCallItems = append(incomingCallItems, item.From)
+-	}
+-	msg := tests.DiffCallHierarchyItems(incomingCallItems, expectedCalls.IncomingCalls)
+-	if msg != "" {
+-		t.Errorf("incoming calls: %s", msg)
+-	}
+-
+-	outgoingCalls, err := r.server.OutgoingCalls(r.ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: items[0]})
+-	if err != nil {
+-		t.Error(err)
+-	}
+-	var outgoingCallItems []protocol.CallHierarchyItem
+-	for _, item := range outgoingCalls {
+-		outgoingCallItems = append(outgoingCallItems, item.To)
+-	}
+-	msg = tests.DiffCallHierarchyItems(outgoingCallItems, expectedCalls.OutgoingCalls)
+-	if msg != "" {
+-		t.Errorf("outgoing calls: %s", msg)
+-	}
+-}
+-
+-func (r *runner) SemanticTokens(t *testing.T, spn span.Span) {
+-	uri := spn.URI()
+-	filename := uri.Filename()
+-	// this is called solely for coverage in semantic.go
+-	_, err := r.server.semanticTokensFull(r.ctx, &protocol.SemanticTokensParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-	})
+-	if err != nil {
+-		t.Errorf("%v for %s", err, filename)
+-	}
+-	_, err = r.server.semanticTokensRange(r.ctx, &protocol.SemanticTokensRangeParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-		// any legal range. Just to exercise the call.
+-		Range: protocol.Range{
+-			Start: protocol.Position{
+-				Line:      0,
+-				Character: 0,
+-			},
+-			End: protocol.Position{
+-				Line:      2,
+-				Character: 0,
+-			},
+-		},
+-	})
+-	if err != nil {
+-		t.Errorf("%v for Range %s", err, filename)
+-	}
+-}
+-
+-func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []tests.SuggestedFix, expectedActions int) {
+-	uri := spn.URI()
+-	view, err := r.server.session.ViewOf(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	m, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	rng, err := m.SpanRange(spn)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	// Get the diagnostics for this view if we have not done it before.
+-	r.collectDiagnostics(view)
+-	var diagnostics []protocol.Diagnostic
+-	for _, d := range r.diagnostics[uri] {
+-		// Compare the start positions rather than the entire range because
+-		// some diagnostics have a range with the same start and end position (8:1-8:1).
+-		// The current marker functionality prevents us from having a range of 0 length.
+-		if protocol.ComparePosition(d.Range.Start, rng.Start) == 0 {
+-			diagnostics = append(diagnostics, toProtocolDiagnostics([]*source.Diagnostic{d})...)
+-			break
+-		}
+-	}
+-	var codeActionKinds []protocol.CodeActionKind
+-	for _, k := range actionKinds {
+-		codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k.ActionKind))
+-	}
+-	allActions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-		Range: rng,
+-		Context: protocol.CodeActionContext{
+-			Only:        codeActionKinds,
+-			Diagnostics: diagnostics,
+-		},
+-	})
+-	if err != nil {
+-		t.Fatalf("CodeAction %s failed: %v", spn, err)
+-	}
+-	var actions []protocol.CodeAction
+-	for _, action := range allActions {
+-		for _, fix := range actionKinds {
+-			if strings.Contains(action.Title, fix.Title) {
+-				actions = append(actions, action)
+-				break
+-			}
+-		}
+-
+-	}
+-	if len(actions) != expectedActions {
+-		var summaries []string
+-		for _, a := range actions {
+-			summaries = append(summaries, fmt.Sprintf("%q (%s)", a.Title, a.Kind))
+-		}
+-		t.Fatalf("CodeAction(...): got %d code actions (%v), want %d", len(actions), summaries, expectedActions)
+-	}
+-	action := actions[0]
+-	var match bool
+-	for _, k := range codeActionKinds {
+-		if action.Kind == k {
+-			match = true
+-			break
+-		}
+-	}
+-	if !match {
+-		t.Fatalf("unexpected kind for code action %s, got %v, want one of %v", action.Title, action.Kind, codeActionKinds)
+-	}
+-	var res map[span.URI][]byte
+-	if cmd := action.Command; cmd != nil {
+-		_, err := r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{
+-			Command:   action.Command.Command,
+-			Arguments: action.Command.Arguments,
+-		})
+-		if err != nil {
+-			t.Fatalf("error converting command %q to edits: %v", action.Command.Command, err)
+-		}
+-		res = <-r.editRecv
+-	} else {
+-		res, err = applyTextDocumentEdits(r, action.Edit.DocumentChanges)
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-	}
+-	for u, got := range res {
+-		want := r.data.Golden(t, "suggestedfix_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) {
+-			return got, nil
+-		})
+-		if diff := compare.Bytes(want, got); diff != "" {
+-			t.Errorf("suggested fixes failed for %s:\n%s", u.Filename(), diff)
+-		}
+-	}
+-}
+-
+-func (r *runner) MethodExtraction(t *testing.T, start span.Span, end span.Span) {
+-	uri := start.URI()
+-	m, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	spn := span.New(start.URI(), start.Start(), end.End())
+-	rng, err := m.SpanRange(spn)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	actionsRaw, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-		Range: rng,
+-		Context: protocol.CodeActionContext{
+-			Only: []protocol.CodeActionKind{"refactor.extract"},
+-		},
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	var actions []protocol.CodeAction
+-	for _, action := range actionsRaw {
+-		if action.Command.Title == "Extract method" {
+-			actions = append(actions, action)
+-		}
+-	}
+-	// Hack: We assume that we only get one matching code action per range.
+-	// TODO(rstambler): Support multiple code actions per test.
+-	if len(actions) == 0 || len(actions) > 1 {
+-		t.Fatalf("unexpected number of code actions, want 1, got %v", len(actions))
+-	}
+-	_, err = r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{
+-		Command:   actions[0].Command.Command,
+-		Arguments: actions[0].Command.Arguments,
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	res := <-r.editRecv
+-	for u, got := range res {
+-		want := r.data.Golden(t, "methodextraction_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) {
+-			return got, nil
+-		})
+-		if diff := compare.Bytes(want, got); diff != "" {
+-			t.Errorf("method extraction failed for %s:\n%s", u.Filename(), diff)
+-		}
+-	}
+-}
+-
+-func (r *runner) InlayHints(t *testing.T, spn span.Span) {
+-	uri := spn.URI()
+-	filename := uri.Filename()
+-
+-	hints, err := r.server.InlayHint(r.ctx, &protocol.InlayHintParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-		// TODO: add Range
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	// Map inlay hints to text edits.
+-	edits := make([]protocol.TextEdit, len(hints))
+-	for i, hint := range hints {
+-		var paddingLeft, paddingRight string
+-		if hint.PaddingLeft {
+-			paddingLeft = " "
+-		}
+-		if hint.PaddingRight {
+-			paddingRight = " "
+-		}
+-		edits[i] = protocol.TextEdit{
+-			Range:   protocol.Range{Start: hint.Position, End: hint.Position},
+-			NewText: fmt.Sprintf("<%s%s%s>", paddingLeft, hint.Label[0].Value, paddingRight),
+-		}
+-	}
+-
+-	m, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	got, _, err := source.ApplyProtocolEdits(m, edits)
+-	if err != nil {
+-		t.Error(err)
+-	}
+-
+-	withinlayHints := r.data.Golden(t, "inlayHint", filename, func() ([]byte, error) {
+-		return got, nil
+-	})
+-
+-	if !bytes.Equal(withinlayHints, got) {
+-		t.Errorf("inlay hints failed for %s, expected:\n%s\ngot:\n%s", filename, withinlayHints, got)
+-	}
+-}
+-
+-func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
+-	tag := fmt.Sprintf("%s-rename", newText)
+-
+-	uri := spn.URI()
+-	filename := uri.Filename()
+-	sm, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	loc, err := sm.SpanLocation(spn)
+-	if err != nil {
+-		t.Fatalf("failed for %v: %v", spn, err)
+-	}
+-
+-	wedit, err := r.server.Rename(r.ctx, &protocol.RenameParams{
+-		TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
+-		Position:     loc.Range.Start,
+-		NewName:      newText,
+-	})
+-	if err != nil {
+-		renamed := string(r.data.Golden(t, tag, filename, func() ([]byte, error) {
+-			return []byte(err.Error()), nil
+-		}))
+-		if err.Error() != renamed {
+-			t.Errorf("%s: rename failed for %s, expected:\n%v\ngot:\n%v\n", spn, newText, renamed, err)
+-		}
+-		return
+-	}
+-	res, err := applyTextDocumentEdits(r, wedit.DocumentChanges)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	var orderedURIs []string
+-	for uri := range res {
+-		orderedURIs = append(orderedURIs, string(uri))
+-	}
+-	sort.Strings(orderedURIs)
+-
+-	// Print the name and content of each modified file,
+-	// concatenated, and compare against the golden.
+-	var buf bytes.Buffer
+-	for i := 0; i < len(res); i++ {
+-		if i != 0 {
+-			buf.WriteByte('\n')
+-		}
+-		uri := span.URIFromURI(orderedURIs[i])
+-		if len(res) > 1 {
+-			buf.WriteString(filepath.Base(uri.Filename()))
+-			buf.WriteString(":\n")
+-		}
+-		buf.Write(res[uri])
+-	}
+-	got := buf.Bytes()
+-	want := r.data.Golden(t, tag, filename, func() ([]byte, error) {
+-		return got, nil
+-	})
+-	if diff := compare.Bytes(want, got); diff != "" {
+-		t.Errorf("rename failed for %s:\n%s", newText, diff)
+-	}
+-}
+-
+-func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) {
+-	m, err := r.data.Mapper(src.URI())
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	loc, err := m.SpanLocation(src)
+-	if err != nil {
+-		t.Fatalf("failed for %v: %v", src, err)
+-	}
+-	params := &protocol.PrepareRenameParams{
+-		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
+-	}
+-	got, err := r.server.PrepareRename(context.Background(), params)
+-	if err != nil {
+-		t.Errorf("prepare rename failed for %v: got error: %v", src, err)
+-		return
+-	}
+-
+-	// TODO(rfindley): can we consolidate on a single representation for
+-	// PrepareRename results, and use cmp.Diff here?
+-
+-	// PrepareRename may fail with no error if there was no object found at the
+-	// position.
+-	if got == nil {
+-		if want.Text != "" { // expected an ident.
+-			t.Errorf("prepare rename failed for %v: got nil", src)
+-		}
+-		return
+-	}
+-	if got.Range.Start == got.Range.End {
+-		// Special case for 0-length ranges. Marks can't specify a 0-length range,
+-		// so just compare the start.
+-		if got.Range.Start != want.Range.Start {
+-			t.Errorf("prepare rename failed: incorrect point, got %v want %v", got.Range.Start, want.Range.Start)
+-		}
+-	} else {
+-		if got.Range != want.Range {
+-			t.Errorf("prepare rename failed: incorrect range got %v want %v", got.Range, want.Range)
+-		}
+-	}
+-	if got.Placeholder != want.Text {
+-		t.Errorf("prepare rename failed: incorrect text got %v want %v", got.Placeholder, want.Text)
+-	}
+-}
+-
+-func applyTextDocumentEdits(r *runner, edits []protocol.DocumentChanges) (map[span.URI][]byte, error) {
+-	res := make(map[span.URI][]byte)
+-	for _, docEdits := range edits {
+-		if docEdits.TextDocumentEdit != nil {
+-			uri := docEdits.TextDocumentEdit.TextDocument.URI.SpanURI()
+-			var m *protocol.Mapper
+-			// If we have already edited this file, we use the edited version (rather than the
+-			// file in its original state) so that we preserve our initial changes.
+-			if content, ok := res[uri]; ok {
+-				m = protocol.NewMapper(uri, content)
+-			} else {
+-				var err error
+-				if m, err = r.data.Mapper(uri); err != nil {
+-					return nil, err
+-				}
+-			}
+-			patched, _, err := source.ApplyProtocolEdits(m, docEdits.TextDocumentEdit.Edits)
+-			if err != nil {
+-				return nil, err
+-			}
+-			res[uri] = patched
+-		}
+-	}
+-	return res, nil
+-}
+-
+-func (r *runner) SignatureHelp(t *testing.T, spn span.Span, want *protocol.SignatureHelp) {
+-	m, err := r.data.Mapper(spn.URI())
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	loc, err := m.SpanLocation(spn)
+-	if err != nil {
+-		t.Fatalf("failed for %v: %v", loc, err)
+-	}
+-	params := &protocol.SignatureHelpParams{
+-		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
+-	}
+-	got, err := r.server.SignatureHelp(r.ctx, params)
+-	if err != nil {
+-		// Only fail if we got an error we did not expect.
+-		if want != nil {
+-			t.Fatal(err)
+-		}
+-		return
+-	}
+-	if want == nil {
+-		if got != nil {
+-			t.Errorf("expected no signature, got %v", got)
+-		}
+-		return
+-	}
+-	if got == nil {
+-		t.Fatalf("expected %v, got nil", want)
+-	}
+-	if diff := tests.DiffSignatures(spn, want, got); diff != "" {
+-		t.Error(diff)
+-	}
+-}
+-
+-func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
+-	m, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	got, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	if diff := tests.DiffLinks(m, wantLinks, got); diff != "" {
+-		t.Error(diff)
+-	}
+-}
+-
+-func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) {
+-	cmd, err := command.NewListKnownPackagesCommand("List Known Packages", command.URIArg{
+-		URI: protocol.URIFromSpanURI(uri),
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	resp, err := r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{
+-		Command:   cmd.Command,
+-		Arguments: cmd.Arguments,
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	res := resp.(command.ListKnownPackagesResult)
+-	var hasPkg bool
+-	for _, p := range res.Packages {
+-		if p == expectedImport {
+-			hasPkg = true
+-			break
+-		}
+-	}
+-	if !hasPkg {
+-		t.Fatalf("%s: got %v packages\nwant contains %q", command.ListKnownPackages, res.Packages, expectedImport)
+-	}
+-	cmd, err = command.NewAddImportCommand("Add Imports", command.AddImportArgs{
+-		URI:        protocol.URIFromSpanURI(uri),
+-		ImportPath: expectedImport,
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	_, err = r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{
+-		Command:   cmd.Command,
+-		Arguments: cmd.Arguments,
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	got := (<-r.editRecv)[uri]
+-	want := r.data.Golden(t, "addimport", uri.Filename(), func() ([]byte, error) {
+-		return []byte(got), nil
+-	})
+-	if want == nil {
+-		t.Fatalf("golden file %q not found", uri.Filename())
+-	}
+-	if diff := compare.Bytes(want, got); diff != "" {
+-		t.Errorf("%s mismatch\n%s", command.AddImport, diff)
+-	}
+-}
+-
+-func (r *runner) SelectionRanges(t *testing.T, spn span.Span) {
+-	uri := spn.URI()
+-	sm, err := r.data.Mapper(uri)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	loc, err := sm.SpanLocation(spn)
+-	if err != nil {
+-		t.Error(err)
+-	}
+-
+-	ranges, err := r.server.selectionRange(r.ctx, &protocol.SelectionRangeParams{
+-		TextDocument: protocol.TextDocumentIdentifier{
+-			URI: protocol.URIFromSpanURI(uri),
+-		},
+-		Positions: []protocol.Position{loc.Range.Start},
+-	})
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-
+-	sb := &strings.Builder{}
+-	for i, path := range ranges {
+-		fmt.Fprintf(sb, "Ranges %d: ", i)
+-		rng := path
+-		for {
+-			s, e, err := sm.RangeOffsets(rng.Range)
+-			if err != nil {
+-				t.Error(err)
+-			}
+-
+-			var snippet string
+-			if e-s < 30 {
+-				snippet = string(sm.Content[s:e])
+-			} else {
+-				snippet = string(sm.Content[s:s+15]) + "..." + string(sm.Content[e-15:e])
+-			}
+-
+-			fmt.Fprintf(sb, "\n\t%v %q", rng.Range, strings.ReplaceAll(snippet, "\n", "\\n"))
+-
+-			if rng.Parent == nil {
+-				break
+-			}
+-			rng = *rng.Parent
+-		}
+-		sb.WriteRune('\n')
+-	}
+-	got := sb.String()
+-
+-	testName := "selectionrange_" + tests.SpanName(spn)
+-	want := r.data.Golden(t, testName, uri.Filename(), func() ([]byte, error) {
+-		return []byte(got), nil
+-	})
+-	if want == nil {
+-		t.Fatalf("golden file %q not found", uri.Filename())
+-	}
+-	if diff := compare.Text(got, string(want)); diff != "" {
+-		t.Errorf("%s mismatch\n%s", testName, diff)
+-	}
+-}
+-
+-func (r *runner) collectDiagnostics(view *cache.View) {
+-	if r.diagnostics != nil {
+-		return
+-	}
+-	r.diagnostics = make(map[span.URI][]*source.Diagnostic)
+-
+-	snapshot, release, err := view.Snapshot()
+-	if err != nil {
+-		panic(err)
+-	}
+-	defer release()
+-
+-	// Always run diagnostics with analysis.
+-	r.server.diagnose(r.ctx, snapshot, analyzeEverything)
+-	for uri, reports := range r.server.diagnostics {
+-		for _, report := range reports.reports {
+-			for _, d := range report.diags {
+-				r.diagnostics[uri] = append(r.diagnostics[uri], d)
+-			}
+-		}
+-	}
+-}
 diff -urN a/gopls/internal/lsp/lsprpc/autostart_default.go b/gopls/internal/lsp/lsprpc/autostart_default.go
 --- a/gopls/internal/lsp/lsprpc/autostart_default.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/autostart_default.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/autostart_default.go	1970-01-01 08:00:00
 @@ -1,39 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41070,7 +47776,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/autostart_posix.go b/gopls/internal/lsp/lsprpc/autostart_posix.go
 --- a/gopls/internal/lsp/lsprpc/autostart_posix.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/autostart_posix.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/autostart_posix.go	1970-01-01 08:00:00
 @@ -1,97 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41171,7 +47877,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/binder.go b/gopls/internal/lsp/lsprpc/binder.go
 --- a/gopls/internal/lsp/lsprpc/binder.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/binder.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/binder.go	1970-01-01 08:00:00
 @@ -1,148 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41323,7 +48029,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/binder_test.go b/gopls/internal/lsp/lsprpc/binder_test.go
 --- a/gopls/internal/lsp/lsprpc/binder_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/binder_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/binder_test.go	1970-01-01 08:00:00
 @@ -1,147 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41474,7 +48180,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/commandinterceptor.go b/gopls/internal/lsp/lsprpc/commandinterceptor.go
 --- a/gopls/internal/lsp/lsprpc/commandinterceptor.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/commandinterceptor.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/commandinterceptor.go	1970-01-01 08:00:00
 @@ -1,44 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41522,7 +48228,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/commandinterceptor_test.go b/gopls/internal/lsp/lsprpc/commandinterceptor_test.go
 --- a/gopls/internal/lsp/lsprpc/commandinterceptor_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/commandinterceptor_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/commandinterceptor_test.go	1970-01-01 08:00:00
 @@ -1,42 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41568,7 +48274,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/dialer.go b/gopls/internal/lsp/lsprpc/dialer.go
 --- a/gopls/internal/lsp/lsprpc/dialer.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/dialer.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/dialer.go	1970-01-01 08:00:00
 @@ -1,114 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41686,7 +48392,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/goenv.go b/gopls/internal/lsp/lsprpc/goenv.go
 --- a/gopls/internal/lsp/lsprpc/goenv.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/goenv.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/goenv.go	1970-01-01 08:00:00
 @@ -1,96 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -41700,10 +48406,10 @@
 -	"fmt"
 -	"os"
 -
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/gocommand"
 -	jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2"
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -)
 -
 -func GoEnvMiddleware() (Middleware, error) {
@@ -41786,8 +48492,8 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/goenv_test.go b/gopls/internal/lsp/lsprpc/goenv_test.go
 --- a/gopls/internal/lsp/lsprpc/goenv_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/goenv_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,65 +0,0 @@
++++ b/gopls/internal/lsp/lsprpc/goenv_test.go	1970-01-01 08:00:00
+@@ -1,68 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -41799,6 +48505,7 @@
 -	"testing"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/internal/testenv"
 -
 -	. "golang.org/x/tools/gopls/internal/lsp/lsprpc"
 -)
@@ -41815,6 +48522,8 @@
 -}
 -
 -func TestGoEnvMiddleware(t *testing.T) {
+-	testenv.NeedsTool(t, "go")
+-
 -	ctx := context.Background()
 -
 -	server := &initServer{}
@@ -41855,8 +48564,8 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/lsprpc.go b/gopls/internal/lsp/lsprpc/lsprpc.go
 --- a/gopls/internal/lsp/lsprpc/lsprpc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/lsprpc.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,543 +0,0 @@
++++ b/gopls/internal/lsp/lsprpc/lsprpc.go	1970-01-01 08:00:00
+@@ -1,545 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -41915,10 +48624,11 @@
 -
 -func (s *StreamServer) Binder() *ServerBinder {
 -	newServer := func(ctx context.Context, client protocol.ClientCloser) protocol.Server {
--		session := cache.NewSession(ctx, s.cache, s.optionsOverrides)
+-		session := cache.NewSession(ctx, s.cache)
 -		server := s.serverForTest
 -		if server == nil {
--			server = lsp.NewServer(session, client)
+-			options := source.DefaultOptions(s.optionsOverrides)
+-			server = lsp.NewServer(session, client, options)
 -			if instance := debug.GetInstance(ctx); instance != nil {
 -				instance.AddService(server, session)
 -			}
@@ -41932,10 +48642,11 @@
 -// incoming streams using a new lsp server.
 -func (s *StreamServer) ServeStream(ctx context.Context, conn jsonrpc2.Conn) error {
 -	client := protocol.ClientDispatcher(conn)
--	session := cache.NewSession(ctx, s.cache, s.optionsOverrides)
+-	session := cache.NewSession(ctx, s.cache)
 -	server := s.serverForTest
 -	if server == nil {
--		server = lsp.NewServer(session, client)
+-		options := source.DefaultOptions(s.optionsOverrides)
+-		server = lsp.NewServer(session, client, options)
 -		if instance := debug.GetInstance(ctx); instance != nil {
 -			instance.AddService(server, session)
 -		}
@@ -42402,8 +49113,8 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/lsprpc_test.go b/gopls/internal/lsp/lsprpc/lsprpc_test.go
 --- a/gopls/internal/lsp/lsprpc/lsprpc_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/lsprpc_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,345 +0,0 @@
++++ b/gopls/internal/lsp/lsprpc/lsprpc_test.go	1970-01-01 08:00:00
+@@ -1,376 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -42412,6 +49123,7 @@
 -
 -import (
 -	"context"
+-	"encoding/json"
 -	"errors"
 -	"regexp"
 -	"strings"
@@ -42425,6 +49137,7 @@
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/jsonrpc2"
 -	"golang.org/x/tools/internal/jsonrpc2/servertest"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -type FakeClient struct {
@@ -42695,6 +49408,8 @@
 -}
 -
 -func TestEnvForwarding(t *testing.T) {
+-	testenv.NeedsTool(t, "go")
+-
 -	ctx := context.Background()
 -
 -	server := &initServer{}
@@ -42749,9 +49464,36 @@
 -		}
 -	}
 -}
+-
+-// For #59479, verify that empty slices are serialized as [].
+-func TestEmptySlices(t *testing.T) {
+-	// The LSP would prefer that empty slices be sent as [] rather than null.
+-	const bad = `{"a":null}`
+-	const good = `{"a":[]}`
+-	var x struct {
+-		A []string `json:"a"`
+-	}
+-	buf, _ := json.Marshal(x)
+-	if string(buf) != bad {
+-		// uninitialized is ezpected to give null
+-		t.Errorf("unexpectedly got %s, want %s", buf, bad)
+-	}
+-	x.A = make([]string, 0)
+-	buf, _ = json.Marshal(x)
+-	if string(buf) != good {
+-		// expect []
+-		t.Errorf("unexpectedly got %s, want %s", buf, good)
+-	}
+-	x.A = []string{}
+-	buf, _ = json.Marshal(x)
+-	if string(buf) != good {
+-		// expect []
+-		t.Errorf("unexpectedly got %s, want %s", buf, good)
+-	}
+-}
 diff -urN a/gopls/internal/lsp/lsprpc/middleware.go b/gopls/internal/lsp/lsprpc/middleware.go
 --- a/gopls/internal/lsp/lsprpc/middleware.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/middleware.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/middleware.go	1970-01-01 08:00:00
 @@ -1,142 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -42897,7 +49639,7 @@
 -}
 diff -urN a/gopls/internal/lsp/lsprpc/middleware_test.go b/gopls/internal/lsp/lsprpc/middleware_test.go
 --- a/gopls/internal/lsp/lsprpc/middleware_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsprpc/middleware_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/lsprpc/middleware_test.go	1970-01-01 08:00:00
 @@ -1,93 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -42992,1373 +49734,9 @@
 -		delay *= 4
 -	}
 -}
-diff -urN a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go
---- a/gopls/internal/lsp/lsp_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/lsp_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1360 +0,0 @@
--// Copyright 2018 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package lsp
--
--import (
--	"bytes"
--	"context"
--	"fmt"
--	"os"
--	"os/exec"
--	"path/filepath"
--	"sort"
--	"strings"
--	"testing"
--
--	"github.com/google/go-cmp/cmp"
--	"github.com/google/go-cmp/cmp/cmpopts"
--	"golang.org/x/tools/gopls/internal/lsp/cache"
--	"golang.org/x/tools/gopls/internal/lsp/command"
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/lsp/tests"
--	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
--	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
--	"golang.org/x/tools/internal/diff"
--	"golang.org/x/tools/internal/event"
--	"golang.org/x/tools/internal/testenv"
--)
--
--func TestMain(m *testing.M) {
--	bug.PanicOnBugs = true
--	testenv.ExitIfSmallMachine()
--
--	// Set the global exporter to nil so that we don't log to stderr. This avoids
--	// a lot of misleading noise in test output.
--	//
--	// TODO(rfindley): investigate whether we can/should capture logs scoped to
--	// individual tests by passing in a context with a local exporter.
--	event.SetExporter(nil)
--
--	os.Exit(m.Run())
--}
--
--// TestLSP runs the marker tests in files beneath testdata/ using
--// implementations of each of the marker operations (e.g. @codelens) that
--// make LSP RPCs (e.g. textDocument/codeLens) to a gopls server.
--func TestLSP(t *testing.T) {
--	tests.RunTests(t, "testdata", true, testLSP)
--}
--
--func testLSP(t *testing.T, datum *tests.Data) {
--	ctx := tests.Context(t)
--
--	session := cache.NewSession(ctx, cache.New(nil), nil)
--	options := source.DefaultOptions().Clone()
--	tests.DefaultOptions(options)
--	session.SetOptions(options)
--	options.SetEnvSlice(datum.Config.Env)
--	view, snapshot, release, err := session.NewView(ctx, datum.Config.Dir, span.URIFromPath(datum.Config.Dir), options)
--	if err != nil {
--		t.Fatal(err)
--	}
--
--	defer session.RemoveView(view)
--
--	// Enable type error analyses for tests.
--	// TODO(golang/go#38212): Delete this once they are enabled by default.
--	tests.EnableAllAnalyzers(options)
--	session.SetViewOptions(ctx, view, options)
--
--	// Enable all inlay hints for tests.
--	tests.EnableAllInlayHints(options)
--
--	// Only run the -modfile specific tests in module mode with Go 1.14 or above.
--	datum.ModfileFlagAvailable = len(snapshot.ModFiles()) > 0 && testenv.Go1Point() >= 14
--	release()
--
--	// Open all files for performance reasons. This is done because gopls only
--	// keeps active packages in memory for open files.
--	//
--	// In practice clients will only send document-oriented requests for open
--	// files.
--	var modifications []source.FileModification
--	for _, module := range datum.Exported.Modules {
--		for name := range module.Files {
--			filename := datum.Exported.File(module.Name, name)
--			if filepath.Ext(filename) != ".go" {
--				continue
--			}
--			content, err := datum.Exported.FileContents(filename)
--			if err != nil {
--				t.Fatal(err)
--			}
--			modifications = append(modifications, source.FileModification{
--				URI:        span.URIFromPath(filename),
--				Action:     source.Open,
--				Version:    -1,
--				Text:       content,
--				LanguageID: "go",
--			})
--		}
--	}
--	for filename, content := range datum.Config.Overlay {
--		if filepath.Ext(filename) != ".go" {
--			continue
--		}
--		modifications = append(modifications, source.FileModification{
--			URI:        span.URIFromPath(filename),
--			Action:     source.Open,
--			Version:    -1,
--			Text:       content,
--			LanguageID: "go",
--		})
--	}
--	if err := session.ModifyFiles(ctx, modifications); err != nil {
--		t.Fatal(err)
--	}
--	r := &runner{
--		data:        datum,
--		ctx:         ctx,
--		normalizers: tests.CollectNormalizers(datum.Exported),
--		editRecv:    make(chan map[span.URI][]byte, 1),
--	}
--
--	r.server = NewServer(session, testClient{runner: r})
--	tests.Run(t, r, datum)
--}
--
--// runner implements tests.Tests by making LSP RPCs to a gopls server.
--type runner struct {
--	server      *Server
--	data        *tests.Data
--	diagnostics map[span.URI][]*source.Diagnostic
--	ctx         context.Context
--	normalizers []tests.Normalizer
--	editRecv    chan map[span.URI][]byte
--}
--
--// testClient stubs any client functions that may be called by LSP functions.
--type testClient struct {
--	protocol.Client
--	runner *runner
--}
--
--func (c testClient) Close() error {
--	return nil
--}
--
--// Trivially implement PublishDiagnostics so that we can call
--// server.publishReports below to de-dup sent diagnostics.
--func (c testClient) PublishDiagnostics(context.Context, *protocol.PublishDiagnosticsParams) error {
--	return nil
--}
--
--func (c testClient) ShowMessage(context.Context, *protocol.ShowMessageParams) error {
--	return nil
--}
--
--func (c testClient) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResult, error) {
--	res, err := applyTextDocumentEdits(c.runner, params.Edit.DocumentChanges)
--	if err != nil {
--		return nil, err
--	}
--	c.runner.editRecv <- res
--	return &protocol.ApplyWorkspaceEditResult{Applied: true}, nil
--}
--
--func (r *runner) CallHierarchy(t *testing.T, spn span.Span, expectedCalls *tests.CallHierarchyResult) {
--	mapper, err := r.data.Mapper(spn.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := mapper.SpanLocation(spn)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", spn, err)
--	}
--
--	params := &protocol.CallHierarchyPrepareParams{
--		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--	}
--
--	items, err := r.server.PrepareCallHierarchy(r.ctx, params)
--	if err != nil {
--		t.Fatal(err)
--	}
--	if len(items) == 0 {
--		t.Fatalf("expected call hierarchy item to be returned for identifier at %v\n", loc.Range)
--	}
--
--	callLocation := protocol.Location{
--		URI:   items[0].URI,
--		Range: items[0].Range,
--	}
--	if callLocation != loc {
--		t.Fatalf("expected server.PrepareCallHierarchy to return identifier at %v but got %v\n", loc, callLocation)
--	}
--
--	incomingCalls, err := r.server.IncomingCalls(r.ctx, &protocol.CallHierarchyIncomingCallsParams{Item: items[0]})
--	if err != nil {
--		t.Error(err)
--	}
--	var incomingCallItems []protocol.CallHierarchyItem
--	for _, item := range incomingCalls {
--		incomingCallItems = append(incomingCallItems, item.From)
--	}
--	msg := tests.DiffCallHierarchyItems(incomingCallItems, expectedCalls.IncomingCalls)
--	if msg != "" {
--		t.Error(fmt.Sprintf("incoming calls: %s", msg))
--	}
--
--	outgoingCalls, err := r.server.OutgoingCalls(r.ctx, &protocol.CallHierarchyOutgoingCallsParams{Item: items[0]})
--	if err != nil {
--		t.Error(err)
--	}
--	var outgoingCallItems []protocol.CallHierarchyItem
--	for _, item := range outgoingCalls {
--		outgoingCallItems = append(outgoingCallItems, item.To)
--	}
--	msg = tests.DiffCallHierarchyItems(outgoingCallItems, expectedCalls.OutgoingCalls)
--	if msg != "" {
--		t.Error(fmt.Sprintf("outgoing calls: %s", msg))
--	}
--}
--
--func (r *runner) CodeLens(t *testing.T, uri span.URI, want []protocol.CodeLens) {
--	if !strings.HasSuffix(uri.Filename(), "go.mod") {
--		return
--	}
--	got, err := r.server.codeLens(r.ctx, &protocol.CodeLensParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.DocumentURI(uri),
--		},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	if diff := tests.DiffCodeLens(uri, want, got); diff != "" {
--		t.Errorf("%s: %s", uri, diff)
--	}
--}
--
--func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnostic) {
--	// Get the diagnostics for this view if we have not done it before.
--	v := r.server.session.View(r.data.Config.Dir)
--	r.collectDiagnostics(v)
--	tests.CompareDiagnostics(t, uri, want, r.diagnostics[uri])
--}
--
--func (r *runner) FoldingRanges(t *testing.T, spn span.Span) {
--	uri := spn.URI()
--	view, err := r.server.session.ViewOf(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	original := view.Options()
--	modified := original
--	defer r.server.session.SetViewOptions(r.ctx, view, original)
--
--	for _, test := range []struct {
--		lineFoldingOnly bool
--		prefix          string
--	}{
--		{false, "foldingRange"},
--		{true, "foldingRange-lineFolding"},
--	} {
--		modified.LineFoldingOnly = test.lineFoldingOnly
--		view, err = r.server.session.SetViewOptions(r.ctx, view, modified)
--		if err != nil {
--			t.Error(err)
--			continue
--		}
--		ranges, err := r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{
--			TextDocument: protocol.TextDocumentIdentifier{
--				URI: protocol.URIFromSpanURI(uri),
--			},
--		})
--		if err != nil {
--			t.Error(err)
--			continue
--		}
--		r.foldingRanges(t, test.prefix, uri, ranges)
--	}
--}
--
--func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, ranges []protocol.FoldingRange) {
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	// Fold all ranges.
--	nonOverlapping := nonOverlappingRanges(ranges)
--	for i, rngs := range nonOverlapping {
--		got, err := foldRanges(m, string(m.Content), rngs)
--		if err != nil {
--			t.Error(err)
--			continue
--		}
--		tag := fmt.Sprintf("%s-%d", prefix, i)
--		want := string(r.data.Golden(t, tag, uri.Filename(), func() ([]byte, error) {
--			return []byte(got), nil
--		}))
--
--		if want != got {
--			t.Errorf("%s: foldingRanges failed for %s, expected:\n%v\ngot:\n%v", tag, uri.Filename(), want, got)
--		}
--	}
--
--	// Filter by kind.
--	kinds := []protocol.FoldingRangeKind{protocol.Imports, protocol.Comment}
--	for _, kind := range kinds {
--		var kindOnly []protocol.FoldingRange
--		for _, fRng := range ranges {
--			if fRng.Kind == string(kind) {
--				kindOnly = append(kindOnly, fRng)
--			}
--		}
--
--		nonOverlapping := nonOverlappingRanges(kindOnly)
--		for i, rngs := range nonOverlapping {
--			got, err := foldRanges(m, string(m.Content), rngs)
--			if err != nil {
--				t.Error(err)
--				continue
--			}
--			tag := fmt.Sprintf("%s-%s-%d", prefix, kind, i)
--			want := string(r.data.Golden(t, tag, uri.Filename(), func() ([]byte, error) {
--				return []byte(got), nil
--			}))
--
--			if want != got {
--				t.Errorf("%s: foldingRanges failed for %s, expected:\n%v\ngot:\n%v", tag, uri.Filename(), want, got)
--			}
--		}
--
--	}
--}
--
--func nonOverlappingRanges(ranges []protocol.FoldingRange) (res [][]protocol.FoldingRange) {
--	for _, fRng := range ranges {
--		setNum := len(res)
--		for i := 0; i < len(res); i++ {
--			canInsert := true
--			for _, rng := range res[i] {
--				if conflict(rng, fRng) {
--					canInsert = false
--					break
--				}
--			}
--			if canInsert {
--				setNum = i
--				break
--			}
--		}
--		if setNum == len(res) {
--			res = append(res, []protocol.FoldingRange{})
--		}
--		res[setNum] = append(res[setNum], fRng)
--	}
--	return res
--}
--
--func conflict(a, b protocol.FoldingRange) bool {
--	// a start position is <= b start positions
--	return (a.StartLine < b.StartLine || (a.StartLine == b.StartLine && a.StartCharacter <= b.StartCharacter)) &&
--		(a.EndLine > b.StartLine || (a.EndLine == b.StartLine && a.EndCharacter > b.StartCharacter))
--}
--
--func foldRanges(m *protocol.Mapper, contents string, ranges []protocol.FoldingRange) (string, error) {
--	foldedText := "<>"
--	res := contents
--	// Apply the edits from the end of the file forward
--	// to preserve the offsets
--	// TODO(adonovan): factor to use diff.ApplyEdits, which validates the input.
--	for i := len(ranges) - 1; i >= 0; i-- {
--		r := ranges[i]
--		start, err := m.PositionPoint(protocol.Position{Line: r.StartLine, Character: r.StartCharacter})
--		if err != nil {
--			return "", err
--		}
--		end, err := m.PositionPoint(protocol.Position{Line: r.EndLine, Character: r.EndCharacter})
--		if err != nil {
--			return "", err
--		}
--		res = res[:start.Offset()] + foldedText + res[end.Offset():]
--	}
--	return res, nil
--}
--
--func (r *runner) Format(t *testing.T, spn span.Span) {
--	uri := spn.URI()
--	filename := uri.Filename()
--	gofmted := r.data.Golden(t, "gofmt", filename, func() ([]byte, error) {
--		cmd := exec.Command("gofmt", filename)
--		out, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files
--		return out, nil
--	})
--
--	edits, err := r.server.Formatting(r.ctx, &protocol.DocumentFormattingParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--	})
--	if err != nil {
--		if len(gofmted) > 0 {
--			t.Error(err)
--		}
--		return
--	}
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got, _, err := source.ApplyProtocolEdits(m, edits)
--	if err != nil {
--		t.Error(err)
--	}
--	if diff := compare.Bytes(gofmted, got); diff != "" {
--		t.Errorf("format failed for %s (-want +got):\n%s", filename, diff)
--	}
--}
--
--func (r *runner) SemanticTokens(t *testing.T, spn span.Span) {
--	uri := spn.URI()
--	filename := uri.Filename()
--	// this is called solely for coverage in semantic.go
--	_, err := r.server.semanticTokensFull(r.ctx, &protocol.SemanticTokensParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--	})
--	if err != nil {
--		t.Errorf("%v for %s", err, filename)
--	}
--	_, err = r.server.semanticTokensRange(r.ctx, &protocol.SemanticTokensRangeParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		// any legal range. Just to exercise the call.
--		Range: protocol.Range{
--			Start: protocol.Position{
--				Line:      0,
--				Character: 0,
--			},
--			End: protocol.Position{
--				Line:      2,
--				Character: 0,
--			},
--		},
--	})
--	if err != nil {
--		t.Errorf("%v for Range %s", err, filename)
--	}
--}
--
--func (r *runner) Import(t *testing.T, spn span.Span) {
--	// Invokes textDocument/codeAction and applies all the "goimports" edits.
--
--	uri := spn.URI()
--	filename := uri.Filename()
--	actions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got := m.Content
--	if len(actions) > 0 {
--		res, err := applyTextDocumentEdits(r, actions[0].Edit.DocumentChanges)
--		if err != nil {
--			t.Fatal(err)
--		}
--		got = res[uri]
--	}
--	want := r.data.Golden(t, "goimports", filename, func() ([]byte, error) {
--		return got, nil
--	})
--	if diff := compare.Bytes(want, got); diff != "" {
--		t.Errorf("import failed for %s:\n%s", filename, diff)
--	}
--}
--
--func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []tests.SuggestedFix, expectedActions int) {
--	uri := spn.URI()
--	view, err := r.server.session.ViewOf(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	rng, err := m.SpanRange(spn)
--	if err != nil {
--		t.Fatal(err)
--	}
--	// Get the diagnostics for this view if we have not done it before.
--	r.collectDiagnostics(view)
--	var diagnostics []protocol.Diagnostic
--	for _, d := range r.diagnostics[uri] {
--		// Compare the start positions rather than the entire range because
--		// some diagnostics have a range with the same start and end position (8:1-8:1).
--		// The current marker functionality prevents us from having a range of 0 length.
--		if protocol.ComparePosition(d.Range.Start, rng.Start) == 0 {
--			diagnostics = append(diagnostics, toProtocolDiagnostics([]*source.Diagnostic{d})...)
--			break
--		}
--	}
--	var codeActionKinds []protocol.CodeActionKind
--	for _, k := range actionKinds {
--		codeActionKinds = append(codeActionKinds, protocol.CodeActionKind(k.ActionKind))
--	}
--	allActions, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		Range: rng,
--		Context: protocol.CodeActionContext{
--			Only:        codeActionKinds,
--			Diagnostics: diagnostics,
--		},
--	})
--	if err != nil {
--		t.Fatalf("CodeAction %s failed: %v", spn, err)
--	}
--	var actions []protocol.CodeAction
--	for _, action := range allActions {
--		for _, fix := range actionKinds {
--			if strings.Contains(action.Title, fix.Title) {
--				actions = append(actions, action)
--				break
--			}
--		}
--
--	}
--	if len(actions) != expectedActions {
--		var summaries []string
--		for _, a := range actions {
--			summaries = append(summaries, fmt.Sprintf("%q (%s)", a.Title, a.Kind))
--		}
--		t.Fatalf("CodeAction(...): got %d code actions (%v), want %d", len(actions), summaries, expectedActions)
--	}
--	action := actions[0]
--	var match bool
--	for _, k := range codeActionKinds {
--		if action.Kind == k {
--			match = true
--			break
--		}
--	}
--	if !match {
--		t.Fatalf("unexpected kind for code action %s, got %v, want one of %v", action.Title, action.Kind, codeActionKinds)
--	}
--	var res map[span.URI][]byte
--	if cmd := action.Command; cmd != nil {
--		_, err := r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{
--			Command:   action.Command.Command,
--			Arguments: action.Command.Arguments,
--		})
--		if err != nil {
--			t.Fatalf("error converting command %q to edits: %v", action.Command.Command, err)
--		}
--		res = <-r.editRecv
--	} else {
--		res, err = applyTextDocumentEdits(r, action.Edit.DocumentChanges)
--		if err != nil {
--			t.Fatal(err)
--		}
--	}
--	for u, got := range res {
--		want := r.data.Golden(t, "suggestedfix_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) {
--			return got, nil
--		})
--		if diff := compare.Bytes(want, got); diff != "" {
--			t.Errorf("suggested fixes failed for %s:\n%s", u.Filename(), diff)
--		}
--	}
--}
--
--func (r *runner) FunctionExtraction(t *testing.T, start span.Span, end span.Span) {
--	uri := start.URI()
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	spn := span.New(start.URI(), start.Start(), end.End())
--	rng, err := m.SpanRange(spn)
--	if err != nil {
--		t.Fatal(err)
--	}
--	actionsRaw, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		Range: rng,
--		Context: protocol.CodeActionContext{
--			Only: []protocol.CodeActionKind{"refactor.extract"},
--		},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	var actions []protocol.CodeAction
--	for _, action := range actionsRaw {
--		if action.Command.Title == "Extract function" {
--			actions = append(actions, action)
--		}
--	}
--	// Hack: We assume that we only get one code action per range.
--	// TODO(rstambler): Support multiple code actions per test.
--	if len(actions) == 0 || len(actions) > 1 {
--		t.Fatalf("unexpected number of code actions, want 1, got %v", len(actions))
--	}
--	_, err = r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{
--		Command:   actions[0].Command.Command,
--		Arguments: actions[0].Command.Arguments,
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	res := <-r.editRecv
--	for u, got := range res {
--		want := r.data.Golden(t, "functionextraction_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) {
--			return got, nil
--		})
--		if diff := compare.Bytes(want, got); diff != "" {
--			t.Errorf("function extraction failed for %s:\n%s", u.Filename(), diff)
--		}
--	}
--}
--
--func (r *runner) MethodExtraction(t *testing.T, start span.Span, end span.Span) {
--	uri := start.URI()
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	spn := span.New(start.URI(), start.Start(), end.End())
--	rng, err := m.SpanRange(spn)
--	if err != nil {
--		t.Fatal(err)
--	}
--	actionsRaw, err := r.server.CodeAction(r.ctx, &protocol.CodeActionParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		Range: rng,
--		Context: protocol.CodeActionContext{
--			Only: []protocol.CodeActionKind{"refactor.extract"},
--		},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	var actions []protocol.CodeAction
--	for _, action := range actionsRaw {
--		if action.Command.Title == "Extract method" {
--			actions = append(actions, action)
--		}
--	}
--	// Hack: We assume that we only get one matching code action per range.
--	// TODO(rstambler): Support multiple code actions per test.
--	if len(actions) == 0 || len(actions) > 1 {
--		t.Fatalf("unexpected number of code actions, want 1, got %v", len(actions))
--	}
--	_, err = r.server.ExecuteCommand(r.ctx, &protocol.ExecuteCommandParams{
--		Command:   actions[0].Command.Command,
--		Arguments: actions[0].Command.Arguments,
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	res := <-r.editRecv
--	for u, got := range res {
--		want := r.data.Golden(t, "methodextraction_"+tests.SpanName(spn), u.Filename(), func() ([]byte, error) {
--			return got, nil
--		})
--		if diff := compare.Bytes(want, got); diff != "" {
--			t.Errorf("method extraction failed for %s:\n%s", u.Filename(), diff)
--		}
--	}
--}
--
--// TODO(rfindley): This handler needs more work. The output is still a bit hard
--// to read (range diffs do not format nicely), and it is too entangled with hover.
--func (r *runner) Definition(t *testing.T, _ span.Span, d tests.Definition) {
--	sm, err := r.data.Mapper(d.Src.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := sm.SpanLocation(d.Src)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", d.Src, err)
--	}
--	tdpp := protocol.LocationTextDocumentPositionParams(loc)
--	var got []protocol.Location
--	var hover *protocol.Hover
--	if d.IsType {
--		params := &protocol.TypeDefinitionParams{
--			TextDocumentPositionParams: tdpp,
--		}
--		got, err = r.server.TypeDefinition(r.ctx, params)
--	} else {
--		params := &protocol.DefinitionParams{
--			TextDocumentPositionParams: tdpp,
--		}
--		got, err = r.server.Definition(r.ctx, params)
--		if err != nil {
--			t.Fatalf("failed for %v: %+v", d.Src, err)
--		}
--		v := &protocol.HoverParams{
--			TextDocumentPositionParams: tdpp,
--		}
--		hover, err = r.server.Hover(r.ctx, v)
--	}
--	if err != nil {
--		t.Fatalf("failed for %v: %v", d.Src, err)
--	}
--	dm, err := r.data.Mapper(d.Def.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	def, err := dm.SpanLocation(d.Def)
--	if err != nil {
--		t.Fatal(err)
--	}
--	if !d.OnlyHover {
--		want := []protocol.Location{def}
--		if diff := cmp.Diff(want, got); diff != "" {
--			t.Fatalf("Definition(%s) mismatch (-want +got):\n%s", d.Src, diff)
--		}
--	}
--	didSomething := false
--	if hover != nil {
--		didSomething = true
--		tag := fmt.Sprintf("%s-hoverdef", d.Name)
--		want := string(r.data.Golden(t, tag, d.Src.URI().Filename(), func() ([]byte, error) {
--			return []byte(hover.Contents.Value), nil
--		}))
--		got := hover.Contents.Value
--		if diff := tests.DiffMarkdown(want, got); diff != "" {
--			t.Errorf("%s: markdown mismatch:\n%s", d.Src, diff)
--		}
--	}
--	if !d.OnlyHover {
--		didSomething = true
--		locURI := got[0].URI.SpanURI()
--		lm, err := r.data.Mapper(locURI)
--		if err != nil {
--			t.Fatal(err)
--		}
--		if def, err := lm.LocationSpan(got[0]); err != nil {
--			t.Fatalf("failed for %v: %v", got[0], err)
--		} else if def != d.Def {
--			t.Errorf("for %v got %v want %v", d.Src, def, d.Def)
--		}
--	}
--	if !didSomething {
--		t.Errorf("no tests ran for %s", d.Src.URI())
--	}
--}
--
--func (r *runner) Implementation(t *testing.T, spn span.Span, wantSpans []span.Span) {
--	sm, err := r.data.Mapper(spn.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := sm.SpanLocation(spn)
--	if err != nil {
--		t.Fatal(err)
--	}
--	gotImpls, err := r.server.Implementation(r.ctx, &protocol.ImplementationParams{
--		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--	})
--	if err != nil {
--		t.Fatalf("Server.Implementation(%s): %v", spn, err)
--	}
--	gotLocs, err := tests.LocationsToSpans(r.data, gotImpls)
--	if err != nil {
--		t.Fatal(err)
--	}
--	sanitize := func(s string) string {
--		return strings.ReplaceAll(s, r.data.Config.Dir, "gopls/internal/lsp/testdata")
--	}
--	want := sanitize(tests.SortAndFormatSpans(wantSpans))
--	got := sanitize(tests.SortAndFormatSpans(gotLocs))
--	if got != want {
--		t.Errorf("implementations(%s):\n%s", sanitize(fmt.Sprint(spn)), diff.Unified("want", "got", want, got))
--	}
--}
--
--func (r *runner) Highlight(t *testing.T, src span.Span, spans []span.Span) {
--	m, err := r.data.Mapper(src.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := m.SpanLocation(src)
--	if err != nil {
--		t.Fatal(err)
--	}
--	params := &protocol.DocumentHighlightParams{
--		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--	}
--	highlights, err := r.server.DocumentHighlight(r.ctx, params)
--	if err != nil {
--		t.Fatalf("DocumentHighlight(%v) failed: %v", params, err)
--	}
--	var got []protocol.Range
--	for _, h := range highlights {
--		got = append(got, h.Range)
--	}
--
--	var want []protocol.Range
--	for _, s := range spans {
--		rng, err := m.SpanRange(s)
--		if err != nil {
--			t.Fatalf("Mapper.SpanRange(%v) failed: %v", s, err)
--		}
--		want = append(want, rng)
--	}
--
--	sortRanges := func(s []protocol.Range) {
--		sort.Slice(s, func(i, j int) bool {
--			return protocol.CompareRange(s[i], s[j]) < 0
--		})
--	}
--
--	sortRanges(got)
--	sortRanges(want)
--
--	if diff := cmp.Diff(want, got); diff != "" {
--		t.Errorf("DocumentHighlight(%v) mismatch (-want +got):\n%s", src, diff)
--	}
--}
--
--func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) {
--	// This test is substantially the same as (*runner).References in source/source_test.go.
--	// TODO(adonovan): Factor (and remove fluff). Where should the common code live?
--
--	sm, err := r.data.Mapper(src.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := sm.SpanLocation(src)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", src, err)
--	}
--	for _, includeDeclaration := range []bool{true, false} {
--		t.Run(fmt.Sprintf("refs-declaration-%v", includeDeclaration), func(t *testing.T) {
--			want := make(map[protocol.Location]bool)
--			for i, pos := range itemList {
--				// We don't want the first result if we aren't including the declaration.
--				// TODO(adonovan): don't assume a single declaration:
--				// there may be >1 if corresponding methods are considered.
--				if i == 0 && !includeDeclaration {
--					continue
--				}
--				m, err := r.data.Mapper(pos.URI())
--				if err != nil {
--					t.Fatal(err)
--				}
--				loc, err := m.SpanLocation(pos)
--				if err != nil {
--					t.Fatalf("failed for %v: %v", src, err)
--				}
--				want[loc] = true
--			}
--			params := &protocol.ReferenceParams{
--				TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--				Context: protocol.ReferenceContext{
--					IncludeDeclaration: includeDeclaration,
--				},
--			}
--			got, err := r.server.References(r.ctx, params)
--			if err != nil {
--				t.Fatalf("failed for %v: %v", src, err)
--			}
--
--			sanitize := func(s string) string {
--				// In practice, CONFIGDIR means "gopls/internal/lsp/testdata".
--				return strings.ReplaceAll(s, r.data.Config.Dir, "CONFIGDIR")
--			}
--			formatLocation := func(loc protocol.Location) string {
--				return fmt.Sprintf("%s:%d.%d-%d.%d",
--					sanitize(string(loc.URI)),
--					loc.Range.Start.Line+1,
--					loc.Range.Start.Character+1,
--					loc.Range.End.Line+1,
--					loc.Range.End.Character+1)
--			}
--			toSlice := func(set map[protocol.Location]bool) []protocol.Location {
--				// TODO(adonovan): use generic maps.Keys(), someday.
--				list := make([]protocol.Location, 0, len(set))
--				for key := range set {
--					list = append(list, key)
--				}
--				return list
--			}
--			toString := func(locs []protocol.Location) string {
--				// TODO(adonovan): use generic JoinValues(locs, formatLocation).
--				strs := make([]string, len(locs))
--				for i, loc := range locs {
--					strs[i] = formatLocation(loc)
--				}
--				sort.Strings(strs)
--				return strings.Join(strs, "\n")
--			}
--			gotStr := toString(got)
--			wantStr := toString(toSlice(want))
--			if gotStr != wantStr {
--				t.Errorf("incorrect references (got %d, want %d) at %s:\n%s",
--					len(got), len(want),
--					formatLocation(loc),
--					diff.Unified("want", "got", wantStr, gotStr))
--			}
--		})
--	}
--}
--
--func (r *runner) InlayHints(t *testing.T, spn span.Span) {
--	uri := spn.URI()
--	filename := uri.Filename()
--
--	hints, err := r.server.InlayHint(r.ctx, &protocol.InlayHintParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		// TODO: add Range
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--
--	// Map inlay hints to text edits.
--	edits := make([]protocol.TextEdit, len(hints))
--	for i, hint := range hints {
--		var paddingLeft, paddingRight string
--		if hint.PaddingLeft {
--			paddingLeft = " "
--		}
--		if hint.PaddingRight {
--			paddingRight = " "
--		}
--		edits[i] = protocol.TextEdit{
--			Range:   protocol.Range{Start: hint.Position, End: hint.Position},
--			NewText: fmt.Sprintf("<%s%s%s>", paddingLeft, hint.Label[0].Value, paddingRight),
--		}
--	}
--
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got, _, err := source.ApplyProtocolEdits(m, edits)
--	if err != nil {
--		t.Error(err)
--	}
--
--	withinlayHints := r.data.Golden(t, "inlayHint", filename, func() ([]byte, error) {
--		return got, nil
--	})
--
--	if !bytes.Equal(withinlayHints, got) {
--		t.Errorf("inlay hints failed for %s, expected:\n%s\ngot:\n%s", filename, withinlayHints, got)
--	}
--}
--
--func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
--	tag := fmt.Sprintf("%s-rename", newText)
--
--	uri := spn.URI()
--	filename := uri.Filename()
--	sm, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := sm.SpanLocation(spn)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", spn, err)
--	}
--
--	wedit, err := r.server.Rename(r.ctx, &protocol.RenameParams{
--		TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
--		Position:     loc.Range.Start,
--		NewName:      newText,
--	})
--	if err != nil {
--		renamed := string(r.data.Golden(t, tag, filename, func() ([]byte, error) {
--			return []byte(err.Error()), nil
--		}))
--		if err.Error() != renamed {
--			t.Errorf("%s: rename failed for %s, expected:\n%v\ngot:\n%v\n", spn, newText, renamed, err)
--		}
--		return
--	}
--	res, err := applyTextDocumentEdits(r, wedit.DocumentChanges)
--	if err != nil {
--		t.Fatal(err)
--	}
--	var orderedURIs []string
--	for uri := range res {
--		orderedURIs = append(orderedURIs, string(uri))
--	}
--	sort.Strings(orderedURIs)
--
--	// Print the name and content of each modified file,
--	// concatenated, and compare against the golden.
--	var buf bytes.Buffer
--	for i := 0; i < len(res); i++ {
--		if i != 0 {
--			buf.WriteByte('\n')
--		}
--		uri := span.URIFromURI(orderedURIs[i])
--		if len(res) > 1 {
--			buf.WriteString(filepath.Base(uri.Filename()))
--			buf.WriteString(":\n")
--		}
--		buf.Write(res[uri])
--	}
--	got := buf.Bytes()
--	want := r.data.Golden(t, tag, filename, func() ([]byte, error) {
--		return got, nil
--	})
--	if diff := compare.Bytes(want, got); diff != "" {
--		t.Errorf("rename failed for %s:\n%s", newText, diff)
--	}
--}
--
--func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) {
--	m, err := r.data.Mapper(src.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := m.SpanLocation(src)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", src, err)
--	}
--	params := &protocol.PrepareRenameParams{
--		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--	}
--	got, err := r.server.PrepareRename(context.Background(), params)
--	if err != nil {
--		t.Errorf("prepare rename failed for %v: got error: %v", src, err)
--		return
--	}
--
--	// TODO(rfindley): can we consolidate on a single representation for
--	// PrepareRename results, and use cmp.Diff here?
--
--	// PrepareRename may fail with no error if there was no object found at the
--	// position.
--	if got == nil {
--		if want.Text != "" { // expected an ident.
--			t.Errorf("prepare rename failed for %v: got nil", src)
--		}
--		return
--	}
--	if got.Range.Start == got.Range.End {
--		// Special case for 0-length ranges. Marks can't specify a 0-length range,
--		// so just compare the start.
--		if got.Range.Start != want.Range.Start {
--			t.Errorf("prepare rename failed: incorrect point, got %v want %v", got.Range.Start, want.Range.Start)
--		}
--	} else {
--		if got.Range != want.Range {
--			t.Errorf("prepare rename failed: incorrect range got %v want %v", got.Range, want.Range)
--		}
--	}
--	if got.Placeholder != want.Text {
--		t.Errorf("prepare rename failed: incorrect text got %v want %v", got.Placeholder, want.Text)
--	}
--}
--
--func applyTextDocumentEdits(r *runner, edits []protocol.DocumentChanges) (map[span.URI][]byte, error) {
--	res := make(map[span.URI][]byte)
--	for _, docEdits := range edits {
--		if docEdits.TextDocumentEdit != nil {
--			uri := docEdits.TextDocumentEdit.TextDocument.URI.SpanURI()
--			var m *protocol.Mapper
--			// If we have already edited this file, we use the edited version (rather than the
--			// file in its original state) so that we preserve our initial changes.
--			if content, ok := res[uri]; ok {
--				m = protocol.NewMapper(uri, content)
--			} else {
--				var err error
--				if m, err = r.data.Mapper(uri); err != nil {
--					return nil, err
--				}
--			}
--			patched, _, err := source.ApplyProtocolEdits(m, docEdits.TextDocumentEdit.Edits)
--			if err != nil {
--				return nil, err
--			}
--			res[uri] = patched
--		}
--	}
--	return res, nil
--}
--
--func (r *runner) Symbols(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) {
--	params := &protocol.DocumentSymbolParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--	}
--	got, err := r.server.DocumentSymbol(r.ctx, params)
--	if err != nil {
--		t.Fatal(err)
--	}
--
--	symbols := make([]protocol.DocumentSymbol, len(got))
--	for i, s := range got {
--		s, ok := s.(protocol.DocumentSymbol)
--		if !ok {
--			t.Fatalf("%v: wanted []DocumentSymbols but got %v", uri, got)
--		}
--		symbols[i] = s
--	}
--
--	// Sort by position to make it easier to find errors.
--	sortSymbols := func(s []protocol.DocumentSymbol) {
--		sort.Slice(s, func(i, j int) bool {
--			return protocol.CompareRange(s[i].SelectionRange, s[j].SelectionRange) < 0
--		})
--	}
--	sortSymbols(expectedSymbols)
--	sortSymbols(symbols)
--
--	// Ignore 'Range' here as it is difficult (impossible?) to express
--	// multi-line ranges in the packagestest framework.
--	ignoreRange := cmpopts.IgnoreFields(protocol.DocumentSymbol{}, "Range")
--	if diff := cmp.Diff(expectedSymbols, symbols, ignoreRange); diff != "" {
--		t.Errorf("mismatching symbols (-want +got)\n%s", diff)
--	}
--}
--
--func (r *runner) WorkspaceSymbols(t *testing.T, uri span.URI, query string, typ tests.WorkspaceSymbolsTestType) {
--	matcher := tests.WorkspaceSymbolsTestTypeToMatcher(typ)
--
--	original := r.server.session.Options()
--	modified := original
--	modified.SymbolMatcher = matcher
--	r.server.session.SetOptions(modified)
--	defer r.server.session.SetOptions(original)
--
--	params := &protocol.WorkspaceSymbolParams{
--		Query: query,
--	}
--	gotSymbols, err := r.server.Symbol(r.ctx, params)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got, err := tests.WorkspaceSymbolsString(r.ctx, r.data, uri, gotSymbols)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got = filepath.ToSlash(tests.Normalize(got, r.normalizers))
--	want := string(r.data.Golden(t, fmt.Sprintf("workspace_symbol-%s-%s", strings.ToLower(string(matcher)), query), uri.Filename(), func() ([]byte, error) {
--		return []byte(got), nil
--	}))
--	if diff := compare.Text(want, got); diff != "" {
--		t.Error(diff)
--	}
--}
--
--func (r *runner) SignatureHelp(t *testing.T, spn span.Span, want *protocol.SignatureHelp) {
--	m, err := r.data.Mapper(spn.URI())
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := m.SpanLocation(spn)
--	if err != nil {
--		t.Fatalf("failed for %v: %v", loc, err)
--	}
--	params := &protocol.SignatureHelpParams{
--		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(loc),
--	}
--	got, err := r.server.SignatureHelp(r.ctx, params)
--	if err != nil {
--		// Only fail if we got an error we did not expect.
--		if want != nil {
--			t.Fatal(err)
--		}
--		return
--	}
--	if want == nil {
--		if got != nil {
--			t.Errorf("expected no signature, got %v", got)
--		}
--		return
--	}
--	if got == nil {
--		t.Fatalf("expected %v, got nil", want)
--	}
--	if diff := tests.DiffSignatures(spn, want, got); diff != "" {
--		t.Error(diff)
--	}
--}
--
--func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
--	m, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	got, err := r.server.DocumentLink(r.ctx, &protocol.DocumentLinkParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	if diff := tests.DiffLinks(m, wantLinks, got); diff != "" {
--		t.Error(diff)
--	}
--}
--
--func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) {
--	cmd, err := command.NewListKnownPackagesCommand("List Known Packages", command.URIArg{
--		URI: protocol.URIFromSpanURI(uri),
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	resp, err := r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{
--		Command:   cmd.Command,
--		Arguments: cmd.Arguments,
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	res := resp.(command.ListKnownPackagesResult)
--	var hasPkg bool
--	for _, p := range res.Packages {
--		if p == expectedImport {
--			hasPkg = true
--			break
--		}
--	}
--	if !hasPkg {
--		t.Fatalf("%s: got %v packages\nwant contains %q", command.ListKnownPackages, res.Packages, expectedImport)
--	}
--	cmd, err = command.NewAddImportCommand("Add Imports", command.AddImportArgs{
--		URI:        protocol.URIFromSpanURI(uri),
--		ImportPath: expectedImport,
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	_, err = r.server.executeCommand(r.ctx, &protocol.ExecuteCommandParams{
--		Command:   cmd.Command,
--		Arguments: cmd.Arguments,
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--	got := (<-r.editRecv)[uri]
--	want := r.data.Golden(t, "addimport", uri.Filename(), func() ([]byte, error) {
--		return []byte(got), nil
--	})
--	if want == nil {
--		t.Fatalf("golden file %q not found", uri.Filename())
--	}
--	if diff := compare.Bytes(want, got); diff != "" {
--		t.Errorf("%s mismatch\n%s", command.AddImport, diff)
--	}
--}
--
--func (r *runner) SelectionRanges(t *testing.T, spn span.Span) {
--	uri := spn.URI()
--	sm, err := r.data.Mapper(uri)
--	if err != nil {
--		t.Fatal(err)
--	}
--	loc, err := sm.SpanLocation(spn)
--	if err != nil {
--		t.Error(err)
--	}
--
--	ranges, err := r.server.selectionRange(r.ctx, &protocol.SelectionRangeParams{
--		TextDocument: protocol.TextDocumentIdentifier{
--			URI: protocol.URIFromSpanURI(uri),
--		},
--		Positions: []protocol.Position{loc.Range.Start},
--	})
--	if err != nil {
--		t.Fatal(err)
--	}
--
--	sb := &strings.Builder{}
--	for i, path := range ranges {
--		fmt.Fprintf(sb, "Ranges %d: ", i)
--		rng := path
--		for {
--			s, e, err := sm.RangeOffsets(rng.Range)
--			if err != nil {
--				t.Error(err)
--			}
--
--			var snippet string
--			if e-s < 30 {
--				snippet = string(sm.Content[s:e])
--			} else {
--				snippet = string(sm.Content[s:s+15]) + "..." + string(sm.Content[e-15:e])
--			}
--
--			fmt.Fprintf(sb, "\n\t%v %q", rng.Range, strings.ReplaceAll(snippet, "\n", "\\n"))
--
--			if rng.Parent == nil {
--				break
--			}
--			rng = *rng.Parent
--		}
--		sb.WriteRune('\n')
--	}
--	got := sb.String()
--
--	testName := "selectionrange_" + tests.SpanName(spn)
--	want := r.data.Golden(t, testName, uri.Filename(), func() ([]byte, error) {
--		return []byte(got), nil
--	})
--	if want == nil {
--		t.Fatalf("golden file %q not found", uri.Filename())
--	}
--	if diff := compare.Text(got, string(want)); diff != "" {
--		t.Errorf("%s mismatch\n%s", testName, diff)
--	}
--}
--
--func (r *runner) collectDiagnostics(view *cache.View) {
--	if r.diagnostics != nil {
--		return
--	}
--	r.diagnostics = make(map[span.URI][]*source.Diagnostic)
--
--	snapshot, release, err := view.Snapshot()
--	if err != nil {
--		panic(err)
--	}
--	defer release()
--
--	// Always run diagnostics with analysis.
--	r.server.diagnose(r.ctx, snapshot, true)
--	for uri, reports := range r.server.diagnostics {
--		for _, report := range reports.reports {
--			for _, d := range report.diags {
--				r.diagnostics[uri] = append(r.diagnostics[uri], d)
--			}
--		}
--	}
--}
 diff -urN a/gopls/internal/lsp/mod/code_lens.go b/gopls/internal/lsp/mod/code_lens.go
 --- a/gopls/internal/lsp/mod/code_lens.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/code_lens.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/mod/code_lens.go	1970-01-01 08:00:00
 @@ -1,191 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -44553,8 +49931,8 @@
 -}
 diff -urN a/gopls/internal/lsp/mod/diagnostics.go b/gopls/internal/lsp/mod/diagnostics.go
 --- a/gopls/internal/lsp/mod/diagnostics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/diagnostics.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,561 +0,0 @@
++++ b/gopls/internal/lsp/mod/diagnostics.go	1970-01-01 08:00:00
+@@ -1,559 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -44566,28 +49944,36 @@
 -import (
 -	"context"
 -	"fmt"
+-	"runtime"
 -	"sort"
 -	"strings"
+-	"sync"
 -
 -	"golang.org/x/mod/modfile"
 -	"golang.org/x/mod/semver"
--	"golang.org/x/tools/gopls/internal/govulncheck"
+-	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck/govulncheck"
 -	"golang.org/x/tools/internal/event"
--	"golang.org/x/vuln/osv"
 -)
 -
--// Diagnostics returns diagnostics for the modules in the workspace.
--//
--// It waits for completion of type-checking of all active packages.
+-// Diagnostics returns diagnostics from parsing the modules in the workspace.
 -func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
 -	ctx, done := event.Start(ctx, "mod.Diagnostics", source.SnapshotLabels(snapshot)...)
 -	defer done()
 -
--	return collectDiagnostics(ctx, snapshot, ModDiagnostics)
+-	return collectDiagnostics(ctx, snapshot, ModParseDiagnostics)
+-}
+-
+-// Diagnostics returns diagnostics from running go mod tidy.
+-func TidyDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
+-	ctx, done := event.Start(ctx, "mod.Diagnostics", source.SnapshotLabels(snapshot)...)
+-	defer done()
+-
+-	return collectDiagnostics(ctx, snapshot, ModTidyDiagnostics)
 -}
 -
 -// UpgradeDiagnostics returns upgrade diagnostics for the modules in the
@@ -44609,32 +49995,41 @@
 -}
 -
 -func collectDiagnostics(ctx context.Context, snapshot source.Snapshot, diagFn func(context.Context, source.Snapshot, source.FileHandle) ([]*source.Diagnostic, error)) (map[span.URI][]*source.Diagnostic, error) {
+-	g, ctx := errgroup.WithContext(ctx)
+-	cpulimit := runtime.GOMAXPROCS(0)
+-	g.SetLimit(cpulimit)
+-
+-	var mu sync.Mutex
 -	reports := make(map[span.URI][]*source.Diagnostic)
+-
 -	for _, uri := range snapshot.ModFiles() {
--		fh, err := snapshot.GetFile(ctx, uri)
--		if err != nil {
--			return nil, err
--		}
--		reports[fh.URI()] = []*source.Diagnostic{}
--		diagnostics, err := diagFn(ctx, snapshot, fh)
--		if err != nil {
--			return nil, err
--		}
--		for _, d := range diagnostics {
--			fh, err := snapshot.GetFile(ctx, d.URI)
+-		uri := uri
+-		g.Go(func() error {
+-			fh, err := snapshot.ReadFile(ctx, uri)
 -			if err != nil {
--				return nil, err
+-				return err
 -			}
--			reports[fh.URI()] = append(reports[fh.URI()], d)
--		}
+-			diagnostics, err := diagFn(ctx, snapshot, fh)
+-			if err != nil {
+-				return err
+-			}
+-			for _, d := range diagnostics {
+-				mu.Lock()
+-				reports[d.URI] = append(reports[fh.URI()], d)
+-				mu.Unlock()
+-			}
+-			return nil
+-		})
+-	}
+-
+-	if err := g.Wait(); err != nil {
+-		return nil, err
 -	}
 -	return reports, nil
 -}
 -
--// ModDiagnostics waits for completion of type-checking of all active
--// packages, then returns diagnostics from diagnosing the packages in
--// the workspace and from tidying the go.mod file.
--func ModDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (diagnostics []*source.Diagnostic, err error) {
+-// ModParseDiagnostics reports diagnostics from parsing the mod file.
+-func ModParseDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (diagnostics []*source.Diagnostic, err error) {
 -	pm, err := snapshot.ParseMod(ctx, fh)
 -	if err != nil {
 -		if pm == nil || len(pm.ParseErrors) == 0 {
@@ -44642,28 +50037,14 @@
 -		}
 -		return pm.ParseErrors, nil
 -	}
+-	return nil, nil
+-}
 -
--	// Packages in the workspace can contribute diagnostics to go.mod files.
--	// TODO(rfindley): Try to avoid type checking all packages in the workspace here,
--	// for every go.mod file. If gc_details is enabled, it looks like this could lead to extra
--	// go command invocations (as gc details is not memoized).
--	active, err := snapshot.ActiveMetadata(ctx)
--	if err != nil && !source.IsNonFatalGoModError(err) {
--		event.Error(ctx, fmt.Sprintf("workspace packages: diagnosing %s", pm.URI), err)
--	}
--	if err == nil {
--		// Note: the call to PackageDiagnostics below may be the first operation
--		// after the initial metadata load, and therefore result in type-checking
--		// or loading many packages.
--		ids := make([]source.PackageID, len(active))
--		for i, meta := range active {
--			ids[i] = meta.ID
--		}
--		diags, err := snapshot.PackageDiagnostics(ctx, ids...)
--		if err != nil {
--			return nil, err
--		}
--		diagnostics = append(diagnostics, diags[fh.URI()]...)
+-// ModTidyDiagnostics reports diagnostics from running go mod tidy.
+-func ModTidyDiagnostics(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) (diagnostics []*source.Diagnostic, err error) {
+-	pm, err := snapshot.ParseMod(ctx, fh) // memoized
+-	if err != nil {
+-		return nil, nil // errors reported by ModDiagnostics above
 -	}
 -
 -	tidied, err := snapshot.ModTidy(ctx, pm)
@@ -44744,14 +50125,14 @@
 -
 -	diagSource := source.Govulncheck
 -	vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()]
--	if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports {
+-	if vs == nil && snapshot.Options().Vulncheck == source.ModeVulncheckImports {
 -		vs, err = snapshot.ModVuln(ctx, fh.URI())
 -		if err != nil {
 -			return nil, err
 -		}
 -		diagSource = source.Vulncheck
 -	}
--	if vs == nil || len(vs.Vulns) == 0 {
+-	if vs == nil || len(vs.Findings) == 0 {
 -		return nil, nil
 -	}
 -
@@ -44760,20 +50141,17 @@
 -		// must not happen
 -		return nil, err // TODO: bug report
 -	}
--	type modVuln struct {
--		mod  *govulncheck.Module
--		vuln *govulncheck.Vuln
--	}
--	vulnsByModule := make(map[string][]modVuln)
--	for _, vuln := range vs.Vulns {
--		for _, mod := range vuln.Modules {
--			vulnsByModule[mod.Path] = append(vulnsByModule[mod.Path], modVuln{mod, vuln})
+-	vulnsByModule := make(map[string][]*govulncheck.Finding)
+-
+-	for _, finding := range vs.Findings {
+-		if vuln, typ := foundVuln(finding); typ == vulnCalled || typ == vulnImported {
+-			vulnsByModule[vuln.Module] = append(vulnsByModule[vuln.Module], finding)
 -		}
 -	}
--
 -	for _, req := range pm.File.Require {
--		vulns := vulnsByModule[req.Mod.Path]
--		if len(vulns) == 0 {
+-		mod := req.Mod.Path
+-		findings := vulnsByModule[mod]
+-		if len(findings) == 0 {
 -			continue
 -		}
 -		// note: req.Syntax is the line corresponding to 'require', which means
@@ -44791,10 +50169,8 @@
 -		// others to 'info' level diagnostics.
 -		// Fixes will include only the upgrades for warning level diagnostics.
 -		var warningFixes, infoFixes []source.SuggestedFix
--		var warning, info []string
--		var relatedInfo []protocol.DiagnosticRelatedInformation
--		for _, mv := range vulns {
--			mod, vuln := mv.mod, mv.vuln
+-		var warningSet, infoSet = map[string]bool{}, map[string]bool{}
+-		for _, finding := range findings {
 -			// It is possible that the source code was changed since the last
 -			// govulncheck run and information in the `vulns` info is stale.
 -			// For example, imagine that a user is in the middle of updating
@@ -44811,33 +50187,42 @@
 -			// version in the require statement is equal to or higher than the
 -			// fixed version, skip generating a diagnostic about the vulnerability.
 -			// Eventually, the user has to rerun govulncheck.
--			if mod.FixedVersion != "" && semver.IsValid(req.Mod.Version) && semver.Compare(mod.FixedVersion, req.Mod.Version) <= 0 {
+-			if finding.FixedVersion != "" && semver.IsValid(req.Mod.Version) && semver.Compare(finding.FixedVersion, req.Mod.Version) <= 0 {
 -				continue
 -			}
--			if !vuln.IsCalled() {
--				info = append(info, vuln.OSV.ID)
--			} else {
--				warning = append(warning, vuln.OSV.ID)
--				relatedInfo = append(relatedInfo, listRelatedInfo(ctx, snapshot, vuln)...)
+-			switch _, typ := foundVuln(finding); typ {
+-			case vulnImported:
+-				infoSet[finding.OSV] = true
+-			case vulnCalled:
+-				warningSet[finding.OSV] = true
 -			}
 -			// Upgrade to the exact version we offer the user, not the most recent.
--			if fixedVersion := mod.FixedVersion; semver.IsValid(fixedVersion) && semver.Compare(req.Mod.Version, fixedVersion) < 0 {
+-			if fixedVersion := finding.FixedVersion; semver.IsValid(fixedVersion) && semver.Compare(req.Mod.Version, fixedVersion) < 0 {
 -				cmd, err := getUpgradeCodeAction(fh, req, fixedVersion)
 -				if err != nil {
 -					return nil, err // TODO: bug report
 -				}
 -				sf := source.SuggestedFixFromCommand(cmd, protocol.QuickFix)
--				if !vuln.IsCalled() {
+-				switch _, typ := foundVuln(finding); typ {
+-				case vulnImported:
 -					infoFixes = append(infoFixes, sf)
--				} else {
+-				case vulnCalled:
 -					warningFixes = append(warningFixes, sf)
 -				}
 -			}
 -		}
 -
--		if len(warning) == 0 && len(info) == 0 {
+-		if len(warningSet) == 0 && len(infoSet) == 0 {
 -			continue
 -		}
+-		// Remove affecting osvs from the non-affecting osv list if any.
+-		if len(warningSet) > 0 {
+-			for k := range infoSet {
+-				if warningSet[k] {
+-					delete(infoSet, k)
+-				}
+-			}
+-		}
 -		// Add an upgrade for module@latest.
 -		// TODO(suzmue): verify if latest is the same as fixedVersion.
 -		latest, err := getUpgradeCodeAction(fh, req, "latest")
@@ -44851,11 +50236,8 @@
 -		if len(infoFixes) > 0 {
 -			infoFixes = append(infoFixes, sf)
 -		}
--
--		sort.Strings(warning)
--		sort.Strings(info)
--
--		if len(warning) > 0 {
+-		if len(warningSet) > 0 {
+-			warning := sortedKeys(warningSet)
 -			warningFixes = append(warningFixes, suggestRunOrResetGovulncheck)
 -			vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{
 -				URI:            fh.URI(),
@@ -44864,10 +50246,10 @@
 -				Source:         diagSource,
 -				Message:        getVulnMessage(req.Mod.Path, warning, true, diagSource == source.Govulncheck),
 -				SuggestedFixes: warningFixes,
--				Related:        relatedInfo,
 -			})
 -		}
--		if len(info) > 0 {
+-		if len(infoSet) > 0 {
+-			info := sortedKeys(infoSet)
 -			infoFixes = append(infoFixes, suggestRunOrResetGovulncheck)
 -			vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{
 -				URI:            fh.URI(),
@@ -44876,7 +50258,6 @@
 -				Source:         diagSource,
 -				Message:        getVulnMessage(req.Mod.Path, info, false, diagSource == source.Govulncheck),
 -				SuggestedFixes: infoFixes,
--				Related:        relatedInfo,
 -			})
 -		}
 -	}
@@ -44884,7 +50265,13 @@
 -	// TODO(hyangah): place this diagnostic on the `go` directive or `toolchain` directive
 -	// after https://go.dev/issue/57001.
 -	const diagnoseStdLib = false
--	if diagnoseStdLib {
+-
+-	// If diagnosing the stdlib, add standard library vulnerability diagnostics
+-	// on the module declaration.
+-	//
+-	// Only proceed if we have a valid module declaration on which to position
+-	// the diagnostics.
+-	if diagnoseStdLib && pm.File.Module != nil && pm.File.Module.Syntax != nil {
 -		// Add standard library vulnerabilities.
 -		stdlibVulns := vulnsByModule["stdlib"]
 -		if len(stdlibVulns) == 0 {
@@ -44897,41 +50284,44 @@
 -			return vulnDiagnostics, nil // TODO: bug report
 -		}
 -
--		stdlib := stdlibVulns[0].mod.FoundVersion
--		var warning, info []string
--		var relatedInfo []protocol.DiagnosticRelatedInformation
--		for _, mv := range stdlibVulns {
--			vuln := mv.vuln
--			stdlib = mv.mod.FoundVersion
--			if !vuln.IsCalled() {
--				info = append(info, vuln.OSV.ID)
--			} else {
--				warning = append(warning, vuln.OSV.ID)
--				relatedInfo = append(relatedInfo, listRelatedInfo(ctx, snapshot, vuln)...)
+-		var warningSet, infoSet = map[string]bool{}, map[string]bool{}
+-		for _, finding := range stdlibVulns {
+-			switch _, typ := foundVuln(finding); typ {
+-			case vulnImported:
+-				infoSet[finding.OSV] = true
+-			case vulnCalled:
+-				warningSet[finding.OSV] = true
 -			}
 -		}
--		if len(warning) > 0 {
+-		if len(warningSet) > 0 {
+-			warning := sortedKeys(warningSet)
 -			fixes := []source.SuggestedFix{suggestRunOrResetGovulncheck}
 -			vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{
 -				URI:            fh.URI(),
 -				Range:          rng,
 -				Severity:       protocol.SeverityWarning,
 -				Source:         diagSource,
--				Message:        getVulnMessage(stdlib, warning, true, diagSource == source.Govulncheck),
+-				Message:        getVulnMessage("go", warning, true, diagSource == source.Govulncheck),
 -				SuggestedFixes: fixes,
--				Related:        relatedInfo,
 -			})
+-
+-			// remove affecting osvs from the non-affecting osv list if any.
+-			for k := range infoSet {
+-				if warningSet[k] {
+-					delete(infoSet, k)
+-				}
+-			}
 -		}
--		if len(info) > 0 {
+-		if len(infoSet) > 0 {
+-			info := sortedKeys(infoSet)
 -			fixes := []source.SuggestedFix{suggestRunOrResetGovulncheck}
 -			vulnDiagnostics = append(vulnDiagnostics, &source.Diagnostic{
 -				URI:            fh.URI(),
 -				Range:          rng,
 -				Severity:       protocol.SeverityInformation,
 -				Source:         diagSource,
--				Message:        getVulnMessage(stdlib, info, false, diagSource == source.Govulncheck),
+-				Message:        getVulnMessage("go", info, false, diagSource == source.Govulncheck),
 -				SuggestedFixes: fixes,
--				Related:        relatedInfo,
 -			})
 -		}
 -	}
@@ -44939,6 +50329,46 @@
 -	return vulnDiagnostics, nil
 -}
 -
+-type vulnFindingType int
+-
+-const (
+-	vulnUnknown vulnFindingType = iota
+-	vulnCalled
+-	vulnImported
+-	vulnRequired
+-)
+-
+-// foundVuln returns the frame info describing discovered vulnerable symbol/package/module
+-// and how this vulnerability affects the analyzed package or module.
+-func foundVuln(finding *govulncheck.Finding) (*govulncheck.Frame, vulnFindingType) {
+-	// finding.Trace is sorted from the imported vulnerable symbol to
+-	// the entry point in the callstack.
+-	// If Function is set, then Package must be set. Module will always be set.
+-	// If Function is set it was found in the call graph, otherwise if Package is set
+-	// it was found in the import graph, otherwise it was found in the require graph.
+-	// See the documentation of govulncheck.Finding.
+-	if len(finding.Trace) == 0 { // this shouldn't happen, but just in case...
+-		return nil, vulnUnknown
+-	}
+-	vuln := finding.Trace[0]
+-	if vuln.Package == "" {
+-		return vuln, vulnRequired
+-	}
+-	if vuln.Function == "" {
+-		return vuln, vulnImported
+-	}
+-	return vuln, vulnCalled
+-}
+-
+-func sortedKeys(m map[string]bool) []string {
+-	ret := make([]string, 0, len(m))
+-	for k := range m {
+-		ret = append(ret, k)
+-	}
+-	sort.Strings(ret)
+-	return ret
+-}
+-
 -// suggestGovulncheckAction returns a code action that suggests either run govulncheck
 -// for more accurate investigation (if the present vulncheck diagnostics are based on
 -// analysis less accurate than govulncheck) or reset the existing govulncheck result
@@ -44993,66 +50423,12 @@
 -	return b.String()
 -}
 -
--func listRelatedInfo(ctx context.Context, snapshot source.Snapshot, vuln *govulncheck.Vuln) []protocol.DiagnosticRelatedInformation {
--	var ri []protocol.DiagnosticRelatedInformation
--	for _, m := range vuln.Modules {
--		for _, p := range m.Packages {
--			for _, c := range p.CallStacks {
--				if len(c.Frames) == 0 {
--					continue
--				}
--				entry := c.Frames[0]
--				pos := entry.Position
--				if pos.Filename == "" {
--					continue // token.Position Filename is an optional field.
--				}
--				uri := span.URIFromPath(pos.Filename)
--				startPos := protocol.Position{
--					Line: uint32(pos.Line) - 1,
--					// We need to read the file contents to precisesly map
--					// token.Position (pos) to the UTF16-based column offset
--					// protocol.Position requires. That can be expensive.
--					// We need this related info to just help users to open
--					// the entry points of the callstack and once the file is
--					// open, we will compute the precise location based on the
--					// open file contents. So, use the beginning of the line
--					// as the position here instead of precise UTF16-based
--					// position computation.
--					Character: 0,
--				}
--				ri = append(ri, protocol.DiagnosticRelatedInformation{
--					Location: protocol.Location{
--						URI: protocol.URIFromSpanURI(uri),
--						Range: protocol.Range{
--							Start: startPos,
--							End:   startPos,
--						},
--					},
--					Message: fmt.Sprintf("[%v] %v -> %v.%v", vuln.OSV.ID, entry.Name(), p.Path, c.Symbol),
--				})
--			}
--		}
--	}
--	return ri
--}
--
--func formatMessage(v *govulncheck.Vuln) string {
--	details := []byte(v.OSV.Details)
--	// Remove any new lines that are not preceded or followed by a new line.
--	for i, r := range details {
--		if r == '\n' && i > 0 && details[i-1] != '\n' && i+1 < len(details) && details[i+1] != '\n' {
--			details[i] = ' '
--		}
--	}
--	return strings.TrimSpace(strings.Replace(string(details), "\n\n", "\n\n  ", -1))
--}
--
 -// href returns the url for the vulnerability information.
 -// Eventually we should retrieve the url embedded in the osv.Entry.
 -// While vuln.go.dev is under development, this always returns
 -// the page in pkg.go.dev.
--func href(vuln *osv.Entry) string {
--	return fmt.Sprintf("https://pkg.go.dev/vuln/%s", vuln.ID)
+-func href(vulnID string) string {
+-	return fmt.Sprintf("https://pkg.go.dev/vuln/%s", vulnID)
 -}
 -
 -func getUpgradeCodeAction(fh source.FileHandle, req *modfile.Require, version string) (protocol.Command, error) {
@@ -45084,7 +50460,7 @@
 -	var chosenVersionedUpgrade string
 -	var selected []protocol.CodeAction
 -
--	seen := make(map[string]bool)
+-	seenTitles := make(map[string]bool)
 -
 -	for _, action := range actions {
 -		if strings.HasPrefix(action.Title, upgradeCodeActionPrefix) {
@@ -45096,8 +50472,8 @@
 -			}
 -		} else if strings.HasPrefix(action.Title, "Reset govulncheck") {
 -			resetAction = action
--		} else if !seen[action.Command.Title] {
--			seen[action.Command.Title] = true
+-		} else if !seenTitles[action.Command.Title] {
+-			seenTitles[action.Command.Title] = true
 -			selected = append(selected, action)
 -		}
 -	}
@@ -45118,7 +50494,7 @@
 -}
 diff -urN a/gopls/internal/lsp/mod/format.go b/gopls/internal/lsp/mod/format.go
 --- a/gopls/internal/lsp/mod/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/format.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/mod/format.go	1970-01-01 08:00:00
 @@ -1,30 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -45147,13 +50523,13 @@
 -		return nil, err
 -	}
 -	// Calculate the edits to be made due to the change.
--	diffs := snapshot.View().Options().ComputeEdits(string(pm.Mapper.Content), string(formatted))
+-	diffs := snapshot.Options().ComputeEdits(string(pm.Mapper.Content), string(formatted))
 -	return source.ToProtocolEdits(pm.Mapper, diffs)
 -}
 diff -urN a/gopls/internal/lsp/mod/hover.go b/gopls/internal/lsp/mod/hover.go
 --- a/gopls/internal/lsp/mod/hover.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/hover.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,358 +0,0 @@
++++ b/gopls/internal/lsp/mod/hover.go	1970-01-01 08:00:00
+@@ -1,378 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -45169,9 +50545,11 @@
 -
 -	"golang.org/x/mod/modfile"
 -	"golang.org/x/mod/semver"
--	"golang.org/x/tools/gopls/internal/govulncheck"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/govulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
 -	"golang.org/x/tools/internal/event"
 -)
 -
@@ -45238,7 +50616,7 @@
 -	// Get the vulnerability info.
 -	fromGovulncheck := true
 -	vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()]
--	if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports {
+-	if vs == nil && snapshot.Options().Vulncheck == source.ModeVulncheckImports {
 -		var err error
 -		vs, err = snapshot.ModVuln(ctx, fh.URI())
 -		if err != nil {
@@ -45246,7 +50624,7 @@
 -		}
 -		fromGovulncheck = false
 -	}
--	affecting, nonaffecting := lookupVulns(vs, req.Mod.Path, req.Mod.Version)
+-	affecting, nonaffecting, osvs := lookupVulns(vs, req.Mod.Path, req.Mod.Version)
 -
 -	// Get the `go mod why` results for the given file.
 -	why, err := snapshot.ModWhy(ctx, fh)
@@ -45265,11 +50643,11 @@
 -	if err != nil {
 -		return nil, err
 -	}
--	options := snapshot.View().Options()
+-	options := snapshot.Options()
 -	isPrivate := snapshot.View().IsGoPrivatePath(req.Mod.Path)
 -	header := formatHeader(req.Mod.Path, options)
 -	explanation = formatExplanation(explanation, req, options, isPrivate)
--	vulns := formatVulnerabilities(req.Mod.Path, affecting, nonaffecting, options, fromGovulncheck)
+-	vulns := formatVulnerabilities(affecting, nonaffecting, osvs, options, fromGovulncheck)
 -
 -	return &protocol.Hover{
 -		Contents: protocol.MarkupContent{
@@ -45296,7 +50674,7 @@
 -	fromGovulncheck := true
 -	vs := snapshot.View().Vulnerabilities(fh.URI())[fh.URI()]
 -
--	if vs == nil && snapshot.View().Options().Vulncheck == source.ModeVulncheckImports {
+-	if vs == nil && snapshot.Options().Vulncheck == source.ModeVulncheckImports {
 -		vs, err = snapshot.ModVuln(ctx, fh.URI())
 -		if err != nil {
 -			return nil, false
@@ -45305,9 +50683,9 @@
 -	}
 -	modpath := "stdlib"
 -	goVersion := snapshot.View().GoVersionString()
--	affecting, nonaffecting := lookupVulns(vs, modpath, goVersion)
--	options := snapshot.View().Options()
--	vulns := formatVulnerabilities(modpath, affecting, nonaffecting, options, fromGovulncheck)
+-	affecting, nonaffecting, osvs := lookupVulns(vs, modpath, goVersion)
+-	options := snapshot.Options()
+-	vulns := formatVulnerabilities(affecting, nonaffecting, osvs, options, fromGovulncheck)
 -
 -	return &protocol.Hover{
 -		Contents: protocol.MarkupContent{
@@ -45330,50 +50708,86 @@
 -	return b.String()
 -}
 -
--func lookupVulns(vulns *govulncheck.Result, modpath, version string) (affecting, nonaffecting []*govulncheck.Vuln) {
--	if vulns == nil {
--		return nil, nil
+-func lookupVulns(vulns *vulncheck.Result, modpath, version string) (affecting, nonaffecting []*govulncheck.Finding, osvs map[string]*osv.Entry) {
+-	if vulns == nil || len(vulns.Entries) == 0 {
+-		return nil, nil, nil
 -	}
--	for _, vuln := range vulns.Vulns {
--		for _, mod := range vuln.Modules {
--			if mod.Path != modpath {
--				continue
--			}
--			// It is possible that the source code was changed since the last
--			// govulncheck run and information in the `vulns` info is stale.
--			// For example, imagine that a user is in the middle of updating
--			// problematic modules detected by the govulncheck run by applying
--			// quick fixes. Stale diagnostics can be confusing and prevent the
--			// user from quickly locating the next module to fix.
--			// Ideally we should rerun the analysis with the updated module
--			// dependencies or any other code changes, but we are not yet
--			// in the position of automatically triggering the analysis
--			// (govulncheck can take a while). We also don't know exactly what
--			// part of source code was changed since `vulns` was computed.
--			// As a heuristic, we assume that a user upgrades the affecting
--			// module to the version with the fix or the latest one, and if the
--			// version in the require statement is equal to or higher than the
--			// fixed version, skip the vulnerability information in the hover.
--			// Eventually, the user has to rerun govulncheck.
--			if mod.FixedVersion != "" && semver.IsValid(version) && semver.Compare(mod.FixedVersion, version) <= 0 {
--				continue
--			}
--			if vuln.IsCalled() {
--				affecting = append(affecting, vuln)
--			} else {
--				nonaffecting = append(nonaffecting, vuln)
--			}
+-	for _, finding := range vulns.Findings {
+-		vuln, typ := foundVuln(finding)
+-		if vuln.Module != modpath {
+-			continue
+-		}
+-		// It is possible that the source code was changed since the last
+-		// govulncheck run and information in the `vulns` info is stale.
+-		// For example, imagine that a user is in the middle of updating
+-		// problematic modules detected by the govulncheck run by applying
+-		// quick fixes. Stale diagnostics can be confusing and prevent the
+-		// user from quickly locating the next module to fix.
+-		// Ideally we should rerun the analysis with the updated module
+-		// dependencies or any other code changes, but we are not yet
+-		// in the position of automatically triggering the analysis
+-		// (govulncheck can take a while). We also don't know exactly what
+-		// part of source code was changed since `vulns` was computed.
+-		// As a heuristic, we assume that a user upgrades the affecting
+-		// module to the version with the fix or the latest one, and if the
+-		// version in the require statement is equal to or higher than the
+-		// fixed version, skip the vulnerability information in the hover.
+-		// Eventually, the user has to rerun govulncheck.
+-		if finding.FixedVersion != "" && semver.IsValid(version) && semver.Compare(finding.FixedVersion, version) <= 0 {
+-			continue
+-		}
+-		switch typ {
+-		case vulnCalled:
+-			affecting = append(affecting, finding)
+-		case vulnImported:
+-			nonaffecting = append(nonaffecting, finding)
 -		}
 -	}
--	sort.Slice(nonaffecting, func(i, j int) bool { return nonaffecting[i].OSV.ID < nonaffecting[j].OSV.ID })
--	sort.Slice(affecting, func(i, j int) bool { return affecting[i].OSV.ID < affecting[j].OSV.ID })
--	return affecting, nonaffecting
+-
+-	// Remove affecting elements from nonaffecting.
+-	// An OSV entry can appear in both lists if an OSV entry covers
+-	// multiple packages imported but not all vulnerable symbols are used.
+-	// The current wording of hover message doesn't clearly
+-	// present this case well IMO, so let's skip reporting nonaffecting.
+-	if len(affecting) > 0 && len(nonaffecting) > 0 {
+-		affectingSet := map[string]bool{}
+-		for _, f := range affecting {
+-			affectingSet[f.OSV] = true
+-		}
+-		n := 0
+-		for _, v := range nonaffecting {
+-			if !affectingSet[v.OSV] {
+-				nonaffecting[n] = v
+-				n++
+-			}
+-		}
+-		nonaffecting = nonaffecting[:n]
+-	}
+-	sort.Slice(nonaffecting, func(i, j int) bool { return nonaffecting[i].OSV < nonaffecting[j].OSV })
+-	sort.Slice(affecting, func(i, j int) bool { return affecting[i].OSV < affecting[j].OSV })
+-	return affecting, nonaffecting, vulns.Entries
 -}
 -
--func formatVulnerabilities(modPath string, affecting, nonaffecting []*govulncheck.Vuln, options *source.Options, fromGovulncheck bool) string {
--	if len(affecting) == 0 && len(nonaffecting) == 0 {
+-func fixedVersion(fixed string) string {
+-	if fixed == "" {
+-		return "No fix is available."
+-	}
+-	return "Fixed in " + fixed + "."
+-}
+-
+-func formatVulnerabilities(affecting, nonaffecting []*govulncheck.Finding, osvs map[string]*osv.Entry, options *source.Options, fromGovulncheck bool) string {
+-	if len(osvs) == 0 || (len(affecting) == 0 && len(nonaffecting) == 0) {
 -		return ""
 -	}
+-	byOSV := func(findings []*govulncheck.Finding) map[string][]*govulncheck.Finding {
+-		m := make(map[string][]*govulncheck.Finding)
+-		for _, f := range findings {
+-			m[f.OSV] = append(m[f.OSV], f)
+-		}
+-		return m
+-	}
+-	affectingByOSV := byOSV(affecting)
+-	nonaffectingByOSV := byOSV(nonaffecting)
 -
 -	// TODO(hyangah): can we use go templates to generate hover messages?
 -	// Then, we can use a different template for markdown case.
@@ -45381,22 +50795,23 @@
 -
 -	var b strings.Builder
 -
--	if len(affecting) > 0 {
+-	if len(affectingByOSV) > 0 {
 -		// TODO(hyangah): make the message more eyecatching (icon/codicon/color)
--		if len(affecting) == 1 {
--			b.WriteString(fmt.Sprintf("\n**WARNING:** Found %d reachable vulnerability.\n", len(affecting)))
+-		if len(affectingByOSV) == 1 {
+-			fmt.Fprintf(&b, "\n**WARNING:** Found %d reachable vulnerability.\n", len(affectingByOSV))
 -		} else {
--			b.WriteString(fmt.Sprintf("\n**WARNING:** Found %d reachable vulnerabilities.\n", len(affecting)))
+-			fmt.Fprintf(&b, "\n**WARNING:** Found %d reachable vulnerabilities.\n", len(affectingByOSV))
 -		}
 -	}
--	for _, v := range affecting {
--		fix := fixedVersionInfo(v, modPath)
--		pkgs := vulnerablePkgsInfo(v, modPath, useMarkdown)
+-	for id, findings := range affectingByOSV {
+-		fix := fixedVersion(findings[0].FixedVersion)
+-		pkgs := vulnerablePkgsInfo(findings, useMarkdown)
+-		osvEntry := osvs[id]
 -
 -		if useMarkdown {
--			fmt.Fprintf(&b, "- [**%v**](%v) %v%v%v\n", v.OSV.ID, href(v.OSV), formatMessage(v), pkgs, fix)
+-			fmt.Fprintf(&b, "- [**%v**](%v) %v%v\n%v\n", id, href(id), osvEntry.Summary, pkgs, fix)
 -		} else {
--			fmt.Fprintf(&b, "  - [%v] %v (%v) %v%v\n", v.OSV.ID, formatMessage(v), href(v.OSV), pkgs, fix)
+-			fmt.Fprintf(&b, "  - [%v] %v (%v) %v%v\n", id, osvEntry.Summary, href(id), pkgs, fix)
 -		}
 -	}
 -	if len(nonaffecting) > 0 {
@@ -45406,60 +50821,41 @@
 -			fmt.Fprintf(&b, "\n**Note:** The project imports packages with known vulnerabilities. Use `govulncheck` to check if the project uses vulnerable symbols.\n")
 -		}
 -	}
--	for _, v := range nonaffecting {
--		fix := fixedVersionInfo(v, modPath)
--		pkgs := vulnerablePkgsInfo(v, modPath, useMarkdown)
+-	for k, findings := range nonaffectingByOSV {
+-		fix := fixedVersion(findings[0].FixedVersion)
+-		pkgs := vulnerablePkgsInfo(findings, useMarkdown)
+-		osvEntry := osvs[k]
+-
 -		if useMarkdown {
--			fmt.Fprintf(&b, "- [%v](%v) %v%v%v\n", v.OSV.ID, href(v.OSV), formatMessage(v), pkgs, fix)
+-			fmt.Fprintf(&b, "- [%v](%v) %v%v\n%v\n", k, href(k), osvEntry.Summary, pkgs, fix)
 -		} else {
--			fmt.Fprintf(&b, "  - [%v] %v (%v) %v%v\n", v.OSV.ID, formatMessage(v), href(v.OSV), pkgs, fix)
+-			fmt.Fprintf(&b, "  - [%v] %v (%v) %v\n%v\n", k, osvEntry.Summary, href(k), pkgs, fix)
 -		}
 -	}
 -	b.WriteString("\n")
 -	return b.String()
 -}
 -
--func vulnerablePkgsInfo(v *govulncheck.Vuln, modPath string, useMarkdown bool) string {
--	var b bytes.Buffer
--	for _, m := range v.Modules {
--		if m.Path != modPath {
--			continue
--		}
--		if c := len(m.Packages); c == 1 {
--			b.WriteString("\n  Vulnerable package is:")
--		} else if c > 1 {
--			b.WriteString("\n  Vulnerable packages are:")
--		}
--		for _, pkg := range m.Packages {
+-func vulnerablePkgsInfo(findings []*govulncheck.Finding, useMarkdown bool) string {
+-	var b strings.Builder
+-	seen := map[string]bool{}
+-	for _, f := range findings {
+-		p := f.Trace[0].Package
+-		if !seen[p] {
+-			seen[p] = true
 -			if useMarkdown {
 -				b.WriteString("\n  * `")
 -			} else {
 -				b.WriteString("\n    ")
 -			}
--			b.WriteString(pkg.Path)
+-			b.WriteString(p)
 -			if useMarkdown {
 -				b.WriteString("`")
 -			}
 -		}
 -	}
--	if b.Len() == 0 {
--		return ""
--	}
 -	return b.String()
 -}
--func fixedVersionInfo(v *govulncheck.Vuln, modPath string) string {
--	fix := "\n\n  **No fix is available.**"
--	for _, m := range v.Modules {
--		if m.Path != modPath {
--			continue
--		}
--		if m.FixedVersion != "" {
--			fix = "\n\n  Fixed in " + m.FixedVersion + "."
--		}
--		break
--	}
--	return fix
--}
 -
 -func formatExplanation(text string, req *modfile.Require, options *source.Options, isPrivate bool) string {
 -	text = strings.TrimSuffix(text, "\n")
@@ -45512,86 +50908,114 @@
 -	b.WriteString("\n```")
 -	return b.String()
 -}
-diff -urN a/gopls/internal/lsp/mod/mod_test.go b/gopls/internal/lsp/mod/mod_test.go
---- a/gopls/internal/lsp/mod/mod_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/mod_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,57 +0,0 @@
--// Copyright 2019 The Go Authors. All rights reserved.
+diff -urN a/gopls/internal/lsp/mod/inlayhint.go b/gopls/internal/lsp/mod/inlayhint.go
+--- a/gopls/internal/lsp/mod/inlayhint.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/mod/inlayhint.go	1970-01-01 08:00:00
+@@ -1,100 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
--
 -package mod
 -
 -import (
--	"io/ioutil"
--	"os"
--	"path/filepath"
--	"testing"
+-	"context"
+-	"fmt"
 -
--	"golang.org/x/tools/gopls/internal/lsp/cache"
+-	"golang.org/x/mod/modfile"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/lsp/tests"
--	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/testenv"
 -)
 -
--func TestMain(m *testing.M) {
--	testenv.ExitIfSmallMachine()
--	os.Exit(m.Run())
+-func InlayHint(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, rng protocol.Range) ([]protocol.InlayHint, error) {
+-	// Inlay hints are enabled if the client supports them.
+-	pm, err := snapshot.ParseMod(ctx, fh)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	// Compare the version of the module used in the snapshot's metadata with the
+-	// version requested by the module, in both cases, taking replaces into account.
+-	// Produce an InlayHint when the version is the module is not the one used.
+-
+-	replaces := make(map[string]*modfile.Replace)
+-	for _, x := range pm.File.Replace {
+-		replaces[x.Old.Path] = x
+-	}
+-
+-	requires := make(map[string]*modfile.Require)
+-	for _, x := range pm.File.Require {
+-		requires[x.Mod.Path] = x
+-	}
+-
+-	am, err := snapshot.AllMetadata(ctx)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	var ans []protocol.InlayHint
+-	seen := make(map[string]bool)
+-	for _, meta := range am {
+-		if meta.Module == nil || seen[meta.Module.Path] {
+-			continue
+-		}
+-		seen[meta.Module.Path] = true
+-		metaVersion := meta.Module.Version
+-		if meta.Module.Replace != nil {
+-			metaVersion = meta.Module.Replace.Version
+-		}
+-		// These versions can be blank, as in gopls/go.mod's local replace
+-		if oldrepl, ok := replaces[meta.Module.Path]; ok && oldrepl.New.Version != metaVersion {
+-			ih := genHint(oldrepl.Syntax, oldrepl.New.Version, metaVersion, pm.Mapper)
+-			if ih != nil {
+-				ans = append(ans, *ih)
+-			}
+-		} else if oldreq, ok := requires[meta.Module.Path]; ok && oldreq.Mod.Version != metaVersion {
+-			// maybe it was replaced:
+-			if _, ok := replaces[meta.Module.Path]; ok {
+-				continue
+-			}
+-			ih := genHint(oldreq.Syntax, oldreq.Mod.Version, metaVersion, pm.Mapper)
+-			if ih != nil {
+-				ans = append(ans, *ih)
+-			}
+-		}
+-	}
+-	return ans, nil
 -}
 -
--func TestModfileRemainsUnchanged(t *testing.T) {
--	ctx := tests.Context(t)
--	session := cache.NewSession(ctx, cache.New(nil), nil)
--	options := source.DefaultOptions().Clone()
--	tests.DefaultOptions(options)
--	options.TempModfile = true
--	options.Env = map[string]string{"GOPACKAGESDRIVER": "off", "GOROOT": ""}
--
--	// Make sure to copy the test directory to a temporary directory so we do not
--	// modify the test code or add go.sum files when we run the tests.
--	folder, err := tests.CopyFolderToTempDir(filepath.Join("testdata", "unchanged"))
+-func genHint(mline *modfile.Line, oldVersion, newVersion string, m *protocol.Mapper) *protocol.InlayHint {
+-	x := mline.End.Byte // the parser has removed trailing whitespace and comments (see modfile_test.go)
+-	x -= len(mline.Token[len(mline.Token)-1])
+-	line, err := m.OffsetPosition(x)
 -	if err != nil {
--		t.Fatal(err)
+-		return nil
 -	}
--	defer os.RemoveAll(folder)
--
--	before, err := ioutil.ReadFile(filepath.Join(folder, "go.mod"))
+-	part := protocol.InlayHintLabelPart{
+-		Value: newVersion,
+-		Tooltip: &protocol.OrPTooltipPLabel{
+-			Value: fmt.Sprintf("used metadata's version %s rather than go.mod's version %s", newVersion, oldVersion),
+-		},
+-	}
+-	rng, err := m.OffsetRange(x, mline.End.Byte)
 -	if err != nil {
--		t.Fatal(err)
+-		return nil
 -	}
--	_, _, release, err := session.NewView(ctx, "diagnostics_test", span.URIFromPath(folder), options)
--	if err != nil {
--		t.Fatal(err)
+-	te := protocol.TextEdit{
+-		Range:   rng,
+-		NewText: newVersion,
 -	}
--	release()
--	after, err := ioutil.ReadFile(filepath.Join(folder, "go.mod"))
--	if err != nil {
--		t.Fatal(err)
+-	return &protocol.InlayHint{
+-		Position:     line,
+-		Label:        []protocol.InlayHintLabelPart{part},
+-		Kind:         protocol.Parameter,
+-		PaddingRight: true,
+-		TextEdits:    []protocol.TextEdit{te},
 -	}
--	if string(before) != string(after) {
--		t.Errorf("the real go.mod file was changed even when tempModfile=true")
--	}
--}
-diff -urN a/gopls/internal/lsp/mod/testdata/unchanged/go.mod b/gopls/internal/lsp/mod/testdata/unchanged/go.mod
---- a/gopls/internal/lsp/mod/testdata/unchanged/go.mod	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/testdata/unchanged/go.mod	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--module unchanged
-diff -urN a/gopls/internal/lsp/mod/testdata/unchanged/main.go b/gopls/internal/lsp/mod/testdata/unchanged/main.go
---- a/gopls/internal/lsp/mod/testdata/unchanged/main.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/mod/testdata/unchanged/main.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
--// Package unchanged does something
--package unchanged
--
--func Yo() {
--	println("yo")
 -}
 diff -urN a/gopls/internal/lsp/progress/progress.go b/gopls/internal/lsp/progress/progress.go
 --- a/gopls/internal/lsp/progress/progress.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/progress/progress.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,271 +0,0 @@
++++ b/gopls/internal/lsp/progress/progress.go	1970-01-01 08:00:00
+@@ -1,283 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -45627,10 +51051,22 @@
 -	}
 -}
 -
+-// SetSupportsWorkDoneProgress sets whether the client supports work done
+-// progress reporting. It must be set before using the tracker.
+-//
+-// TODO(rfindley): fix this broken initialization pattern.
+-// Also: do we actually need the fall-back progress behavior using ShowMessage?
+-// Surely ShowMessage notifications are too noisy to be worthwhile.
 -func (tracker *Tracker) SetSupportsWorkDoneProgress(b bool) {
 -	tracker.supportsWorkDoneProgress = b
 -}
 -
+-// SupportsWorkDoneProgress reports whether the tracker supports work done
+-// progress reporting.
+-func (tracker *Tracker) SupportsWorkDoneProgress() bool {
+-	return tracker.supportsWorkDoneProgress
+-}
+-
 -// Start notifies the client of work being done on the server. It uses either
 -// ShowMessage RPCs or $/progress messages, depending on the capabilities of
 -// the client.  The returned WorkDone handle may be used to report incremental
@@ -45865,7 +51301,7 @@
 -}
 diff -urN a/gopls/internal/lsp/progress/progress_test.go b/gopls/internal/lsp/progress/progress_test.go
 --- a/gopls/internal/lsp/progress/progress_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/progress/progress_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/progress/progress_test.go	1970-01-01 08:00:00
 @@ -1,161 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -46028,9 +51464,416 @@
 -		}
 -	}
 -}
+diff -urN a/gopls/internal/lsp/prompt.go b/gopls/internal/lsp/prompt.go
+--- a/gopls/internal/lsp/prompt.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/prompt.go	1970-01-01 08:00:00
+@@ -1,317 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package lsp
+-
+-import (
+-	"context"
+-	"fmt"
+-	"os"
+-	"path/filepath"
+-	"time"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-	"golang.org/x/tools/internal/event"
+-)
+-
+-// promptTimeout is the amount of time we wait for an ongoing prompt before
+-// prompting again. This gives the user time to reply. However, at some point
+-// we must assume that the client is not displaying the prompt, the user is
+-// ignoring it, or the prompt has been disrupted in some way (e.g. by a gopls
+-// crash).
+-const promptTimeout = 24 * time.Hour
+-
+-// The following constants are used for testing telemetry integration.
+-const (
+-	TelemetryPromptWorkTitle    = "Checking telemetry prompt"     // progress notification title, for awaiting in tests
+-	GoplsConfigDirEnvvar        = "GOPLS_CONFIG_DIR"              // overridden for testing
+-	FakeTelemetryModefileEnvvar = "GOPLS_FAKE_TELEMETRY_MODEFILE" // overridden for testing
+-	TelemetryYes                = "Yes, I'd like to help."
+-	TelemetryNo                 = "No, thanks."
+-)
+-
+-// getenv returns the effective environment variable value for the provided
+-// key, looking up the key in the session environment before falling back on
+-// the process environment.
+-func (s *Server) getenv(key string) string {
+-	if v, ok := s.Options().Env[key]; ok {
+-		return v
+-	}
+-	return os.Getenv(key)
+-}
+-
+-// configDir returns the root of the gopls configuration dir. By default this
+-// is os.UserConfigDir/gopls, but it may be overridden for tests.
+-func (s *Server) configDir() (string, error) {
+-	if d := s.getenv(GoplsConfigDirEnvvar); d != "" {
+-		return d, nil
+-	}
+-	userDir, err := os.UserConfigDir()
+-	if err != nil {
+-		return "", err
+-	}
+-	return filepath.Join(userDir, "gopls"), nil
+-}
+-
+-// telemetryMode returns the current effective telemetry mode.
+-// By default this is x/telemetry.Mode(), but it may be overridden for tests.
+-func (s *Server) telemetryMode() string {
+-	if fake := s.getenv(FakeTelemetryModefileEnvvar); fake != "" {
+-		if data, err := os.ReadFile(fake); err == nil {
+-			return string(data)
+-		}
+-		return "off"
+-	}
+-	return telemetry.Mode()
+-}
+-
+-// setTelemetryMode sets the current telemetry mode.
+-// By default this calls x/telemetry.SetMode, but it may be overridden for
+-// tests.
+-func (s *Server) setTelemetryMode(mode string) error {
+-	if fake := s.getenv(FakeTelemetryModefileEnvvar); fake != "" {
+-		return os.WriteFile(fake, []byte(mode), 0666)
+-	}
+-	return telemetry.SetMode(mode)
+-}
+-
+-// maybePromptForTelemetry checks for the right conditions, and then prompts
+-// the user to ask if they want to enable Go telemetry uploading. If the user
+-// responds 'Yes', the telemetry mode is set to "on".
+-//
+-// The actual conditions for prompting are defensive, erring on the side of not
+-// prompting.
+-// If enabled is false, this will not prompt the user in any condition,
+-// but will send work progress reports to help testing.
+-func (s *Server) maybePromptForTelemetry(ctx context.Context, enabled bool) {
+-	if s.Options().VerboseWorkDoneProgress {
+-		work := s.progress.Start(ctx, TelemetryPromptWorkTitle, "Checking if gopls should prompt about telemetry...", nil, nil)
+-		defer work.End(ctx, "Done.")
+-	}
+-
+-	if !enabled { // check this after the work progress message for testing.
+-		return // prompt is disabled
+-	}
+-
+-	if s.telemetryMode() == "on" {
+-		// Telemetry is already on -- nothing to ask about.
+-		return
+-	}
+-
+-	errorf := func(format string, args ...any) {
+-		err := fmt.Errorf(format, args...)
+-		event.Error(ctx, "telemetry prompt failed", err)
+-	}
+-
+-	// Only prompt if we can read/write the prompt config file.
+-	configDir, err := s.configDir()
+-	if err != nil {
+-		errorf("unable to determine config dir: %v", err)
+-		return
+-	}
+-
+-	var (
+-		promptDir  = filepath.Join(configDir, "prompt")    // prompt configuration directory
+-		promptFile = filepath.Join(promptDir, "telemetry") // telemetry prompt file
+-	)
+-
+-	// prompt states, to be written to the prompt file
+-	const (
+-		pYes     = "yes"     // user said yes
+-		pNo      = "no"      // user said no
+-		pPending = "pending" // current prompt is still pending
+-		pFailed  = "failed"  // prompt was asked but failed
+-	)
+-	validStates := map[string]bool{
+-		pYes:     true,
+-		pNo:      true,
+-		pPending: true,
+-		pFailed:  true,
+-	}
+-
+-	// parse the current prompt file
+-	var (
+-		state    string
+-		attempts = 0 // number of times we've asked already
+-	)
+-	if content, err := os.ReadFile(promptFile); err == nil {
+-		if _, err := fmt.Sscanf(string(content), "%s %d", &state, &attempts); err == nil && validStates[state] {
+-			if state == pYes || state == pNo {
+-				// Prompt has been answered. Nothing to do.
+-				return
+-			}
+-		} else {
+-			state, attempts = "", 0
+-			errorf("malformed prompt result %q", string(content))
+-		}
+-	} else if !os.IsNotExist(err) {
+-		errorf("reading prompt file: %v", err)
+-		// Something went wrong. Since we don't know how many times we've asked the
+-		// prompt, err on the side of not spamming.
+-		return
+-	}
+-
+-	if attempts >= 5 {
+-		// We've tried asking enough; give up.
+-		return
+-	}
+-	if attempts == 0 {
+-		// First time asking the prompt; we may need to make the prompt dir.
+-		if err := os.MkdirAll(promptDir, 0777); err != nil {
+-			errorf("creating prompt dir: %v", err)
+-			return
+-		}
+-	}
+-
+-	// Acquire the lock and write "pending" to the prompt file before actually
+-	// prompting.
+-	//
+-	// This ensures that the prompt file is writeable, and that we increment the
+-	// attempt counter before we prompt, so that we don't end up in a failure
+-	// mode where we keep prompting and then failing to record the response.
+-
+-	release, ok, err := acquireLockFile(promptFile)
+-	if err != nil {
+-		errorf("acquiring prompt: %v", err)
+-		return
+-	}
+-	if !ok {
+-		// Another prompt is currently pending.
+-		return
+-	}
+-	defer release()
+-
+-	attempts++
+-
+-	pendingContent := []byte(fmt.Sprintf("%s %d", pPending, attempts))
+-	if err := os.WriteFile(promptFile, pendingContent, 0666); err != nil {
+-		errorf("writing pending state: %v", err)
+-		return
+-	}
+-
+-	var prompt = `Go telemetry helps us improve Go by periodically sending anonymous metrics and crash reports to the Go team. Learn more at https://telemetry.go.dev/privacy.
+-
+-Would you like to enable Go telemetry?
+-`
+-	if s.Options().LinkifyShowMessage {
+-		prompt = `Go telemetry helps us improve Go by periodically sending anonymous metrics and crash reports to the Go team. Learn more at [telemetry.go.dev/privacy](https://telemetry.go.dev/privacy).
+-
+-Would you like to enable Go telemetry?
+-`
+-	}
+-	// TODO(rfindley): investigate a "tell me more" action in combination with ShowDocument.
+-	params := &protocol.ShowMessageRequestParams{
+-		Type:    protocol.Info,
+-		Message: prompt,
+-		Actions: []protocol.MessageActionItem{
+-			{Title: TelemetryYes},
+-			{Title: TelemetryNo},
+-		},
+-	}
+-
+-	item, err := s.client.ShowMessageRequest(ctx, params)
+-	if err != nil {
+-		errorf("ShowMessageRequest failed: %v", err)
+-		// Defensive: ensure item == nil for the logic below.
+-		item = nil
+-	}
+-
+-	message := func(typ protocol.MessageType, msg string) {
+-		if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
+-			Type:    typ,
+-			Message: msg,
+-		}); err != nil {
+-			errorf("ShowMessage(unrecognize) failed: %v", err)
+-		}
+-	}
+-
+-	result := pFailed
+-	if item == nil {
+-		// e.g. dialog was dismissed
+-		errorf("no response")
+-	} else {
+-		// Response matches MessageActionItem.Title.
+-		switch item.Title {
+-		case TelemetryYes:
+-			result = pYes
+-			if err := s.setTelemetryMode("on"); err == nil {
+-				message(protocol.Info, telemetryOnMessage(s.Options().LinkifyShowMessage))
+-			} else {
+-				errorf("enabling telemetry failed: %v", err)
+-				msg := fmt.Sprintf("Failed to enable Go telemetry: %v\nTo enable telemetry manually, please run `go run golang.org/x/telemetry/cmd/gotelemetry@latest on`", err)
+-				message(protocol.Error, msg)
+-			}
+-
+-		case TelemetryNo:
+-			result = pNo
+-		default:
+-			errorf("unrecognized response %q", item.Title)
+-			message(protocol.Error, fmt.Sprintf("Unrecognized response %q", item.Title))
+-		}
+-	}
+-	resultContent := []byte(fmt.Sprintf("%s %d", result, attempts))
+-	if err := os.WriteFile(promptFile, resultContent, 0666); err != nil {
+-		errorf("error writing result state to prompt file: %v", err)
+-	}
+-}
+-
+-func telemetryOnMessage(linkify bool) string {
+-	format := `Thank you. Telemetry uploading is now enabled.
+-
+-To disable telemetry uploading, run %s.
+-`
+-	var runCmd = "`go run golang.org/x/telemetry/cmd/gotelemetry@latest off`"
+-	if linkify {
+-		runCmd = "[gotelemetry off](https://golang.org/x/telemetry/cmd/gotelemetry)"
+-	}
+-	return fmt.Sprintf(format, runCmd)
+-}
+-
+-// acquireLockFile attempts to "acquire a lock" for writing to path.
+-//
+-// This is achieved by creating an exclusive lock file at <path>.lock. Lock
+-// files expire after a period, at which point acquireLockFile will remove and
+-// recreate the lock file.
+-//
+-// acquireLockFile fails if path is in a directory that doesn't exist.
+-func acquireLockFile(path string) (func(), bool, error) {
+-	lockpath := path + ".lock"
+-	fi, err := os.Stat(lockpath)
+-	if err == nil {
+-		if time.Since(fi.ModTime()) > promptTimeout {
+-			_ = os.Remove(lockpath) // ignore error
+-		} else {
+-			return nil, false, nil
+-		}
+-	} else if !os.IsNotExist(err) {
+-		return nil, false, fmt.Errorf("statting lockfile: %v", err)
+-	}
+-
+-	f, err := os.OpenFile(lockpath, os.O_CREATE|os.O_EXCL, 0666)
+-	if err != nil {
+-		if os.IsExist(err) {
+-			return nil, false, nil
+-		}
+-		return nil, false, fmt.Errorf("creating lockfile: %v", err)
+-	}
+-	fi, err = f.Stat()
+-	if err != nil {
+-		return nil, false, err
+-	}
+-	release := func() {
+-		_ = f.Close() // ignore error
+-		fi2, err := os.Stat(lockpath)
+-		if err == nil && os.SameFile(fi, fi2) {
+-			// Only clean up the lockfile if it's the same file we created.
+-			// Otherwise, our lock has expired and something else has the lock.
+-			//
+-			// There's a race here, in that the file could have changed since the
+-			// stat above; but given that we've already waited 24h this is extremely
+-			// unlikely, and acceptable.
+-			_ = os.Remove(lockpath)
+-		}
+-	}
+-	return release, true, nil
+-}
+diff -urN a/gopls/internal/lsp/prompt_test.go b/gopls/internal/lsp/prompt_test.go
+--- a/gopls/internal/lsp/prompt_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/prompt_test.go	1970-01-01 08:00:00
+@@ -1,82 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package lsp
+-
+-import (
+-	"path/filepath"
+-	"sync"
+-	"sync/atomic"
+-	"testing"
+-)
+-
+-func TestAcquireFileLock(t *testing.T) {
+-	name := filepath.Join(t.TempDir(), "config.json")
+-
+-	const concurrency = 100
+-	var acquired int32
+-	var releasers [concurrency]func()
+-	defer func() {
+-		for _, r := range releasers {
+-			if r != nil {
+-				r()
+-			}
+-		}
+-	}()
+-
+-	var wg sync.WaitGroup
+-	for i := range releasers {
+-		i := i
+-		wg.Add(1)
+-		go func() {
+-			defer wg.Done()
+-
+-			release, ok, err := acquireLockFile(name)
+-			if err != nil {
+-				t.Errorf("Acquire failed: %v", err)
+-				return
+-			}
+-			if ok {
+-				atomic.AddInt32(&acquired, 1)
+-				releasers[i] = release
+-			}
+-		}()
+-	}
+-
+-	wg.Wait()
+-
+-	if acquired != 1 {
+-		t.Errorf("Acquire succeeded %d times, expected exactly 1", acquired)
+-	}
+-}
+-
+-func TestReleaseAndAcquireFileLock(t *testing.T) {
+-	name := filepath.Join(t.TempDir(), "config.json")
+-
+-	acquire := func() (func(), bool) {
+-		t.Helper()
+-		release, ok, err := acquireLockFile(name)
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-		return release, ok
+-	}
+-
+-	release, ok := acquire()
+-	if !ok {
+-		t.Fatal("failed to Acquire")
+-	}
+-	if release2, ok := acquire(); ok {
+-		release()
+-		release2()
+-		t.Fatalf("Acquire succeeded unexpectedly")
+-	}
+-
+-	release()
+-	release3, ok := acquire()
+-	release3()
+-	if !ok {
+-		t.Fatalf("failed to Acquire")
+-	}
+-}
 diff -urN a/gopls/internal/lsp/protocol/codeactionkind.go b/gopls/internal/lsp/protocol/codeactionkind.go
 --- a/gopls/internal/lsp/protocol/codeactionkind.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/codeactionkind.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/codeactionkind.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -46045,8 +51888,8 @@
 -)
 diff -urN a/gopls/internal/lsp/protocol/context.go b/gopls/internal/lsp/protocol/context.go
 --- a/gopls/internal/lsp/protocol/context.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/context.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,43 +0,0 @@
++++ b/gopls/internal/lsp/protocol/context.go	1970-01-01 08:00:00
+@@ -1,45 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -46087,12 +51930,14 @@
 -	if event.IsError(ev) {
 -		msg.Type = Error
 -	}
+-	// TODO(adonovan): the goroutine here could cause log
+-	// messages to be delivered out of order! Use a queue.
 -	go client.LogMessage(xcontext.Detach(ctx), msg)
 -	return ctx
 -}
 diff -urN a/gopls/internal/lsp/protocol/doc.go b/gopls/internal/lsp/protocol/doc.go
 --- a/gopls/internal/lsp/protocol/doc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/doc.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/doc.go	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -46114,7 +51959,7 @@
 -package protocol
 diff -urN a/gopls/internal/lsp/protocol/enums.go b/gopls/internal/lsp/protocol/enums.go
 --- a/gopls/internal/lsp/protocol/enums.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/enums.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/enums.go	1970-01-01 08:00:00
 @@ -1,231 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -46347,9 +52192,157 @@
 -func ParseTextDocumentSaveReason(s string) TextDocumentSaveReason {
 -	return TextDocumentSaveReason(parseEnum(s, namesTextDocumentSaveReason[:]))
 -}
+diff -urN a/gopls/internal/lsp/protocol/generate/README.md b/gopls/internal/lsp/protocol/generate/README.md
+--- a/gopls/internal/lsp/protocol/generate/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/protocol/generate/README.md	1970-01-01 08:00:00
+@@ -1,144 +0,0 @@
+-# LSP Support for gopls
+-
+-## The protocol
+-
+-The LSP protocol exchanges json-encoded messages between the client and the server.
+-(gopls is the server.) The messages are either Requests, which require Responses, or
+-Notifications, which generate no response. Each Request or Notification has a method name
+-such as "textDocument/hover" that indicates its meaning and determines which function in the server will handle it.
+-The protocol is described in a
+-[web page](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/),
+-in words, and in a json file (metaModel.json) available either linked towards the bottom of the
+-web page, or in the vscode-languageserver-node repository. This code uses the latter so the
+-exact version can be tied to a githash. By default, the command will download the `github.com/microsoft/vscode-languageserver-node` repository to a temporary directory.
+-
+-The specification has five sections
+-
+-1. Requests, which describe the Request and Response types for request methods (e.g., *textDocument/didChange*),
+-2. Notifications, which describe the Request types for notification methods,
+-3. Structures, which describe named struct-like types,
+-4. TypeAliases, which describe type aliases,
+-5. Enumerations, which describe named constants.
+-
+-Requests and Notifications are tagged with a Method (e.g., `"textDocument/hover"`).
+-The specification does not specify the names of the functions that handle the messages. These
+-names are specified by the `methodNames` map. Enumerations generate Go `const`s, but
+-in Typescript they are scoped to namespaces, while in Go they are scoped to a package, so the Go names
+-may need to be modified to avoid name collisions. (See the `disambiguate` map, and its use.)
+-
+-Finally, the specified types are Typescript types, which are quite different from Go types.
+-
+-### Optionality
+-
+-The specification can mark fields in structs as Optional. The client distinguishes between missing
+-fields and `null` fields in some cases. The Go translation for an optional type
+-should be making sure the field's value
+-can be `nil`, and adding the json tag `,omitempty`. The former condition would be satisfied by
+-adding `*` to the field's type if the type is not a reference type.
+-
+-### Types
+-
+-The specification uses a number of different types, only a few of which correspond directly to Go types.
+-The specification's types are "base", "reference", "map", "literal", "stringLiteral", "tuple", "and", "or".
+-The "base" types correspond directly to Go types, although some Go types needs to be chosen for `URI` and `DocumentUri`. (The "base" types`RegExp`, `BooleanLiteral`, `NumericLiteral` never occur.)
+-
+-"reference" types are the struct-like types in the Structures section of the specification. The given
+-names are suitable for Go to use, except the code needs to change names like `_Initialze` to `XInitialize` so
+-they are exported for json marshaling and unmarshaling.
+-
+-"map" types are just like Go. (The key type in all of them is `DocumentUri`.)
+-
+-"stringLiteral" types are types whose type name and value are a single string. The chosen Go equivalent
+-is to make the type `string` and the value a constant. (The alternative would be to generate a new
+-named type, which seemed redundant.)
+-
+-"literal" types are like Go anonymous structs, so they have to be given a name. (All instances
+-of the remaining types have to be given names. One approach is to construct the name from the components
+-of the type, but this leads to misleading punning, and is unstable if components are added. The other approach
+-is to construct the name from the context of the definition, that is, from the types it is defined within.
+-For instance `Lit__InitializeParams_clientInfo` is the "literal" type at the
+-`clientInfo` field in the `_InitializeParams`
+-struct. Although this choice is sensitive to the ordering of the components, the code uses this approach,
+-presuming that reordering components is an unlikely protocol change.)
+-
+-"tuple" types are generated as Go structs. (There is only one, with two `uint32` fields.)
+-
+-"and" types are Go structs with embedded type names. (There is only one, `And_Param_workspace_configuration`.)
+-
+-"or" types are the most complicated. There are a lot of them and there is no simple Go equivalent.
+-They are defined as structs with a single `Value interface{}` field and custom json marshaling
+-and unmarshaling code. Users can assign anything to `Value` but the type will be checked, and
+-correctly marshaled, by the custom marshaling code. The unmarshaling code checks types, so `Value`
+-will have one of the permitted types. (`nil` is always allowed.) There are about 40 "or" types that
+-have a single non-null component, and these are converted to the component type.
+-
+-## Processing
+-
+-The code parses the json specification file, and scans all the types. It assigns names, as described
+-above, to the types that are unnamed in the specification, and constructs Go equivalents as required.
+-(Most of this code is in typenames.go.)
+-
+-There are four output files. tsclient.go and tsserver.go contain the definition and implementation
+-of the `protocol.Client` and `protocol.Server` types and the code that dispatches on the Method
+-of the Request or Notification. tsjson.go contains the custom marshaling and unmarshaling code.
+-And tsprotocol.go contains the type and const definitions.
+-
+-### Accommodating gopls
+-
+-As the code generates output, mostly in generateoutput.go and main.go,
+-it makes adjustments so that no changes are required to the existing Go code.
+-(Organizing the computation this way makes the code's structure simpler, but results in
+-a lot of unused types.)
+-There are three major classes of these adjustments, and leftover special cases.
+-
+-The first major
+-adjustment is to change generated type names to the ones gopls expects. Some of these don't change the
+-semantics of the type, just the name.
+-But for historical reasons a lot of them replace "or" types by a single
+-component of the type. (Until fairly recently Go only saw or used only one of components.)
+-The `goplsType` map in tables.go controls this process.
+-
+-The second major adjustment is to the types of fields of structs, which is done using the
+-`renameProp` map in tables.go.
+-
+-The third major adjustment handles optionality, controlling `*` and `,omitempty` placement when
+-the default rules don't match what gopls is expecting. (The map is `goplsStar`, also in tables.go)
+-(If the intermediate components in expressions of the form `A.B.C.S` were optional, the code would need
+-a lot of useless checking for nils. Typescript has a language construct to avoid most checks.)
+-
+-Then there are some additional special cases. There are a few places with adjustments to avoid
+-recursive types. For instance `LSPArray` is `[]LSPAny`, but `LSPAny` is an "or" type including `LSPArray`.
+-The solution is to make `LSPAny` an `interface{}`. Another instance is `_InitializeParams.trace`
+-whose type is an "or" of 3 stringLiterals, which just becomes a `string`.
+-
+-### Checking
+-
+-`TestAll(t *testing.T)` checks that there are no unexpected fields in the json specification.
+-
+-While the code is executing, it checks that all the entries in the maps in tables.go are used.
+-It also checks that the entries in `renameProp` and `goplsStar` are not redundant.
+-
+-As a one-time check on the first release of this code, diff-ing the existing and generated tsclient.go
+-and tsserver.go code results in only whitespace and comment diffs. The existing and generated
+-tsprotocol.go differ in whitespace and comments, and in a substantial number of new type definitions
+-that the older, more heuristic, code did not generate. (And the unused type `_InitializeParams` differs
+-slightly between the new and the old, and is not worth fixing.)
+-
+-### Some history
+-
+-The original stub code was written by hand, but with the protocol under active development, that
+-couldn't last. The web page existed before the json specification, but it lagged the implementation
+-and was hard to process by machine. So the earlier version of the generating code was written in Typescript, and
+-used the Typescript compiler's API to parse the protocol code in the repository.
+-It then used a set of heuristics
+-to pick out the elements of the protocol, and another set of overlapping heuristics to create the Go code.
+-The output was functional, but idiosyncratic, and the code was fragile and barely maintainable.
+-
+-### The future
+-
+-Most of the adjustments using the maps in tables.go could be removed by making changes, mostly to names,
+-in the gopls code. Using more "or" types in gopls requires more elaborate, but stereotyped, changes.
+-But even without all the adjustments, making this its own module would face problems; a number of
+-dependencies would have to be factored out. And, it is fragile. The custom unmarshaling code knows what
+-types it expects. A design that return an 'any' on unexpected types would match the json
+-'ignore unexpected values' philosophy better, but the Go code would need extra checking.
 diff -urN a/gopls/internal/lsp/protocol/generate/generate.go b/gopls/internal/lsp/protocol/generate/generate.go
 --- a/gopls/internal/lsp/protocol/generate/generate.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/generate.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/generate/generate.go	1970-01-01 08:00:00
 @@ -1,121 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -46474,8 +52467,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/generate/main.go b/gopls/internal/lsp/protocol/generate/main.go
 --- a/gopls/internal/lsp/protocol/generate/main.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/main.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,387 +0,0 @@
++++ b/gopls/internal/lsp/protocol/generate/main.go	1970-01-01 08:00:00
+@@ -1,390 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -46489,6 +52482,8 @@
 -// To run it, type 'go generate' in the parent (protocol) directory.
 -package main
 -
+-// see https://github.com/golang/go/issues/61217 for discussion of an issue
+-
 -import (
 -	"bytes"
 -	"encoding/json"
@@ -46509,14 +52504,15 @@
 -// For example, tag release/protocol/3.17.3 of the repo defines protocol version 3.17.0.
 -// (Point releases are reflected in the git tag version even when they are cosmetic
 -// and don't change the protocol.)
--var lspGitRef = "release/protocol/3.17.3-next.6"
+-var lspGitRef = "release/protocol/3.17.4-next.2"
 -
 -var (
 -	repodir   = flag.String("d", "", "directory containing clone of "+vscodeRepo)
 -	outputdir = flag.String("o", ".", "output directory")
 -	// PJW: not for real code
--	cmpdir = flag.String("c", "", "directory of earlier code")
--	doboth = flag.String("b", "", "generate and compare")
+-	cmpdir      = flag.String("c", "", "directory of earlier code")
+-	doboth      = flag.String("b", "", "generate and compare")
+-	lineNumbers = flag.Bool("l", false, "add line numbers to generated output")
 -)
 -
 -func main() {
@@ -46865,8 +52861,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/generate/main_test.go b/gopls/internal/lsp/protocol/generate/main_test.go
 --- a/gopls/internal/lsp/protocol/generate/main_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/main_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,118 +0,0 @@
++++ b/gopls/internal/lsp/protocol/generate/main_test.go	1970-01-01 08:00:00
+@@ -1,119 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -46891,6 +52887,7 @@
 -// (in vscode, just run the test with  "go.coverOnSingleTest": true)
 -func TestAll(t *testing.T) {
 -	t.Skip("needs vscode-languageserver-node repository")
+-	*lineNumbers = true
 -	log.SetFlags(log.Lshortfile)
 -	main()
 -}
@@ -46987,8 +52984,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/generate/output.go b/gopls/internal/lsp/protocol/generate/output.go
 --- a/gopls/internal/lsp/protocol/generate/output.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/output.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,420 +0,0 @@
++++ b/gopls/internal/lsp/protocol/generate/output.go	1970-01-01 08:00:00
+@@ -1,427 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -47044,7 +53041,7 @@
 -}
 -
 -func genDecl(method string, param, result *Type, dir string) {
--	fname := methodNames[method]
+-	fname := methodName(method)
 -	p := ""
 -	if notNil(param) {
 -		p = ", *" + goplsName(param)
@@ -47083,7 +53080,7 @@
 -	out := new(bytes.Buffer)
 -	fmt.Fprintf(out, "\tcase %q:\n", method)
 -	var p string
--	fname := methodNames[method]
+-	fname := methodName(method)
 -	if notNil(param) {
 -		nm := goplsName(param)
 -		if method == "workspace/configuration" { // gopls compatibility
@@ -47145,7 +53142,7 @@
 -		r = "([]LSPAny, error)"
 -		goResult = "[]LSPAny"
 -	}
--	fname := methodNames[method]
+-	fname := methodName(method)
 -	fmt.Fprintf(out, "func (s *%%sDispatcher) %s(ctx context.Context%s) %s {\n",
 -		fname, p, r)
 -
@@ -47208,7 +53205,7 @@
 -			// a weird case, and needed only so the generated code contains the old gopls code
 -			nm = "DocumentDiagnosticParams"
 -		}
--		fmt.Fprintf(out, "type %s struct { // line %d\n", nm, s.Line)
+-		fmt.Fprintf(out, "type %s struct {%s\n", nm, linex(s.Line))
 -		// for gpls compatibilitye, embed most extensions, but expand the rest some day
 -		props := append([]NameType{}, s.Properties...)
 -		if s.Name == "SymbolInformation" { // but expand this one
@@ -47278,7 +53275,7 @@
 -		switch nt.kind {
 -		case "literal":
 -			fmt.Fprintf(out, "// created for Literal (%s)\n", nt.name)
--			fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1)
+-			fmt.Fprintf(out, "type %s struct {%s\n", nm, linex(nt.line+1))
 -			genProps(out, nt.properties, nt.name) // systematic name, not gopls name; is this a good choice?
 -		case "or":
 -			if !strings.HasPrefix(nm, "Or") {
@@ -47293,18 +53290,18 @@
 -			}
 -			sort.Strings(names)
 -			fmt.Fprintf(out, "// created for Or %v\n", names)
--			fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1)
+-			fmt.Fprintf(out, "type %s struct {%s\n", nm, linex(nt.line+1))
 -			fmt.Fprintf(out, "\tValue interface{} `json:\"value\"`\n")
 -		case "and":
 -			fmt.Fprintf(out, "// created for And\n")
--			fmt.Fprintf(out, "type %s struct { // line %d\n", nm, nt.line+1)
+-			fmt.Fprintf(out, "type %s struct {%s\n", nm, linex(nt.line+1))
 -			for _, x := range nt.items {
 -				nm := goplsName(x)
 -				fmt.Fprintf(out, "\t%s\n", nm)
 -			}
 -		case "tuple": // there's only this one
 -			nt.name = "UIntCommaUInt"
--			fmt.Fprintf(out, "//created for Tuple\ntype %s struct { // line %d\n", nm, nt.line+1)
+-			fmt.Fprintf(out, "//created for Tuple\ntype %s struct {%s\n", nm, linex(nt.line+1))
 -			fmt.Fprintf(out, "\tFld0 uint32 `json:\"fld0\"`\n")
 -			fmt.Fprintf(out, "\tFld1 uint32 `json:\"fld1\"`\n")
 -		default:
@@ -47320,7 +53317,7 @@
 -		generateDoc(out, e.Documentation)
 -		tp := goplsName(e.Type)
 -		nm := goName(e.Name)
--		fmt.Fprintf(out, "type %s %s // line %d\n", nm, tp, e.Line)
+-		fmt.Fprintf(out, "type %s %s%s\n", nm, tp, linex(e.Line))
 -		types[nm] = out.String()
 -		vals := new(bytes.Buffer)
 -		generateDoc(vals, e.Documentation)
@@ -47342,7 +53339,7 @@
 -			default:
 -				log.Fatalf("impossible type %T", v)
 -			}
--			fmt.Fprintf(vals, "\t%s %s = %s // line %d\n", nm, e.Name, val, v.Line)
+-			fmt.Fprintf(vals, "\t%s %s = %s%s\n", nm, e.Name, val, linex(v.Line))
 -		}
 -		consts[nm] = vals.String()
 -	}
@@ -47384,6 +53381,13 @@
 -	}
 -}
 -
+-func linex(n int) string {
+-	if *lineNumbers {
+-		return fmt.Sprintf(" // line %d", n)
+-	}
+-	return ""
+-}
+-
 -func goplsName(t *Type) string {
 -	nm := typeNames[t]
 -	// translate systematic name to gopls name
@@ -47409,150 +53413,10 @@
 -	// that's all the cases that occur currently
 -	return false
 -}
-diff -urN a/gopls/internal/lsp/protocol/generate/README.md b/gopls/internal/lsp/protocol/generate/README.md
---- a/gopls/internal/lsp/protocol/generate/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,136 +0,0 @@
--# LSP Support for gopls
--
--## The protocol
--
--The LSP protocol exchanges json-encoded messages between the client and the server.
--(gopls is the server.) The messages are either Requests, which require Responses, or
--Notifications, which generate no response. Each Request or Notification has a method name
--such as "textDocument/hover" that indicates its meaning and determines which function in the server will handle it.
--The protocol is described in a
--[web page](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/),
--in words, and in a json file (metaModel.json) available either linked towards the bottom of the
--web page, or in the vscode-languageserver-node repository. This code uses the latter so the
--exact version can be tied to a githash. By default, the command will download the `github.com/microsoft/vscode-languageserver-node` repository to a temporary directory.
--
--The specification has five sections
--1. Requests, which describe the Request and Response types for request methods (e.g., *textDocument/didChange*),
--2. Notifications, which describe the Request types for notification methods,
--3. Structures, which describe named struct-like types,
--4. TypeAliases, which describe type aliases,
--5. Enumerations, which describe named constants.
--
--Requests and Notifications are tagged with a Method (e.g., `"textDocument/hover"`).
--The specification does not specify the names of the functions that handle the messages. These
--names are specified by the `methodNames` map. Enumerations generate Go `const`s, but
--in Typescript they are scoped to namespaces, while in Go they are scoped to a package, so the Go names
--may need to be modified to avoid name collisions. (See the `disambiguate` map, and its use.)
--
--Finally, the specified types are Typescript types, which are quite different from Go types.
--
--### Optionality
--The specification can mark fields in structs as Optional. The client distinguishes between missing
--fields and `null` fields in some cases. The Go translation for an optional type
--should be making sure the field's value
--can be `nil`, and adding the json tag `,omitempty`. The former condition would be satisfied by
--adding `*` to the field's type if the type is not a reference type.
--
--### Types
--The specification uses a number of different types, only a few of which correspond directly to Go types.
--The specification's types are "base", "reference", "map", "literal", "stringLiteral", "tuple", "and", "or".
--The "base" types correspond directly to Go types, although some Go types needs to be chosen for `URI` and `DocumentUri`. (The "base" types`RegExp`, `BooleanLiteral`, `NumericLiteral` never occur.)
--
--"reference" types are the struct-like types in the Structures section of the specification. The given
--names are suitable for Go to use, except the code needs to change names like `_Initialze` to `XInitialize` so
--they are exported for json marshaling and unmarshaling.
--
--"map" types are just like Go. (The key type in all of them is `DocumentUri`.)
--
--"stringLiteral" types are types whose type name and value are a single string. The chosen Go equivalent
--is to make the type `string` and the value a constant. (The alternative would be to generate a new
--named type, which seemed redundant.)
--
--"literal" types are like Go anonymous structs, so they have to be given a name. (All instances
--of the remaining types have to be given names. One approach is to construct the name from the components
--of the type, but this leads to misleading punning, and is unstable if components are added. The other approach
--is to construct the name from the context of the definition, that is, from the types it is defined within.
--For instance `Lit__InitializeParams_clientInfo` is the "literal" type at the
--`clientInfo` field in the `_InitializeParams`
--struct. Although this choice is sensitive to the ordering of the components, the code uses this approach,
--presuming that reordering components is an unlikely protocol change.)
--
--"tuple" types are generated as Go structs. (There is only one, with two `uint32` fields.)
--
--"and" types are Go structs with embedded type names. (There is only one, `And_Param_workspace_configuration`.)
--
--"or" types are the most complicated. There are a lot of them and there is no simple Go equivalent.
--They are defined as structs with a single `Value interface{}` field and custom json marshaling
--and unmarshaling code. Users can assign anything to `Value` but the type will be checked, and
--correctly marshaled, by the custom marshaling code. The unmarshaling code checks types, so `Value`
--will have one of the permitted types. (`nil` is always allowed.) There are about 40 "or" types that
--have a single non-null component, and these are converted to the component type.
--
--## Processing
--The code parses the json specification file, and scans all the types. It assigns names, as described
--above, to the types that are unnamed in the specification, and constructs Go equivalents as required.
--(Most of this code is in typenames.go.)
--
--There are four output files. tsclient.go and tsserver.go contain the definition and implementation
--of the `protocol.Client` and `protocol.Server` types and the code that dispatches on the Method
--of the Request or Notification. tsjson.go contains the custom marshaling and unmarshaling code.
--And tsprotocol.go contains the type and const definitions.
--
--### Accommodating gopls
--As the code generates output, mostly in generateoutput.go and main.go,
--it makes adjustments so that no changes are required to the existing Go code.
--(Organizing the computation this way makes the code's structure simpler, but results in
--a lot of unused types.)
--There are three major classes of these adjustments, and leftover special cases.
--
--The first major
--adjustment is to change generated type names to the ones gopls expects. Some of these don't change the
--semantics of the type, just the name.
--But for historical reasons a lot of them replace "or" types by a single
--component of the type. (Until fairly recently Go only saw or used only one of components.)
--The `goplsType` map in tables.go controls this process.
--
--The second major adjustment is to the types of fields of structs, which is done using the
--`renameProp` map in tables.go.
--
--The third major adjustment handles optionality, controlling `*` and `,omitempty` placement when
--the default rules don't match what gopls is expecting. (The map is `goplsStar`, also in tables.go)
--(If the intermediate components in expressions of the form `A.B.C.S` were optional, the code would need
--a lot of useless checking for nils. Typescript has a language construct to avoid most checks.)
--
--Then there are some additional special cases. There are a few places with adjustments to avoid
--recursive types. For instance `LSPArray` is `[]LSPAny`, but `LSPAny` is an "or" type including `LSPArray`.
--The solution is to make `LSPAny` an `interface{}`. Another instance is `_InitializeParams.trace`
--whose type is an "or" of 3 stringLiterals, which just becomes a `string`.
--
--### Checking
--`TestAll(t *testing.T)` checks that there are no unexpected fields in the json specification.
--
--While the code is executing, it checks that all the entries in the maps in tables.go are used.
--It also checks that the entries in `renameProp` and `goplsStar` are not redundant.
--
--As a one-time check on the first release of this code, diff-ing the existing and generated tsclient.go
--and tsserver.go code results in only whitespace and comment diffs. The existing and generated
--tsprotocol.go differ in whitespace and comments, and in a substantial number of new type definitions
--that the older, more heuristic, code did not generate. (And the unused type `_InitializeParams` differs
--slightly between the new and the old, and is not worth fixing.)
--
--### Some history
--The original stub code was written by hand, but with the protocol under active development, that
--couldn't last. The web page existed before the json specification, but it lagged the implementation
--and was hard to process by machine. So the earlier version of the generating code was written in Typescript, and
--used the Typescript compiler's API to parse the protocol code in the repository.
--It then used a set of heuristics
--to pick out the elements of the protocol, and another set of overlapping heuristics to create the Go code.
--The output was functional, but idiosyncratic, and the code was fragile and barely maintainable.
--
--### The future
--Most of the adjustments using the maps in tables.go could be removed by making changes, mostly to names,
--in the gopls code. Using more "or" types in gopls requires more elaborate, but stereotyped, changes.
--But even without all the adjustments, making this its own module would face problems; a number of
--dependencies would have to be factored out. And, it is fragile. The custom unmarshaling code knows what
--types it expects. A design that return an 'any' on unexpected types would match the json
--'ignore unexpected values' philosophy better, but the the Go code would need extra checking.
 diff -urN a/gopls/internal/lsp/protocol/generate/tables.go b/gopls/internal/lsp/protocol/generate/tables.go
 --- a/gopls/internal/lsp/protocol/generate/tables.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/tables.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,327 +0,0 @@
++++ b/gopls/internal/lsp/protocol/generate/tables.go	1970-01-01 08:00:00
+@@ -1,341 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -47562,6 +53426,8 @@
 -
 -package main
 -
+-import "log"
+-
 -// prop combines the name of a property with the name of the structure it is in.
 -type prop [2]string
 -
@@ -47623,6 +53489,7 @@
 -	{"Command", "arguments"}:       "[]json.RawMessage",
 -	{"CompletionItem", "textEdit"}: "TextEdit",
 -	{"Diagnostic", "code"}:         "interface{}",
+-	{"Diagnostic", "data"}:         "json.RawMessage", // delay unmarshalling quickfixes
 -
 -	{"DocumentDiagnosticReportPartialResult", "relatedDocuments"}: "map[DocumentURI]interface{}",
 -
@@ -47665,6 +53532,7 @@
 -	"DiagnosticSeverity":           {"Severity", ""},
 -	"DocumentDiagnosticReportKind": {"Diagnostic", ""},
 -	"FileOperationPatternKind":     {"", "Pattern"},
+-	"InlineCompletionTriggerKind":  {"Inline", ""},
 -	"InsertTextFormat":             {"", "TextFormat"},
 -	"SemanticTokenModifiers":       {"Mod", ""},
 -	"SemanticTokenTypes":           {"", "Type"},
@@ -47831,6 +53699,7 @@
 -	"textDocument/hover":                     "Hover",
 -	"textDocument/implementation":            "Implementation",
 -	"textDocument/inlayHint":                 "InlayHint",
+-	"textDocument/inlineCompletion":          "InlineCompletion",
 -	"textDocument/inlineValue":               "InlineValue",
 -	"textDocument/linkedEditingRange":        "LinkedEditingRange",
 -	"textDocument/moniker":                   "Moniker",
@@ -47840,6 +53709,7 @@
 -	"textDocument/prepareTypeHierarchy":      "PrepareTypeHierarchy",
 -	"textDocument/publishDiagnostics":        "PublishDiagnostics",
 -	"textDocument/rangeFormatting":           "RangeFormatting",
+-	"textDocument/rangesFormatting":          "RangesFormatting",
 -	"textDocument/references":                "References",
 -	"textDocument/rename":                    "Rename",
 -	"textDocument/selectionRange":            "SelectionRange",
@@ -47880,9 +53750,17 @@
 -	"workspace/workspaceFolders":             "WorkspaceFolders",
 -	"workspaceSymbol/resolve":                "ResolveWorkspaceSymbol",
 -}
+-
+-func methodName(method string) string {
+-	ans := methodNames[method]
+-	if ans == "" {
+-		log.Fatalf("unknown method %q", method)
+-	}
+-	return ans
+-}
 diff -urN a/gopls/internal/lsp/protocol/generate/typenames.go b/gopls/internal/lsp/protocol/generate/typenames.go
 --- a/gopls/internal/lsp/protocol/generate/typenames.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/typenames.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/generate/typenames.go	1970-01-01 08:00:00
 @@ -1,184 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -48070,7 +53948,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/generate/types.go b/gopls/internal/lsp/protocol/generate/types.go
 --- a/gopls/internal/lsp/protocol/generate/types.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/generate/types.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/generate/types.go	1970-01-01 08:00:00
 @@ -1,170 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -48244,7 +54122,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/log.go b/gopls/internal/lsp/protocol/log.go
 --- a/gopls/internal/lsp/protocol/log.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/log.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/log.go	1970-01-01 08:00:00
 @@ -1,136 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -48384,7 +54262,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/mapper.go b/gopls/internal/lsp/protocol/mapper.go
 --- a/gopls/internal/lsp/protocol/mapper.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/mapper.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/mapper.go	1970-01-01 08:00:00
 @@ -1,529 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -48460,9 +54338,9 @@
 -	"sync"
 -	"unicode/utf8"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -// A Mapper wraps the content of a file and provides mapping
@@ -48917,8 +54795,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/mapper_test.go b/gopls/internal/lsp/protocol/mapper_test.go
 --- a/gopls/internal/lsp/protocol/mapper_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/mapper_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,441 +0,0 @@
++++ b/gopls/internal/lsp/protocol/mapper_test.go	1970-01-01 08:00:00
+@@ -1,439 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -49358,11 +55236,9 @@
 -		}
 -	}
 -}
--
--// -- end --
 diff -urN a/gopls/internal/lsp/protocol/protocol.go b/gopls/internal/lsp/protocol/protocol.go
 --- a/gopls/internal/lsp/protocol/protocol.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/protocol.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/protocol.go	1970-01-01 08:00:00
 @@ -1,284 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -49650,7 +55526,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/span.go b/gopls/internal/lsp/protocol/span.go
 --- a/gopls/internal/lsp/protocol/span.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/span.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/span.go	1970-01-01 08:00:00
 @@ -1,118 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -49772,7 +55648,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/tsclient.go b/gopls/internal/lsp/protocol/tsclient.go
 --- a/gopls/internal/lsp/protocol/tsclient.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/tsclient.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/tsclient.go	1970-01-01 08:00:00
 @@ -1,249 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -49782,8 +55658,8 @@
 -
 -package protocol
 -
--// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f).
--// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json
+-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.4-next.2 (hash 184c8a7f010d335582f24337fe182baa6f2fccdd).
+-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.4-next.2/protocol/metaModel.json
 -// LSP metaData.version = 3.17.0.
 -
 -import (
@@ -50025,7 +55901,7 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/tsdocument_changes.go b/gopls/internal/lsp/protocol/tsdocument_changes.go
 --- a/gopls/internal/lsp/protocol/tsdocument_changes.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/tsdocument_changes.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/protocol/tsdocument_changes.go	1970-01-01 08:00:00
 @@ -1,42 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -50071,8 +55947,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/tsjson.go b/gopls/internal/lsp/protocol/tsjson.go
 --- a/gopls/internal/lsp/protocol/tsjson.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/tsjson.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1997 +0,0 @@
++++ b/gopls/internal/lsp/protocol/tsjson.go	1970-01-01 08:00:00
+@@ -1,2090 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -50081,8 +55957,8 @@
 -
 -package protocol
 -
--// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f).
--// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json
+-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.4-next.2 (hash 184c8a7f010d335582f24337fe182baa6f2fccdd).
+-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.4-next.2/protocol/metaModel.json
 -// LSP metaData.version = 3.17.0.
 -
 -import "encoding/json"
@@ -50099,7 +55975,7 @@
 -	return e.msg
 -}
 -
--// from line 4769
+-// from line 4964
 -func (t OrFEditRangePItemDefaults) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FEditRangePItemDefaults:
@@ -50130,7 +56006,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FEditRangePItemDefaults Range]"}
 -}
 -
--// from line 9811
+-// from line 10165
 -func (t OrFNotebookPNotebookSelector) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case NotebookDocumentFilter:
@@ -50161,7 +56037,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"}
 -}
 -
--// from line 5520
+-// from line 5715
 -func (t OrPLocation_workspace_symbol) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case Location:
@@ -50192,7 +56068,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [Location PLocationMsg_workspace_symbol]"}
 -}
 -
--// from line 4163
+-// from line 4358
 -func (t OrPSection_workspace_didChangeConfiguration) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case []string:
@@ -50223,7 +56099,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [[]string string]"}
 -}
 -
--// from line 7075
+-// from line 7311
 -func (t OrPTooltipPLabel) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MarkupContent:
@@ -50254,7 +56130,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"}
 -}
 -
--// from line 3699
+-// from line 3772
 -func (t OrPTooltip_textDocument_inlayHint) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MarkupContent:
@@ -50285,7 +56161,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"}
 -}
 -
--// from line 6184
+-// from line 6420
 -func (t Or_CancelParams_id) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case int32:
@@ -50316,7 +56192,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [int32 string]"}
 -}
 -
--// from line 4582
+-// from line 4777
 -func (t Or_CompletionItem_documentation) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MarkupContent:
@@ -50347,7 +56223,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"}
 -}
 -
--// from line 4665
+-// from line 4860
 -func (t Or_CompletionItem_textEdit) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case InsertReplaceEdit:
@@ -50378,7 +56254,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [InsertReplaceEdit TextEdit]"}
 -}
 -
--// from line 13753
+-// from line 14168
 -func (t Or_Definition) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case Location:
@@ -50409,7 +56285,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [Location []Location]"}
 -}
 -
--// from line 8547
+-// from line 8865
 -func (t Or_Diagnostic_code) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case int32:
@@ -50440,7 +56316,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [int32 string]"}
 -}
 -
--// from line 13885
+-// from line 14300
 -func (t Or_DocumentDiagnosticReport) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case RelatedFullDocumentDiagnosticReport:
@@ -50471,7 +56347,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [RelatedFullDocumentDiagnosticReport RelatedUnchangedDocumentDiagnosticReport]"}
 -}
 -
--// from line 3822
+-// from line 3895
 -func (t Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FullDocumentDiagnosticReport:
@@ -50502,7 +56378,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"}
 -}
 -
--// from line 14095
+-// from line 14510
 -func (t Or_DocumentFilter) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case NotebookCellTextDocumentFilter:
@@ -50533,7 +56409,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [NotebookCellTextDocumentFilter TextDocumentFilter]"}
 -}
 -
--// from line 4891
+-// from line 5086
 -func (t Or_Hover_contents) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MarkedString:
@@ -50571,7 +56447,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MarkedString MarkupContent []MarkedString]"}
 -}
 -
--// from line 3658
+-// from line 3731
 -func (t Or_InlayHint_label) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case []InlayHintLabelPart:
@@ -50602,7 +56478,38 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [[]InlayHintLabelPart string]"}
 -}
 -
--// from line 13863
+-// from line 4163
+-func (t Or_InlineCompletionItem_insertText) MarshalJSON() ([]byte, error) {
+-	switch x := t.Value.(type) {
+-	case StringValue:
+-		return json.Marshal(x)
+-	case string:
+-		return json.Marshal(x)
+-	case nil:
+-		return []byte("null"), nil
+-	}
+-	return nil, fmt.Errorf("type %T not one of [StringValue string]", t)
+-}
+-
+-func (t *Or_InlineCompletionItem_insertText) UnmarshalJSON(x []byte) error {
+-	if string(x) == "null" {
+-		t.Value = nil
+-		return nil
+-	}
+-	var h0 StringValue
+-	if err := json.Unmarshal(x, &h0); err == nil {
+-		t.Value = h0
+-		return nil
+-	}
+-	var h1 string
+-	if err := json.Unmarshal(x, &h1); err == nil {
+-		t.Value = h1
+-		return nil
+-	}
+-	return &UnmarshalError{"unmarshal failed to match one of [StringValue string]"}
+-}
+-
+-// from line 14278
 -func (t Or_InlineValue) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case InlineValueEvaluatableExpression:
@@ -50640,7 +56547,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [InlineValueEvaluatableExpression InlineValueText InlineValueVariableLookup]"}
 -}
 -
--// from line 14060
+-// from line 14475
 -func (t Or_MarkedString) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case Msg_MarkedString:
@@ -50671,7 +56578,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [Msg_MarkedString string]"}
 -}
 -
--// from line 10118
+-// from line 10472
 -func (t Or_NotebookCellTextDocumentFilter_notebook) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case NotebookDocumentFilter:
@@ -50702,7 +56609,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"}
 -}
 -
--// from line 9857
+-// from line 10211
 -func (t Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case NotebookDocumentFilter:
@@ -50733,7 +56640,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentFilter string]"}
 -}
 -
--// from line 7168
+-// from line 7404
 -func (t Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FullDocumentDiagnosticReport:
@@ -50764,7 +56671,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"}
 -}
 -
--// from line 7207
+-// from line 7443
 -func (t Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FullDocumentDiagnosticReport:
@@ -50795,7 +56702,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]"}
 -}
 -
--// from line 10741
+-// from line 11106
 -func (t Or_RelativePattern_baseUri) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case URI:
@@ -50826,7 +56733,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [URI WorkspaceFolder]"}
 -}
 -
--// from line 1371
+-// from line 1413
 -func (t Or_Result_textDocument_codeAction_Item0_Elem) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case CodeAction:
@@ -50857,7 +56764,38 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [CodeAction Command]"}
 -}
 -
--// from line 12197
+-// from line 980
+-func (t Or_Result_textDocument_inlineCompletion) MarshalJSON() ([]byte, error) {
+-	switch x := t.Value.(type) {
+-	case InlineCompletionList:
+-		return json.Marshal(x)
+-	case []InlineCompletionItem:
+-		return json.Marshal(x)
+-	case nil:
+-		return []byte("null"), nil
+-	}
+-	return nil, fmt.Errorf("type %T not one of [InlineCompletionList []InlineCompletionItem]", t)
+-}
+-
+-func (t *Or_Result_textDocument_inlineCompletion) UnmarshalJSON(x []byte) error {
+-	if string(x) == "null" {
+-		t.Value = nil
+-		return nil
+-	}
+-	var h0 InlineCompletionList
+-	if err := json.Unmarshal(x, &h0); err == nil {
+-		t.Value = h0
+-		return nil
+-	}
+-	var h1 []InlineCompletionItem
+-	if err := json.Unmarshal(x, &h1); err == nil {
+-		t.Value = h1
+-		return nil
+-	}
+-	return &UnmarshalError{"unmarshal failed to match one of [InlineCompletionList []InlineCompletionItem]"}
+-}
+-
+-// from line 12573
 -func (t Or_SemanticTokensClientCapabilities_requests_full) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FFullPRequests:
@@ -50888,7 +56826,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FFullPRequests bool]"}
 -}
 -
--// from line 12177
+-// from line 12553
 -func (t Or_SemanticTokensClientCapabilities_requests_range) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FRangePRequests:
@@ -50919,7 +56857,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FRangePRequests bool]"}
 -}
 -
--// from line 6579
+-// from line 6815
 -func (t Or_SemanticTokensOptions_full) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case PFullESemanticTokensOptions:
@@ -50950,7 +56888,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [PFullESemanticTokensOptions bool]"}
 -}
 -
--// from line 6559
+-// from line 6795
 -func (t Or_SemanticTokensOptions_range) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case PRangeESemanticTokensOptions:
@@ -50981,7 +56919,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [PRangeESemanticTokensOptions bool]"}
 -}
 -
--// from line 8227
+-// from line 8525
 -func (t Or_ServerCapabilities_callHierarchyProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case CallHierarchyOptions:
@@ -51019,7 +56957,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [CallHierarchyOptions CallHierarchyRegistrationOptions bool]"}
 -}
 -
--// from line 8035
+-// from line 8333
 -func (t Or_ServerCapabilities_codeActionProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case CodeActionOptions:
@@ -51050,7 +56988,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [CodeActionOptions bool]"}
 -}
 -
--// from line 8071
+-// from line 8369
 -func (t Or_ServerCapabilities_colorProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DocumentColorOptions:
@@ -51088,7 +57026,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DocumentColorOptions DocumentColorRegistrationOptions bool]"}
 -}
 -
--// from line 7897
+-// from line 8195
 -func (t Or_ServerCapabilities_declarationProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DeclarationOptions:
@@ -51126,7 +57064,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DeclarationOptions DeclarationRegistrationOptions bool]"}
 -}
 -
--// from line 7919
+-// from line 8217
 -func (t Or_ServerCapabilities_definitionProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DefinitionOptions:
@@ -51157,7 +57095,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DefinitionOptions bool]"}
 -}
 -
--// from line 8384
+-// from line 8682
 -func (t Or_ServerCapabilities_diagnosticProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DiagnosticOptions:
@@ -51188,7 +57126,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DiagnosticOptions DiagnosticRegistrationOptions]"}
 -}
 -
--// from line 8111
+-// from line 8409
 -func (t Or_ServerCapabilities_documentFormattingProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DocumentFormattingOptions:
@@ -51219,7 +57157,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DocumentFormattingOptions bool]"}
 -}
 -
--// from line 7999
+-// from line 8297
 -func (t Or_ServerCapabilities_documentHighlightProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DocumentHighlightOptions:
@@ -51250,7 +57188,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DocumentHighlightOptions bool]"}
 -}
 -
--// from line 8129
+-// from line 8427
 -func (t Or_ServerCapabilities_documentRangeFormattingProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DocumentRangeFormattingOptions:
@@ -51281,7 +57219,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DocumentRangeFormattingOptions bool]"}
 -}
 -
--// from line 8017
+-// from line 8315
 -func (t Or_ServerCapabilities_documentSymbolProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case DocumentSymbolOptions:
@@ -51312,7 +57250,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [DocumentSymbolOptions bool]"}
 -}
 -
--// from line 8174
+-// from line 8472
 -func (t Or_ServerCapabilities_foldingRangeProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case FoldingRangeOptions:
@@ -51350,7 +57288,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [FoldingRangeOptions FoldingRangeRegistrationOptions bool]"}
 -}
 -
--// from line 7870
+-// from line 8168
 -func (t Or_ServerCapabilities_hoverProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case HoverOptions:
@@ -51381,7 +57319,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [HoverOptions bool]"}
 -}
 -
--// from line 7959
+-// from line 8257
 -func (t Or_ServerCapabilities_implementationProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case ImplementationOptions:
@@ -51419,7 +57357,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [ImplementationOptions ImplementationRegistrationOptions bool]"}
 -}
 -
--// from line 8361
+-// from line 8659
 -func (t Or_ServerCapabilities_inlayHintProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case InlayHintOptions:
@@ -51457,7 +57395,38 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [InlayHintOptions InlayHintRegistrationOptions bool]"}
 -}
 -
--// from line 8338
+-// from line 8701
+-func (t Or_ServerCapabilities_inlineCompletionProvider) MarshalJSON() ([]byte, error) {
+-	switch x := t.Value.(type) {
+-	case InlineCompletionOptions:
+-		return json.Marshal(x)
+-	case bool:
+-		return json.Marshal(x)
+-	case nil:
+-		return []byte("null"), nil
+-	}
+-	return nil, fmt.Errorf("type %T not one of [InlineCompletionOptions bool]", t)
+-}
+-
+-func (t *Or_ServerCapabilities_inlineCompletionProvider) UnmarshalJSON(x []byte) error {
+-	if string(x) == "null" {
+-		t.Value = nil
+-		return nil
+-	}
+-	var h0 InlineCompletionOptions
+-	if err := json.Unmarshal(x, &h0); err == nil {
+-		t.Value = h0
+-		return nil
+-	}
+-	var h1 bool
+-	if err := json.Unmarshal(x, &h1); err == nil {
+-		t.Value = h1
+-		return nil
+-	}
+-	return &UnmarshalError{"unmarshal failed to match one of [InlineCompletionOptions bool]"}
+-}
+-
+-// from line 8636
 -func (t Or_ServerCapabilities_inlineValueProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case InlineValueOptions:
@@ -51495,7 +57464,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [InlineValueOptions InlineValueRegistrationOptions bool]"}
 -}
 -
--// from line 8250
+-// from line 8548
 -func (t Or_ServerCapabilities_linkedEditingRangeProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case LinkedEditingRangeOptions:
@@ -51533,7 +57502,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [LinkedEditingRangeOptions LinkedEditingRangeRegistrationOptions bool]"}
 -}
 -
--// from line 8292
+-// from line 8590
 -func (t Or_ServerCapabilities_monikerProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MonikerOptions:
@@ -51571,7 +57540,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MonikerOptions MonikerRegistrationOptions bool]"}
 -}
 -
--// from line 7842
+-// from line 8140
 -func (t Or_ServerCapabilities_notebookDocumentSync) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case NotebookDocumentSyncOptions:
@@ -51602,7 +57571,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [NotebookDocumentSyncOptions NotebookDocumentSyncRegistrationOptions]"}
 -}
 -
--// from line 7981
+-// from line 8279
 -func (t Or_ServerCapabilities_referencesProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case ReferenceOptions:
@@ -51633,7 +57602,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [ReferenceOptions bool]"}
 -}
 -
--// from line 8156
+-// from line 8454
 -func (t Or_ServerCapabilities_renameProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case RenameOptions:
@@ -51664,7 +57633,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [RenameOptions bool]"}
 -}
 -
--// from line 8196
+-// from line 8494
 -func (t Or_ServerCapabilities_selectionRangeProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case SelectionRangeOptions:
@@ -51702,7 +57671,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [SelectionRangeOptions SelectionRangeRegistrationOptions bool]"}
 -}
 -
--// from line 8273
+-// from line 8571
 -func (t Or_ServerCapabilities_semanticTokensProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case SemanticTokensOptions:
@@ -51733,7 +57702,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [SemanticTokensOptions SemanticTokensRegistrationOptions]"}
 -}
 -
--// from line 7824
+-// from line 8122
 -func (t Or_ServerCapabilities_textDocumentSync) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case TextDocumentSyncKind:
@@ -51764,7 +57733,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [TextDocumentSyncKind TextDocumentSyncOptions]"}
 -}
 -
--// from line 7937
+-// from line 8235
 -func (t Or_ServerCapabilities_typeDefinitionProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case TypeDefinitionOptions:
@@ -51802,7 +57771,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [TypeDefinitionOptions TypeDefinitionRegistrationOptions bool]"}
 -}
 -
--// from line 8315
+-// from line 8613
 -func (t Or_ServerCapabilities_typeHierarchyProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case TypeHierarchyOptions:
@@ -51840,7 +57809,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [TypeHierarchyOptions TypeHierarchyRegistrationOptions bool]"}
 -}
 -
--// from line 8093
+-// from line 8391
 -func (t Or_ServerCapabilities_workspaceSymbolProvider) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case WorkspaceSymbolOptions:
@@ -51871,7 +57840,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [WorkspaceSymbolOptions bool]"}
 -}
 -
--// from line 8841
+-// from line 9159
 -func (t Or_SignatureInformation_documentation) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case MarkupContent:
@@ -51902,7 +57871,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [MarkupContent string]"}
 -}
 -
--// from line 6692
+-// from line 6928
 -func (t Or_TextDocumentEdit_edits_Elem) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case AnnotatedTextEdit:
@@ -51933,7 +57902,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [AnnotatedTextEdit TextEdit]"}
 -}
 -
--// from line 9777
+-// from line 10131
 -func (t Or_TextDocumentSyncOptions_save) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case SaveOptions:
@@ -51964,7 +57933,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [SaveOptions bool]"}
 -}
 -
--// from line 13986
+-// from line 14401
 -func (t Or_WorkspaceDocumentDiagnosticReport) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case WorkspaceFullDocumentDiagnosticReport:
@@ -51995,7 +57964,7 @@
 -	return &UnmarshalError{"unmarshal failed to match one of [WorkspaceFullDocumentDiagnosticReport WorkspaceUnchangedDocumentDiagnosticReport]"}
 -}
 -
--// from line 3219
+-// from line 3292
 -func (t Or_WorkspaceEdit_documentChanges_Elem) MarshalJSON() ([]byte, error) {
 -	switch x := t.Value.(type) {
 -	case CreateFile:
@@ -52072,8 +58041,8 @@
 -}
 diff -urN a/gopls/internal/lsp/protocol/tsprotocol.go b/gopls/internal/lsp/protocol/tsprotocol.go
 --- a/gopls/internal/lsp/protocol/tsprotocol.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/tsprotocol.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5450 +0,0 @@
++++ b/gopls/internal/lsp/protocol/tsprotocol.go	1970-01-01 08:00:00
+@@ -1,5642 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -52082,8 +58051,8 @@
 -
 -package protocol
 -
--// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f).
--// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json
+-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.4-next.2 (hash 184c8a7f010d335582f24337fe182baa6f2fccdd).
+-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.4-next.2/protocol/metaModel.json
 -// LSP metaData.version = 3.17.0.
 -
 -import "encoding/json"
@@ -52091,14 +58060,14 @@
 -// A special text edit with an additional change annotation.
 -//
 -// @since 3.16.0.
--type AnnotatedTextEdit struct { // line 9372
+-type AnnotatedTextEdit struct {
 -	// The actual identifier of the change annotation
 -	AnnotationID ChangeAnnotationIdentifier `json:"annotationId"`
 -	TextEdit
 -}
 -
--// The parameters passed via a apply workspace edit request.
--type ApplyWorkspaceEditParams struct { // line 5984
+-// The parameters passed via an apply workspace edit request.
+-type ApplyWorkspaceEditParams struct {
 -	// An optional label of the workspace edit. This label is
 -	// presented in the user interface for example on an undo
 -	// stack to undo the workspace edit.
@@ -52110,7 +58079,7 @@
 -// The result returned from the apply workspace edit request.
 -//
 -// @since 3.17 renamed from ApplyWorkspaceEditResponse
--type ApplyWorkspaceEditResult struct { // line 6007
+-type ApplyWorkspaceEditResult struct {
 -	// Indicates whether the edit was applied or not.
 -	Applied bool `json:"applied"`
 -	// An optional textual description for why the edit was not applied.
@@ -52124,7 +58093,7 @@
 -}
 -
 -// A base for all symbol information.
--type BaseSymbolInformation struct { // line 8966
+-type BaseSymbolInformation struct {
 -	// The name of this symbol.
 -	Name string `json:"name"`
 -	// The kind of this symbol.
@@ -52141,7 +58110,7 @@
 -}
 -
 -// @since 3.16.0
--type CallHierarchyClientCapabilities struct { // line 12141
+-type CallHierarchyClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
 -	// return value for the corresponding server capability as well.
@@ -52151,7 +58120,7 @@
 -// Represents an incoming call, e.g. a caller of a method or constructor.
 -//
 -// @since 3.16.0
--type CallHierarchyIncomingCall struct { // line 2779
+-type CallHierarchyIncomingCall struct {
 -	// The item that makes the call.
 -	From CallHierarchyItem `json:"from"`
 -	// The ranges at which the calls appear. This is relative to the caller
@@ -52162,7 +58131,7 @@
 -// The parameter of a `callHierarchy/incomingCalls` request.
 -//
 -// @since 3.16.0
--type CallHierarchyIncomingCallsParams struct { // line 2755
+-type CallHierarchyIncomingCallsParams struct {
 -	Item CallHierarchyItem `json:"item"`
 -	WorkDoneProgressParams
 -	PartialResultParams
@@ -52172,7 +58141,7 @@
 -// of call hierarchy.
 -//
 -// @since 3.16.0
--type CallHierarchyItem struct { // line 2656
+-type CallHierarchyItem struct {
 -	// The name of this item.
 -	Name string `json:"name"`
 -	// The kind of this item.
@@ -52196,14 +58165,14 @@
 -// Call hierarchy options used during static registration.
 -//
 -// @since 3.16.0
--type CallHierarchyOptions struct { // line 6534
+-type CallHierarchyOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc.
 -//
 -// @since 3.16.0
--type CallHierarchyOutgoingCall struct { // line 2829
+-type CallHierarchyOutgoingCall struct {
 -	// The item that is called.
 -	To CallHierarchyItem `json:"to"`
 -	// The range at which this item is called. This is the range relative to the caller, e.g the item
@@ -52215,7 +58184,7 @@
 -// The parameter of a `callHierarchy/outgoingCalls` request.
 -//
 -// @since 3.16.0
--type CallHierarchyOutgoingCallsParams struct { // line 2805
+-type CallHierarchyOutgoingCallsParams struct {
 -	Item CallHierarchyItem `json:"item"`
 -	WorkDoneProgressParams
 -	PartialResultParams
@@ -52224,7 +58193,7 @@
 -// The parameter of a `textDocument/prepareCallHierarchy` request.
 -//
 -// @since 3.16.0
--type CallHierarchyPrepareParams struct { // line 2638
+-type CallHierarchyPrepareParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -}
@@ -52232,12 +58201,12 @@
 -// Call hierarchy options used during static or dynamic registration.
 -//
 -// @since 3.16.0
--type CallHierarchyRegistrationOptions struct { // line 2733
+-type CallHierarchyRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	CallHierarchyOptions
 -	StaticRegistrationOptions
 -}
--type CancelParams struct { // line 6179
+-type CancelParams struct {
 -	// The request id to cancel.
 -	ID interface{} `json:"id"`
 -}
@@ -52245,7 +58214,7 @@
 -// Additional information that describes document changes.
 -//
 -// @since 3.16.0
--type ChangeAnnotation struct { // line 6831
+-type ChangeAnnotation struct {
 -	// A human-readable string describing the actual change. The string
 -	// is rendered prominent in the user interface.
 -	Label string `json:"label"`
@@ -52258,9 +58227,9 @@
 -}
 -
 -// An identifier to refer to a change annotation stored with a workspace edit.
--type ChangeAnnotationIdentifier = string // (alias) line 13976
+-type ChangeAnnotationIdentifier = string // (alias) line 14391
 -// Defines the capabilities provided by the client.
--type ClientCapabilities struct { // line 9674
+-type ClientCapabilities struct {
 -	// Workspace specific client capabilities.
 -	Workspace WorkspaceClientCapabilities `json:"workspace,omitempty"`
 -	// Text document specific client capabilities.
@@ -52283,7 +58252,7 @@
 -// to refactor code.
 -//
 -// A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed.
--type CodeAction struct { // line 5382
+-type CodeAction struct {
 -	// A short, human-readable, title for this code action.
 -	Title string `json:"title"`
 -	// The kind of the code action.
@@ -52330,7 +58299,7 @@
 -}
 -
 -// The Client Capabilities of a {@link CodeActionRequest}.
--type CodeActionClientCapabilities struct { // line 11721
+-type CodeActionClientCapabilities struct {
 -	// Whether code action supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client support code action literals of type `CodeAction` as a valid
@@ -52370,7 +58339,7 @@
 -
 -// Contains additional diagnostic information about the context in which
 -// a {@link CodeActionProvider.provideCodeActions code action} is run.
--type CodeActionContext struct { // line 9032
+-type CodeActionContext struct {
 -	// An array of diagnostics known on the client side overlapping the range provided to the
 -	// `textDocument/codeAction` request. They are provided so that the server knows which
 -	// errors are currently presented to the user for the given range. There is no guarantee
@@ -52389,9 +58358,10 @@
 -}
 -
 -// A set of predefined code action kinds
--type CodeActionKind string // line 13326
+-type CodeActionKind string
+-
 -// Provider options for a {@link CodeActionRequest}.
--type CodeActionOptions struct { // line 9071
+-type CodeActionOptions struct {
 -	// CodeActionKinds that this server may return.
 -	//
 -	// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
@@ -52406,7 +58376,7 @@
 -}
 -
 -// The parameters of a {@link CodeActionRequest}.
--type CodeActionParams struct { // line 5308
+-type CodeActionParams struct {
 -	// The document in which the command was invoked.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The range for which the command was invoked.
@@ -52418,7 +58388,7 @@
 -}
 -
 -// Registration options for a {@link CodeActionRequest}.
--type CodeActionRegistrationOptions struct { // line 5476
+-type CodeActionRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	CodeActionOptions
 -}
@@ -52426,11 +58396,12 @@
 -// The reason why code actions were requested.
 -//
 -// @since 3.17.0
--type CodeActionTriggerKind uint32 // line 13606
+-type CodeActionTriggerKind uint32
+-
 -// Structure to capture a description for an error code.
 -//
 -// @since 3.16.0
--type CodeDescription struct { // line 10026
+-type CodeDescription struct {
 -	// An URI to open with more information about the diagnostic error.
 -	Href URI `json:"href"`
 -}
@@ -52440,7 +58411,7 @@
 -//
 -// A code lens is _unresolved_ when no command is associated to it. For performance
 -// reasons the creation of a code lens and resolving should be done in two stages.
--type CodeLens struct { // line 5599
+-type CodeLens struct {
 -	// The range in which this code lens is valid. Should only span a single line.
 -	Range Range `json:"range"`
 -	// The command this code lens represents.
@@ -52452,20 +58423,20 @@
 -}
 -
 -// The client capabilities  of a {@link CodeLensRequest}.
--type CodeLensClientCapabilities struct { // line 11835
+-type CodeLensClientCapabilities struct {
 -	// Whether code lens supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// Code Lens provider options of a {@link CodeLensRequest}.
--type CodeLensOptions struct { // line 9127
+-type CodeLensOptions struct {
 -	// Code lens has a resolve provider as well.
 -	ResolveProvider bool `json:"resolveProvider,omitempty"`
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameters of a {@link CodeLensRequest}.
--type CodeLensParams struct { // line 5575
+-type CodeLensParams struct {
 -	// The document to request code lens for.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
@@ -52473,13 +58444,13 @@
 -}
 -
 -// Registration options for a {@link CodeLensRequest}.
--type CodeLensRegistrationOptions struct { // line 5631
+-type CodeLensRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	CodeLensOptions
 -}
 -
 -// @since 3.16.0
--type CodeLensWorkspaceClientCapabilities struct { // line 10993
+-type CodeLensWorkspaceClientCapabilities struct {
 -	// Whether the client implementation supports a refresh request sent from the
 -	// server to the client.
 -	//
@@ -52491,7 +58462,7 @@
 -}
 -
 -// Represents a color in RGBA space.
--type Color struct { // line 6433
+-type Color struct {
 -	// The red component of this color in the range [0-1].
 -	Red float64 `json:"red"`
 -	// The green component of this color in the range [0-1].
@@ -52503,13 +58474,13 @@
 -}
 -
 -// Represents a color range from a document.
--type ColorInformation struct { // line 2239
+-type ColorInformation struct {
 -	// The range in the document where this color appears.
 -	Range Range `json:"range"`
 -	// The actual color value for this color range.
 -	Color Color `json:"color"`
 -}
--type ColorPresentation struct { // line 2321
+-type ColorPresentation struct {
 -	// The label of this color presentation. It will be shown on the color
 -	// picker header. By default this is also the text that is inserted when selecting
 -	// this color presentation.
@@ -52524,7 +58495,7 @@
 -}
 -
 -// Parameters for a {@link ColorPresentationRequest}.
--type ColorPresentationParams struct { // line 2281
+-type ColorPresentationParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The color to request presentations for.
@@ -52539,7 +58510,7 @@
 -// will be used to represent a command in the UI and, optionally,
 -// an array of arguments which will be passed to the command handler
 -// function when invoked.
--type Command struct { // line 5348
+-type Command struct {
 -	// Title of the command, like `save`.
 -	Title string `json:"title"`
 -	// The identifier of the actual command handler.
@@ -52550,7 +58521,7 @@
 -}
 -
 -// Completion client capabilities
--type CompletionClientCapabilities struct { // line 11168
+-type CompletionClientCapabilities struct {
 -	// Whether completion supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client supports the following `CompletionItem` specific
@@ -52574,7 +58545,7 @@
 -}
 -
 -// Contains additional information about the context in which a completion request is triggered.
--type CompletionContext struct { // line 8628
+-type CompletionContext struct {
 -	// How the completion was triggered.
 -	TriggerKind CompletionTriggerKind `json:"triggerKind"`
 -	// The trigger character (a single character) that has trigger code complete.
@@ -52584,7 +58555,7 @@
 -
 -// A completion item represents a text snippet that is
 -// proposed to complete text that is being typed.
--type CompletionItem struct { // line 4528
+-type CompletionItem struct {
 -	// The label of this completion item.
 -	//
 -	// The label property is also by default the text that
@@ -52705,11 +58676,12 @@
 -}
 -
 -// The kind of a completion entry.
--type CompletionItemKind uint32 // line 13134
+-type CompletionItemKind uint32
+-
 -// Additional details for a completion item label.
 -//
 -// @since 3.17.0
--type CompletionItemLabelDetails struct { // line 8651
+-type CompletionItemLabelDetails struct {
 -	// An optional string which is rendered less prominently directly after {@link CompletionItem.label label},
 -	// without any spacing. Should be used for function signatures and type annotations.
 -	Detail string `json:"detail,omitempty"`
@@ -52722,10 +58694,11 @@
 -// item.
 -//
 -// @since 3.15.0
--type CompletionItemTag uint32 // line 13244
+-type CompletionItemTag uint32
+-
 -// Represents a collection of {@link CompletionItem completion items} to be presented
 -// in the editor.
--type CompletionList struct { // line 4737
+-type CompletionList struct {
 -	// This list it not complete. Further typing results in recomputing this list.
 -	//
 -	// Recomputed lists have all their items replaced (not appended) in the
@@ -52750,7 +58723,7 @@
 -}
 -
 -// Completion options.
--type CompletionOptions struct { // line 8707
+-type CompletionOptions struct {
 -	// Most tools trigger completion request automatically without explicitly requesting
 -	// it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
 -	// starts to type an identifier. For example if the user types `c` in a JavaScript file
@@ -52781,7 +58754,7 @@
 -}
 -
 -// Completion parameters
--type CompletionParams struct { // line 4497
+-type CompletionParams struct {
 -	// The completion context. This is only available it the client specifies
 -	// to send this using the client capability `textDocument.completion.contextSupport === true`
 -	Context CompletionContext `json:"context,omitempty"`
@@ -52791,14 +58764,14 @@
 -}
 -
 -// Registration options for a {@link CompletionRequest}.
--type CompletionRegistrationOptions struct { // line 4854
+-type CompletionRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	CompletionOptions
 -}
 -
 -// How a completion was triggered
--type CompletionTriggerKind uint32 // line 13555
--type ConfigurationItem struct {   // line 6396
+-type CompletionTriggerKind uint32
+-type ConfigurationItem struct {
 -	// The scope to get the configuration section for.
 -	ScopeURI string `json:"scopeUri,omitempty"`
 -	// The configuration section asked for.
@@ -52806,12 +58779,12 @@
 -}
 -
 -// The parameters of a configuration request.
--type ConfigurationParams struct { // line 2199
+-type ConfigurationParams struct {
 -	Items []ConfigurationItem `json:"items"`
 -}
 -
 -// Create file operation.
--type CreateFile struct { // line 6712
+-type CreateFile struct {
 -	// A create
 -	Kind string `json:"kind"`
 -	// The resource to create.
@@ -52822,7 +58795,7 @@
 -}
 -
 -// Options to create a file.
--type CreateFileOptions struct { // line 9417
+-type CreateFileOptions struct {
 -	// Overwrite existing file. Overwrite wins over `ignoreIfExists`
 -	Overwrite bool `json:"overwrite,omitempty"`
 -	// Ignore if exists.
@@ -52833,15 +58806,15 @@
 -// files.
 -//
 -// @since 3.16.0
--type CreateFilesParams struct { // line 3175
+-type CreateFilesParams struct {
 -	// An array of all files/folders created in this operation.
 -	Files []FileCreate `json:"files"`
 -}
 -
 -// The declaration of a symbol representation as one or many {@link Location locations}.
--type Declaration = []Location // (alias) line 13833
+-type Declaration = []Location // (alias) line 14248
 -// @since 3.14.0
--type DeclarationClientCapabilities struct { // line 11509
+-type DeclarationClientCapabilities struct {
 -	// Whether declaration supports dynamic registration. If this is set to `true`
 -	// the client supports the new `DeclarationRegistrationOptions` return value
 -	// for the corresponding server capability as well.
@@ -52857,16 +58830,16 @@
 -//
 -// Servers should prefer returning `DeclarationLink` over `Declaration` if supported
 -// by the client.
--type DeclarationLink = LocationLink // (alias) line 13853
--type DeclarationOptions struct {    // line 6491
+-type DeclarationLink = LocationLink // (alias) line 14268
+-type DeclarationOptions struct {
 -	WorkDoneProgressOptions
 -}
--type DeclarationParams struct { // line 2494
+-type DeclarationParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type DeclarationRegistrationOptions struct { // line 2514
+-type DeclarationRegistrationOptions struct {
 -	DeclarationOptions
 -	TextDocumentRegistrationOptions
 -	StaticRegistrationOptions
@@ -52878,9 +58851,9 @@
 -//
 -// Servers should prefer returning `DefinitionLink` over `Definition` if supported
 -// by the client.
--type Definition = Or_Definition // (alias) line 13751
+-type Definition = Or_Definition // (alias) line 14166
 -// Client Capabilities for a {@link DefinitionRequest}.
--type DefinitionClientCapabilities struct { // line 11534
+-type DefinitionClientCapabilities struct {
 -	// Whether definition supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client supports additional metadata in the form of definition links.
@@ -52893,27 +58866,27 @@
 -//
 -// Provides additional metadata over normal {@link Location location} definitions, including the range of
 -// the defining symbol
--type DefinitionLink = LocationLink // (alias) line 13771
+-type DefinitionLink = LocationLink // (alias) line 14186
 -// Server Capabilities for a {@link DefinitionRequest}.
--type DefinitionOptions struct { // line 8919
+-type DefinitionOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link DefinitionRequest}.
--type DefinitionParams struct { // line 5018
+-type DefinitionParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
 -
 -// Registration options for a {@link DefinitionRequest}.
--type DefinitionRegistrationOptions struct { // line 5039
+-type DefinitionRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DefinitionOptions
 -}
 -
 -// Delete file operation
--type DeleteFile struct { // line 6794
+-type DeleteFile struct {
 -	// A delete
 -	Kind string `json:"kind"`
 -	// The file to delete.
@@ -52924,7 +58897,7 @@
 -}
 -
 -// Delete file options
--type DeleteFileOptions struct { // line 9465
+-type DeleteFileOptions struct {
 -	// Delete the content recursively if a folder is denoted.
 -	Recursive bool `json:"recursive,omitempty"`
 -	// Ignore the operation if the file doesn't exist.
@@ -52935,14 +58908,14 @@
 -// files.
 -//
 -// @since 3.16.0
--type DeleteFilesParams struct { // line 3300
+-type DeleteFilesParams struct {
 -	// An array of all files/folders deleted in this operation.
 -	Files []FileDelete `json:"files"`
 -}
 -
 -// Represents a diagnostic, such as a compiler error or warning. Diagnostic objects
 -// are only valid in the scope of a resource.
--type Diagnostic struct { // line 8525
+-type Diagnostic struct {
 -	// The range at which the message applies
 -	Range Range `json:"range"`
 -	// The diagnostic's severity. Can be omitted. If omitted it is up to the
@@ -52972,13 +58945,13 @@
 -	// notification and `textDocument/codeAction` request.
 -	//
 -	// @since 3.16.0
--	Data interface{} `json:"data,omitempty"`
+-	Data *json.RawMessage `json:"data,omitempty"`
 -}
 -
 -// Client capabilities specific to diagnostic pull requests.
 -//
 -// @since 3.17.0
--type DiagnosticClientCapabilities struct { // line 12408
+-type DiagnosticClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
 -	// return value for the corresponding server capability as well.
@@ -52990,7 +58963,7 @@
 -// Diagnostic options.
 -//
 -// @since 3.17.0
--type DiagnosticOptions struct { // line 7293
+-type DiagnosticOptions struct {
 -	// An optional identifier under which the diagnostics are
 -	// managed by the client.
 -	Identifier string `json:"identifier,omitempty"`
@@ -53007,7 +58980,7 @@
 -// Diagnostic registration options.
 -//
 -// @since 3.17.0
--type DiagnosticRegistrationOptions struct { // line 3855
+-type DiagnosticRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DiagnosticOptions
 -	StaticRegistrationOptions
@@ -53016,7 +58989,7 @@
 -// Represents a related message and source code location for a diagnostic. This should be
 -// used to point to code locations that cause or related to a diagnostics, e.g when duplicating
 -// a symbol in a scope.
--type DiagnosticRelatedInformation struct { // line 10041
+-type DiagnosticRelatedInformation struct {
 -	// The location of this related diagnostic information.
 -	Location Location `json:"location"`
 -	// The message of this related diagnostic information.
@@ -53026,20 +58999,22 @@
 -// Cancellation data returned from a diagnostic request.
 -//
 -// @since 3.17.0
--type DiagnosticServerCancellationData struct { // line 3841
+-type DiagnosticServerCancellationData struct {
 -	RetriggerRequest bool `json:"retriggerRequest"`
 -}
 -
 -// The diagnostic's severity.
--type DiagnosticSeverity uint32 // line 13504
+-type DiagnosticSeverity uint32
+-
 -// The diagnostic tags.
 -//
 -// @since 3.15.0
--type DiagnosticTag uint32 // line 13534
+-type DiagnosticTag uint32
+-
 -// Workspace client capabilities specific to diagnostic pull requests.
 -//
 -// @since 3.17.0
--type DiagnosticWorkspaceClientCapabilities struct { // line 11111
+-type DiagnosticWorkspaceClientCapabilities struct {
 -	// Whether the client implementation supports a refresh request sent from
 -	// the server to the client.
 -	//
@@ -53049,24 +59024,24 @@
 -	// change that requires such a calculation.
 -	RefreshSupport bool `json:"refreshSupport,omitempty"`
 -}
--type DidChangeConfigurationClientCapabilities struct { // line 10837
+-type DidChangeConfigurationClientCapabilities struct {
 -	// Did change configuration notification supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// The parameters of a change configuration notification.
--type DidChangeConfigurationParams struct { // line 4144
+-type DidChangeConfigurationParams struct {
 -	// The actual changed settings
 -	Settings interface{} `json:"settings"`
 -}
--type DidChangeConfigurationRegistrationOptions struct { // line 4158
+-type DidChangeConfigurationRegistrationOptions struct {
 -	Section *OrPSection_workspace_didChangeConfiguration `json:"section,omitempty"`
 -}
 -
 -// The params sent in a change notebook document notification.
 -//
 -// @since 3.17.0
--type DidChangeNotebookDocumentParams struct { // line 3974
+-type DidChangeNotebookDocumentParams struct {
 -	// The notebook document that did change. The version number points
 -	// to the version after all provided changes have been applied. If
 -	// only the text document content of a cell changes the notebook version
@@ -53090,7 +59065,7 @@
 -}
 -
 -// The change text document notification's parameters.
--type DidChangeTextDocumentParams struct { // line 4287
+-type DidChangeTextDocumentParams struct {
 -	// The document that did change. The version number points
 -	// to the version after all provided content changes have
 -	// been applied.
@@ -53109,7 +59084,7 @@
 -	//   you receive them.
 -	ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"`
 -}
--type DidChangeWatchedFilesClientCapabilities struct { // line 10851
+-type DidChangeWatchedFilesClientCapabilities struct {
 -	// Did change watched files notification supports dynamic registration. Please note
 -	// that the current protocol doesn't support static configuration for file changes
 -	// from the server side.
@@ -53122,19 +59097,19 @@
 -}
 -
 -// The watched files change notification's parameters.
--type DidChangeWatchedFilesParams struct { // line 4428
+-type DidChangeWatchedFilesParams struct {
 -	// The actual file events.
 -	Changes []FileEvent `json:"changes"`
 -}
 -
 -// Describe options to be used when registered for text document change events.
--type DidChangeWatchedFilesRegistrationOptions struct { // line 4445
+-type DidChangeWatchedFilesRegistrationOptions struct {
 -	// The watchers to register.
 -	Watchers []FileSystemWatcher `json:"watchers"`
 -}
 -
 -// The parameters of a `workspace/didChangeWorkspaceFolders` notification.
--type DidChangeWorkspaceFoldersParams struct { // line 2185
+-type DidChangeWorkspaceFoldersParams struct {
 -	// The actual workspace folder change event.
 -	Event WorkspaceFoldersChangeEvent `json:"event"`
 -}
@@ -53142,7 +59117,7 @@
 -// The params sent in a close notebook document notification.
 -//
 -// @since 3.17.0
--type DidCloseNotebookDocumentParams struct { // line 4012
+-type DidCloseNotebookDocumentParams struct {
 -	// The notebook document that got closed.
 -	NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"`
 -	// The text documents that represent the content
@@ -53151,7 +59126,7 @@
 -}
 -
 -// The parameters sent in a close text document notification
--type DidCloseTextDocumentParams struct { // line 4332
+-type DidCloseTextDocumentParams struct {
 -	// The document that was closed.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -}
@@ -53159,7 +59134,7 @@
 -// The params sent in an open notebook document notification.
 -//
 -// @since 3.17.0
--type DidOpenNotebookDocumentParams struct { // line 3948
+-type DidOpenNotebookDocumentParams struct {
 -	// The notebook document that got opened.
 -	NotebookDocument NotebookDocument `json:"notebookDocument"`
 -	// The text documents that represent the content
@@ -53168,7 +59143,7 @@
 -}
 -
 -// The parameters sent in an open text document notification
--type DidOpenTextDocumentParams struct { // line 4273
+-type DidOpenTextDocumentParams struct {
 -	// The document that was opened.
 -	TextDocument TextDocumentItem `json:"textDocument"`
 -}
@@ -53176,37 +59151,37 @@
 -// The params sent in a save notebook document notification.
 -//
 -// @since 3.17.0
--type DidSaveNotebookDocumentParams struct { // line 3997
+-type DidSaveNotebookDocumentParams struct {
 -	// The notebook document that got saved.
 -	NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"`
 -}
 -
 -// The parameters sent in a save text document notification
--type DidSaveTextDocumentParams struct { // line 4346
+-type DidSaveTextDocumentParams struct {
 -	// The document that was saved.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// Optional the content when saved. Depends on the includeText value
 -	// when the save notification was requested.
 -	Text *string `json:"text,omitempty"`
 -}
--type DocumentColorClientCapabilities struct { // line 11875
+-type DocumentColorClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `DocumentColorRegistrationOptions` return value
 -	// for the corresponding server capability as well.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
--type DocumentColorOptions struct { // line 6471
+-type DocumentColorOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link DocumentColorRequest}.
--type DocumentColorParams struct { // line 2215
+-type DocumentColorParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type DocumentColorRegistrationOptions struct { // line 2261
+-type DocumentColorRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentColorOptions
 -	StaticRegistrationOptions
@@ -53215,7 +59190,7 @@
 -// Parameters of the document diagnostic request.
 -//
 -// @since 3.17.0
--type DocumentDiagnosticParams struct { // line 3768
+-type DocumentDiagnosticParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The additional identifier  provided during registration.
@@ -53229,11 +59204,12 @@
 -// The document diagnostic report kinds.
 -//
 -// @since 3.17.0
--type DocumentDiagnosticReportKind string // line 12722
+-type DocumentDiagnosticReportKind string
+-
 -// A partial result for a document diagnostic report.
 -//
 -// @since 3.17.0
--type DocumentDiagnosticReportPartialResult struct { // line 3811
+-type DocumentDiagnosticReportPartialResult struct {
 -	RelatedDocuments map[DocumentURI]interface{} `json:"relatedDocuments"`
 -}
 -
@@ -53241,20 +59217,20 @@
 -// a notebook cell document.
 -//
 -// @since 3.17.0 - proposed support for NotebookCellTextDocumentFilter.
--type DocumentFilter = Or_DocumentFilter // (alias) line 14093
+-type DocumentFilter = Or_DocumentFilter // (alias) line 14508
 -// Client capabilities of a {@link DocumentFormattingRequest}.
--type DocumentFormattingClientCapabilities struct { // line 11889
+-type DocumentFormattingClientCapabilities struct {
 -	// Whether formatting supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// Provider options for a {@link DocumentFormattingRequest}.
--type DocumentFormattingOptions struct { // line 9221
+-type DocumentFormattingOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameters of a {@link DocumentFormattingRequest}.
--type DocumentFormattingParams struct { // line 5727
+-type DocumentFormattingParams struct {
 -	// The document to format.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The format options.
@@ -53263,7 +59239,7 @@
 -}
 -
 -// Registration options for a {@link DocumentFormattingRequest}.
--type DocumentFormattingRegistrationOptions struct { // line 5755
+-type DocumentFormattingRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentFormattingOptions
 -}
@@ -53271,7 +59247,7 @@
 -// A document highlight is a range inside a text document which deserves
 -// special attention. Usually a document highlight is visualized by changing
 -// the background color of its range.
--type DocumentHighlight struct { // line 5119
+-type DocumentHighlight struct {
 -	// The range this highlight applies to.
 -	Range Range `json:"range"`
 -	// The highlight kind, default is {@link DocumentHighlightKind.Text text}.
@@ -53279,38 +59255,39 @@
 -}
 -
 -// Client Capabilities for a {@link DocumentHighlightRequest}.
--type DocumentHighlightClientCapabilities struct { // line 11624
+-type DocumentHighlightClientCapabilities struct {
 -	// Whether document highlight supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// A document highlight kind.
--type DocumentHighlightKind uint32 // line 13301
+-type DocumentHighlightKind uint32
+-
 -// Provider options for a {@link DocumentHighlightRequest}.
--type DocumentHighlightOptions struct { // line 8955
+-type DocumentHighlightOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link DocumentHighlightRequest}.
--type DocumentHighlightParams struct { // line 5098
+-type DocumentHighlightParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
 -
 -// Registration options for a {@link DocumentHighlightRequest}.
--type DocumentHighlightRegistrationOptions struct { // line 5142
+-type DocumentHighlightRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentHighlightOptions
 -}
 -
 -// A document link is a range in a text document that links to an internal or external resource, like another
 -// text document or a web site.
--type DocumentLink struct { // line 5670
+-type DocumentLink struct {
 -	// The range this link applies to.
 -	Range Range `json:"range"`
 -	// The uri this link points to. If missing a resolve request is sent later.
--	Target string `json:"target,omitempty"`
+-	Target *URI `json:"target,omitempty"`
 -	// The tooltip text when you hover over this link.
 -	//
 -	// If a tooltip is provided, is will be displayed in a string that includes instructions on how to
@@ -53325,7 +59302,7 @@
 -}
 -
 -// The client capabilities of a {@link DocumentLinkRequest}.
--type DocumentLinkClientCapabilities struct { // line 11850
+-type DocumentLinkClientCapabilities struct {
 -	// Whether document link supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Whether the client supports the `tooltip` property on `DocumentLink`.
@@ -53335,14 +59312,14 @@
 -}
 -
 -// Provider options for a {@link DocumentLinkRequest}.
--type DocumentLinkOptions struct { // line 9148
+-type DocumentLinkOptions struct {
 -	// Document links have a resolve provider as well.
 -	ResolveProvider bool `json:"resolveProvider,omitempty"`
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameters of a {@link DocumentLinkRequest}.
--type DocumentLinkParams struct { // line 5646
+-type DocumentLinkParams struct {
 -	// The document to provide document links for.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
@@ -53350,19 +59327,19 @@
 -}
 -
 -// Registration options for a {@link DocumentLinkRequest}.
--type DocumentLinkRegistrationOptions struct { // line 5712
+-type DocumentLinkRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentLinkOptions
 -}
 -
 -// Client capabilities of a {@link DocumentOnTypeFormattingRequest}.
--type DocumentOnTypeFormattingClientCapabilities struct { // line 11919
+-type DocumentOnTypeFormattingClientCapabilities struct {
 -	// Whether on type formatting supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// Provider options for a {@link DocumentOnTypeFormattingRequest}.
--type DocumentOnTypeFormattingOptions struct { // line 9243
+-type DocumentOnTypeFormattingOptions struct {
 -	// A character on which formatting should be triggered, like `{`.
 -	FirstTriggerCharacter string `json:"firstTriggerCharacter"`
 -	// More trigger characters.
@@ -53370,7 +59347,7 @@
 -}
 -
 -// The parameters of a {@link DocumentOnTypeFormattingRequest}.
--type DocumentOnTypeFormattingParams struct { // line 5821
+-type DocumentOnTypeFormattingParams struct {
 -	// The document to format.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The position around which the on type formatting should happen.
@@ -53387,24 +59364,34 @@
 -}
 -
 -// Registration options for a {@link DocumentOnTypeFormattingRequest}.
--type DocumentOnTypeFormattingRegistrationOptions struct { // line 5859
+-type DocumentOnTypeFormattingRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentOnTypeFormattingOptions
 -}
 -
 -// Client capabilities of a {@link DocumentRangeFormattingRequest}.
--type DocumentRangeFormattingClientCapabilities struct { // line 11904
+-type DocumentRangeFormattingClientCapabilities struct {
 -	// Whether range formatting supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+-	// Whether the client supports formatting multiple ranges at once.
+-	//
+-	// @since 3.18.0
+-	// @proposed
+-	RangesSupport bool `json:"rangesSupport,omitempty"`
 -}
 -
 -// Provider options for a {@link DocumentRangeFormattingRequest}.
--type DocumentRangeFormattingOptions struct { // line 9232
+-type DocumentRangeFormattingOptions struct {
+-	// Whether the server supports formatting multiple ranges at once.
+-	//
+-	// @since 3.18.0
+-	// @proposed
+-	RangesSupport bool `json:"rangesSupport,omitempty"`
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameters of a {@link DocumentRangeFormattingRequest}.
--type DocumentRangeFormattingParams struct { // line 5770
+-type DocumentRangeFormattingParams struct {
 -	// The document to format.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The range to format
@@ -53415,22 +59402,36 @@
 -}
 -
 -// Registration options for a {@link DocumentRangeFormattingRequest}.
--type DocumentRangeFormattingRegistrationOptions struct { // line 5806
+-type DocumentRangeFormattingRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentRangeFormattingOptions
 -}
 -
+-// The parameters of a {@link DocumentRangesFormattingRequest}.
+-//
+-// @since 3.18.0
+-// @proposed
+-type DocumentRangesFormattingParams struct {
+-	// The document to format.
+-	TextDocument TextDocumentIdentifier `json:"textDocument"`
+-	// The ranges to format
+-	Ranges []Range `json:"ranges"`
+-	// The format options
+-	Options FormattingOptions `json:"options"`
+-	WorkDoneProgressParams
+-}
+-
 -// A document selector is the combination of one or many document filters.
 -//
 -// @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`;
 -//
 -// The use of a string as a document filter is deprecated @since 3.16.0.
--type DocumentSelector = []DocumentFilter // (alias) line 13948
+-type DocumentSelector = []DocumentFilter // (alias) line 14363
 -// Represents programming constructs like variables, classes, interfaces etc.
 -// that appear in a document. Document symbols can be hierarchical and they
 -// have two ranges: one that encloses its definition and one that points to
 -// its most interesting range, e.g. the range of an identifier.
--type DocumentSymbol struct { // line 5211
+-type DocumentSymbol struct {
 -	// The name of this symbol. Will be displayed in the user interface and therefore must not be
 -	// an empty string or a string only consisting of white spaces.
 -	Name string `json:"name"`
@@ -53458,7 +59459,7 @@
 -}
 -
 -// Client Capabilities for a {@link DocumentSymbolRequest}.
--type DocumentSymbolClientCapabilities struct { // line 11639
+-type DocumentSymbolClientCapabilities struct {
 -	// Whether document symbol supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Specific capabilities for the `SymbolKind` in the
@@ -53480,7 +59481,7 @@
 -}
 -
 -// Provider options for a {@link DocumentSymbolRequest}.
--type DocumentSymbolOptions struct { // line 9010
+-type DocumentSymbolOptions struct {
 -	// A human-readable string that is shown when multiple outlines trees
 -	// are shown for the same document.
 -	//
@@ -53490,7 +59491,7 @@
 -}
 -
 -// Parameters for a {@link DocumentSymbolRequest}.
--type DocumentSymbolParams struct { // line 5157
+-type DocumentSymbolParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
@@ -53498,29 +59499,30 @@
 -}
 -
 -// Registration options for a {@link DocumentSymbolRequest}.
--type DocumentSymbolRegistrationOptions struct { // line 5293
+-type DocumentSymbolRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	DocumentSymbolOptions
 -}
 -type DocumentURI string
 -
 -// Predefined error codes.
--type ErrorCodes int32 // line 12743
+-type ErrorCodes int32
+-
 -// The client capabilities of a {@link ExecuteCommandRequest}.
--type ExecuteCommandClientCapabilities struct { // line 10962
+-type ExecuteCommandClientCapabilities struct {
 -	// Execute command supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// The server capabilities of a {@link ExecuteCommandRequest}.
--type ExecuteCommandOptions struct { // line 9291
+-type ExecuteCommandOptions struct {
 -	// The commands to be executed on the server
 -	Commands []string `json:"commands"`
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameters of a {@link ExecuteCommandRequest}.
--type ExecuteCommandParams struct { // line 5941
+-type ExecuteCommandParams struct {
 -	// The identifier of the actual command handler.
 -	Command string `json:"command"`
 -	// Arguments that the command should be invoked with.
@@ -53529,10 +59531,10 @@
 -}
 -
 -// Registration options for a {@link ExecuteCommandRequest}.
--type ExecuteCommandRegistrationOptions struct { // line 5973
+-type ExecuteCommandRegistrationOptions struct {
 -	ExecuteCommandOptions
 -}
--type ExecutionSummary struct { // line 10162
+-type ExecutionSummary struct {
 -	// A strict monotonically increasing value
 -	// indicating the execution order of a cell
 -	// inside a notebook.
@@ -53543,7 +59545,7 @@
 -}
 -
 -// created for Literal (Lit_CodeActionClientCapabilities_codeActionLiteralSupport_codeActionKind)
--type FCodeActionKindPCodeActionLiteralSupport struct { // line 11742
+-type FCodeActionKindPCodeActionLiteralSupport struct {
 -	// The code action kind values the client supports. When this
 -	// property exists the client also guarantees that it will
 -	// handle values outside its set gracefully and falls back
@@ -53552,25 +59554,25 @@
 -}
 -
 -// created for Literal (Lit_CompletionList_itemDefaults_editRange_Item1)
--type FEditRangePItemDefaults struct { // line 4777
+-type FEditRangePItemDefaults struct {
 -	Insert  Range `json:"insert"`
 -	Replace Range `json:"replace"`
 -}
 -
 -// created for Literal (Lit_SemanticTokensClientCapabilities_requests_full_Item1)
--type FFullPRequests struct { // line 12205
+-type FFullPRequests struct {
 -	// The client will send the `textDocument/semanticTokens/full/delta` request if
 -	// the server provides a corresponding handler.
 -	Delta bool `json:"delta"`
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionItem_insertTextModeSupport)
--type FInsertTextModeSupportPCompletionItem struct { // line 11295
+-type FInsertTextModeSupportPCompletionItem struct {
 -	ValueSet []InsertTextMode `json:"valueSet"`
 -}
 -
 -// created for Literal (Lit_SignatureHelpClientCapabilities_signatureInformation_parameterInformation)
--type FParameterInformationPSignatureInformation struct { // line 11461
+-type FParameterInformationPSignatureInformation struct {
 -	// The client supports processing label offsets instead of a
 -	// simple label string.
 -	//
@@ -53579,17 +59581,17 @@
 -}
 -
 -// created for Literal (Lit_SemanticTokensClientCapabilities_requests_range_Item1)
--type FRangePRequests struct { // line 12185
+-type FRangePRequests struct {
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionItem_resolveSupport)
--type FResolveSupportPCompletionItem struct { // line 11271
+-type FResolveSupportPCompletionItem struct {
 -	// The properties that a client can resolve lazily.
 -	Properties []string `json:"properties"`
 -}
 -
 -// created for Literal (Lit_NotebookDocumentChangeEvent_cells_structure)
--type FStructurePCells struct { // line 7487
+-type FStructurePCells struct {
 -	// The change to the cell array.
 -	Array NotebookCellArrayChange `json:"array"`
 -	// Additional opened cell text documents.
@@ -53599,17 +59601,19 @@
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionItem_tagSupport)
--type FTagSupportPCompletionItem struct { // line 11237
+-type FTagSupportPCompletionItem struct {
 -	// The tags supported by the client.
 -	ValueSet []CompletionItemTag `json:"valueSet"`
 -}
--type FailureHandlingKind string // line 13693
+-type FailureHandlingKind string
+-
 -// The file event type
--type FileChangeType uint32 // line 13454
+-type FileChangeType uint32
+-
 -// Represents information on a file/folder create.
 -//
 -// @since 3.16.0
--type FileCreate struct { // line 6662
+-type FileCreate struct {
 -	// A file:// URI for the location of the file/folder being created.
 -	URI string `json:"uri"`
 -}
@@ -53617,13 +59621,13 @@
 -// Represents information on a file/folder delete.
 -//
 -// @since 3.16.0
--type FileDelete struct { // line 6911
+-type FileDelete struct {
 -	// A file:// URI for the location of the file/folder being deleted.
 -	URI string `json:"uri"`
 -}
 -
 -// An event describing a file change.
--type FileEvent struct { // line 8480
+-type FileEvent struct {
 -	// The file's uri.
 -	URI DocumentURI `json:"uri"`
 -	// The change type.
@@ -53636,7 +59640,7 @@
 -// like renaming a file in the UI.
 -//
 -// @since 3.16.0
--type FileOperationClientCapabilities struct { // line 11009
+-type FileOperationClientCapabilities struct {
 -	// Whether the client supports dynamic registration for file requests/notifications.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client has support for sending didCreateFiles notifications.
@@ -53657,7 +59661,7 @@
 -// the server is interested in receiving.
 -//
 -// @since 3.16.0
--type FileOperationFilter struct { // line 6864
+-type FileOperationFilter struct {
 -	// A Uri scheme like `file` or `untitled`.
 -	Scheme string `json:"scheme,omitempty"`
 -	// The actual file operation pattern.
@@ -53667,7 +59671,7 @@
 -// Options for notifications/requests for user operations on files.
 -//
 -// @since 3.16.0
--type FileOperationOptions struct { // line 9965
+-type FileOperationOptions struct {
 -	// The server is interested in receiving didCreateFiles notifications.
 -	DidCreate *FileOperationRegistrationOptions `json:"didCreate,omitempty"`
 -	// The server is interested in receiving willCreateFiles requests.
@@ -53686,7 +59690,7 @@
 -// the server is interested in receiving.
 -//
 -// @since 3.16.0
--type FileOperationPattern struct { // line 9489
+-type FileOperationPattern struct {
 -	// The glob pattern to match. Glob patterns can have the following syntax:
 -	//
 -	//  - `*` to match one or more characters in a path segment
@@ -53708,11 +59712,12 @@
 -// both.
 -//
 -// @since 3.16.0
--type FileOperationPatternKind string // line 13627
+-type FileOperationPatternKind string
+-
 -// Matching options for the file operation pattern.
 -//
 -// @since 3.16.0
--type FileOperationPatternOptions struct { // line 10146
+-type FileOperationPatternOptions struct {
 -	// The pattern should be matched ignoring casing.
 -	IgnoreCase bool `json:"ignoreCase,omitempty"`
 -}
@@ -53720,7 +59725,7 @@
 -// The options to register for file operations.
 -//
 -// @since 3.16.0
--type FileOperationRegistrationOptions struct { // line 3264
+-type FileOperationRegistrationOptions struct {
 -	// The actual filters.
 -	Filters []FileOperationFilter `json:"filters"`
 -}
@@ -53728,13 +59733,13 @@
 -// Represents information on a file/folder rename.
 -//
 -// @since 3.16.0
--type FileRename struct { // line 6888
+-type FileRename struct {
 -	// A file:// URI for the original location of the file/folder being renamed.
 -	OldURI string `json:"oldUri"`
 -	// A file:// URI for the new location of the file/folder being renamed.
 -	NewURI string `json:"newUri"`
 -}
--type FileSystemWatcher struct { // line 8502
+-type FileSystemWatcher struct {
 -	// The glob pattern to watch. See {@link GlobPattern glob pattern} for more detail.
 -	//
 -	// @since 3.17.0 support for relative patterns.
@@ -53747,7 +59752,7 @@
 -
 -// Represents a folding range. To be valid, start and end line must be bigger than zero and smaller
 -// than the number of lines in the document. Clients are free to ignore invalid ranges.
--type FoldingRange struct { // line 2415
+-type FoldingRange struct {
 -	// The zero-based start line of the range to fold. The folded area starts after the line's last character.
 -	// To be valid, the end must be zero or larger and smaller than the number of lines in the document.
 -	StartLine uint32 `json:"startLine"`
@@ -53769,7 +59774,7 @@
 -	// @since 3.17.0
 -	CollapsedText string `json:"collapsedText,omitempty"`
 -}
--type FoldingRangeClientCapabilities struct { // line 11978
+-type FoldingRangeClientCapabilities struct {
 -	// Whether implementation supports dynamic registration for folding range
 -	// providers. If this is set to `true` the client supports the new
 -	// `FoldingRangeRegistrationOptions` return value for the corresponding
@@ -53794,26 +59799,26 @@
 -}
 -
 -// A set of predefined range kinds.
--type FoldingRangeKind string      // line 12815
--type FoldingRangeOptions struct { // line 6481
+-type FoldingRangeKind string
+-type FoldingRangeOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link FoldingRangeRequest}.
--type FoldingRangeParams struct { // line 2391
+-type FoldingRangeParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type FoldingRangeRegistrationOptions struct { // line 2474
+-type FoldingRangeRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	FoldingRangeOptions
 -	StaticRegistrationOptions
 -}
 -
 -// Value-object describing what options formatting should use.
--type FormattingOptions struct { // line 9169
+-type FormattingOptions struct {
 -	// Size of a tab in spaces.
 -	TabSize uint32 `json:"tabSize"`
 -	// Prefer spaces over tabs.
@@ -53835,7 +59840,7 @@
 -// A diagnostic report with a full set of problems.
 -//
 -// @since 3.17.0
--type FullDocumentDiagnosticReport struct { // line 7235
+-type FullDocumentDiagnosticReport struct {
 -	// A full document diagnostic report.
 -	Kind string `json:"kind"`
 -	// An optional result id. If provided it will
@@ -53849,7 +59854,7 @@
 -// General client capabilities.
 -//
 -// @since 3.16.0
--type GeneralClientCapabilities struct { // line 10664
+-type GeneralClientCapabilities struct {
 -	// Client capability that signals how the client
 -	// handles stale requests (e.g. a request
 -	// for which the client will not process the response
@@ -53889,16 +59894,16 @@
 -// The glob pattern. Either a string pattern or a relative pattern.
 -//
 -// @since 3.17.0
--type GlobPattern = string // (alias) line 14127
+-type GlobPattern = string // (alias) line 14542
 -// The result of a hover request.
--type Hover struct { // line 4886
+-type Hover struct {
 -	// The hover's content
 -	Contents MarkupContent `json:"contents"`
 -	// An optional range inside the text document that is used to
 -	// visualize the hover, e.g. by changing the background color.
 -	Range Range `json:"range,omitempty"`
 -}
--type HoverClientCapabilities struct { // line 11402
+-type HoverClientCapabilities struct {
 -	// Whether hover supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Client supports the following content formats for the content
@@ -53907,24 +59912,24 @@
 -}
 -
 -// Hover options.
--type HoverOptions struct { // line 8776
+-type HoverOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link HoverRequest}.
--type HoverParams struct { // line 4869
+-type HoverParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -}
 -
 -// Registration options for a {@link HoverRequest}.
--type HoverRegistrationOptions struct { // line 4925
+-type HoverRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	HoverOptions
 -}
 -
 -// @since 3.6.0
--type ImplementationClientCapabilities struct { // line 11583
+-type ImplementationClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `ImplementationRegistrationOptions` return value
 -	// for the corresponding server capability as well.
@@ -53934,15 +59939,15 @@
 -	// @since 3.14.0
 -	LinkSupport bool `json:"linkSupport,omitempty"`
 -}
--type ImplementationOptions struct { // line 6333
+-type ImplementationOptions struct {
 -	WorkDoneProgressOptions
 -}
--type ImplementationParams struct { // line 2063
+-type ImplementationParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type ImplementationRegistrationOptions struct { // line 2103
+-type ImplementationRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	ImplementationOptions
 -	StaticRegistrationOptions
@@ -53950,20 +59955,20 @@
 -
 -// The data type of the ResponseError if the
 -// initialize request fails.
--type InitializeError struct { // line 4126
+-type InitializeError struct {
 -	// Indicates whether the client execute the following retry logic:
 -	// (1) show the message provided by the ResponseError to the user
 -	// (2) user selects retry or cancel
 -	// (3) if user selected retry the initialize method is sent again.
 -	Retry bool `json:"retry"`
 -}
--type InitializeParams struct { // line 4068
+-type InitializeParams struct {
 -	XInitializeParams
 -	WorkspaceFoldersInitializeParams
 -}
 -
 -// The result returned from an initialize request.
--type InitializeResult struct { // line 4082
+-type InitializeResult struct {
 -	// The capabilities the language server provides.
 -	Capabilities ServerCapabilities `json:"capabilities"`
 -	// Information about the server.
@@ -53971,13 +59976,13 @@
 -	// @since 3.15.0
 -	ServerInfo *PServerInfoMsg_initialize `json:"serverInfo,omitempty"`
 -}
--type InitializedParams struct { // line 4140
+-type InitializedParams struct {
 -}
 -
 -// Inlay hint information.
 -//
 -// @since 3.17.0
--type InlayHint struct { // line 3645
+-type InlayHint struct {
 -	// The position of this hint.
 -	Position Position `json:"position"`
 -	// The label of this hint. A human readable string or an array of
@@ -54016,7 +60021,7 @@
 -// Inlay hint client capabilities.
 -//
 -// @since 3.17.0
--type InlayHintClientCapabilities struct { // line 12369
+-type InlayHintClientCapabilities struct {
 -	// Whether inlay hints support dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Indicates which properties a client can resolve lazily on an inlay
@@ -54027,12 +60032,13 @@
 -// Inlay hint kinds.
 -//
 -// @since 3.17.0
--type InlayHintKind uint32 // line 13033
+-type InlayHintKind uint32
+-
 -// An inlay hint label part allows for interactive and composite labels
 -// of inlay hints.
 -//
 -// @since 3.17.0
--type InlayHintLabelPart struct { // line 7062
+-type InlayHintLabelPart struct {
 -	// The value of this label part.
 -	Value string `json:"value"`
 -	// The tooltip text when you hover over this label part. Depending on
@@ -54061,7 +60067,7 @@
 -// Inlay hint options used during static registration.
 -//
 -// @since 3.17.0
--type InlayHintOptions struct { // line 7135
+-type InlayHintOptions struct {
 -	// The server provides support to resolve additional
 -	// information for an inlay hint item.
 -	ResolveProvider bool `json:"resolveProvider,omitempty"`
@@ -54071,7 +60077,7 @@
 -// A parameter literal used in inlay hint requests.
 -//
 -// @since 3.17.0
--type InlayHintParams struct { // line 3616
+-type InlayHintParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The document range for which inlay hints should be computed.
@@ -54082,7 +60088,7 @@
 -// Inlay hint options used during static or dynamic registration.
 -//
 -// @since 3.17.0
--type InlayHintRegistrationOptions struct { // line 3746
+-type InlayHintRegistrationOptions struct {
 -	InlayHintOptions
 -	TextDocumentRegistrationOptions
 -	StaticRegistrationOptions
@@ -54091,7 +60097,7 @@
 -// Client workspace capabilities specific to inlay hints.
 -//
 -// @since 3.17.0
--type InlayHintWorkspaceClientCapabilities struct { // line 11095
+-type InlayHintWorkspaceClientCapabilities struct {
 -	// Whether the client implementation supports a refresh request sent from
 -	// the server to the client.
 -	//
@@ -54102,6 +60108,86 @@
 -	RefreshSupport bool `json:"refreshSupport,omitempty"`
 -}
 -
+-// Client capabilities specific to inline completions.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionClientCapabilities struct {
+-	// Whether implementation supports dynamic registration for inline completion providers.
+-	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
+-}
+-
+-// Provides information about the context in which an inline completion was requested.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionContext struct {
+-	// Describes how the inline completion was triggered.
+-	TriggerKind InlineCompletionTriggerKind `json:"triggerKind"`
+-	// Provides information about the currently selected item in the autocomplete widget if it is visible.
+-	SelectedCompletionInfo *SelectedCompletionInfo `json:"selectedCompletionInfo,omitempty"`
+-}
+-
+-// An inline completion item represents a text snippet that is proposed inline to complete text that is being typed.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionItem struct {
+-	// The text to replace the range with. Must be set.
+-	InsertText Or_InlineCompletionItem_insertText `json:"insertText"`
+-	// A text that is used to decide if this inline completion should be shown. When `falsy` the {@link InlineCompletionItem.insertText} is used.
+-	FilterText string `json:"filterText,omitempty"`
+-	// The range to replace. Must begin and end on the same line.
+-	Range *Range `json:"range,omitempty"`
+-	// An optional {@link Command} that is executed *after* inserting this completion.
+-	Command *Command `json:"command,omitempty"`
+-}
+-
+-// Represents a collection of {@link InlineCompletionItem inline completion items} to be presented in the editor.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionList struct {
+-	// The inline completion items
+-	Items []InlineCompletionItem `json:"items"`
+-}
+-
+-// Inline completion options used during static registration.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionOptions struct {
+-	WorkDoneProgressOptions
+-}
+-
+-// A parameter literal used in inline completion requests.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionParams struct {
+-	// Additional information about the context in which inline completions were
+-	// requested.
+-	Context InlineCompletionContext `json:"context"`
+-	TextDocumentPositionParams
+-	WorkDoneProgressParams
+-}
+-
+-// Inline completion options used during static or dynamic registration.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionRegistrationOptions struct {
+-	InlineCompletionOptions
+-	TextDocumentRegistrationOptions
+-	StaticRegistrationOptions
+-}
+-
+-// Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered.
+-//
+-// @since 3.18.0
+-// @proposed
+-type InlineCompletionTriggerKind uint32
+-
 -// Inline value information can be provided by different means:
 -//
 -//   - directly as a text value (class InlineValueText).
@@ -54111,17 +60197,17 @@
 -// The InlineValue types combines all inline value types into one type.
 -//
 -// @since 3.17.0
--type InlineValue = Or_InlineValue // (alias) line 13861
+-type InlineValue = Or_InlineValue // (alias) line 14276
 -// Client capabilities specific to inline values.
 -//
 -// @since 3.17.0
--type InlineValueClientCapabilities struct { // line 12353
+-type InlineValueClientCapabilities struct {
 -	// Whether implementation supports dynamic registration for inline value providers.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// @since 3.17.0
--type InlineValueContext struct { // line 6948
+-type InlineValueContext struct {
 -	// The stack frame (as a DAP Id) where the execution has stopped.
 -	FrameID int32 `json:"frameId"`
 -	// The document range where execution has stopped.
@@ -54134,7 +60220,7 @@
 -// An optional expression can be used to override the extracted expression.
 -//
 -// @since 3.17.0
--type InlineValueEvaluatableExpression struct { // line 7026
+-type InlineValueEvaluatableExpression struct {
 -	// The document range for which the inline value applies.
 -	// The range is used to extract the evaluatable expression from the underlying document.
 -	Range Range `json:"range"`
@@ -54145,14 +60231,14 @@
 -// Inline value options used during static registration.
 -//
 -// @since 3.17.0
--type InlineValueOptions struct { // line 7050
+-type InlineValueOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// A parameter literal used in inline value requests.
 -//
 -// @since 3.17.0
--type InlineValueParams struct { // line 3557
+-type InlineValueParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The document range for which inline values should be computed.
@@ -54166,7 +60252,7 @@
 -// Inline value options used during static or dynamic registration.
 -//
 -// @since 3.17.0
--type InlineValueRegistrationOptions struct { // line 3594
+-type InlineValueRegistrationOptions struct {
 -	InlineValueOptions
 -	TextDocumentRegistrationOptions
 -	StaticRegistrationOptions
@@ -54175,7 +60261,7 @@
 -// Provide inline value as text.
 -//
 -// @since 3.17.0
--type InlineValueText struct { // line 6971
+-type InlineValueText struct {
 -	// The document range for which the inline value applies.
 -	Range Range `json:"range"`
 -	// The text of the inline value.
@@ -54187,7 +60273,7 @@
 -// An optional variable name can be used to override the extracted name.
 -//
 -// @since 3.17.0
--type InlineValueVariableLookup struct { // line 6994
+-type InlineValueVariableLookup struct {
 -	// The document range for which the inline value applies.
 -	// The range is used to extract the variable name from the underlying document.
 -	Range Range `json:"range"`
@@ -54200,7 +60286,7 @@
 -// Client workspace capabilities specific to inline values.
 -//
 -// @since 3.17.0
--type InlineValueWorkspaceClientCapabilities struct { // line 11079
+-type InlineValueWorkspaceClientCapabilities struct {
 -	// Whether the client implementation supports a refresh request sent from the
 -	// server to the client.
 -	//
@@ -54214,7 +60300,7 @@
 -// A special text edit to provide an insert and a replace operation.
 -//
 -// @since 3.16.0
--type InsertReplaceEdit struct { // line 8676
+-type InsertReplaceEdit struct {
 -	// The string to be inserted.
 -	NewText string `json:"newText"`
 -	// The range if the insert is requested
@@ -54225,38 +60311,40 @@
 -
 -// Defines whether the insert text in a completion item should be interpreted as
 -// plain text or a snippet.
--type InsertTextFormat uint32 // line 13260
+-type InsertTextFormat uint32
+-
 -// How whitespace and indentation is handled during completion
 -// item insertion.
 -//
 -// @since 3.16.0
--type InsertTextMode uint32 // line 13280
+-type InsertTextMode uint32
 -type LSPAny = interface{}
 -
 -// LSP arrays.
 -// @since 3.17.0
--type LSPArray = []interface{} // (alias) line 13779
--type LSPErrorCodes int32      // line 12783
+-type LSPArray = []interface{} // (alias) line 14194
+-type LSPErrorCodes int32
+-
 -// LSP object definition.
 -// @since 3.17.0
--type LSPObject = map[string]LSPAny // (alias) line 14111
+-type LSPObject = map[string]LSPAny // (alias) line 14526
 -// Client capabilities for the linked editing range request.
 -//
 -// @since 3.16.0
--type LinkedEditingRangeClientCapabilities struct { // line 12305
+-type LinkedEditingRangeClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
 -	// return value for the corresponding server capability as well.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
--type LinkedEditingRangeOptions struct { // line 6652
+-type LinkedEditingRangeOptions struct {
 -	WorkDoneProgressOptions
 -}
--type LinkedEditingRangeParams struct { // line 3112
+-type LinkedEditingRangeParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -}
--type LinkedEditingRangeRegistrationOptions struct { // line 3155
+-type LinkedEditingRangeRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	LinkedEditingRangeOptions
 -	StaticRegistrationOptions
@@ -54265,7 +60353,7 @@
 -// The result of a linked editing range request.
 -//
 -// @since 3.16.0
--type LinkedEditingRanges struct { // line 3128
+-type LinkedEditingRanges struct {
 -	// A list of ranges that can be edited together. The ranges must have
 -	// identical length and contain identical text content. The ranges cannot overlap.
 -	Ranges []Range `json:"ranges"`
@@ -54276,13 +60364,13 @@
 -}
 -
 -// created for Literal (Lit_NotebookDocumentChangeEvent_cells_textContent_Elem)
--type Lit_NotebookDocumentChangeEvent_cells_textContent_Elem struct { // line 7545
+-type Lit_NotebookDocumentChangeEvent_cells_textContent_Elem struct {
 -	Document VersionedTextDocumentIdentifier  `json:"document"`
 -	Changes  []TextDocumentContentChangeEvent `json:"changes"`
 -}
 -
 -// created for Literal (Lit_NotebookDocumentFilter_Item1)
--type Lit_NotebookDocumentFilter_Item1 struct { // line 14293
+-type Lit_NotebookDocumentFilter_Item1 struct {
 -	// The type of the enclosing notebook.
 -	NotebookType string `json:"notebookType,omitempty"`
 -	// A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.
@@ -54292,7 +60380,7 @@
 -}
 -
 -// created for Literal (Lit_NotebookDocumentFilter_Item2)
--type Lit_NotebookDocumentFilter_Item2 struct { // line 14326
+-type Lit_NotebookDocumentFilter_Item2 struct {
 -	// The type of the enclosing notebook.
 -	NotebookType string `json:"notebookType,omitempty"`
 -	// A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.
@@ -54302,12 +60390,12 @@
 -}
 -
 -// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem)
--type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem struct { // line 9831
+-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0_cells_Elem struct {
 -	Language string `json:"language"`
 -}
 -
 -// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1)
--type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1 struct { // line 9852
+-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1 struct {
 -	// The notebook to be synced If a string
 -	// value is provided it matches against the
 -	// notebook type. '*' matches every notebook.
@@ -54317,23 +60405,23 @@
 -}
 -
 -// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem)
--type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem struct { // line 9878
+-type Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_cells_Elem struct {
 -	Language string `json:"language"`
 -}
 -
 -// created for Literal (Lit_PrepareRenameResult_Item2)
--type Lit_PrepareRenameResult_Item2 struct { // line 13932
+-type Lit_PrepareRenameResult_Item2 struct {
 -	DefaultBehavior bool `json:"defaultBehavior"`
 -}
 -
 -// created for Literal (Lit_TextDocumentContentChangeEvent_Item1)
--type Lit_TextDocumentContentChangeEvent_Item1 struct { // line 14040
+-type Lit_TextDocumentContentChangeEvent_Item1 struct {
 -	// The new text of the whole document.
 -	Text string `json:"text"`
 -}
 -
 -// created for Literal (Lit_TextDocumentFilter_Item2)
--type Lit_TextDocumentFilter_Item2 struct { // line 14217
+-type Lit_TextDocumentFilter_Item2 struct {
 -	// A language id, like `typescript`.
 -	Language string `json:"language,omitempty"`
 -	// A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.
@@ -54344,14 +60432,14 @@
 -
 -// Represents a location inside a resource, such as a line
 -// inside a text file.
--type Location struct { // line 2083
+-type Location struct {
 -	URI   DocumentURI `json:"uri"`
 -	Range Range       `json:"range"`
 -}
 -
 -// Represents the connection of two locations. Provides additional metadata over normal {@link Location locations},
 -// including an origin range.
--type LocationLink struct { // line 6272
+-type LocationLink struct {
 -	// Span of the origin of this link.
 -	//
 -	// Used as the underlined span for mouse interaction. Defaults to the word range at
@@ -54369,13 +60457,13 @@
 -}
 -
 -// The log message parameters.
--type LogMessageParams struct { // line 4251
+-type LogMessageParams struct {
 -	// The message type. See {@link MessageType}
 -	Type MessageType `json:"type"`
 -	// The actual message.
 -	Message string `json:"message"`
 -}
--type LogTraceParams struct { // line 6159
+-type LogTraceParams struct {
 -	Message string `json:"message"`
 -	Verbose string `json:"verbose,omitempty"`
 -}
@@ -54383,7 +60471,7 @@
 -// Client capabilities specific to the used markdown parser.
 -//
 -// @since 3.16.0
--type MarkdownClientCapabilities struct { // line 12524
+-type MarkdownClientCapabilities struct {
 -	// The name of the parser.
 -	Parser string `json:"parser"`
 -	// The version of the parser.
@@ -54407,7 +60495,7 @@
 -//
 -// Note that markdown strings will be sanitized - that means html will be escaped.
 -// @deprecated use MarkupContent instead.
--type MarkedString = Or_MarkedString // (alias) line 14058
+-type MarkedString = Or_MarkedString // (alias) line 14473
 -// A `MarkupContent` literal represents a string value which content is interpreted base on its
 -// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds.
 -//
@@ -54432,7 +60520,7 @@
 -//
 -// *Please Note* that clients might sanitize the return markdown. A client could decide to
 -// remove HTML from the markdown to avoid script execution.
--type MarkupContent struct { // line 7113
+-type MarkupContent struct {
 -	// The type of the Markup
 -	Kind MarkupKind `json:"kind"`
 -	// The content itself
@@ -54444,18 +60532,19 @@
 -//
 -// Please note that `MarkupKinds` must not start with a `$`. This kinds
 -// are reserved for internal usage.
--type MarkupKind string          // line 13407
--type MessageActionItem struct { // line 4238
+-type MarkupKind string
+-type MessageActionItem struct {
 -	// A short title like 'Retry', 'Open Log' etc.
 -	Title string `json:"title"`
 -}
 -
 -// The message type
--type MessageType uint32 // line 13054
+-type MessageType uint32
+-
 -// Moniker definition to match LSIF 0.5 moniker definition.
 -//
 -// @since 3.16.0
--type Moniker struct { // line 3338
+-type Moniker struct {
 -	// The scheme of the moniker. For example tsc or .Net
 -	Scheme string `json:"scheme"`
 -	// The identifier of the moniker. The value is opaque in LSIF however
@@ -54470,7 +60559,7 @@
 -// Client capabilities specific to the moniker request.
 -//
 -// @since 3.16.0
--type MonikerClientCapabilities struct { // line 12321
+-type MonikerClientCapabilities struct {
 -	// Whether moniker supports dynamic registration. If this is set to `true`
 -	// the client supports the new `MonikerRegistrationOptions` return value
 -	// for the corresponding server capability as well.
@@ -54480,28 +60569,28 @@
 -// The moniker kind.
 -//
 -// @since 3.16.0
--type MonikerKind string      // line 13007
--type MonikerOptions struct { // line 6926
+-type MonikerKind string
+-type MonikerOptions struct {
 -	WorkDoneProgressOptions
 -}
--type MonikerParams struct { // line 3318
+-type MonikerParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type MonikerRegistrationOptions struct { // line 3378
+-type MonikerRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	MonikerOptions
 -}
 -
 -// created for Literal (Lit_MarkedString_Item1)
--type Msg_MarkedString struct { // line 14068
+-type Msg_MarkedString struct {
 -	Language string `json:"language"`
 -	Value    string `json:"value"`
 -}
 -
 -// created for Literal (Lit_NotebookDocumentFilter_Item0)
--type Msg_NotebookDocumentFilter struct { // line 14260
+-type Msg_NotebookDocumentFilter struct {
 -	// The type of the enclosing notebook.
 -	NotebookType string `json:"notebookType"`
 -	// A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.
@@ -54511,13 +60600,13 @@
 -}
 -
 -// created for Literal (Lit_PrepareRenameResult_Item1)
--type Msg_PrepareRename2Gn struct { // line 13911
+-type Msg_PrepareRename2Gn struct {
 -	Range       Range  `json:"range"`
 -	Placeholder string `json:"placeholder"`
 -}
 -
 -// created for Literal (Lit_TextDocumentContentChangeEvent_Item0)
--type Msg_TextDocumentContentChangeEvent struct { // line 14008
+-type Msg_TextDocumentContentChangeEvent struct {
 -	// The range of the document that changed.
 -	Range *Range `json:"range"`
 -	// The optional length of the range that got replaced.
@@ -54529,7 +60618,7 @@
 -}
 -
 -// created for Literal (Lit_TextDocumentFilter_Item1)
--type Msg_TextDocumentFilter struct { // line 14184
+-type Msg_TextDocumentFilter struct {
 -	// A language id, like `typescript`.
 -	Language string `json:"language,omitempty"`
 -	// A Uri {@link Uri.scheme scheme}, like `file` or `untitled`.
@@ -54539,7 +60628,7 @@
 -}
 -
 -// created for Literal (Lit__InitializeParams_clientInfo)
--type Msg_XInitializeParams_clientInfo struct { // line 7673
+-type Msg_XInitializeParams_clientInfo struct {
 -	// The name of the client as defined by the client.
 -	Name string `json:"name"`
 -	// The client's version as defined by the client.
@@ -54553,7 +60642,7 @@
 -// notebook cell or the cell's text document.
 -//
 -// @since 3.17.0
--type NotebookCell struct { // line 9598
+-type NotebookCell struct {
 -	// The cell's kind
 -	Kind NotebookCellKind `json:"kind"`
 -	// The URI of the cell's text document
@@ -54572,7 +60661,7 @@
 -// array from state S to S'.
 -//
 -// @since 3.17.0
--type NotebookCellArrayChange struct { // line 9639
+-type NotebookCellArrayChange struct {
 -	// The start oftest of the cell that changed.
 -	Start uint32 `json:"start"`
 -	// The deleted cells
@@ -54584,12 +60673,13 @@
 -// A notebook cell kind.
 -//
 -// @since 3.17.0
--type NotebookCellKind uint32 // line 13648
+-type NotebookCellKind uint32
+-
 -// A notebook cell text document filter denotes a cell text
 -// document by different properties.
 -//
 -// @since 3.17.0
--type NotebookCellTextDocumentFilter struct { // line 10113
+-type NotebookCellTextDocumentFilter struct {
 -	// A filter that matches against the notebook
 -	// containing the notebook cell. If a string
 -	// value is provided it matches against the
@@ -54605,7 +60695,7 @@
 -// A notebook document.
 -//
 -// @since 3.17.0
--type NotebookDocument struct { // line 7354
+-type NotebookDocument struct {
 -	// The notebook document's uri.
 -	URI URI `json:"uri"`
 -	// The type of the notebook.
@@ -54625,7 +60715,7 @@
 -// A change event for a notebook document.
 -//
 -// @since 3.17.0
--type NotebookDocumentChangeEvent struct { // line 7466
+-type NotebookDocumentChangeEvent struct {
 -	// The changed meta data if any.
 -	//
 -	// Note: should always be an object literal (e.g. LSPObject)
@@ -54637,7 +60727,7 @@
 -// Capabilities specific to the notebook document support.
 -//
 -// @since 3.17.0
--type NotebookDocumentClientCapabilities struct { // line 10613
+-type NotebookDocumentClientCapabilities struct {
 -	// Capabilities specific to notebook document synchronization
 -	//
 -	// @since 3.17.0
@@ -54649,11 +60739,11 @@
 -// against the notebook's URI (same as with documents)
 -//
 -// @since 3.17.0
--type NotebookDocumentFilter = Msg_NotebookDocumentFilter // (alias) line 14254
+-type NotebookDocumentFilter = Msg_NotebookDocumentFilter // (alias) line 14669
 -// A literal to identify a notebook document in the client.
 -//
 -// @since 3.17.0
--type NotebookDocumentIdentifier struct { // line 7582
+-type NotebookDocumentIdentifier struct {
 -	// The notebook document's uri.
 -	URI URI `json:"uri"`
 -}
@@ -54661,7 +60751,7 @@
 -// Notebook specific client capabilities.
 -//
 -// @since 3.17.0
--type NotebookDocumentSyncClientCapabilities struct { // line 12433
+-type NotebookDocumentSyncClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is
 -	// set to `true` the client supports the new
 -	// `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
@@ -54684,7 +60774,7 @@
 -// cell will be synced.
 -//
 -// @since 3.17.0
--type NotebookDocumentSyncOptions struct { // line 9795
+-type NotebookDocumentSyncOptions struct {
 -	// The notebooks to be synced
 -	NotebookSelector []PNotebookSelectorPNotebookDocumentSync `json:"notebookSelector"`
 -	// Whether save notification should be forwarded to
@@ -54695,13 +60785,13 @@
 -// Registration options specific to a notebook.
 -//
 -// @since 3.17.0
--type NotebookDocumentSyncRegistrationOptions struct { // line 9915
+-type NotebookDocumentSyncRegistrationOptions struct {
 -	NotebookDocumentSyncOptions
 -	StaticRegistrationOptions
 -}
 -
 -// A text document identifier to optionally denote a specific version of a text document.
--type OptionalVersionedTextDocumentIdentifier struct { // line 9343
+-type OptionalVersionedTextDocumentIdentifier struct {
 -	// The version number of this document. If a versioned text document identifier
 -	// is sent from the server to the client and the file is not open in the editor
 -	// (the server has not received an open notification before) the server can send
@@ -54712,307 +60802,322 @@
 -}
 -
 -// created for Or [FEditRangePItemDefaults Range]
--type OrFEditRangePItemDefaults struct { // line 4770
+-type OrFEditRangePItemDefaults struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [NotebookDocumentFilter string]
--type OrFNotebookPNotebookSelector struct { // line 9812
+-type OrFNotebookPNotebookSelector struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [Location PLocationMsg_workspace_symbol]
--type OrPLocation_workspace_symbol struct { // line 5521
+-type OrPLocation_workspace_symbol struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [[]string string]
--type OrPSection_workspace_didChangeConfiguration struct { // line 4164
+-type OrPSection_workspace_didChangeConfiguration struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MarkupContent string]
--type OrPTooltipPLabel struct { // line 7076
+-type OrPTooltipPLabel struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MarkupContent string]
--type OrPTooltip_textDocument_inlayHint struct { // line 3700
+-type OrPTooltip_textDocument_inlayHint struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [int32 string]
--type Or_CancelParams_id struct { // line 6185
+-type Or_CancelParams_id struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MarkupContent string]
--type Or_CompletionItem_documentation struct { // line 4583
+-type Or_CompletionItem_documentation struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [InsertReplaceEdit TextEdit]
--type Or_CompletionItem_textEdit struct { // line 4666
+-type Or_CompletionItem_textEdit struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [Location []Location]
--type Or_Definition struct { // line 13754
+-type Or_Definition struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [int32 string]
--type Or_Diagnostic_code struct { // line 8548
+-type Or_Diagnostic_code struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [RelatedFullDocumentDiagnosticReport RelatedUnchangedDocumentDiagnosticReport]
--type Or_DocumentDiagnosticReport struct { // line 13886
+-type Or_DocumentDiagnosticReport struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]
--type Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value struct { // line 3823
+-type Or_DocumentDiagnosticReportPartialResult_relatedDocuments_Value struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [NotebookCellTextDocumentFilter TextDocumentFilter]
--type Or_DocumentFilter struct { // line 14096
+-type Or_DocumentFilter struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MarkedString MarkupContent []MarkedString]
--type Or_Hover_contents struct { // line 4892
+-type Or_Hover_contents struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [[]InlayHintLabelPart string]
--type Or_InlayHint_label struct { // line 3659
+-type Or_InlayHint_label struct {
+-	Value interface{} `json:"value"`
+-}
+-
+-// created for Or [StringValue string]
+-type Or_InlineCompletionItem_insertText struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [InlineValueEvaluatableExpression InlineValueText InlineValueVariableLookup]
--type Or_InlineValue struct { // line 13864
+-type Or_InlineValue struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [Msg_MarkedString string]
--type Or_MarkedString struct { // line 14061
+-type Or_MarkedString struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [NotebookDocumentFilter string]
--type Or_NotebookCellTextDocumentFilter_notebook struct { // line 10119
+-type Or_NotebookCellTextDocumentFilter_notebook struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [NotebookDocumentFilter string]
--type Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook struct { // line 9858
+-type Or_NotebookDocumentSyncOptions_notebookSelector_Elem_Item1_notebook struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]
--type Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value struct { // line 7169
+-type Or_RelatedFullDocumentDiagnosticReport_relatedDocuments_Value struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FullDocumentDiagnosticReport UnchangedDocumentDiagnosticReport]
--type Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value struct { // line 7208
+-type Or_RelatedUnchangedDocumentDiagnosticReport_relatedDocuments_Value struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [URI WorkspaceFolder]
--type Or_RelativePattern_baseUri struct { // line 10742
+-type Or_RelativePattern_baseUri struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [CodeAction Command]
--type Or_Result_textDocument_codeAction_Item0_Elem struct { // line 1372
+-type Or_Result_textDocument_codeAction_Item0_Elem struct {
+-	Value interface{} `json:"value"`
+-}
+-
+-// created for Or [InlineCompletionList []InlineCompletionItem]
+-type Or_Result_textDocument_inlineCompletion struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FFullPRequests bool]
--type Or_SemanticTokensClientCapabilities_requests_full struct { // line 12198
+-type Or_SemanticTokensClientCapabilities_requests_full struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FRangePRequests bool]
--type Or_SemanticTokensClientCapabilities_requests_range struct { // line 12178
+-type Or_SemanticTokensClientCapabilities_requests_range struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [PFullESemanticTokensOptions bool]
--type Or_SemanticTokensOptions_full struct { // line 6580
+-type Or_SemanticTokensOptions_full struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [PRangeESemanticTokensOptions bool]
--type Or_SemanticTokensOptions_range struct { // line 6560
+-type Or_SemanticTokensOptions_range struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [CallHierarchyOptions CallHierarchyRegistrationOptions bool]
--type Or_ServerCapabilities_callHierarchyProvider struct { // line 8228
+-type Or_ServerCapabilities_callHierarchyProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [CodeActionOptions bool]
--type Or_ServerCapabilities_codeActionProvider struct { // line 8036
+-type Or_ServerCapabilities_codeActionProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DocumentColorOptions DocumentColorRegistrationOptions bool]
--type Or_ServerCapabilities_colorProvider struct { // line 8072
+-type Or_ServerCapabilities_colorProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DeclarationOptions DeclarationRegistrationOptions bool]
--type Or_ServerCapabilities_declarationProvider struct { // line 7898
+-type Or_ServerCapabilities_declarationProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DefinitionOptions bool]
--type Or_ServerCapabilities_definitionProvider struct { // line 7920
+-type Or_ServerCapabilities_definitionProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DiagnosticOptions DiagnosticRegistrationOptions]
--type Or_ServerCapabilities_diagnosticProvider struct { // line 8385
+-type Or_ServerCapabilities_diagnosticProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DocumentFormattingOptions bool]
--type Or_ServerCapabilities_documentFormattingProvider struct { // line 8112
+-type Or_ServerCapabilities_documentFormattingProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DocumentHighlightOptions bool]
--type Or_ServerCapabilities_documentHighlightProvider struct { // line 8000
+-type Or_ServerCapabilities_documentHighlightProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DocumentRangeFormattingOptions bool]
--type Or_ServerCapabilities_documentRangeFormattingProvider struct { // line 8130
+-type Or_ServerCapabilities_documentRangeFormattingProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [DocumentSymbolOptions bool]
--type Or_ServerCapabilities_documentSymbolProvider struct { // line 8018
+-type Or_ServerCapabilities_documentSymbolProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [FoldingRangeOptions FoldingRangeRegistrationOptions bool]
--type Or_ServerCapabilities_foldingRangeProvider struct { // line 8175
+-type Or_ServerCapabilities_foldingRangeProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [HoverOptions bool]
--type Or_ServerCapabilities_hoverProvider struct { // line 7871
+-type Or_ServerCapabilities_hoverProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [ImplementationOptions ImplementationRegistrationOptions bool]
--type Or_ServerCapabilities_implementationProvider struct { // line 7960
+-type Or_ServerCapabilities_implementationProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [InlayHintOptions InlayHintRegistrationOptions bool]
--type Or_ServerCapabilities_inlayHintProvider struct { // line 8362
+-type Or_ServerCapabilities_inlayHintProvider struct {
+-	Value interface{} `json:"value"`
+-}
+-
+-// created for Or [InlineCompletionOptions bool]
+-type Or_ServerCapabilities_inlineCompletionProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [InlineValueOptions InlineValueRegistrationOptions bool]
--type Or_ServerCapabilities_inlineValueProvider struct { // line 8339
+-type Or_ServerCapabilities_inlineValueProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [LinkedEditingRangeOptions LinkedEditingRangeRegistrationOptions bool]
--type Or_ServerCapabilities_linkedEditingRangeProvider struct { // line 8251
+-type Or_ServerCapabilities_linkedEditingRangeProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MonikerOptions MonikerRegistrationOptions bool]
--type Or_ServerCapabilities_monikerProvider struct { // line 8293
+-type Or_ServerCapabilities_monikerProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [NotebookDocumentSyncOptions NotebookDocumentSyncRegistrationOptions]
--type Or_ServerCapabilities_notebookDocumentSync struct { // line 7843
+-type Or_ServerCapabilities_notebookDocumentSync struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [ReferenceOptions bool]
--type Or_ServerCapabilities_referencesProvider struct { // line 7982
+-type Or_ServerCapabilities_referencesProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [RenameOptions bool]
--type Or_ServerCapabilities_renameProvider struct { // line 8157
+-type Or_ServerCapabilities_renameProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [SelectionRangeOptions SelectionRangeRegistrationOptions bool]
--type Or_ServerCapabilities_selectionRangeProvider struct { // line 8197
+-type Or_ServerCapabilities_selectionRangeProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [SemanticTokensOptions SemanticTokensRegistrationOptions]
--type Or_ServerCapabilities_semanticTokensProvider struct { // line 8274
+-type Or_ServerCapabilities_semanticTokensProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [TextDocumentSyncKind TextDocumentSyncOptions]
--type Or_ServerCapabilities_textDocumentSync struct { // line 7825
+-type Or_ServerCapabilities_textDocumentSync struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [TypeDefinitionOptions TypeDefinitionRegistrationOptions bool]
--type Or_ServerCapabilities_typeDefinitionProvider struct { // line 7938
+-type Or_ServerCapabilities_typeDefinitionProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [TypeHierarchyOptions TypeHierarchyRegistrationOptions bool]
--type Or_ServerCapabilities_typeHierarchyProvider struct { // line 8316
+-type Or_ServerCapabilities_typeHierarchyProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [WorkspaceSymbolOptions bool]
--type Or_ServerCapabilities_workspaceSymbolProvider struct { // line 8094
+-type Or_ServerCapabilities_workspaceSymbolProvider struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [MarkupContent string]
--type Or_SignatureInformation_documentation struct { // line 8842
+-type Or_SignatureInformation_documentation struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [AnnotatedTextEdit TextEdit]
--type Or_TextDocumentEdit_edits_Elem struct { // line 6693
+-type Or_TextDocumentEdit_edits_Elem struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [SaveOptions bool]
--type Or_TextDocumentSyncOptions_save struct { // line 9778
+-type Or_TextDocumentSyncOptions_save struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [WorkspaceFullDocumentDiagnosticReport WorkspaceUnchangedDocumentDiagnosticReport]
--type Or_WorkspaceDocumentDiagnosticReport struct { // line 13987
+-type Or_WorkspaceDocumentDiagnosticReport struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [CreateFile DeleteFile RenameFile TextDocumentEdit]
--type Or_WorkspaceEdit_documentChanges_Elem struct { // line 3220
+-type Or_WorkspaceEdit_documentChanges_Elem struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Or [Declaration []DeclarationLink]
--type Or_textDocument_declaration struct { // line 249
+-type Or_textDocument_declaration struct {
 -	Value interface{} `json:"value"`
 -}
 -
 -// created for Literal (Lit_NotebookDocumentChangeEvent_cells)
--type PCellsPChange struct { // line 7481
+-type PCellsPChange struct {
 -	// Changes to the cell structure to add or
 -	// remove cells.
 -	Structure *FStructurePCells `json:"structure,omitempty"`
@@ -55024,7 +61129,7 @@
 -}
 -
 -// created for Literal (Lit_WorkspaceEditClientCapabilities_changeAnnotationSupport)
--type PChangeAnnotationSupportPWorkspaceEdit struct { // line 10816
+-type PChangeAnnotationSupportPWorkspaceEdit struct {
 -	// Whether the client groups edits with equal labels into tree nodes,
 -	// for instance all edits labelled with "Changes in Strings" would
 -	// be a tree node.
@@ -55032,14 +61137,14 @@
 -}
 -
 -// created for Literal (Lit_CodeActionClientCapabilities_codeActionLiteralSupport)
--type PCodeActionLiteralSupportPCodeAction struct { // line 11736
+-type PCodeActionLiteralSupportPCodeAction struct {
 -	// The code action kind is support with the following value
 -	// set.
 -	CodeActionKind FCodeActionKindPCodeActionLiteralSupport `json:"codeActionKind"`
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionItemKind)
--type PCompletionItemKindPCompletion struct { // line 11334
+-type PCompletionItemKindPCompletion struct {
 -	// The completion item kind values the client supports. When this
 -	// property exists the client also guarantees that it will
 -	// handle values outside its set gracefully and falls back
@@ -55052,7 +61157,7 @@
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionItem)
--type PCompletionItemPCompletion struct { // line 11183
+-type PCompletionItemPCompletion struct {
 -	// Client supports snippets as insert text.
 -	//
 -	// A snippet can define tab stops and placeholders with `$1`, `$2`
@@ -55101,7 +61206,7 @@
 -}
 -
 -// created for Literal (Lit_CompletionOptions_completionItem)
--type PCompletionItemPCompletionProvider struct { // line 8747
+-type PCompletionItemPCompletionProvider struct {
 -	// The server has support for completion item label
 -	// details (see also `CompletionItemLabelDetails`) when
 -	// receiving a completion item in a resolve call.
@@ -55111,7 +61216,7 @@
 -}
 -
 -// created for Literal (Lit_CompletionClientCapabilities_completionList)
--type PCompletionListPCompletion struct { // line 11376
+-type PCompletionListPCompletion struct {
 -	// The client supports the following itemDefaults on
 -	// a completion list.
 -	//
@@ -55124,7 +61229,7 @@
 -}
 -
 -// created for Literal (Lit_CodeAction_disabled)
--type PDisabledMsg_textDocument_codeAction struct { // line 5427
+-type PDisabledMsg_textDocument_codeAction struct {
 -	// Human readable description of why the code action is currently disabled.
 -	//
 -	// This is displayed in the code actions UI.
@@ -55132,7 +61237,7 @@
 -}
 -
 -// created for Literal (Lit_FoldingRangeClientCapabilities_foldingRangeKind)
--type PFoldingRangeKindPFoldingRange struct { // line 12011
+-type PFoldingRangeKindPFoldingRange struct {
 -	// The folding range kind values the client supports. When this
 -	// property exists the client also guarantees that it will
 -	// handle values outside its set gracefully and falls back
@@ -55141,7 +61246,7 @@
 -}
 -
 -// created for Literal (Lit_FoldingRangeClientCapabilities_foldingRange)
--type PFoldingRangePFoldingRange struct { // line 12036
+-type PFoldingRangePFoldingRange struct {
 -	// If set, the client signals that it supports setting collapsedText on
 -	// folding ranges to display custom labels instead of the default text.
 -	//
@@ -55150,13 +61255,13 @@
 -}
 -
 -// created for Literal (Lit_SemanticTokensOptions_full_Item1)
--type PFullESemanticTokensOptions struct { // line 6587
+-type PFullESemanticTokensOptions struct {
 -	// The server supports deltas for full documents.
 -	Delta bool `json:"delta"`
 -}
 -
 -// created for Literal (Lit_CompletionList_itemDefaults)
--type PItemDefaultsMsg_textDocument_completion struct { // line 4751
+-type PItemDefaultsMsg_textDocument_completion struct {
 -	// A default commit character set.
 -	//
 -	// @since 3.17.0
@@ -55180,12 +61285,12 @@
 -}
 -
 -// created for Literal (Lit_WorkspaceSymbol_location_Item1)
--type PLocationMsg_workspace_symbol struct { // line 5528
+-type PLocationMsg_workspace_symbol struct {
 -	URI DocumentURI `json:"uri"`
 -}
 -
 -// created for Literal (Lit_ShowMessageRequestClientCapabilities_messageActionItem)
--type PMessageActionItemPShowMessage struct { // line 12464
+-type PMessageActionItemPShowMessage struct {
 -	// Whether the client supports additional attributes which
 -	// are preserved and send back to the server in the
 -	// request's response.
@@ -55193,7 +61298,7 @@
 -}
 -
 -// created for Literal (Lit_NotebookDocumentSyncOptions_notebookSelector_Elem_Item0)
--type PNotebookSelectorPNotebookDocumentSync struct { // line 9806
+-type PNotebookSelectorPNotebookDocumentSync struct {
 -	// The notebook to be synced If a string
 -	// value is provided it matches against the
 -	// notebook type. '*' matches every notebook.
@@ -55203,11 +61308,11 @@
 -}
 -
 -// created for Literal (Lit_SemanticTokensOptions_range_Item1)
--type PRangeESemanticTokensOptions struct { // line 6567
+-type PRangeESemanticTokensOptions struct {
 -}
 -
 -// created for Literal (Lit_SemanticTokensClientCapabilities_requests)
--type PRequestsPSemanticTokens struct { // line 12172
+-type PRequestsPSemanticTokens struct {
 -	// The client will send the `textDocument/semanticTokens/range` request if
 -	// the server provides a corresponding handler.
 -	Range Or_SemanticTokensClientCapabilities_requests_range `json:"range"`
@@ -55217,26 +61322,26 @@
 -}
 -
 -// created for Literal (Lit_CodeActionClientCapabilities_resolveSupport)
--type PResolveSupportPCodeAction struct { // line 11801
+-type PResolveSupportPCodeAction struct {
 -	// The properties that a client can resolve lazily.
 -	Properties []string `json:"properties"`
 -}
 -
 -// created for Literal (Lit_InlayHintClientCapabilities_resolveSupport)
--type PResolveSupportPInlayHint struct { // line 12384
+-type PResolveSupportPInlayHint struct {
 -	// The properties that a client can resolve lazily.
 -	Properties []string `json:"properties"`
 -}
 -
 -// created for Literal (Lit_WorkspaceSymbolClientCapabilities_resolveSupport)
--type PResolveSupportPSymbol struct { // line 10938
+-type PResolveSupportPSymbol struct {
 -	// The properties that a client can resolve lazily. Usually
 -	// `location.range`
 -	Properties []string `json:"properties"`
 -}
 -
 -// created for Literal (Lit_InitializeResult_serverInfo)
--type PServerInfoMsg_initialize struct { // line 4096
+-type PServerInfoMsg_initialize struct {
 -	// The name of the server as defined by the server.
 -	Name string `json:"name"`
 -	// The server's version as defined by the server.
@@ -55244,7 +61349,7 @@
 -}
 -
 -// created for Literal (Lit_SignatureHelpClientCapabilities_signatureInformation)
--type PSignatureInformationPSignatureHelp struct { // line 11443
+-type PSignatureInformationPSignatureHelp struct {
 -	// Client supports the following content formats for the documentation
 -	// property. The order describes the preferred format of the client.
 -	DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"`
@@ -55258,7 +61363,7 @@
 -}
 -
 -// created for Literal (Lit_GeneralClientCapabilities_staleRequestSupport)
--type PStaleRequestSupportPGeneral struct { // line 10670
+-type PStaleRequestSupportPGeneral struct {
 -	// The client will actively cancel the request.
 -	Cancel bool `json:"cancel"`
 -	// The list of requests for which the client
@@ -55268,7 +61373,7 @@
 -}
 -
 -// created for Literal (Lit_DocumentSymbolClientCapabilities_symbolKind)
--type PSymbolKindPDocumentSymbol struct { // line 11654
+-type PSymbolKindPDocumentSymbol struct {
 -	// The symbol kind values the client supports. When this
 -	// property exists the client also guarantees that it will
 -	// handle values outside its set gracefully and falls back
@@ -55281,7 +61386,7 @@
 -}
 -
 -// created for Literal (Lit_WorkspaceSymbolClientCapabilities_symbolKind)
--type PSymbolKindPSymbol struct { // line 10890
+-type PSymbolKindPSymbol struct {
 -	// The symbol kind values the client supports. When this
 -	// property exists the client also guarantees that it will
 -	// handle values outside its set gracefully and falls back
@@ -55294,35 +61399,35 @@
 -}
 -
 -// created for Literal (Lit_DocumentSymbolClientCapabilities_tagSupport)
--type PTagSupportPDocumentSymbol struct { // line 11687
+-type PTagSupportPDocumentSymbol struct {
 -	// The tags supported by the client.
 -	ValueSet []SymbolTag `json:"valueSet"`
 -}
 -
 -// created for Literal (Lit_PublishDiagnosticsClientCapabilities_tagSupport)
--type PTagSupportPPublishDiagnostics struct { // line 12087
+-type PTagSupportPPublishDiagnostics struct {
 -	// The tags supported by the client.
 -	ValueSet []DiagnosticTag `json:"valueSet"`
 -}
 -
 -// created for Literal (Lit_WorkspaceSymbolClientCapabilities_tagSupport)
--type PTagSupportPSymbol struct { // line 10914
+-type PTagSupportPSymbol struct {
 -	// The tags supported by the client.
 -	ValueSet []SymbolTag `json:"valueSet"`
 -}
 -
 -// The parameters of a configuration request.
--type ParamConfiguration struct { // line 2199
+-type ParamConfiguration struct {
 -	Items []ConfigurationItem `json:"items"`
 -}
--type ParamInitialize struct { // line 4068
+-type ParamInitialize struct {
 -	XInitializeParams
 -	WorkspaceFoldersInitializeParams
 -}
 -
 -// Represents a parameter of a callable-signature. A parameter can
 -// have a label and a doc-comment.
--type ParameterInformation struct { // line 10063
+-type ParameterInformation struct {
 -	// The label of this parameter information.
 -	//
 -	// Either a string or an inclusive start and exclusive end offsets within its containing
@@ -55336,7 +61441,7 @@
 -	// in the UI but can be omitted.
 -	Documentation string `json:"documentation,omitempty"`
 -}
--type PartialResultParams struct { // line 6258
+-type PartialResultParams struct {
 -	// An optional token that a server can use to report partial results (e.g. streaming) to
 -	// the client.
 -	PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"`
@@ -55352,7 +61457,7 @@
 -//   - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
 -//
 -// @since 3.17.0
--type Pattern = string // (alias) line 14363
+-type Pattern = string // (alias) line 14778
 -// Position in a text document expressed as zero-based line and character
 -// offset. Prior to 3.17 the offsets were always based on a UTF-16 string
 -// representation. So a string of the form `a𐐀b` the character offset of the
@@ -55380,7 +61485,7 @@
 -// that denotes `\r|\n` or `\n|` where `|` represents the character offset.
 -//
 -// @since 3.17.0 - support for negotiated position encoding.
--type Position struct { // line 6501
+-type Position struct {
 -	// Line position in a document (zero-based).
 -	//
 -	// If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document.
@@ -55399,18 +61504,19 @@
 -// A set of predefined position encoding kinds.
 -//
 -// @since 3.17.0
--type PositionEncodingKind string             // line 13427
+-type PositionEncodingKind string
 -type PrepareRename2Gn = Msg_PrepareRename2Gn // (alias) line 13927
--type PrepareRenameParams struct {            // line 5925
+-type PrepareRenameParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -}
 -type PrepareRenameResult = Msg_PrepareRename2Gn // (alias) line 13927
--type PrepareSupportDefaultBehavior uint32       // line 13722
+-type PrepareSupportDefaultBehavior uint32
+-
 -// A previous result id in a workspace pull request.
 -//
 -// @since 3.17.0
--type PreviousResultID struct { // line 7331
+-type PreviousResultID struct {
 -	// The URI for which the client knowns a
 -	// result id.
 -	URI DocumentURI `json:"uri"`
@@ -55421,22 +61527,22 @@
 -// A previous result id in a workspace pull request.
 -//
 -// @since 3.17.0
--type PreviousResultId struct { // line 7331
+-type PreviousResultId struct {
 -	// The URI for which the client knowns a
 -	// result id.
 -	URI DocumentURI `json:"uri"`
 -	// The value of the previous result id.
 -	Value string `json:"value"`
 -}
--type ProgressParams struct { // line 6201
+-type ProgressParams struct {
 -	// The progress token provided by the client or server.
 -	Token ProgressToken `json:"token"`
 -	// The progress data.
 -	Value interface{} `json:"value"`
 -}
--type ProgressToken = interface{} // (alias) line 13960
+-type ProgressToken = interface{} // (alias) line 14375
 -// The publish diagnostic client capabilities.
--type PublishDiagnosticsClientCapabilities struct { // line 12072
+-type PublishDiagnosticsClientCapabilities struct {
 -	// Whether the clients accepts diagnostics with related information.
 -	RelatedInformation bool `json:"relatedInformation,omitempty"`
 -	// Client supports the tag property to provide meta data about a diagnostic.
@@ -55462,7 +61568,7 @@
 -}
 -
 -// The publish diagnostic notification's parameters.
--type PublishDiagnosticsParams struct { // line 4462
+-type PublishDiagnosticsParams struct {
 -	// The URI for which diagnostic information is reported.
 -	URI DocumentURI `json:"uri"`
 -	// Optional the version number of the document the diagnostics are published for.
@@ -55486,7 +61592,7 @@
 -//	}
 -//
 -// ```
--type Range struct { // line 6311
+-type Range struct {
 -	// The range's start position.
 -	Start Position `json:"start"`
 -	// The range's end position.
@@ -55494,25 +61600,25 @@
 -}
 -
 -// Client Capabilities for a {@link ReferencesRequest}.
--type ReferenceClientCapabilities struct { // line 11609
+-type ReferenceClientCapabilities struct {
 -	// Whether references supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
 -
 -// Value-object that contains additional information when
 -// requesting references.
--type ReferenceContext struct { // line 8930
+-type ReferenceContext struct {
 -	// Include the declaration of the current symbol.
 -	IncludeDeclaration bool `json:"includeDeclaration"`
 -}
 -
 -// Reference options.
--type ReferenceOptions struct { // line 8944
+-type ReferenceOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// Parameters for a {@link ReferencesRequest}.
--type ReferenceParams struct { // line 5054
+-type ReferenceParams struct {
 -	Context ReferenceContext `json:"context"`
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
@@ -55520,13 +61626,13 @@
 -}
 -
 -// Registration options for a {@link ReferencesRequest}.
--type ReferenceRegistrationOptions struct { // line 5083
+-type ReferenceRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	ReferenceOptions
 -}
 -
--// General parameters to to register for an notification or to register a provider.
--type Registration struct { // line 7597
+-// General parameters to register for a notification or to register a provider.
+-type Registration struct {
 -	// The id used to register the request. The id can be used to deregister
 -	// the request again.
 -	ID string `json:"id"`
@@ -55535,14 +61641,14 @@
 -	// Options necessary for the registration.
 -	RegisterOptions interface{} `json:"registerOptions,omitempty"`
 -}
--type RegistrationParams struct { // line 4038
+-type RegistrationParams struct {
 -	Registrations []Registration `json:"registrations"`
 -}
 -
 -// Client capabilities specific to regular expressions.
 -//
 -// @since 3.16.0
--type RegularExpressionsClientCapabilities struct { // line 12500
+-type RegularExpressionsClientCapabilities struct {
 -	// The engine's name.
 -	Engine string `json:"engine"`
 -	// The engine's version.
@@ -55552,7 +61658,7 @@
 -// A full diagnostic report with a set of related documents.
 -//
 -// @since 3.17.0
--type RelatedFullDocumentDiagnosticReport struct { // line 7157
+-type RelatedFullDocumentDiagnosticReport struct {
 -	// Diagnostics of related documents. This information is useful
 -	// in programming languages where code in a file A can generate
 -	// diagnostics in a file B which A depends on. An example of
@@ -55567,7 +61673,7 @@
 -// An unchanged diagnostic report with a set of related documents.
 -//
 -// @since 3.17.0
--type RelatedUnchangedDocumentDiagnosticReport struct { // line 7196
+-type RelatedUnchangedDocumentDiagnosticReport struct {
 -	// Diagnostics of related documents. This information is useful
 -	// in programming languages where code in a file A can generate
 -	// diagnostics in a file B which A depends on. An example of
@@ -55584,14 +61690,14 @@
 -// folder root, but it can be another absolute URI as well.
 -//
 -// @since 3.17.0
--type RelativePattern struct { // line 10736
+-type RelativePattern struct {
 -	// A workspace folder or a base URI to which this pattern will be matched
 -	// against relatively.
 -	BaseURI Or_RelativePattern_baseUri `json:"baseUri"`
 -	// The actual glob pattern;
 -	Pattern Pattern `json:"pattern"`
 -}
--type RenameClientCapabilities struct { // line 11934
+-type RenameClientCapabilities struct {
 -	// Whether rename supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Client supports testing for validity of rename operations
@@ -55617,7 +61723,7 @@
 -}
 -
 -// Rename file operation
--type RenameFile struct { // line 6749
+-type RenameFile struct {
 -	// A rename
 -	Kind string `json:"kind"`
 -	// The old (existing) location.
@@ -55630,7 +61736,7 @@
 -}
 -
 -// Rename file options
--type RenameFileOptions struct { // line 9441
+-type RenameFileOptions struct {
 -	// Overwrite target if existing. Overwrite wins over `ignoreIfExists`
 -	Overwrite bool `json:"overwrite,omitempty"`
 -	// Ignores if target exists.
@@ -55641,14 +61747,14 @@
 -// files.
 -//
 -// @since 3.16.0
--type RenameFilesParams struct { // line 3282
+-type RenameFilesParams struct {
 -	// An array of all files/folders renamed in this operation. When a folder is renamed, only
 -	// the folder will be included, and not its children.
 -	Files []FileRename `json:"files"`
 -}
 -
 -// Provider options for a {@link RenameRequest}.
--type RenameOptions struct { // line 9269
+-type RenameOptions struct {
 -	// Renames should be checked and tested before being executed.
 -	//
 -	// @since version 3.12.0
@@ -55657,7 +61763,7 @@
 -}
 -
 -// The parameters of a {@link RenameRequest}.
--type RenameParams struct { // line 5874
+-type RenameParams struct {
 -	// The document to rename.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The position at which this request was sent.
@@ -55670,13 +61776,13 @@
 -}
 -
 -// Registration options for a {@link RenameRequest}.
--type RenameRegistrationOptions struct { // line 5910
+-type RenameRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	RenameOptions
 -}
 -
 -// A generic resource operation.
--type ResourceOperation struct { // line 9393
+-type ResourceOperation struct {
 -	// The resource operation kind.
 -	Kind string `json:"kind"`
 -	// An optional annotation identifier describing the operation.
@@ -55684,33 +61790,45 @@
 -	// @since 3.16.0
 -	AnnotationID *ChangeAnnotationIdentifier `json:"annotationId,omitempty"`
 -}
--type ResourceOperationKind string // line 13669
+-type ResourceOperationKind string
+-
 -// Save options.
--type SaveOptions struct { // line 8465
+-type SaveOptions struct {
 -	// The client is supposed to include the content on save.
 -	IncludeText bool `json:"includeText,omitempty"`
 -}
 -
+-// Describes the currently selected completion item.
+-//
+-// @since 3.18.0
+-// @proposed
+-type SelectedCompletionInfo struct {
+-	// The range that will be replaced if this completion item is accepted.
+-	Range Range `json:"range"`
+-	// The text the range will be replaced with if this completion is accepted.
+-	Text string `json:"text"`
+-}
+-
 -// A selection range represents a part of a selection hierarchy. A selection range
 -// may have a parent selection range that contains it.
--type SelectionRange struct { // line 2569
+-type SelectionRange struct {
 -	// The {@link Range range} of this selection range.
 -	Range Range `json:"range"`
 -	// The parent selection range containing this range. Therefore `parent.range` must contain `this.range`.
 -	Parent *SelectionRange `json:"parent,omitempty"`
 -}
--type SelectionRangeClientCapabilities struct { // line 12058
+-type SelectionRangeClientCapabilities struct {
 -	// Whether implementation supports dynamic registration for selection range providers. If this is set to `true`
 -	// the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server
 -	// capability as well.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -}
--type SelectionRangeOptions struct { // line 6524
+-type SelectionRangeOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// A parameter literal used in selection range requests.
--type SelectionRangeParams struct { // line 2534
+-type SelectionRangeParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The positions inside the text document.
@@ -55718,7 +61836,7 @@
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type SelectionRangeRegistrationOptions struct { // line 2592
+-type SelectionRangeRegistrationOptions struct {
 -	SelectionRangeOptions
 -	TextDocumentRegistrationOptions
 -	StaticRegistrationOptions
@@ -55729,15 +61847,17 @@
 -// corresponding client capabilities.
 -//
 -// @since 3.16.0
--type SemanticTokenModifiers string // line 12670
+-type SemanticTokenModifiers string
+-
 -// A set of predefined token types. This set is not fixed
 -// an clients can specify additional token types via the
 -// corresponding client capabilities.
 -//
 -// @since 3.16.0
--type SemanticTokenTypes string // line 12563
+-type SemanticTokenTypes string
+-
 -// @since 3.16.0
--type SemanticTokens struct { // line 2880
+-type SemanticTokens struct {
 -	// An optional result id. If provided and clients support delta updating
 -	// the client will include the result id in the next semantic token request.
 -	// A server can then instead of computing all semantic tokens again simply
@@ -55748,7 +61868,7 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensClientCapabilities struct { // line 12157
+-type SemanticTokensClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
 -	// return value for the corresponding server capability as well.
@@ -55793,14 +61913,14 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensDelta struct { // line 2979
+-type SemanticTokensDelta struct {
 -	ResultID string `json:"resultId,omitempty"`
 -	// The semantic token edits to transform a previous result into a new result.
 -	Edits []SemanticTokensEdit `json:"edits"`
 -}
 -
 -// @since 3.16.0
--type SemanticTokensDeltaParams struct { // line 2946
+-type SemanticTokensDeltaParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The result id of a previous response. The result Id can either point to a full response
@@ -55811,12 +61931,12 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensDeltaPartialResult struct { // line 3005
+-type SemanticTokensDeltaPartialResult struct {
 -	Edits []SemanticTokensEdit `json:"edits"`
 -}
 -
 -// @since 3.16.0
--type SemanticTokensEdit struct { // line 6617
+-type SemanticTokensEdit struct {
 -	// The start offset of the edit.
 -	Start uint32 `json:"start"`
 -	// The count of elements to remove.
@@ -55826,7 +61946,7 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensLegend struct { // line 9314
+-type SemanticTokensLegend struct {
 -	// The token types a server uses.
 -	TokenTypes []string `json:"tokenTypes"`
 -	// The token modifiers a server uses.
@@ -55834,7 +61954,7 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensOptions struct { // line 6546
+-type SemanticTokensOptions struct {
 -	// The legend used by the server
 -	Legend SemanticTokensLegend `json:"legend"`
 -	// Server supports providing semantic tokens for a specific range
@@ -55846,7 +61966,7 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensParams struct { // line 2855
+-type SemanticTokensParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	WorkDoneProgressParams
@@ -55854,12 +61974,12 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensPartialResult struct { // line 2907
+-type SemanticTokensPartialResult struct {
 -	Data []uint32 `json:"data"`
 -}
 -
 -// @since 3.16.0
--type SemanticTokensRangeParams struct { // line 3022
+-type SemanticTokensRangeParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The range the semantic tokens are requested for.
@@ -55869,14 +61989,14 @@
 -}
 -
 -// @since 3.16.0
--type SemanticTokensRegistrationOptions struct { // line 2924
+-type SemanticTokensRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	SemanticTokensOptions
 -	StaticRegistrationOptions
 -}
 -
 -// @since 3.16.0
--type SemanticTokensWorkspaceClientCapabilities struct { // line 10977
+-type SemanticTokensWorkspaceClientCapabilities struct {
 -	// Whether the client implementation supports a refresh request sent from
 -	// the server to the client.
 -	//
@@ -55889,7 +62009,7 @@
 -
 -// Defines the capabilities provided by a language
 -// server.
--type ServerCapabilities struct { // line 7809
+-type ServerCapabilities struct {
 -	// The position encoding the server picked from the encodings offered
 -	// by the client via the client capability `general.positionEncodings`.
 -	//
@@ -55988,32 +62108,37 @@
 -	//
 -	// @since 3.17.0
 -	DiagnosticProvider *Or_ServerCapabilities_diagnosticProvider `json:"diagnosticProvider,omitempty"`
+-	// Inline completion options used during static registration.
+-	//
+-	// @since 3.18.0
+-	// @proposed
+-	InlineCompletionProvider *Or_ServerCapabilities_inlineCompletionProvider `json:"inlineCompletionProvider,omitempty"`
 -	// Workspace specific server capabilities.
 -	Workspace *Workspace6Gn `json:"workspace,omitempty"`
 -	// Experimental server capabilities.
 -	Experimental interface{} `json:"experimental,omitempty"`
 -}
--type SetTraceParams struct { // line 6147
+-type SetTraceParams struct {
 -	Value TraceValues `json:"value"`
 -}
 -
 -// Client capabilities for the showDocument request.
 -//
 -// @since 3.16.0
--type ShowDocumentClientCapabilities struct { // line 12485
+-type ShowDocumentClientCapabilities struct {
 -	// The client has support for the showDocument
 -	// request.
 -	Support bool `json:"support"`
 -}
 -
--// Params to show a document.
+-// Params to show a resource in the UI.
 -//
 -// @since 3.16.0
--type ShowDocumentParams struct { // line 3055
--	// The document uri to show.
+-type ShowDocumentParams struct {
+-	// The uri to show.
 -	URI URI `json:"uri"`
 -	// Indicates to show the resource in an external program.
--	// To show for example `https://code.visualstudio.com/`
+-	// To show, for example, `https://code.visualstudio.com/`
 -	// in the default WEB browser set `external` to `true`.
 -	External bool `json:"external,omitempty"`
 -	// An optional property to indicate whether the editor
@@ -56031,13 +62156,13 @@
 -// The result of a showDocument request.
 -//
 -// @since 3.16.0
--type ShowDocumentResult struct { // line 3097
+-type ShowDocumentResult struct {
 -	// A boolean indicating if the show was successful.
 -	Success bool `json:"success"`
 -}
 -
 -// The parameters of a notification message.
--type ShowMessageParams struct { // line 4183
+-type ShowMessageParams struct {
 -	// The message type. See {@link MessageType}
 -	Type MessageType `json:"type"`
 -	// The actual message.
@@ -56045,11 +62170,11 @@
 -}
 -
 -// Show message request client capabilities
--type ShowMessageRequestClientCapabilities struct { // line 12458
+-type ShowMessageRequestClientCapabilities struct {
 -	// Capabilities specific to the `MessageActionItem` type.
 -	MessageActionItem *PMessageActionItemPShowMessage `json:"messageActionItem,omitempty"`
 -}
--type ShowMessageRequestParams struct { // line 4205
+-type ShowMessageRequestParams struct {
 -	// The message type. See {@link MessageType}
 -	Type MessageType `json:"type"`
 -	// The actual message.
@@ -56061,7 +62186,7 @@
 -// Signature help represents the signature of something
 -// callable. There can be multiple signature but only one
 -// active and only one active parameter.
--type SignatureHelp struct { // line 4968
+-type SignatureHelp struct {
 -	// One or more signatures.
 -	Signatures []SignatureInformation `json:"signatures"`
 -	// The active signature. If omitted or the value lies outside the
@@ -56085,7 +62210,7 @@
 -}
 -
 -// Client Capabilities for a {@link SignatureHelpRequest}.
--type SignatureHelpClientCapabilities struct { // line 11428
+-type SignatureHelpClientCapabilities struct {
 -	// Whether signature help supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client supports the following `SignatureInformation`
@@ -56103,7 +62228,7 @@
 -// Additional information about the context in which a signature help request was triggered.
 -//
 -// @since 3.15.0
--type SignatureHelpContext struct { // line 8787
+-type SignatureHelpContext struct {
 -	// Action that caused signature help to be triggered.
 -	TriggerKind SignatureHelpTriggerKind `json:"triggerKind"`
 -	// Character that caused signature help to be triggered.
@@ -56123,7 +62248,7 @@
 -}
 -
 -// Server Capabilities for a {@link SignatureHelpRequest}.
--type SignatureHelpOptions struct { // line 8882
+-type SignatureHelpOptions struct {
 -	// List of characters that trigger signature help automatically.
 -	TriggerCharacters []string `json:"triggerCharacters,omitempty"`
 -	// List of characters that re-trigger signature help.
@@ -56137,7 +62262,7 @@
 -}
 -
 -// Parameters for a {@link SignatureHelpRequest}.
--type SignatureHelpParams struct { // line 4940
+-type SignatureHelpParams struct {
 -	// The signature help context. This is only available if the client specifies
 -	// to send this using the client capability `textDocument.signatureHelp.contextSupport === true`
 -	//
@@ -56148,7 +62273,7 @@
 -}
 -
 -// Registration options for a {@link SignatureHelpRequest}.
--type SignatureHelpRegistrationOptions struct { // line 5003
+-type SignatureHelpRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	SignatureHelpOptions
 -}
@@ -56156,11 +62281,12 @@
 -// How a signature help was triggered.
 -//
 -// @since 3.15.0
--type SignatureHelpTriggerKind uint32 // line 13580
+-type SignatureHelpTriggerKind uint32
+-
 -// Represents the signature of something callable. A signature
 -// can have a label, like a function-name, a doc-comment, and
 -// a set of parameters.
--type SignatureInformation struct { // line 8828
+-type SignatureInformation struct {
 -	// The label of this signature. Will be shown in
 -	// the UI.
 -	Label string `json:"label"`
@@ -56179,15 +62305,32 @@
 -
 -// Static registration options to be returned in the initialize
 -// request.
--type StaticRegistrationOptions struct { // line 6343
+-type StaticRegistrationOptions struct {
 -	// The id used to register the request. The id can be used to deregister
 -	// the request again. See also Registration#id.
 -	ID string `json:"id,omitempty"`
 -}
 -
+-// A string value used as a snippet is a template which allows to insert text
+-// and to control the editor cursor when insertion happens.
+-//
+-// A snippet can define tab stops and placeholders with `$1`, `$2`
+-// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+-// the end of the snippet. Variables are defined with `$name` and
+-// `${name:default value}`.
+-//
+-// @since 3.18.0
+-// @proposed
+-type StringValue struct {
+-	// The kind of string value.
+-	Kind string `json:"kind"`
+-	// The snippet string.
+-	Value string `json:"value"`
+-}
+-
 -// Represents information about programming constructs like variables, classes,
 -// interfaces etc.
--type SymbolInformation struct { // line 5181
+-type SymbolInformation struct {
 -	// extends BaseSymbolInformation
 -	// Indicates if this symbol is deprecated.
 -	//
@@ -56219,20 +62362,22 @@
 -}
 -
 -// A symbol kind.
--type SymbolKind uint32 // line 12841
+-type SymbolKind uint32
+-
 -// Symbol tags are extra annotations that tweak the rendering of a symbol.
 -//
 -// @since 3.16
--type SymbolTag uint32 // line 12955
+-type SymbolTag uint32
+-
 -// Describe options to be used when registered for text document change events.
--type TextDocumentChangeRegistrationOptions struct { // line 4312
+-type TextDocumentChangeRegistrationOptions struct {
 -	// How documents are synced to the server.
 -	SyncKind TextDocumentSyncKind `json:"syncKind"`
 -	TextDocumentRegistrationOptions
 -}
 -
 -// Text document specific client capabilities.
--type TextDocumentClientCapabilities struct { // line 10323
+-type TextDocumentClientCapabilities struct {
 -	// Defines which synchronization capabilities the client supports.
 -	Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"`
 -	// Capabilities specific to the `textDocument/completion` request.
@@ -56322,16 +62467,21 @@
 -	//
 -	// @since 3.17.0
 -	Diagnostic *DiagnosticClientCapabilities `json:"diagnostic,omitempty"`
+-	// Client capabilities specific to inline completions.
+-	//
+-	// @since 3.18.0
+-	// @proposed
+-	InlineCompletion *InlineCompletionClientCapabilities `json:"inlineCompletion,omitempty"`
 -}
 -
 -// An event describing a change to a text document. If only a text is provided
 -// it is considered to be the full content of the document.
--type TextDocumentContentChangeEvent = Msg_TextDocumentContentChangeEvent // (alias) line 14002
+-type TextDocumentContentChangeEvent = Msg_TextDocumentContentChangeEvent // (alias) line 14417
 -// Describes textual changes on a text document. A TextDocumentEdit describes all changes
 -// on a document version Si and after they are applied move the document to version Si+1.
 -// So the creator of a TextDocumentEdit doesn't need to sort the array of edits or do any
 -// kind of ordering. However the edits must be non overlapping.
--type TextDocumentEdit struct { // line 6677
+-type TextDocumentEdit struct {
 -	// The text document to change.
 -	TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"`
 -	// The edits to be applied.
@@ -56358,16 +62508,16 @@
 -// @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }`
 -//
 -// @since 3.17.0
--type TextDocumentFilter = Msg_TextDocumentFilter // (alias) line 14145
+-type TextDocumentFilter = Msg_TextDocumentFilter // (alias) line 14560
 -// A literal to identify a text document in the client.
--type TextDocumentIdentifier struct { // line 6419
+-type TextDocumentIdentifier struct {
 -	// The text document's uri.
 -	URI DocumentURI `json:"uri"`
 -}
 -
 -// An item to transfer a text document from the client to the
 -// server.
--type TextDocumentItem struct { // line 7405
+-type TextDocumentItem struct {
 -	// The text document's uri.
 -	URI DocumentURI `json:"uri"`
 -	// The text document's language identifier.
@@ -56381,7 +62531,7 @@
 -
 -// A parameter literal used in requests to pass a text document and a position inside that
 -// document.
--type TextDocumentPositionParams struct { // line 6222
+-type TextDocumentPositionParams struct {
 -	// The text document.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The position inside the text document.
@@ -56389,20 +62539,21 @@
 -}
 -
 -// General text document registration options.
--type TextDocumentRegistrationOptions struct { // line 2368
+-type TextDocumentRegistrationOptions struct {
 -	// A document selector to identify the scope of the registration. If set to null
 -	// the document selector provided on the client side will be used.
 -	DocumentSelector DocumentSelector `json:"documentSelector"`
 -}
 -
 -// Represents reasons why a text document is saved.
--type TextDocumentSaveReason uint32 // line 13109
+-type TextDocumentSaveReason uint32
+-
 -// Save registration options.
--type TextDocumentSaveRegistrationOptions struct { // line 4369
+-type TextDocumentSaveRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	SaveOptions
 -}
--type TextDocumentSyncClientCapabilities struct { // line 11127
+-type TextDocumentSyncClientCapabilities struct {
 -	// Whether text document synchronization supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// The client supports sending will save notifications.
@@ -56417,8 +62568,8 @@
 -
 -// Defines how the host (editor) should sync
 -// document changes to the language server.
--type TextDocumentSyncKind uint32      // line 13084
--type TextDocumentSyncOptions struct { // line 9736
+-type TextDocumentSyncKind uint32
+-type TextDocumentSyncOptions struct {
 -	// Open and close notifications are sent to the server. If omitted open close notification should not
 -	// be sent.
 -	OpenClose bool `json:"openClose,omitempty"`
@@ -56437,7 +62588,7 @@
 -}
 -
 -// A text edit applicable to a text document.
--type TextEdit struct { // line 4406
+-type TextEdit struct {
 -	// The range of the text document to be manipulated. To insert
 -	// text into a document create a range where start === end.
 -	Range Range `json:"range"`
@@ -56445,10 +62596,11 @@
 -	// empty string.
 -	NewText string `json:"newText"`
 -}
--type TokenFormat string // line 13736
--type TraceValues string // line 13383
+-type TokenFormat string
+-type TraceValues string
+-
 -// Since 3.6.0
--type TypeDefinitionClientCapabilities struct { // line 11559
+-type TypeDefinitionClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `TypeDefinitionRegistrationOptions` return value
 -	// for the corresponding server capability as well.
@@ -56458,22 +62610,22 @@
 -	// Since 3.14.0
 -	LinkSupport bool `json:"linkSupport,omitempty"`
 -}
--type TypeDefinitionOptions struct { // line 6358
+-type TypeDefinitionOptions struct {
 -	WorkDoneProgressOptions
 -}
--type TypeDefinitionParams struct { // line 2123
+-type TypeDefinitionParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
--type TypeDefinitionRegistrationOptions struct { // line 2143
+-type TypeDefinitionRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	TypeDefinitionOptions
 -	StaticRegistrationOptions
 -}
 -
 -// @since 3.17.0
--type TypeHierarchyClientCapabilities struct { // line 12337
+-type TypeHierarchyClientCapabilities struct {
 -	// Whether implementation supports dynamic registration. If this is set to `true`
 -	// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
 -	// return value for the corresponding server capability as well.
@@ -56481,7 +62633,7 @@
 -}
 -
 -// @since 3.17.0
--type TypeHierarchyItem struct { // line 3410
+-type TypeHierarchyItem struct {
 -	// The name of this item.
 -	Name string `json:"name"`
 -	// The kind of this item.
@@ -56509,14 +62661,14 @@
 -// Type hierarchy options used during static registration.
 -//
 -// @since 3.17.0
--type TypeHierarchyOptions struct { // line 6936
+-type TypeHierarchyOptions struct {
 -	WorkDoneProgressOptions
 -}
 -
 -// The parameter of a `textDocument/prepareTypeHierarchy` request.
 -//
 -// @since 3.17.0
--type TypeHierarchyPrepareParams struct { // line 3392
+-type TypeHierarchyPrepareParams struct {
 -	TextDocumentPositionParams
 -	WorkDoneProgressParams
 -}
@@ -56524,7 +62676,7 @@
 -// Type hierarchy options used during static or dynamic registration.
 -//
 -// @since 3.17.0
--type TypeHierarchyRegistrationOptions struct { // line 3487
+-type TypeHierarchyRegistrationOptions struct {
 -	TextDocumentRegistrationOptions
 -	TypeHierarchyOptions
 -	StaticRegistrationOptions
@@ -56533,7 +62685,7 @@
 -// The parameter of a `typeHierarchy/subtypes` request.
 -//
 -// @since 3.17.0
--type TypeHierarchySubtypesParams struct { // line 3533
+-type TypeHierarchySubtypesParams struct {
 -	Item TypeHierarchyItem `json:"item"`
 -	WorkDoneProgressParams
 -	PartialResultParams
@@ -56542,14 +62694,14 @@
 -// The parameter of a `typeHierarchy/supertypes` request.
 -//
 -// @since 3.17.0
--type TypeHierarchySupertypesParams struct { // line 3509
+-type TypeHierarchySupertypesParams struct {
 -	Item TypeHierarchyItem `json:"item"`
 -	WorkDoneProgressParams
 -	PartialResultParams
 -}
 -
 -// created for Tuple
--type UIntCommaUInt struct { // line 10076
+-type UIntCommaUInt struct {
 -	Fld0 uint32 `json:"fld0"`
 -	Fld1 uint32 `json:"fld1"`
 -}
@@ -56559,7 +62711,7 @@
 -// report is still accurate.
 -//
 -// @since 3.17.0
--type UnchangedDocumentDiagnosticReport struct { // line 7270
+-type UnchangedDocumentDiagnosticReport struct {
 -	// A document diagnostic report indicating
 -	// no changes to the last result. A server can
 -	// only return `unchanged` if result ids are
@@ -56573,23 +62725,24 @@
 -// Moniker uniqueness level to define scope of the moniker.
 -//
 -// @since 3.16.0
--type UniquenessLevel string // line 12971
+-type UniquenessLevel string
+-
 -// General parameters to unregister a request or notification.
--type Unregistration struct { // line 7628
+-type Unregistration struct {
 -	// The id used to unregister the request or notification. Usually an id
 -	// provided during the register request.
 -	ID string `json:"id"`
 -	// The method to unregister for.
 -	Method string `json:"method"`
 -}
--type UnregistrationParams struct { // line 4053
+-type UnregistrationParams struct {
 -	Unregisterations []Unregistration `json:"unregisterations"`
 -}
 -
 -// A versioned notebook document identifier.
 -//
 -// @since 3.17.0
--type VersionedNotebookDocumentIdentifier struct { // line 7443
+-type VersionedNotebookDocumentIdentifier struct {
 -	// The version number of this notebook document.
 -	Version int32 `json:"version"`
 -	// The notebook document's uri.
@@ -56597,19 +62750,19 @@
 -}
 -
 -// A text document identifier to denote a specific version of a text document.
--type VersionedTextDocumentIdentifier struct { // line 8445
+-type VersionedTextDocumentIdentifier struct {
 -	// The version number of this document.
 -	Version int32 `json:"version"`
 -	TextDocumentIdentifier
 -}
--type WatchKind = uint32                  // line 13505// The parameters sent in a will save text document notification.
--type WillSaveTextDocumentParams struct { // line 4384
+-type WatchKind = uint32 // line 13505// The parameters sent in a will save text document notification.
+-type WillSaveTextDocumentParams struct {
 -	// The document that will be saved.
 -	TextDocument TextDocumentIdentifier `json:"textDocument"`
 -	// The 'TextDocumentSaveReason'.
 -	Reason TextDocumentSaveReason `json:"reason"`
 -}
--type WindowClientCapabilities struct { // line 10629
+-type WindowClientCapabilities struct {
 -	// It indicates whether the client supports server initiated
 -	// progress using the `window/workDoneProgress/create` request.
 -	//
@@ -56629,7 +62782,7 @@
 -	// @since 3.16.0
 -	ShowDocument *ShowDocumentClientCapabilities `json:"showDocument,omitempty"`
 -}
--type WorkDoneProgressBegin struct { // line 6040
+-type WorkDoneProgressBegin struct {
 -	Kind string `json:"kind"`
 -	// Mandatory title of the progress operation. Used to briefly inform about
 -	// the kind of operation being performed.
@@ -56654,34 +62807,34 @@
 -	// that are not following this rule. The value range is [0, 100].
 -	Percentage uint32 `json:"percentage,omitempty"`
 -}
--type WorkDoneProgressCancelParams struct { // line 2625
+-type WorkDoneProgressCancelParams struct {
 -	// The token to be used to report progress.
 -	Token ProgressToken `json:"token"`
 -}
--type WorkDoneProgressCreateParams struct { // line 2612
+-type WorkDoneProgressCreateParams struct {
 -	// The token to be used to report progress.
 -	Token ProgressToken `json:"token"`
 -}
--type WorkDoneProgressEnd struct { // line 6126
+-type WorkDoneProgressEnd struct {
 -	Kind string `json:"kind"`
 -	// Optional, a final message indicating to for example indicate the outcome
 -	// of the operation.
 -	Message string `json:"message,omitempty"`
 -}
--type WorkDoneProgressOptions struct { // line 2355
+-type WorkDoneProgressOptions struct {
 -	WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
 -}
 -
 -// created for And
--type WorkDoneProgressOptionsAndTextDocumentRegistrationOptions struct { // line 196
+-type WorkDoneProgressOptionsAndTextDocumentRegistrationOptions struct {
 -	WorkDoneProgressOptions
 -	TextDocumentRegistrationOptions
 -}
--type WorkDoneProgressParams struct { // line 6244
+-type WorkDoneProgressParams struct {
 -	// An optional token that a server can use to report work done progress.
 -	WorkDoneToken ProgressToken `json:"workDoneToken,omitempty"`
 -}
--type WorkDoneProgressReport struct { // line 6087
+-type WorkDoneProgressReport struct {
 -	Kind string `json:"kind"`
 -	// Controls enablement state of a cancel button.
 -	//
@@ -56704,7 +62857,7 @@
 -}
 -
 -// created for Literal (Lit_ServerCapabilities_workspace)
--type Workspace6Gn struct { // line 8404
+-type Workspace6Gn struct {
 -	// The server supports workspace folder.
 -	//
 -	// @since 3.6.0
@@ -56716,7 +62869,7 @@
 -}
 -
 -// Workspace specific client capabilities.
--type WorkspaceClientCapabilities struct { // line 10184
+-type WorkspaceClientCapabilities struct {
 -	// The client supports applying batch edits
 -	// to the workspace by supporting the request
 -	// 'workspace/applyEdit'
@@ -56773,7 +62926,7 @@
 -// Parameters of the workspace diagnostic request.
 -//
 -// @since 3.17.0
--type WorkspaceDiagnosticParams struct { // line 3877
+-type WorkspaceDiagnosticParams struct {
 -	// The additional identifier provided during registration.
 -	Identifier string `json:"identifier,omitempty"`
 -	// The currently known diagnostic reports with their
@@ -56786,21 +62939,21 @@
 -// A workspace diagnostic report.
 -//
 -// @since 3.17.0
--type WorkspaceDiagnosticReport struct { // line 3914
+-type WorkspaceDiagnosticReport struct {
 -	Items []WorkspaceDocumentDiagnosticReport `json:"items"`
 -}
 -
 -// A partial result for a workspace diagnostic report.
 -//
 -// @since 3.17.0
--type WorkspaceDiagnosticReportPartialResult struct { // line 3931
+-type WorkspaceDiagnosticReportPartialResult struct {
 -	Items []WorkspaceDocumentDiagnosticReport `json:"items"`
 -}
 -
 -// A workspace diagnostic document report.
 -//
 -// @since 3.17.0
--type WorkspaceDocumentDiagnosticReport = Or_WorkspaceDocumentDiagnosticReport // (alias) line 13984
+-type WorkspaceDocumentDiagnosticReport = Or_WorkspaceDocumentDiagnosticReport // (alias) line 14399
 -// A workspace edit represents changes to many resources managed in the workspace. The edit
 -// should either provide `changes` or `documentChanges`. If documentChanges are present
 -// they are preferred over `changes` if the client can handle versioned document edits.
@@ -56813,7 +62966,7 @@
 -// An invalid sequence (e.g. (1) delete file a.txt and (2) insert text into file a.txt) will
 -// cause failure of the operation. How the client recovers from the failure is described by
 -// the client capability: `workspace.workspaceEdit.failureHandling`
--type WorkspaceEdit struct { // line 3193
+-type WorkspaceEdit struct {
 -	// Holds changes to existing resources.
 -	Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"`
 -	// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes
@@ -56835,7 +62988,7 @@
 -	// @since 3.16.0
 -	ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"`
 -}
--type WorkspaceEditClientCapabilities struct { // line 10768
+-type WorkspaceEditClientCapabilities struct {
 -	// The client supports versioned document changes in `WorkspaceEdit`s
 -	DocumentChanges bool `json:"documentChanges,omitempty"`
 -	// The resource operations the client supports. Clients should at least
@@ -56864,14 +63017,14 @@
 -}
 -
 -// A workspace folder inside a client.
--type WorkspaceFolder struct { // line 2163
+-type WorkspaceFolder struct {
 -	// The associated URI for this workspace folder.
 -	URI URI `json:"uri"`
 -	// The name of the workspace folder. Used to refer to this
 -	// workspace folder in the user interface.
 -	Name string `json:"name"`
 -}
--type WorkspaceFolders5Gn struct { // line 9933
+-type WorkspaceFolders5Gn struct {
 -	// The server has support for workspace folders
 -	Supported bool `json:"supported,omitempty"`
 -	// Whether the server wants to receive workspace folder
@@ -56885,13 +63038,13 @@
 -}
 -
 -// The workspace folder change event.
--type WorkspaceFoldersChangeEvent struct { // line 6368
+-type WorkspaceFoldersChangeEvent struct {
 -	// The array of added workspace folders
 -	Added []WorkspaceFolder `json:"added"`
 -	// The array of the removed workspace folders
 -	Removed []WorkspaceFolder `json:"removed"`
 -}
--type WorkspaceFoldersInitializeParams struct { // line 7782
+-type WorkspaceFoldersInitializeParams struct {
 -	// The workspace folders configured in the client when the server starts.
 -	//
 -	// This property is only available if the client supports workspace folders.
@@ -56901,7 +63054,7 @@
 -	// @since 3.6.0
 -	WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"`
 -}
--type WorkspaceFoldersServerCapabilities struct { // line 9933
+-type WorkspaceFoldersServerCapabilities struct {
 -	// The server has support for workspace folders
 -	Supported bool `json:"supported,omitempty"`
 -	// Whether the server wants to receive workspace folder
@@ -56917,7 +63070,7 @@
 -// A full document diagnostic report for a workspace diagnostic result.
 -//
 -// @since 3.17.0
--type WorkspaceFullDocumentDiagnosticReport struct { // line 9522
+-type WorkspaceFullDocumentDiagnosticReport struct {
 -	// The URI for which diagnostic information is reported.
 -	URI DocumentURI `json:"uri"`
 -	// The version number for which the diagnostics are reported.
@@ -56931,7 +63084,7 @@
 -// See also SymbolInformation.
 -//
 -// @since 3.17.0
--type WorkspaceSymbol struct { // line 5515
+-type WorkspaceSymbol struct {
 -	// The location of the symbol. Whether a server is allowed to
 -	// return a location without a range depends on the client
 -	// capability `workspace.symbol.resolveSupport`.
@@ -56945,7 +63098,7 @@
 -}
 -
 -// Client capabilities for a {@link WorkspaceSymbolRequest}.
--type WorkspaceSymbolClientCapabilities struct { // line 10875
+-type WorkspaceSymbolClientCapabilities struct {
 -	// Symbol request supports dynamic registration.
 -	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
 -	// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
@@ -56964,7 +63117,7 @@
 -}
 -
 -// Server capabilities for a {@link WorkspaceSymbolRequest}.
--type WorkspaceSymbolOptions struct { // line 9105
+-type WorkspaceSymbolOptions struct {
 -	// The server provides support to resolve additional
 -	// information for a workspace symbol.
 -	//
@@ -56974,7 +63127,7 @@
 -}
 -
 -// The parameters of a {@link WorkspaceSymbolRequest}.
--type WorkspaceSymbolParams struct { // line 5491
+-type WorkspaceSymbolParams struct {
 -	// A query string to filter symbols by. Clients may send an empty
 -	// string here to request all symbols.
 -	Query string `json:"query"`
@@ -56983,14 +63136,14 @@
 -}
 -
 -// Registration options for a {@link WorkspaceSymbolRequest}.
--type WorkspaceSymbolRegistrationOptions struct { // line 5564
+-type WorkspaceSymbolRegistrationOptions struct {
 -	WorkspaceSymbolOptions
 -}
 -
 -// An unchanged document diagnostic report for a workspace diagnostic result.
 -//
 -// @since 3.17.0
--type WorkspaceUnchangedDocumentDiagnosticReport struct { // line 9560
+-type WorkspaceUnchangedDocumentDiagnosticReport struct {
 -	// The URI for which diagnostic information is reported.
 -	URI DocumentURI `json:"uri"`
 -	// The version number for which the diagnostics are reported.
@@ -57000,7 +63153,7 @@
 -}
 -
 -// The initialize parameters
--type XInitializeParams struct { // line 7650
+-type XInitializeParams struct {
 -	// The process Id of the parent process that started
 -	// the server.
 -	//
@@ -57041,7 +63194,7 @@
 -}
 -
 -// The initialize parameters
--type _InitializeParams struct { // line 7650
+-type _InitializeParams struct {
 -	// The process Id of the parent process that started
 -	// the server.
 -	//
@@ -57084,11 +63237,11 @@
 -const (
 -	// A set of predefined code action kinds
 -	// Empty kind.
--	Empty CodeActionKind = "" // line 13333
+-	Empty CodeActionKind = ""
 -	// Base kind for quickfix actions: 'quickfix'
--	QuickFix CodeActionKind = "quickfix" // line 13338
+-	QuickFix CodeActionKind = "quickfix"
 -	// Base kind for refactoring actions: 'refactor'
--	Refactor CodeActionKind = "refactor" // line 13343
+-	Refactor CodeActionKind = "refactor"
 -	// Base kind for refactoring extraction actions: 'refactor.extract'
 -	//
 -	// Example extract actions:
@@ -57099,7 +63252,7 @@
 -	//  - Extract variable
 -	//  - Extract interface from class
 -	//  - ...
--	RefactorExtract CodeActionKind = "refactor.extract" // line 13348
+-	RefactorExtract CodeActionKind = "refactor.extract"
 -	// Base kind for refactoring inline actions: 'refactor.inline'
 -	//
 -	// Example inline actions:
@@ -57109,7 +63262,7 @@
 -	//  - Inline variable
 -	//  - Inline constant
 -	//  - ...
--	RefactorInline CodeActionKind = "refactor.inline" // line 13353
+-	RefactorInline CodeActionKind = "refactor.inline"
 -	// Base kind for refactoring rewrite actions: 'refactor.rewrite'
 -	//
 -	// Example rewrite actions:
@@ -57121,80 +63274,80 @@
 -	//  - Make method static
 -	//  - Move method to base class
 -	//  - ...
--	RefactorRewrite CodeActionKind = "refactor.rewrite" // line 13358
+-	RefactorRewrite CodeActionKind = "refactor.rewrite"
 -	// Base kind for source actions: `source`
 -	//
 -	// Source code actions apply to the entire file.
--	Source CodeActionKind = "source" // line 13363
+-	Source CodeActionKind = "source"
 -	// Base kind for an organize imports source action: `source.organizeImports`
--	SourceOrganizeImports CodeActionKind = "source.organizeImports" // line 13368
+-	SourceOrganizeImports CodeActionKind = "source.organizeImports"
 -	// Base kind for auto-fix source actions: `source.fixAll`.
 -	//
 -	// Fix all actions automatically fix errors that have a clear fix that do not require user input.
 -	// They should not suppress errors or perform unsafe fixes such as generating new types or classes.
 -	//
 -	// @since 3.15.0
--	SourceFixAll CodeActionKind = "source.fixAll" // line 13373
+-	SourceFixAll CodeActionKind = "source.fixAll"
 -	// The reason why code actions were requested.
 -	//
 -	// @since 3.17.0
 -	// Code actions were explicitly requested by the user or by an extension.
--	CodeActionInvoked CodeActionTriggerKind = 1 // line 13613
+-	CodeActionInvoked CodeActionTriggerKind = 1
 -	// Code actions were requested automatically.
 -	//
 -	// This typically happens when current selection in a file changes, but can
 -	// also be triggered when file content changes.
--	CodeActionAutomatic CodeActionTriggerKind = 2 // line 13618
+-	CodeActionAutomatic CodeActionTriggerKind = 2
 -	// The kind of a completion entry.
--	TextCompletion          CompletionItemKind = 1  // line 13141
--	MethodCompletion        CompletionItemKind = 2  // line 13145
--	FunctionCompletion      CompletionItemKind = 3  // line 13149
--	ConstructorCompletion   CompletionItemKind = 4  // line 13153
--	FieldCompletion         CompletionItemKind = 5  // line 13157
--	VariableCompletion      CompletionItemKind = 6  // line 13161
--	ClassCompletion         CompletionItemKind = 7  // line 13165
--	InterfaceCompletion     CompletionItemKind = 8  // line 13169
--	ModuleCompletion        CompletionItemKind = 9  // line 13173
--	PropertyCompletion      CompletionItemKind = 10 // line 13177
--	UnitCompletion          CompletionItemKind = 11 // line 13181
--	ValueCompletion         CompletionItemKind = 12 // line 13185
--	EnumCompletion          CompletionItemKind = 13 // line 13189
--	KeywordCompletion       CompletionItemKind = 14 // line 13193
--	SnippetCompletion       CompletionItemKind = 15 // line 13197
--	ColorCompletion         CompletionItemKind = 16 // line 13201
--	FileCompletion          CompletionItemKind = 17 // line 13205
--	ReferenceCompletion     CompletionItemKind = 18 // line 13209
--	FolderCompletion        CompletionItemKind = 19 // line 13213
--	EnumMemberCompletion    CompletionItemKind = 20 // line 13217
--	ConstantCompletion      CompletionItemKind = 21 // line 13221
--	StructCompletion        CompletionItemKind = 22 // line 13225
--	EventCompletion         CompletionItemKind = 23 // line 13229
--	OperatorCompletion      CompletionItemKind = 24 // line 13233
--	TypeParameterCompletion CompletionItemKind = 25 // line 13237
+-	TextCompletion          CompletionItemKind = 1
+-	MethodCompletion        CompletionItemKind = 2
+-	FunctionCompletion      CompletionItemKind = 3
+-	ConstructorCompletion   CompletionItemKind = 4
+-	FieldCompletion         CompletionItemKind = 5
+-	VariableCompletion      CompletionItemKind = 6
+-	ClassCompletion         CompletionItemKind = 7
+-	InterfaceCompletion     CompletionItemKind = 8
+-	ModuleCompletion        CompletionItemKind = 9
+-	PropertyCompletion      CompletionItemKind = 10
+-	UnitCompletion          CompletionItemKind = 11
+-	ValueCompletion         CompletionItemKind = 12
+-	EnumCompletion          CompletionItemKind = 13
+-	KeywordCompletion       CompletionItemKind = 14
+-	SnippetCompletion       CompletionItemKind = 15
+-	ColorCompletion         CompletionItemKind = 16
+-	FileCompletion          CompletionItemKind = 17
+-	ReferenceCompletion     CompletionItemKind = 18
+-	FolderCompletion        CompletionItemKind = 19
+-	EnumMemberCompletion    CompletionItemKind = 20
+-	ConstantCompletion      CompletionItemKind = 21
+-	StructCompletion        CompletionItemKind = 22
+-	EventCompletion         CompletionItemKind = 23
+-	OperatorCompletion      CompletionItemKind = 24
+-	TypeParameterCompletion CompletionItemKind = 25
 -	// Completion item tags are extra annotations that tweak the rendering of a completion
 -	// item.
 -	//
 -	// @since 3.15.0
 -	// Render a completion as obsolete, usually using a strike-out.
--	ComplDeprecated CompletionItemTag = 1 // line 13251
+-	ComplDeprecated CompletionItemTag = 1
 -	// How a completion was triggered
 -	// Completion was triggered by typing an identifier (24x7 code
 -	// complete), manual invocation (e.g Ctrl+Space) or via API.
--	Invoked CompletionTriggerKind = 1 // line 13562
+-	Invoked CompletionTriggerKind = 1
 -	// Completion was triggered by a trigger character specified by
 -	// the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
--	TriggerCharacter CompletionTriggerKind = 2 // line 13567
+-	TriggerCharacter CompletionTriggerKind = 2
 -	// Completion was re-triggered as current completion list is incomplete
--	TriggerForIncompleteCompletions CompletionTriggerKind = 3 // line 13572
+-	TriggerForIncompleteCompletions CompletionTriggerKind = 3
 -	// The diagnostic's severity.
 -	// Reports an error.
--	SeverityError DiagnosticSeverity = 1 // line 13511
+-	SeverityError DiagnosticSeverity = 1
 -	// Reports a warning.
--	SeverityWarning DiagnosticSeverity = 2 // line 13516
+-	SeverityWarning DiagnosticSeverity = 2
 -	// Reports an information.
--	SeverityInformation DiagnosticSeverity = 3 // line 13521
+-	SeverityInformation DiagnosticSeverity = 3
 -	// Reports a hint.
--	SeverityHint DiagnosticSeverity = 4 // line 13526
+-	SeverityHint DiagnosticSeverity = 4
 -	// The diagnostic tags.
 -	//
 -	// @since 3.15.0
@@ -57202,83 +63355,91 @@
 -	//
 -	// Clients are allowed to render diagnostics with this tag faded out instead of having
 -	// an error squiggle.
--	Unnecessary DiagnosticTag = 1 // line 13541
+-	Unnecessary DiagnosticTag = 1
 -	// Deprecated or obsolete code.
 -	//
 -	// Clients are allowed to rendered diagnostics with this tag strike through.
--	Deprecated DiagnosticTag = 2 // line 13546
+-	Deprecated DiagnosticTag = 2
 -	// The document diagnostic report kinds.
 -	//
 -	// @since 3.17.0
 -	// A diagnostic report with a full
 -	// set of problems.
--	DiagnosticFull DocumentDiagnosticReportKind = "full" // line 12729
+-	DiagnosticFull DocumentDiagnosticReportKind = "full"
 -	// A report indicating that the last
 -	// returned report is still accurate.
--	DiagnosticUnchanged DocumentDiagnosticReportKind = "unchanged" // line 12734
+-	DiagnosticUnchanged DocumentDiagnosticReportKind = "unchanged"
 -	// A document highlight kind.
 -	// A textual occurrence.
--	Text DocumentHighlightKind = 1 // line 13308
+-	Text DocumentHighlightKind = 1
 -	// Read-access of a symbol, like reading a variable.
--	Read DocumentHighlightKind = 2 // line 13313
+-	Read DocumentHighlightKind = 2
 -	// Write-access of a symbol, like writing to a variable.
--	Write DocumentHighlightKind = 3 // line 13318
+-	Write DocumentHighlightKind = 3
 -	// Predefined error codes.
--	ParseError     ErrorCodes = -32700 // line 12750
--	InvalidRequest ErrorCodes = -32600 // line 12754
--	MethodNotFound ErrorCodes = -32601 // line 12758
--	InvalidParams  ErrorCodes = -32602 // line 12762
--	InternalError  ErrorCodes = -32603 // line 12766
+-	ParseError     ErrorCodes = -32700
+-	InvalidRequest ErrorCodes = -32600
+-	MethodNotFound ErrorCodes = -32601
+-	InvalidParams  ErrorCodes = -32602
+-	InternalError  ErrorCodes = -32603
 -	// Error code indicating that a server received a notification or
 -	// request before the server has received the `initialize` request.
--	ServerNotInitialized ErrorCodes = -32002 // line 12770
--	UnknownErrorCode     ErrorCodes = -32001 // line 12775
+-	ServerNotInitialized ErrorCodes = -32002
+-	UnknownErrorCode     ErrorCodes = -32001
 -	// Applying the workspace change is simply aborted if one of the changes provided
 -	// fails. All operations executed before the failing operation stay executed.
--	Abort FailureHandlingKind = "abort" // line 13700
+-	Abort FailureHandlingKind = "abort"
 -	// All operations are executed transactional. That means they either all
 -	// succeed or no changes at all are applied to the workspace.
--	Transactional FailureHandlingKind = "transactional" // line 13705
+-	Transactional FailureHandlingKind = "transactional"
 -	// If the workspace edit contains only textual file changes they are executed transactional.
 -	// If resource changes (create, rename or delete file) are part of the change the failure
 -	// handling strategy is abort.
--	TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional" // line 13710
+-	TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional"
 -	// The client tries to undo the operations already executed. But there is no
 -	// guarantee that this is succeeding.
--	Undo FailureHandlingKind = "undo" // line 13715
+-	Undo FailureHandlingKind = "undo"
 -	// The file event type
 -	// The file got created.
--	Created FileChangeType = 1 // line 13461
+-	Created FileChangeType = 1
 -	// The file got changed.
--	Changed FileChangeType = 2 // line 13466
+-	Changed FileChangeType = 2
 -	// The file got deleted.
--	Deleted FileChangeType = 3 // line 13471
+-	Deleted FileChangeType = 3
 -	// A pattern kind describing if a glob pattern matches a file a folder or
 -	// both.
 -	//
 -	// @since 3.16.0
 -	// The pattern matches a file only.
--	FilePattern FileOperationPatternKind = "file" // line 13634
+-	FilePattern FileOperationPatternKind = "file"
 -	// The pattern matches a folder only.
--	FolderPattern FileOperationPatternKind = "folder" // line 13639
+-	FolderPattern FileOperationPatternKind = "folder"
 -	// A set of predefined range kinds.
 -	// Folding range for a comment
--	Comment FoldingRangeKind = "comment" // line 12822
+-	Comment FoldingRangeKind = "comment"
 -	// Folding range for an import or include
--	Imports FoldingRangeKind = "imports" // line 12827
+-	Imports FoldingRangeKind = "imports"
 -	// Folding range for a region (e.g. `#region`)
--	Region FoldingRangeKind = "region" // line 12832
+-	Region FoldingRangeKind = "region"
 -	// Inlay hint kinds.
 -	//
 -	// @since 3.17.0
 -	// An inlay hint that for a type annotation.
--	Type InlayHintKind = 1 // line 13040
+-	Type InlayHintKind = 1
 -	// An inlay hint that is for a parameter.
--	Parameter InlayHintKind = 2 // line 13045
+-	Parameter InlayHintKind = 2
+-	// Describes how an {@link InlineCompletionItemProvider inline completion provider} was triggered.
+-	//
+-	// @since 3.18.0
+-	// @proposed
+-	// Completion was triggered explicitly by a user gesture.
+-	InlineInvoked InlineCompletionTriggerKind = 0
+-	// Completion was triggered automatically while editing.
+-	InlineAutomatic InlineCompletionTriggerKind = 1
 -	// Defines whether the insert text in a completion item should be interpreted as
 -	// plain text or a snippet.
 -	// The primary text to be inserted is treated as a plain string.
--	PlainTextTextFormat InsertTextFormat = 1 // line 13267
+-	PlainTextTextFormat InsertTextFormat = 1
 -	// The primary text to be inserted is treated as a snippet.
 -	//
 -	// A snippet can define tab stops and placeholders with `$1`, `$2`
@@ -57287,7 +63448,7 @@
 -	// that is typing in one will update others too.
 -	//
 -	// See also: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#snippet_syntax
--	SnippetTextFormat InsertTextFormat = 2 // line 13272
+-	SnippetTextFormat InsertTextFormat = 2
 -	// How whitespace and indentation is handled during completion
 -	// item insertion.
 -	//
@@ -57297,7 +63458,7 @@
 -	// inserted using the indentation defined in the string value.
 -	// The client will not apply any kind of adjustments to the
 -	// string.
--	AsIs InsertTextMode = 1 // line 13287
+-	AsIs InsertTextMode = 1
 -	// The editor adjusts leading whitespace of new lines so that
 -	// they match the indentation up to the cursor of the line for
 -	// which the item is accepted.
@@ -57305,20 +63466,20 @@
 -	// Consider a line like this: <2tabs><cursor><3tabs>foo. Accepting a
 -	// multi line completion item is indented using 2 tabs and all
 -	// following lines inserted will be indented using 2 tabs as well.
--	AdjustIndentation InsertTextMode = 2 // line 13292
+-	AdjustIndentation InsertTextMode = 2
 -	// A request failed but it was syntactically correct, e.g the
 -	// method name was known and the parameters were valid. The error
 -	// message should contain human readable information about why
 -	// the request failed.
 -	//
 -	// @since 3.17.0
--	RequestFailed LSPErrorCodes = -32803 // line 12790
+-	RequestFailed LSPErrorCodes = -32803
 -	// The server cancelled the request. This error code should
 -	// only be used for requests that explicitly support being
 -	// server cancellable.
 -	//
 -	// @since 3.17.0
--	ServerCancelled LSPErrorCodes = -32802 // line 12796
+-	ServerCancelled LSPErrorCodes = -32802
 -	// The server detected that the content of a document got
 -	// modified outside normal conditions. A server should
 -	// NOT send this error code if it detects a content change
@@ -57327,207 +63488,207 @@
 -	//
 -	// If a client decides that a result is not of any use anymore
 -	// the client should cancel the request.
--	ContentModified LSPErrorCodes = -32801 // line 12802
+-	ContentModified LSPErrorCodes = -32801
 -	// The client has canceled a request and a server as detected
 -	// the cancel.
--	RequestCancelled LSPErrorCodes = -32800 // line 12807
+-	RequestCancelled LSPErrorCodes = -32800
 -	// Describes the content type that a client supports in various
 -	// result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
 -	//
 -	// Please note that `MarkupKinds` must not start with a `$`. This kinds
 -	// are reserved for internal usage.
 -	// Plain text is supported as a content format
--	PlainText MarkupKind = "plaintext" // line 13414
+-	PlainText MarkupKind = "plaintext"
 -	// Markdown is supported as a content format
--	Markdown MarkupKind = "markdown" // line 13419
+-	Markdown MarkupKind = "markdown"
 -	// The message type
 -	// An error message.
--	Error MessageType = 1 // line 13061
+-	Error MessageType = 1
 -	// A warning message.
--	Warning MessageType = 2 // line 13066
+-	Warning MessageType = 2
 -	// An information message.
--	Info MessageType = 3 // line 13071
+-	Info MessageType = 3
 -	// A log message.
--	Log MessageType = 4 // line 13076
+-	Log MessageType = 4
 -	// The moniker kind.
 -	//
 -	// @since 3.16.0
 -	// The moniker represent a symbol that is imported into a project
--	Import MonikerKind = "import" // line 13014
+-	Import MonikerKind = "import"
 -	// The moniker represents a symbol that is exported from a project
--	Export MonikerKind = "export" // line 13019
+-	Export MonikerKind = "export"
 -	// The moniker represents a symbol that is local to a project (e.g. a local
 -	// variable of a function, a class not visible outside the project, ...)
--	Local MonikerKind = "local" // line 13024
+-	Local MonikerKind = "local"
 -	// A notebook cell kind.
 -	//
 -	// @since 3.17.0
 -	// A markup-cell is formatted source that is used for display.
--	Markup NotebookCellKind = 1 // line 13655
+-	Markup NotebookCellKind = 1
 -	// A code-cell is source code.
--	Code NotebookCellKind = 2 // line 13660
+-	Code NotebookCellKind = 2
 -	// A set of predefined position encoding kinds.
 -	//
 -	// @since 3.17.0
--	// Character offsets count UTF-8 code units.
--	UTF8 PositionEncodingKind = "utf-8" // line 13434
+-	// Character offsets count UTF-8 code units (e.g. bytes).
+-	UTF8 PositionEncodingKind = "utf-8"
 -	// Character offsets count UTF-16 code units.
 -	//
 -	// This is the default and must always be supported
 -	// by servers
--	UTF16 PositionEncodingKind = "utf-16" // line 13439
+-	UTF16 PositionEncodingKind = "utf-16"
 -	// Character offsets count UTF-32 code units.
 -	//
--	// Implementation note: these are the same as Unicode code points,
+-	// Implementation note: these are the same as Unicode codepoints,
 -	// so this `PositionEncodingKind` may also be used for an
 -	// encoding-agnostic representation of character offsets.
--	UTF32 PositionEncodingKind = "utf-32" // line 13444
+-	UTF32 PositionEncodingKind = "utf-32"
 -	// The client's default behavior is to select the identifier
 -	// according the to language's syntax rule.
--	Identifier PrepareSupportDefaultBehavior = 1 // line 13729
+-	Identifier PrepareSupportDefaultBehavior = 1
 -	// Supports creating new files and folders.
--	Create ResourceOperationKind = "create" // line 13676
+-	Create ResourceOperationKind = "create"
 -	// Supports renaming existing files and folders.
--	Rename ResourceOperationKind = "rename" // line 13681
+-	Rename ResourceOperationKind = "rename"
 -	// Supports deleting existing files and folders.
--	Delete ResourceOperationKind = "delete" // line 13686
+-	Delete ResourceOperationKind = "delete"
 -	// A set of predefined token modifiers. This set is not fixed
 -	// an clients can specify additional token types via the
 -	// corresponding client capabilities.
 -	//
 -	// @since 3.16.0
--	ModDeclaration    SemanticTokenModifiers = "declaration"    // line 12677
--	ModDefinition     SemanticTokenModifiers = "definition"     // line 12681
--	ModReadonly       SemanticTokenModifiers = "readonly"       // line 12685
--	ModStatic         SemanticTokenModifiers = "static"         // line 12689
--	ModDeprecated     SemanticTokenModifiers = "deprecated"     // line 12693
--	ModAbstract       SemanticTokenModifiers = "abstract"       // line 12697
--	ModAsync          SemanticTokenModifiers = "async"          // line 12701
--	ModModification   SemanticTokenModifiers = "modification"   // line 12705
--	ModDocumentation  SemanticTokenModifiers = "documentation"  // line 12709
--	ModDefaultLibrary SemanticTokenModifiers = "defaultLibrary" // line 12713
+-	ModDeclaration    SemanticTokenModifiers = "declaration"
+-	ModDefinition     SemanticTokenModifiers = "definition"
+-	ModReadonly       SemanticTokenModifiers = "readonly"
+-	ModStatic         SemanticTokenModifiers = "static"
+-	ModDeprecated     SemanticTokenModifiers = "deprecated"
+-	ModAbstract       SemanticTokenModifiers = "abstract"
+-	ModAsync          SemanticTokenModifiers = "async"
+-	ModModification   SemanticTokenModifiers = "modification"
+-	ModDocumentation  SemanticTokenModifiers = "documentation"
+-	ModDefaultLibrary SemanticTokenModifiers = "defaultLibrary"
 -	// A set of predefined token types. This set is not fixed
 -	// an clients can specify additional token types via the
 -	// corresponding client capabilities.
 -	//
 -	// @since 3.16.0
--	NamespaceType SemanticTokenTypes = "namespace" // line 12570
+-	NamespaceType SemanticTokenTypes = "namespace"
 -	// Represents a generic type. Acts as a fallback for types which can't be mapped to
 -	// a specific type like class or enum.
--	TypeType          SemanticTokenTypes = "type"          // line 12574
--	ClassType         SemanticTokenTypes = "class"         // line 12579
--	EnumType          SemanticTokenTypes = "enum"          // line 12583
--	InterfaceType     SemanticTokenTypes = "interface"     // line 12587
--	StructType        SemanticTokenTypes = "struct"        // line 12591
--	TypeParameterType SemanticTokenTypes = "typeParameter" // line 12595
--	ParameterType     SemanticTokenTypes = "parameter"     // line 12599
--	VariableType      SemanticTokenTypes = "variable"      // line 12603
--	PropertyType      SemanticTokenTypes = "property"      // line 12607
--	EnumMemberType    SemanticTokenTypes = "enumMember"    // line 12611
--	EventType         SemanticTokenTypes = "event"         // line 12615
--	FunctionType      SemanticTokenTypes = "function"      // line 12619
--	MethodType        SemanticTokenTypes = "method"        // line 12623
--	MacroType         SemanticTokenTypes = "macro"         // line 12627
--	KeywordType       SemanticTokenTypes = "keyword"       // line 12631
--	ModifierType      SemanticTokenTypes = "modifier"      // line 12635
--	CommentType       SemanticTokenTypes = "comment"       // line 12639
--	StringType        SemanticTokenTypes = "string"        // line 12643
--	NumberType        SemanticTokenTypes = "number"        // line 12647
--	RegexpType        SemanticTokenTypes = "regexp"        // line 12651
--	OperatorType      SemanticTokenTypes = "operator"      // line 12655
+-	TypeType          SemanticTokenTypes = "type"
+-	ClassType         SemanticTokenTypes = "class"
+-	EnumType          SemanticTokenTypes = "enum"
+-	InterfaceType     SemanticTokenTypes = "interface"
+-	StructType        SemanticTokenTypes = "struct"
+-	TypeParameterType SemanticTokenTypes = "typeParameter"
+-	ParameterType     SemanticTokenTypes = "parameter"
+-	VariableType      SemanticTokenTypes = "variable"
+-	PropertyType      SemanticTokenTypes = "property"
+-	EnumMemberType    SemanticTokenTypes = "enumMember"
+-	EventType         SemanticTokenTypes = "event"
+-	FunctionType      SemanticTokenTypes = "function"
+-	MethodType        SemanticTokenTypes = "method"
+-	MacroType         SemanticTokenTypes = "macro"
+-	KeywordType       SemanticTokenTypes = "keyword"
+-	ModifierType      SemanticTokenTypes = "modifier"
+-	CommentType       SemanticTokenTypes = "comment"
+-	StringType        SemanticTokenTypes = "string"
+-	NumberType        SemanticTokenTypes = "number"
+-	RegexpType        SemanticTokenTypes = "regexp"
+-	OperatorType      SemanticTokenTypes = "operator"
 -	// @since 3.17.0
--	DecoratorType SemanticTokenTypes = "decorator" // line 12659
+-	DecoratorType SemanticTokenTypes = "decorator"
 -	// How a signature help was triggered.
 -	//
 -	// @since 3.15.0
 -	// Signature help was invoked manually by the user or by a command.
--	SigInvoked SignatureHelpTriggerKind = 1 // line 13587
+-	SigInvoked SignatureHelpTriggerKind = 1
 -	// Signature help was triggered by a trigger character.
--	SigTriggerCharacter SignatureHelpTriggerKind = 2 // line 13592
+-	SigTriggerCharacter SignatureHelpTriggerKind = 2
 -	// Signature help was triggered by the cursor moving or by the document content changing.
--	SigContentChange SignatureHelpTriggerKind = 3 // line 13597
+-	SigContentChange SignatureHelpTriggerKind = 3
 -	// A symbol kind.
--	File          SymbolKind = 1  // line 12848
--	Module        SymbolKind = 2  // line 12852
--	Namespace     SymbolKind = 3  // line 12856
--	Package       SymbolKind = 4  // line 12860
--	Class         SymbolKind = 5  // line 12864
--	Method        SymbolKind = 6  // line 12868
--	Property      SymbolKind = 7  // line 12872
--	Field         SymbolKind = 8  // line 12876
--	Constructor   SymbolKind = 9  // line 12880
--	Enum          SymbolKind = 10 // line 12884
--	Interface     SymbolKind = 11 // line 12888
--	Function      SymbolKind = 12 // line 12892
--	Variable      SymbolKind = 13 // line 12896
--	Constant      SymbolKind = 14 // line 12900
--	String        SymbolKind = 15 // line 12904
--	Number        SymbolKind = 16 // line 12908
--	Boolean       SymbolKind = 17 // line 12912
--	Array         SymbolKind = 18 // line 12916
--	Object        SymbolKind = 19 // line 12920
--	Key           SymbolKind = 20 // line 12924
--	Null          SymbolKind = 21 // line 12928
--	EnumMember    SymbolKind = 22 // line 12932
--	Struct        SymbolKind = 23 // line 12936
--	Event         SymbolKind = 24 // line 12940
--	Operator      SymbolKind = 25 // line 12944
--	TypeParameter SymbolKind = 26 // line 12948
+-	File          SymbolKind = 1
+-	Module        SymbolKind = 2
+-	Namespace     SymbolKind = 3
+-	Package       SymbolKind = 4
+-	Class         SymbolKind = 5
+-	Method        SymbolKind = 6
+-	Property      SymbolKind = 7
+-	Field         SymbolKind = 8
+-	Constructor   SymbolKind = 9
+-	Enum          SymbolKind = 10
+-	Interface     SymbolKind = 11
+-	Function      SymbolKind = 12
+-	Variable      SymbolKind = 13
+-	Constant      SymbolKind = 14
+-	String        SymbolKind = 15
+-	Number        SymbolKind = 16
+-	Boolean       SymbolKind = 17
+-	Array         SymbolKind = 18
+-	Object        SymbolKind = 19
+-	Key           SymbolKind = 20
+-	Null          SymbolKind = 21
+-	EnumMember    SymbolKind = 22
+-	Struct        SymbolKind = 23
+-	Event         SymbolKind = 24
+-	Operator      SymbolKind = 25
+-	TypeParameter SymbolKind = 26
 -	// Symbol tags are extra annotations that tweak the rendering of a symbol.
 -	//
 -	// @since 3.16
 -	// Render a symbol as obsolete, usually using a strike-out.
--	DeprecatedSymbol SymbolTag = 1 // line 12962
+-	DeprecatedSymbol SymbolTag = 1
 -	// Represents reasons why a text document is saved.
 -	// Manually triggered, e.g. by the user pressing save, by starting debugging,
 -	// or by an API call.
--	Manual TextDocumentSaveReason = 1 // line 13116
+-	Manual TextDocumentSaveReason = 1
 -	// Automatic after a delay.
--	AfterDelay TextDocumentSaveReason = 2 // line 13121
+-	AfterDelay TextDocumentSaveReason = 2
 -	// When the editor lost focus.
--	FocusOut TextDocumentSaveReason = 3 // line 13126
+-	FocusOut TextDocumentSaveReason = 3
 -	// Defines how the host (editor) should sync
 -	// document changes to the language server.
 -	// Documents should not be synced at all.
--	None TextDocumentSyncKind = 0 // line 13091
+-	None TextDocumentSyncKind = 0
 -	// Documents are synced by always sending the full content
 -	// of the document.
--	Full TextDocumentSyncKind = 1 // line 13096
+-	Full TextDocumentSyncKind = 1
 -	// Documents are synced by sending the full content on open.
 -	// After that only incremental updates to the document are
 -	// send.
--	Incremental TextDocumentSyncKind = 2          // line 13101
--	Relative    TokenFormat          = "relative" // line 13743
+-	Incremental TextDocumentSyncKind = 2
+-	Relative    TokenFormat          = "relative"
 -	// Turn tracing off.
--	Off TraceValues = "off" // line 13390
+-	Off TraceValues = "off"
 -	// Trace messages only.
--	Messages TraceValues = "messages" // line 13395
+-	Messages TraceValues = "messages"
 -	// Verbose message tracing.
--	Verbose TraceValues = "verbose" // line 13400
+-	Verbose TraceValues = "verbose"
 -	// Moniker uniqueness level to define scope of the moniker.
 -	//
 -	// @since 3.16.0
 -	// The moniker is only unique inside a document
--	Document UniquenessLevel = "document" // line 12978
+-	Document UniquenessLevel = "document"
 -	// The moniker is unique inside a project for which a dump got created
--	Project UniquenessLevel = "project" // line 12983
+-	Project UniquenessLevel = "project"
 -	// The moniker is unique inside the group to which a project belongs
--	Group UniquenessLevel = "group" // line 12988
+-	Group UniquenessLevel = "group"
 -	// The moniker is unique inside the moniker scheme.
--	Scheme UniquenessLevel = "scheme" // line 12993
+-	Scheme UniquenessLevel = "scheme"
 -	// The moniker is globally unique
--	Global UniquenessLevel = "global" // line 12998
+-	Global UniquenessLevel = "global"
 -	// Interested in create events.
--	WatchCreate WatchKind = 1 // line 13486
+-	WatchCreate WatchKind = 1
 -	// Interested in change events
--	WatchChange WatchKind = 2 // line 13491
+-	WatchChange WatchKind = 2
 -	// Interested in delete events
--	WatchDelete WatchKind = 4 // line 13496
+-	WatchDelete WatchKind = 4
 -)
 diff -urN a/gopls/internal/lsp/protocol/tsserver.go b/gopls/internal/lsp/protocol/tsserver.go
 --- a/gopls/internal/lsp/protocol/tsserver.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/protocol/tsserver.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1160 +0,0 @@
++++ b/gopls/internal/lsp/protocol/tsserver.go	1970-01-01 08:00:00
+@@ -1,1196 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -57536,8 +63697,8 @@
 -
 -package protocol
 -
--// Code generated from protocol/metaModel.json at ref release/protocol/3.17.3-next.6 (hash 56c23c557e3568a9f56f42435fd5a80f9458957f).
--// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.3-next.6/protocol/metaModel.json
+-// Code generated from protocol/metaModel.json at ref release/protocol/3.17.4-next.2 (hash 184c8a7f010d335582f24337fe182baa6f2fccdd).
+-// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.17.4-next.2/protocol/metaModel.json
 -// LSP metaData.version = 3.17.0.
 -
 -import (
@@ -57548,77 +63709,79 @@
 -)
 -
 -type Server interface {
--	Progress(context.Context, *ProgressParams) error                                                       // $/progress
--	SetTrace(context.Context, *SetTraceParams) error                                                       // $/setTrace
--	IncomingCalls(context.Context, *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall, error) // callHierarchy/incomingCalls
--	OutgoingCalls(context.Context, *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall, error) // callHierarchy/outgoingCalls
--	ResolveCodeAction(context.Context, *CodeAction) (*CodeAction, error)                                   // codeAction/resolve
--	ResolveCodeLens(context.Context, *CodeLens) (*CodeLens, error)                                         // codeLens/resolve
--	ResolveCompletionItem(context.Context, *CompletionItem) (*CompletionItem, error)                       // completionItem/resolve
--	ResolveDocumentLink(context.Context, *DocumentLink) (*DocumentLink, error)                             // documentLink/resolve
--	Exit(context.Context) error                                                                            // exit
--	Initialize(context.Context, *ParamInitialize) (*InitializeResult, error)                               // initialize
--	Initialized(context.Context, *InitializedParams) error                                                 // initialized
--	Resolve(context.Context, *InlayHint) (*InlayHint, error)                                               // inlayHint/resolve
--	DidChangeNotebookDocument(context.Context, *DidChangeNotebookDocumentParams) error                     // notebookDocument/didChange
--	DidCloseNotebookDocument(context.Context, *DidCloseNotebookDocumentParams) error                       // notebookDocument/didClose
--	DidOpenNotebookDocument(context.Context, *DidOpenNotebookDocumentParams) error                         // notebookDocument/didOpen
--	DidSaveNotebookDocument(context.Context, *DidSaveNotebookDocumentParams) error                         // notebookDocument/didSave
--	Shutdown(context.Context) error                                                                        // shutdown
--	CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error)                                   // textDocument/codeAction
--	CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error)                                         // textDocument/codeLens
--	ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error)              // textDocument/colorPresentation
--	Completion(context.Context, *CompletionParams) (*CompletionList, error)                                // textDocument/completion
--	Declaration(context.Context, *DeclarationParams) (*Or_textDocument_declaration, error)                 // textDocument/declaration
--	Definition(context.Context, *DefinitionParams) ([]Location, error)                                     // textDocument/definition
--	Diagnostic(context.Context, *string) (*string, error)                                                  // textDocument/diagnostic
--	DidChange(context.Context, *DidChangeTextDocumentParams) error                                         // textDocument/didChange
--	DidClose(context.Context, *DidCloseTextDocumentParams) error                                           // textDocument/didClose
--	DidOpen(context.Context, *DidOpenTextDocumentParams) error                                             // textDocument/didOpen
--	DidSave(context.Context, *DidSaveTextDocumentParams) error                                             // textDocument/didSave
--	DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error)                       // textDocument/documentColor
--	DocumentHighlight(context.Context, *DocumentHighlightParams) ([]DocumentHighlight, error)              // textDocument/documentHighlight
--	DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error)                             // textDocument/documentLink
--	DocumentSymbol(context.Context, *DocumentSymbolParams) ([]interface{}, error)                          // textDocument/documentSymbol
--	FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange, error)                             // textDocument/foldingRange
--	Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error)                             // textDocument/formatting
--	Hover(context.Context, *HoverParams) (*Hover, error)                                                   // textDocument/hover
--	Implementation(context.Context, *ImplementationParams) ([]Location, error)                             // textDocument/implementation
--	InlayHint(context.Context, *InlayHintParams) ([]InlayHint, error)                                      // textDocument/inlayHint
--	InlineValue(context.Context, *InlineValueParams) ([]InlineValue, error)                                // textDocument/inlineValue
--	LinkedEditingRange(context.Context, *LinkedEditingRangeParams) (*LinkedEditingRanges, error)           // textDocument/linkedEditingRange
--	Moniker(context.Context, *MonikerParams) ([]Moniker, error)                                            // textDocument/moniker
--	OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error)                 // textDocument/onTypeFormatting
--	PrepareCallHierarchy(context.Context, *CallHierarchyPrepareParams) ([]CallHierarchyItem, error)        // textDocument/prepareCallHierarchy
--	PrepareRename(context.Context, *PrepareRenameParams) (*PrepareRename2Gn, error)                        // textDocument/prepareRename
--	PrepareTypeHierarchy(context.Context, *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error)        // textDocument/prepareTypeHierarchy
--	RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error)                   // textDocument/rangeFormatting
--	References(context.Context, *ReferenceParams) ([]Location, error)                                      // textDocument/references
--	Rename(context.Context, *RenameParams) (*WorkspaceEdit, error)                                         // textDocument/rename
--	SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange, error)                       // textDocument/selectionRange
--	SemanticTokensFull(context.Context, *SemanticTokensParams) (*SemanticTokens, error)                    // textDocument/semanticTokens/full
--	SemanticTokensFullDelta(context.Context, *SemanticTokensDeltaParams) (interface{}, error)              // textDocument/semanticTokens/full/delta
--	SemanticTokensRange(context.Context, *SemanticTokensRangeParams) (*SemanticTokens, error)              // textDocument/semanticTokens/range
--	SignatureHelp(context.Context, *SignatureHelpParams) (*SignatureHelp, error)                           // textDocument/signatureHelp
--	TypeDefinition(context.Context, *TypeDefinitionParams) ([]Location, error)                             // textDocument/typeDefinition
--	WillSave(context.Context, *WillSaveTextDocumentParams) error                                           // textDocument/willSave
--	WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error)                    // textDocument/willSaveWaitUntil
--	Subtypes(context.Context, *TypeHierarchySubtypesParams) ([]TypeHierarchyItem, error)                   // typeHierarchy/subtypes
--	Supertypes(context.Context, *TypeHierarchySupertypesParams) ([]TypeHierarchyItem, error)               // typeHierarchy/supertypes
--	WorkDoneProgressCancel(context.Context, *WorkDoneProgressCancelParams) error                           // window/workDoneProgress/cancel
--	DiagnosticWorkspace(context.Context, *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error)   // workspace/diagnostic
--	DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error                           // workspace/didChangeConfiguration
--	DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error                             // workspace/didChangeWatchedFiles
--	DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error                     // workspace/didChangeWorkspaceFolders
--	DidCreateFiles(context.Context, *CreateFilesParams) error                                              // workspace/didCreateFiles
--	DidDeleteFiles(context.Context, *DeleteFilesParams) error                                              // workspace/didDeleteFiles
--	DidRenameFiles(context.Context, *RenameFilesParams) error                                              // workspace/didRenameFiles
--	ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error)                            // workspace/executeCommand
--	Symbol(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error)                           // workspace/symbol
--	WillCreateFiles(context.Context, *CreateFilesParams) (*WorkspaceEdit, error)                           // workspace/willCreateFiles
--	WillDeleteFiles(context.Context, *DeleteFilesParams) (*WorkspaceEdit, error)                           // workspace/willDeleteFiles
--	WillRenameFiles(context.Context, *RenameFilesParams) (*WorkspaceEdit, error)                           // workspace/willRenameFiles
--	ResolveWorkspaceSymbol(context.Context, *WorkspaceSymbol) (*WorkspaceSymbol, error)                    // workspaceSymbol/resolve
+-	Progress(context.Context, *ProgressParams) error                                                             // $/progress
+-	SetTrace(context.Context, *SetTraceParams) error                                                             // $/setTrace
+-	IncomingCalls(context.Context, *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall, error)       // callHierarchy/incomingCalls
+-	OutgoingCalls(context.Context, *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall, error)       // callHierarchy/outgoingCalls
+-	ResolveCodeAction(context.Context, *CodeAction) (*CodeAction, error)                                         // codeAction/resolve
+-	ResolveCodeLens(context.Context, *CodeLens) (*CodeLens, error)                                               // codeLens/resolve
+-	ResolveCompletionItem(context.Context, *CompletionItem) (*CompletionItem, error)                             // completionItem/resolve
+-	ResolveDocumentLink(context.Context, *DocumentLink) (*DocumentLink, error)                                   // documentLink/resolve
+-	Exit(context.Context) error                                                                                  // exit
+-	Initialize(context.Context, *ParamInitialize) (*InitializeResult, error)                                     // initialize
+-	Initialized(context.Context, *InitializedParams) error                                                       // initialized
+-	Resolve(context.Context, *InlayHint) (*InlayHint, error)                                                     // inlayHint/resolve
+-	DidChangeNotebookDocument(context.Context, *DidChangeNotebookDocumentParams) error                           // notebookDocument/didChange
+-	DidCloseNotebookDocument(context.Context, *DidCloseNotebookDocumentParams) error                             // notebookDocument/didClose
+-	DidOpenNotebookDocument(context.Context, *DidOpenNotebookDocumentParams) error                               // notebookDocument/didOpen
+-	DidSaveNotebookDocument(context.Context, *DidSaveNotebookDocumentParams) error                               // notebookDocument/didSave
+-	Shutdown(context.Context) error                                                                              // shutdown
+-	CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error)                                         // textDocument/codeAction
+-	CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error)                                               // textDocument/codeLens
+-	ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error)                    // textDocument/colorPresentation
+-	Completion(context.Context, *CompletionParams) (*CompletionList, error)                                      // textDocument/completion
+-	Declaration(context.Context, *DeclarationParams) (*Or_textDocument_declaration, error)                       // textDocument/declaration
+-	Definition(context.Context, *DefinitionParams) ([]Location, error)                                           // textDocument/definition
+-	Diagnostic(context.Context, *string) (*string, error)                                                        // textDocument/diagnostic
+-	DidChange(context.Context, *DidChangeTextDocumentParams) error                                               // textDocument/didChange
+-	DidClose(context.Context, *DidCloseTextDocumentParams) error                                                 // textDocument/didClose
+-	DidOpen(context.Context, *DidOpenTextDocumentParams) error                                                   // textDocument/didOpen
+-	DidSave(context.Context, *DidSaveTextDocumentParams) error                                                   // textDocument/didSave
+-	DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error)                             // textDocument/documentColor
+-	DocumentHighlight(context.Context, *DocumentHighlightParams) ([]DocumentHighlight, error)                    // textDocument/documentHighlight
+-	DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error)                                   // textDocument/documentLink
+-	DocumentSymbol(context.Context, *DocumentSymbolParams) ([]interface{}, error)                                // textDocument/documentSymbol
+-	FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange, error)                                   // textDocument/foldingRange
+-	Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error)                                   // textDocument/formatting
+-	Hover(context.Context, *HoverParams) (*Hover, error)                                                         // textDocument/hover
+-	Implementation(context.Context, *ImplementationParams) ([]Location, error)                                   // textDocument/implementation
+-	InlayHint(context.Context, *InlayHintParams) ([]InlayHint, error)                                            // textDocument/inlayHint
+-	InlineCompletion(context.Context, *InlineCompletionParams) (*Or_Result_textDocument_inlineCompletion, error) // textDocument/inlineCompletion
+-	InlineValue(context.Context, *InlineValueParams) ([]InlineValue, error)                                      // textDocument/inlineValue
+-	LinkedEditingRange(context.Context, *LinkedEditingRangeParams) (*LinkedEditingRanges, error)                 // textDocument/linkedEditingRange
+-	Moniker(context.Context, *MonikerParams) ([]Moniker, error)                                                  // textDocument/moniker
+-	OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error)                       // textDocument/onTypeFormatting
+-	PrepareCallHierarchy(context.Context, *CallHierarchyPrepareParams) ([]CallHierarchyItem, error)              // textDocument/prepareCallHierarchy
+-	PrepareRename(context.Context, *PrepareRenameParams) (*PrepareRename2Gn, error)                              // textDocument/prepareRename
+-	PrepareTypeHierarchy(context.Context, *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error)              // textDocument/prepareTypeHierarchy
+-	RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error)                         // textDocument/rangeFormatting
+-	RangesFormatting(context.Context, *DocumentRangesFormattingParams) ([]TextEdit, error)                       // textDocument/rangesFormatting
+-	References(context.Context, *ReferenceParams) ([]Location, error)                                            // textDocument/references
+-	Rename(context.Context, *RenameParams) (*WorkspaceEdit, error)                                               // textDocument/rename
+-	SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange, error)                             // textDocument/selectionRange
+-	SemanticTokensFull(context.Context, *SemanticTokensParams) (*SemanticTokens, error)                          // textDocument/semanticTokens/full
+-	SemanticTokensFullDelta(context.Context, *SemanticTokensDeltaParams) (interface{}, error)                    // textDocument/semanticTokens/full/delta
+-	SemanticTokensRange(context.Context, *SemanticTokensRangeParams) (*SemanticTokens, error)                    // textDocument/semanticTokens/range
+-	SignatureHelp(context.Context, *SignatureHelpParams) (*SignatureHelp, error)                                 // textDocument/signatureHelp
+-	TypeDefinition(context.Context, *TypeDefinitionParams) ([]Location, error)                                   // textDocument/typeDefinition
+-	WillSave(context.Context, *WillSaveTextDocumentParams) error                                                 // textDocument/willSave
+-	WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error)                          // textDocument/willSaveWaitUntil
+-	Subtypes(context.Context, *TypeHierarchySubtypesParams) ([]TypeHierarchyItem, error)                         // typeHierarchy/subtypes
+-	Supertypes(context.Context, *TypeHierarchySupertypesParams) ([]TypeHierarchyItem, error)                     // typeHierarchy/supertypes
+-	WorkDoneProgressCancel(context.Context, *WorkDoneProgressCancelParams) error                                 // window/workDoneProgress/cancel
+-	DiagnosticWorkspace(context.Context, *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error)         // workspace/diagnostic
+-	DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error                                 // workspace/didChangeConfiguration
+-	DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error                                   // workspace/didChangeWatchedFiles
+-	DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error                           // workspace/didChangeWorkspaceFolders
+-	DidCreateFiles(context.Context, *CreateFilesParams) error                                                    // workspace/didCreateFiles
+-	DidDeleteFiles(context.Context, *DeleteFilesParams) error                                                    // workspace/didDeleteFiles
+-	DidRenameFiles(context.Context, *RenameFilesParams) error                                                    // workspace/didRenameFiles
+-	ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error)                                  // workspace/executeCommand
+-	Symbol(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error)                                 // workspace/symbol
+-	WillCreateFiles(context.Context, *CreateFilesParams) (*WorkspaceEdit, error)                                 // workspace/willCreateFiles
+-	WillDeleteFiles(context.Context, *DeleteFilesParams) (*WorkspaceEdit, error)                                 // workspace/willDeleteFiles
+-	WillRenameFiles(context.Context, *RenameFilesParams) (*WorkspaceEdit, error)                                 // workspace/willRenameFiles
+-	ResolveWorkspaceSymbol(context.Context, *WorkspaceSymbol) (*WorkspaceSymbol, error)                          // workspaceSymbol/resolve
 -	NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error)
 -}
 -
@@ -57947,6 +64110,16 @@
 -			return true, reply(ctx, nil, err)
 -		}
 -		return true, reply(ctx, resp, nil)
+-	case "textDocument/inlineCompletion":
+-		var params InlineCompletionParams
+-		if err := json.Unmarshal(r.Params(), &params); err != nil {
+-			return true, sendParseError(ctx, reply, err)
+-		}
+-		resp, err := server.InlineCompletion(ctx, &params)
+-		if err != nil {
+-			return true, reply(ctx, nil, err)
+-		}
+-		return true, reply(ctx, resp, nil)
 -	case "textDocument/inlineValue":
 -		var params InlineValueParams
 -		if err := json.Unmarshal(r.Params(), &params); err != nil {
@@ -58027,6 +64200,16 @@
 -			return true, reply(ctx, nil, err)
 -		}
 -		return true, reply(ctx, resp, nil)
+-	case "textDocument/rangesFormatting":
+-		var params DocumentRangesFormattingParams
+-		if err := json.Unmarshal(r.Params(), &params); err != nil {
+-			return true, sendParseError(ctx, reply, err)
+-		}
+-		resp, err := server.RangesFormatting(ctx, &params)
+-		if err != nil {
+-			return true, reply(ctx, nil, err)
+-		}
+-		return true, reply(ctx, resp, nil)
 -	case "textDocument/references":
 -		var params ReferenceParams
 -		if err := json.Unmarshal(r.Params(), &params); err != nil {
@@ -58475,6 +64658,13 @@
 -	}
 -	return result, nil
 -}
+-func (s *serverDispatcher) InlineCompletion(ctx context.Context, params *InlineCompletionParams) (*Or_Result_textDocument_inlineCompletion, error) {
+-	var result *Or_Result_textDocument_inlineCompletion
+-	if err := s.sender.Call(ctx, "textDocument/inlineCompletion", params, &result); err != nil {
+-		return nil, err
+-	}
+-	return result, nil
+-}
 -func (s *serverDispatcher) InlineValue(ctx context.Context, params *InlineValueParams) ([]InlineValue, error) {
 -	var result []InlineValue
 -	if err := s.sender.Call(ctx, "textDocument/inlineValue", params, &result); err != nil {
@@ -58531,6 +64721,13 @@
 -	}
 -	return result, nil
 -}
+-func (s *serverDispatcher) RangesFormatting(ctx context.Context, params *DocumentRangesFormattingParams) ([]TextEdit, error) {
+-	var result []TextEdit
+-	if err := s.sender.Call(ctx, "textDocument/rangesFormatting", params, &result); err != nil {
+-		return nil, err
+-	}
+-	return result, nil
+-}
 -func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) {
 -	var result []Location
 -	if err := s.sender.Call(ctx, "textDocument/references", params, &result); err != nil {
@@ -58688,21 +64885,10 @@
 -	}
 -	return result, nil
 -}
-diff -urN a/gopls/internal/lsp/README.md b/gopls/internal/lsp/README.md
---- a/gopls/internal/lsp/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
--# lsp
--
--internal/lsp provides much of the Language Server Protocol (lsp) implementation
--for gopls.
--
--Documentation for users and contributors can be found in the
--[`gopls/doc`](../../gopls/doc) directory.
 diff -urN a/gopls/internal/lsp/references.go b/gopls/internal/lsp/references.go
 --- a/gopls/internal/lsp/references.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/references.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,25 +0,0 @@
++++ b/gopls/internal/lsp/references.go	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -58715,22 +64901,33 @@
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
--func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) {
+-func (s *Server) references(ctx context.Context, params *protocol.ReferenceParams) (_ []protocol.Location, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("references")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
+-	ctx, done := event.Start(ctx, "lsp.Server.references", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
 -	defer release()
 -	if !ok {
 -		return nil, err
 -	}
--	if snapshot.View().FileKind(fh) == source.Tmpl {
+-	if snapshot.FileKind(fh) == source.Tmpl {
 -		return template.References(ctx, snapshot, fh, params)
 -	}
 -	return source.References(ctx, snapshot, fh, params.Position, params.Context.IncludeDeclaration)
 -}
 diff -urN a/gopls/internal/lsp/regtest/doc.go b/gopls/internal/lsp/regtest/doc.go
 --- a/gopls/internal/lsp/regtest/doc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/doc.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/regtest/doc.go	1970-01-01 08:00:00
 @@ -1,157 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -58891,8 +65088,8 @@
 -package regtest
 diff -urN a/gopls/internal/lsp/regtest/env.go b/gopls/internal/lsp/regtest/env.go
 --- a/gopls/internal/lsp/regtest/env.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/env.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,391 +0,0 @@
++++ b/gopls/internal/lsp/regtest/env.go	1970-01-01 08:00:00
+@@ -1,403 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -58964,6 +65161,7 @@
 -		OnLogMessage:             a.onLogMessage,
 -		OnWorkDoneProgressCreate: a.onWorkDoneProgressCreate,
 -		OnProgress:               a.onProgress,
+-		OnShowDocument:           a.onShowDocument,
 -		OnShowMessage:            a.onShowMessage,
 -		OnShowMessageRequest:     a.onShowMessageRequest,
 -		OnRegisterCapability:     a.onRegisterCapability,
@@ -58977,6 +65175,7 @@
 -	// diagnostics are a map of relative path->diagnostics params
 -	diagnostics        map[string]*protocol.PublishDiagnosticsParams
 -	logs               []*protocol.LogMessageParams
+-	showDocument       []*protocol.ShowDocumentParams
 -	showMessage        []*protocol.ShowMessageParams
 -	showMessageRequest []*protocol.ShowMessageRequestParams
 -
@@ -59096,6 +65295,15 @@
 -	return nil
 -}
 -
+-func (a *Awaiter) onShowDocument(_ context.Context, params *protocol.ShowDocumentParams) error {
+-	a.mu.Lock()
+-	defer a.mu.Unlock()
+-
+-	a.state.showDocument = append(a.state.showDocument, params)
+-	a.checkConditionsLocked()
+-	return nil
+-}
+-
 -func (a *Awaiter) onShowMessage(_ context.Context, m *protocol.ShowMessageParams) error {
 -	a.mu.Lock()
 -	defer a.mu.Unlock()
@@ -59237,6 +65445,7 @@
 -// unmeetable. If it was met, OnceMet checks that the state meets all
 -// expectations in mustMeets.
 -func (e *Env) OnceMet(precondition Expectation, mustMeets ...Expectation) {
+-	e.T.Helper()
 -	e.Await(OnceMet(precondition, mustMeets...))
 -}
 -
@@ -59286,7 +65495,7 @@
 -}
 diff -urN a/gopls/internal/lsp/regtest/env_test.go b/gopls/internal/lsp/regtest/env_test.go
 --- a/gopls/internal/lsp/regtest/env_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/env_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/regtest/env_test.go	1970-01-01 08:00:00
 @@ -1,66 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -59356,8 +65565,8 @@
 -}
 diff -urN a/gopls/internal/lsp/regtest/expectation.go b/gopls/internal/lsp/regtest/expectation.go
 --- a/gopls/internal/lsp/regtest/expectation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/expectation.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,769 +0,0 @@
++++ b/gopls/internal/lsp/regtest/expectation.go	1970-01-01 08:00:00
+@@ -1,807 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -59370,6 +65579,7 @@
 -	"sort"
 -	"strings"
 -
+-	"github.com/google/go-cmp/cmp"
 -	"golang.org/x/tools/gopls/internal/lsp"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -)
@@ -59465,6 +65675,26 @@
 -	return strings.Join(descriptions, "\n")
 -}
 -
+-// Not inverts the sense of an expectation: a met expectation is unmet, and an
+-// unmet expectation is met.
+-func Not(e Expectation) Expectation {
+-	check := func(s State) Verdict {
+-		switch v := e.Check(s); v {
+-		case Met:
+-			return Unmet
+-		case Unmet, Unmeetable:
+-			return Met
+-		default:
+-			panic(fmt.Sprintf("unexpected verdict %v", v))
+-		}
+-	}
+-	description := describeExpectations(e)
+-	return Expectation{
+-		Check:       check,
+-		Description: fmt.Sprintf("not: %s", description),
+-	}
+-}
+-
 -// AnyOf returns an expectation that is satisfied when any of the given
 -// expectations is met.
 -func AnyOf(anyOf ...Expectation) Expectation {
@@ -59551,18 +65781,20 @@
 -	}
 -}
 -
--// NoOutstandingWork asserts that there is no work initiated using the LSP
--// $/progress API that has not completed.
--func NoOutstandingWork() Expectation {
+-// ShownDocument asserts that the client has received a
+-// ShowDocumentRequest for the given URI.
+-func ShownDocument(uri protocol.URI) Expectation {
 -	check := func(s State) Verdict {
--		if len(s.outstandingWork()) == 0 {
--			return Met
+-		for _, params := range s.showDocument {
+-			if params.URI == uri {
+-				return Met
+-			}
 -		}
 -		return Unmet
 -	}
 -	return Expectation{
 -		Check:       check,
--		Description: "no outstanding work",
+-		Description: fmt.Sprintf("received window/showDocument for URI %s", uri),
 -	}
 -}
 -
@@ -59595,30 +65827,28 @@
 -	}
 -	return Expectation{
 -		Check:       check,
--		Description: "received ShowMessage",
+-		Description: fmt.Sprintf("received window/showMessage containing %q", containing),
 -	}
 -}
 -
--// ShowMessageRequest asserts that the editor has received a ShowMessageRequest
--// with an action item that has the given title.
--func ShowMessageRequest(title string) Expectation {
+-// ShownMessageRequest asserts that the editor has received a
+-// ShowMessageRequest with message matching the given regular expression.
+-func ShownMessageRequest(messageRegexp string) Expectation {
+-	msgRE := regexp.MustCompile(messageRegexp)
 -	check := func(s State) Verdict {
 -		if len(s.showMessageRequest) == 0 {
 -			return Unmet
 -		}
--		// Only check the most recent one.
--		m := s.showMessageRequest[len(s.showMessageRequest)-1]
--		if len(m.Actions) == 0 || len(m.Actions) > 1 {
--			return Unmet
--		}
--		if m.Actions[0].Title == title {
--			return Met
+-		for _, m := range s.showMessageRequest {
+-			if msgRE.MatchString(m.Message) {
+-				return Met
+-			}
 -		}
 -		return Unmet
 -	}
 -	return Expectation{
 -		Check:       check,
--		Description: "received ShowMessageRequest",
+-		Description: fmt.Sprintf("ShowMessageRequest matching %q", messageRegexp),
 -	}
 -}
 -
@@ -59634,11 +65864,12 @@
 -func (e *Env) DoneDiagnosingChanges() Expectation {
 -	stats := e.Editor.Stats()
 -	statsBySource := map[lsp.ModificationSource]uint64{
--		lsp.FromDidOpen:               stats.DidOpen,
--		lsp.FromDidChange:             stats.DidChange,
--		lsp.FromDidSave:               stats.DidSave,
--		lsp.FromDidChangeWatchedFiles: stats.DidChangeWatchedFiles,
--		lsp.FromDidClose:              stats.DidClose,
+-		lsp.FromDidOpen:                stats.DidOpen,
+-		lsp.FromDidChange:              stats.DidChange,
+-		lsp.FromDidSave:                stats.DidSave,
+-		lsp.FromDidChangeWatchedFiles:  stats.DidChangeWatchedFiles,
+-		lsp.FromDidClose:               stats.DidClose,
+-		lsp.FromDidChangeConfiguration: stats.DidChangeConfiguration,
 -	}
 -
 -	var expected []lsp.ModificationSource
@@ -59817,6 +66048,46 @@
 -	}
 -}
 -
+-// NoOutstandingWork asserts that there is no work initiated using the LSP
+-// $/progress API that has not completed.
+-//
+-// If non-nil, the ignore func is used to ignore certain work items for the
+-// purpose of this check.
+-//
+-// TODO(rfindley): consider refactoring to treat outstanding work the same way
+-// we treat diagnostics: with an algebra of filters.
+-func NoOutstandingWork(ignore func(title, msg string) bool) Expectation {
+-	check := func(s State) Verdict {
+-		for _, w := range s.work {
+-			if w.complete {
+-				continue
+-			}
+-			if w.title == "" {
+-				// A token that has been created but not yet used.
+-				//
+-				// TODO(rfindley): this should be separated in the data model: until
+-				// the "begin" notification, work should not be in progress.
+-				continue
+-			}
+-			if ignore(w.title, w.msg) {
+-				continue
+-			}
+-			return Unmet
+-		}
+-		return Met
+-	}
+-	return Expectation{
+-		Check:       check,
+-		Description: "no outstanding work",
+-	}
+-}
+-
+-// IgnoreTelemetryPromptWork may be used in conjunction with NoOutStandingWork
+-// to ignore the telemetry prompt.
+-func IgnoreTelemetryPromptWork(title, msg string) bool {
+-	return title == lsp.TelemetryPromptWorkTitle
+-}
+-
 -// NoErrorLogs asserts that the client has not received any log messages of
 -// error severity.
 -func NoErrorLogs() Expectation {
@@ -59829,6 +66100,10 @@
 -// The count argument specifies the expected number of matching logs. If
 -// atLeast is set, this is a lower bound, otherwise there must be exactly count
 -// matching logs.
+-//
+-// Logs are asynchronous to other LSP messages, so this expectation should not
+-// be used with combinators such as OnceMet or AfterChange that assert on
+-// ordering with respect to other operations.
 -func LogMatching(typ protocol.MessageType, re string, count int, atLeast bool) Expectation {
 -	rec, err := regexp.Compile(re)
 -	if err != nil {
@@ -59845,6 +66120,11 @@
 -		if found == count || (found >= count && atLeast) {
 -			return Met
 -		}
+-		// If we require an exact count, and have received more than expected, the
+-		// expectation can never be met.
+-		if found > count && !atLeast {
+-			return Unmeetable
+-		}
 -		return Unmet
 -	}
 -	desc := fmt.Sprintf("log message matching %q expected %v times", re, count)
@@ -59936,50 +66216,6 @@
 -	return jsonProperty(m[path[0]], path[1:]...)
 -}
 -
--// RegistrationMatching asserts that the client has received a capability
--// registration matching the given regexp.
--//
--// TODO(rfindley): remove this once TestWatchReplaceTargets has been revisited.
--//
--// Deprecated: use (No)FileWatchMatching
--func RegistrationMatching(re string) Expectation {
--	rec := regexp.MustCompile(re)
--	check := func(s State) Verdict {
--		for _, p := range s.registrations {
--			for _, r := range p.Registrations {
--				if rec.Match([]byte(r.Method)) {
--					return Met
--				}
--			}
--		}
--		return Unmet
--	}
--	return Expectation{
--		Check:       check,
--		Description: fmt.Sprintf("registration matching %q", re),
--	}
--}
--
--// UnregistrationMatching asserts that the client has received an
--// unregistration whose ID matches the given regexp.
--func UnregistrationMatching(re string) Expectation {
--	rec := regexp.MustCompile(re)
--	check := func(s State) Verdict {
--		for _, p := range s.unregistrations {
--			for _, r := range p.Unregisterations {
--				if rec.Match([]byte(r.Method)) {
--					return Met
--				}
--			}
--		}
--		return Unmet
--	}
--	return Expectation{
--		Check:       check,
--		Description: fmt.Sprintf("unregistration matching %q", re),
--	}
--}
--
 -// Diagnostics asserts that there is at least one diagnostic matching the given
 -// filters.
 -func Diagnostics(filters ...DiagnosticFilter) Expectation {
@@ -60127,10 +66363,21 @@
 -		},
 -	}
 -}
+-
+-// WithSeverityTags filters to diagnostics whose severity and tags match
+-// the given expectation.
+-func WithSeverityTags(diagName string, severity protocol.DiagnosticSeverity, tags []protocol.DiagnosticTag) DiagnosticFilter {
+-	return DiagnosticFilter{
+-		desc: fmt.Sprintf("with diagnostic %q with severity %q and tag %#q", diagName, severity, tags),
+-		check: func(_ string, d protocol.Diagnostic) bool {
+-			return d.Source == diagName && d.Severity == severity && cmp.Equal(d.Tags, tags)
+-		},
+-	}
+-}
 diff -urN a/gopls/internal/lsp/regtest/marker.go b/gopls/internal/lsp/regtest/marker.go
 --- a/gopls/internal/lsp/regtest/marker.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/marker.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1273 +0,0 @@
++++ b/gopls/internal/lsp/regtest/marker.go	1970-01-01 08:00:00
+@@ -1,2227 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -60144,16 +66391,20 @@
 -	"flag"
 -	"fmt"
 -	"go/token"
+-	"go/types"
 -	"io/fs"
+-	"log"
 -	"os"
 -	"path"
 -	"path/filepath"
 -	"reflect"
 -	"regexp"
+-	"runtime"
 -	"sort"
 -	"strings"
 -	"testing"
 -
+-	"github.com/google/go-cmp/cmp"
 -	"golang.org/x/tools/go/expect"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/cache"
@@ -60174,6 +66425,11 @@
 -var update = flag.Bool("update", false, "if set, update test data during marker tests")
 -
 -// RunMarkerTests runs "marker" tests in the given test data directory.
+-// (In practice: ../../regtest/marker/testdata)
+-//
+-// Use this command to run the tests:
+-//
+-//	$ go test ./gopls/internal/regtest/marker [-update]
 -//
 -// A marker test uses the '//@' marker syntax of the x/tools/go/expect package
 -// to annotate source code with various information such as locations and
@@ -60223,14 +66479,28 @@
 -//
 -// # Special files
 -//
--// There are three types of file within the test archive that are given special
+-// There are several types of file within the test archive that are given special
 -// treatment by the test runner:
+-//   - "skip": the presence of this file causes the test to be skipped, with
+-//     the file content used as the skip message.
 -//   - "flags": this file is treated as a whitespace-separated list of flags
--//     that configure the MarkerTest instance. For example, -min_go=go1.18 sets
--//     the minimum required Go version for the test.
+-//     that configure the MarkerTest instance. Supported flags:
+-//     -min_go=go1.18 sets the minimum Go version for the test;
+-//     -cgo requires that CGO_ENABLED is set and the cgo tool is available
+-//     -write_sumfile=a,b,c instructs the test runner to generate go.sum files
+-//     in these directories before running the test.
+-//     -skip_goos=a,b,c instructs the test runner to skip the test for the
+-//     listed GOOS values.
+-//     -ignore_extra_diags suppresses errors for unmatched diagnostics
+-//     TODO(rfindley): using build constraint expressions for -skip_goos would
+-//     be clearer.
 -//     TODO(rfindley): support flag values containing whitespace.
 -//   - "settings.json": this file is parsed as JSON, and used as the
 -//     session configuration (see gopls/doc/settings.md)
+-//   - "capabilities.json": this file is parsed as JSON client capabilities,
+-//     and applied as an overlay over the default editor client capabilities.
+-//     see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#clientCapabilities
+-//     for more details.
 -//   - "env": this file is parsed as a list of VAR=VALUE fields specifying the
 -//     editor environment.
 -//   - Golden files: Within the archive, file names starting with '@' are
@@ -60240,22 +66510,88 @@
 -//     Foo were of type *Golden, the test runner would convert the identifier a
 -//     in the call @foo(a, "b", 3) into a *Golden by collecting golden file
 -//     data starting with "@a/".
+-//   - proxy files: any file starting with proxy/ is treated as a Go proxy
+-//     file. If present, these files are written to a separate temporary
+-//     directory and GOPROXY is set to file://<proxy directory>.
 -//
 -// # Marker types
 -//
+-// Markers are of two kinds. A few are "value markers" (e.g. @item), which are
+-// processed in a first pass and each computes a value that may be referred to
+-// by name later. Most are "action markers", which are processed in a second
+-// pass and take some action such as testing an LSP operation; they may refer
+-// to values computed by value markers.
+-//
 -// The following markers are supported within marker tests:
 -//
+-//   - acceptcompletion(location, label, golden): specifies that accepting the
+-//     completion candidate produced at the given location with provided label
+-//     results in the given golden state.
+-//
+-//   - codeaction(kind, start, end, golden): specifies a codeaction to request
+-//     for the given range. To support multi-line ranges, the range is defined
+-//     to be between start.Start and end.End. The golden directory contains
+-//     changed file content after the code action is applied.
+-//
+-//   - codeactionerr(kind, start, end, wantError): specifies a codeaction that
+-//     fails with an error that matches the expectation.
+-//
+-//   - codelens(location, title): specifies that a codelens is expected at the
+-//     given location, with given title. Must be used in conjunction with
+-//     @codelenses.
+-//
+-//   - codelenses(): specifies that textDocument/codeLens should be run for the
+-//     current document, with results compared to the @codelens annotations in
+-//     the current document.
+-//
+-//   - complete(location, ...items): specifies expected completion results at
+-//     the given location. Must be used in conjunction with @item.
+-//
 -//   - diag(location, regexp): specifies an expected diagnostic matching the
 -//     given regexp at the given location. The test runner requires
--//     a 1:1 correspondence between observed diagnostics and diag annotations
+-//     a 1:1 correspondence between observed diagnostics and diag annotations.
+-//     The diagnostics source and kind fields are ignored, to reduce fuss.
+-//
+-//     The specified location must match the start position of the diagnostic,
+-//     but end positions are ignored.
+-//
+-//     TODO(adonovan): in the older marker framework, the annotation asserted
+-//     two additional fields (source="compiler", kind="error"). Restore them?
 -//
 -//   - def(src, dst location): perform a textDocument/definition request at
--//     the src location, and check the the result points to the dst location.
+-//     the src location, and check the result points to the dst location.
+-//
+-//   - foldingrange(golden): perform a textDocument/foldingRange for the
+-//     current document, and compare with the golden content, which is the
+-//     original source annotated with numbered tags delimiting the resulting
+-//     ranges (e.g. <1 kind="..."> ... </1>).
+-//
+-//   - format(golden): perform a textDocument/format request for the enclosing
+-//     file, and compare against the named golden file. If the formatting
+-//     request succeeds, the golden file must contain the resulting formatted
+-//     source. If the formatting request fails, the golden file must contain
+-//     the error message.
+-//
+-//   - highlight(src location, dsts ...location): makes a
+-//     textDocument/highlight request at the given src location, which should
+-//     highlight the provided dst locations.
 -//
 -//   - hover(src, dst location, g Golden): perform a textDocument/hover at the
 -//     src location, and checks that the result is the dst location, with hover
 -//     content matching "hover.md" in the golden data g.
 -//
+-//   - implementations(src location, want ...location): makes a
+-//     textDocument/implementation query at the src location and
+-//     checks that the resulting set of locations matches want.
+-//
+-//   - item(label, details, kind): defines a completion item with the provided
+-//     fields. This information is not positional, and therefore @item markers
+-//     may occur anywhere in the source. Used in conjunction with @complete,
+-//     snippet, or rank.
+-//
+-//     TODO(rfindley): rethink whether floating @item annotations are the best
+-//     way to specify completion results.
+-//
 -//   - loc(name, location): specifies the name for a location in the source. These
 -//     locations may be referenced by other markers.
 -//
@@ -60272,6 +66608,47 @@
 -//     This action is executed for its editing effects on the source files.
 -//     Like rename, the golden directory contains the expected transformed files.
 -//
+-//   - rank(location, ...completionItem): executes a textDocument/completion
+-//     request at the given location, and verifies that each expected
+-//     completion item occurs in the results, in the expected order. Other
+-//     unexpected completion items may occur in the results.
+-//     TODO(rfindley): this exists for compatibility with the old marker tests.
+-//     Replace this with rankl, and rename.
+-//
+-//   - rankl(location, ...label): like rank, but only cares about completion
+-//     item labels.
+-//
+-//   - refs(location, want ...location): executes a textDocument/references
+-//     request at the first location and asserts that the result is the set of
+-//     'want' locations. The first want location must be the declaration
+-//     (assumedly unique).
+-//
+-//   - snippet(location, completionItem, snippet): executes a
+-//     textDocument/completion request at the location, and searches for a
+-//     result with label matching that of the provided completion item
+-//     (TODO(rfindley): accept a label rather than a completion item). Check
+-//     the the result snippet matches the provided snippet.
+-//
+-//   - symbol(golden): makes a textDocument/documentSymbol request
+-//     for the enclosing file, formats the response with one symbol
+-//     per line, sorts it, and compares against the named golden file.
+-//     Each line is of the form:
+-//
+-//     dotted.symbol.name kind "detail" +n lines
+-//
+-//     where the "+n lines" part indicates that the declaration spans
+-//     several lines. The test otherwise makes no attempt to check
+-//     location information. There is no point to using more than one
+-//     @symbol marker in a given file.
+-//
+-//   - workspacesymbol(query, golden): makes a workspace/symbol request for the
+-//     given query, formats the response with one symbol per line, and compares
+-//     against the named golden file. As workspace symbols are by definition a
+-//     workspace-wide request, the location of the workspace symbol marker does
+-//     not matter. Each line is of the form:
+-//
+-//     location name kind
+-//
 -// # Argument conversion
 -//
 -// Marker arguments are first parsed by the go/expect package, which accepts
@@ -60357,36 +66734,30 @@
 -// internal/lsp/tests.
 -//
 -// Remaining TODO:
--//   - parallelize/optimize test execution
+-//   - optimize test execution
 -//   - reorganize regtest packages (and rename to just 'test'?)
 -//   - Rename the files .txtar.
+-//   - Provide some means by which locations in the standard library
+-//     (or builtin.go) can be named, so that, for example, we can we
+-//     can assert that MyError implements the built-in error type.
 -//
--// Existing marker tests to port:
+-// Existing marker tests (in ../testdata) to port:
 -//   - CallHierarchy
--//   - CodeLens
 -//   - Diagnostics
 -//   - CompletionItems
 -//   - Completions
 -//   - CompletionSnippets
--//   - UnimportedCompletions
 -//   - DeepCompletions
 -//   - FuzzyCompletions
 -//   - CaseSensitiveCompletions
 -//   - RankCompletions
--//   - FoldingRanges
 -//   - Formats
 -//   - Imports
 -//   - SemanticTokens
--//   - SuggestedFixes
 -//   - FunctionExtractions
 -//   - MethodExtractions
--//   - Definitions
--//   - Implementations
--//   - Highlights
--//   - References
 -//   - Renames
 -//   - PrepareRenames
--//   - Symbols
 -//   - InlayHints
 -//   - WorkspaceSymbols
 -//   - Signatures
@@ -60407,7 +66778,18 @@
 -	cache := cache.New(nil)
 -
 -	for _, test := range tests {
+-		test := test
 -		t.Run(test.name, func(t *testing.T) {
+-			t.Parallel()
+-			if test.skipReason != "" {
+-				t.Skip(test.skipReason)
+-			}
+-			for _, goos := range test.skipGOOS {
+-				if runtime.GOOS == goos {
+-					t.Skipf("skipping on %s due to -skip_goos", runtime.GOOS)
+-				}
+-			}
+-
 -			// TODO(rfindley): it may be more useful to have full support for build
 -			// constraints.
 -			if test.minGoVersion != "" {
@@ -60415,18 +66797,31 @@
 -				if _, err := fmt.Sscanf(test.minGoVersion, "go1.%d", &go1point); err != nil {
 -					t.Fatalf("parsing -min_go version: %v", err)
 -				}
--				testenv.NeedsGo1Point(t, 18)
+-				testenv.NeedsGo1Point(t, go1point)
+-			}
+-			if test.cgo {
+-				testenv.NeedsTool(t, "cgo")
 -			}
 -			config := fake.EditorConfig{
--				Settings: test.settings,
--				Env:      test.env,
+-				Settings:         test.settings,
+-				CapabilitiesJSON: test.capabilities,
+-				Env:              test.env,
 -			}
--			run := &markerTestRun{
--				test: test,
--				env:  newEnv(t, cache, test.files, config),
+-			if _, ok := config.Settings["diagnosticsDelay"]; !ok {
+-				if config.Settings == nil {
+-					config.Settings = make(map[string]any)
+-				}
+-				config.Settings["diagnosticsDelay"] = "10ms"
+-			}
+-			// inv: config.Settings != nil
 -
--				locations: make(map[expect.Identifier]protocol.Location),
--				diags:     make(map[protocol.Location][]protocol.Diagnostic),
+-			run := &markerTestRun{
+-				test:       test,
+-				env:        newEnv(t, cache, test.files, test.proxyFiles, test.writeGoSum, config),
+-				settings:   config.Settings,
+-				values:     make(map[expect.Identifier]any),
+-				diags:      make(map[protocol.Location][]protocol.Diagnostic),
+-				extraNotes: make(map[protocol.DocumentURI]map[string][]*expect.Note),
 -			}
 -			// TODO(rfindley): make it easier to clean up the regtest environment.
 -			defer run.env.Editor.Shutdown(context.Background()) // ignore error
@@ -60440,19 +66835,6 @@
 -			for file := range test.files {
 -				run.env.OpenFile(file)
 -			}
--
--			// Pre-process locations.
--			var markers []marker
--			for _, note := range test.notes {
--				mark := marker{run: run, note: note}
--				switch note.Name {
--				case "loc":
--					mark.execute()
--				default:
--					markers = append(markers, mark)
--				}
--			}
--
 -			// Wait for the didOpen notifications to be processed, then collect
 -			// diagnostics.
 -			var diags map[string]*protocol.PublishDiagnosticsParams
@@ -60461,22 +66843,52 @@
 -				uri := run.env.Sandbox.Workdir.URI(path)
 -				for _, diag := range params.Diagnostics {
 -					loc := protocol.Location{
--						URI:   uri,
--						Range: diag.Range,
+-						URI: uri,
+-						Range: protocol.Range{
+-							Start: diag.Range.Start,
+-							End:   diag.Range.Start, // ignore end positions
+-						},
 -					}
 -					run.diags[loc] = append(run.diags[loc], diag)
 -				}
 -			}
 -
+-			var markers []marker
+-			for _, note := range test.notes {
+-				mark := marker{run: run, note: note}
+-				if fn, ok := valueMarkerFuncs[note.Name]; ok {
+-					fn(mark)
+-				} else if _, ok := actionMarkerFuncs[note.Name]; ok {
+-					markers = append(markers, mark) // save for later
+-				} else {
+-					uri := mark.uri()
+-					if run.extraNotes[uri] == nil {
+-						run.extraNotes[uri] = make(map[string][]*expect.Note)
+-					}
+-					run.extraNotes[uri][note.Name] = append(run.extraNotes[uri][note.Name], note)
+-				}
+-			}
+-
 -			// Invoke each remaining marker in the test.
 -			for _, mark := range markers {
--				mark.execute()
+-				actionMarkerFuncs[mark.note.Name](mark)
 -			}
 -
 -			// Any remaining (un-eliminated) diagnostics are an error.
--			for loc, diags := range run.diags {
--				for _, diag := range diags {
--					t.Errorf("%s: unexpected diagnostic: %q", run.fmtLoc(loc), diag.Message)
+-			if !test.ignoreExtraDiags {
+-				for loc, diags := range run.diags {
+-					for _, diag := range diags {
+-						t.Errorf("%s: unexpected diagnostic: %q", run.fmtLoc(loc), diag.Message)
+-					}
+-				}
+-			}
+-
+-			// TODO(rfindley): use these for whole-file marker tests.
+-			for uri, extras := range run.extraNotes {
+-				for name, extra := range extras {
+-					if len(extra) > 0 {
+-						t.Errorf("%s: %d unused %q markers", run.env.Sandbox.Workdir.URIToPath(uri), len(extra), name)
+-					}
 -				}
 -			}
 -
@@ -60505,6 +66917,10 @@
 -			}
 -		})
 -	}
+-
+-	if abs, err := filepath.Abs(dir); err == nil && t.Failed() {
+-		t.Logf("(Filenames are relative to %s.)", abs)
+-	}
 -}
 -
 -// A marker holds state for the execution of a single @marker
@@ -60514,9 +66930,16 @@
 -	note *expect.Note
 -}
 -
+-// server returns the LSP server for the marker test run.
+-func (m marker) server() protocol.Server {
+-	return m.run.env.Editor.Server
+-}
+-
 -// errorf reports an error with a prefix indicating the position of the marker note.
--func (mark marker) errorf(format string, args ...interface{}) {
--	msg := fmt.Sprintf(format, args...)
+-//
+-// It formats the error message using mark.sprintf.
+-func (mark marker) errorf(format string, args ...any) {
+-	msg := mark.sprintf(format, args...)
 -	// TODO(adonovan): consider using fmt.Fprintf(os.Stderr)+t.Fail instead of
 -	// t.Errorf to avoid reporting uninteresting positions in the Go source of
 -	// the driver. However, this loses the order of stderr wrt "FAIL: TestFoo"
@@ -60524,56 +66947,164 @@
 -	mark.run.env.T.Errorf("%s: %s", mark.run.fmtPos(mark.note.Pos), msg)
 -}
 -
--// execute invokes the marker's function with the arguments from note.
--func (mark marker) execute() {
--	fn, ok := markerFuncs[mark.note.Name]
--	if !ok {
--		mark.errorf("no marker function named %s", mark.note.Name)
--		return
+-// valueMarkerFunc returns a wrapper around a function that allows it to be
+-// called during the processing of value markers (e.g. @value(v, 123)) with marker
+-// arguments converted to function parameters. The provided function's first
+-// parameter must be of type 'marker', and it must return a value.
+-//
+-// Unlike action markers, which are executed for actions such as test
+-// assertions, value markers are all evaluated first, and each computes
+-// a value that is recorded by its identifier, which is the marker's first
+-// argument. These values may be referred to from an action marker by
+-// this identifier, e.g. @action(... , v, ...).
+-//
+-// For example, given a fn with signature
+-//
+-//	func(mark marker, label, details, kind string) CompletionItem
+-//
+-// The result of valueMarkerFunc can associated with @item notes, and invoked
+-// as follows:
+-//
+-//	//@item(FooCompletion, "Foo", "func() int", "func")
+-//
+-// The provided fn should not mutate the test environment.
+-func valueMarkerFunc(fn any) func(marker) {
+-	ftype := reflect.TypeOf(fn)
+-	if ftype.NumIn() == 0 || ftype.In(0) != markerType {
+-		panic(fmt.Sprintf("value marker function %#v must accept marker as its first argument", ftype))
+-	}
+-	if ftype.NumOut() != 1 {
+-		panic(fmt.Sprintf("value marker function %#v must have exactly 1 result", ftype))
 -	}
 -
--	// The first converter corresponds to the *Env argument.
--	// All others must be converted from the marker syntax.
--	if got, want := len(mark.note.Args), len(fn.converters); got != want {
--		mark.errorf("got %d arguments to %s, expect %d", got, mark.note.Name, want)
--		return
--	}
--
--	args := []reflect.Value{reflect.ValueOf(mark)}
--	for i, in := range mark.note.Args {
--		// Special handling for the blank identifier: treat it as the zero
--		// value.
--		if ident, ok := in.(expect.Identifier); ok && ident == "_" {
--			zero := reflect.Zero(fn.paramTypes[i])
--			args = append(args, zero)
--			continue
--		}
--		out, err := fn.converters[i](mark, in)
--		if err != nil {
--			mark.errorf("converting argument #%d of %s (%v): %v", i, mark.note.Name, in, err)
+-	return func(mark marker) {
+-		if len(mark.note.Args) == 0 || !is[expect.Identifier](mark.note.Args[0]) {
+-			mark.errorf("first argument to a value marker function must be an identifier")
 -			return
 -		}
--		args = append(args, reflect.ValueOf(out))
+-		id := mark.note.Args[0].(expect.Identifier)
+-		if alt, ok := mark.run.values[id]; ok {
+-			mark.errorf("%s already declared as %T", id, alt)
+-			return
+-		}
+-		args := append([]any{mark}, mark.note.Args[1:]...)
+-		argValues, err := convertArgs(mark, ftype, args)
+-		if err != nil {
+-			mark.errorf("converting args: %v", err)
+-			return
+-		}
+-		results := reflect.ValueOf(fn).Call(argValues)
+-		mark.run.values[id] = results[0].Interface()
 -	}
--
--	fn.fn.Call(args)
 -}
 -
--// Supported marker functions.
+-// actionMarkerFunc returns a wrapper around a function that allows it to be
+-// called during the processing of action markers (e.g. @action("abc", 123))
+-// with marker arguments converted to function parameters. The provided
+-// function's first parameter must be of type 'marker', and it must not return
+-// any values.
 -//
--// Each marker function must accept a marker as its first argument, with
--// subsequent arguments converted from the marker arguments.
--//
--// Marker funcs should not mutate the test environment (e.g. via opening files
--// or applying edits in the editor).
--var markerFuncs = map[string]markerFunc{
--	"def":          makeMarkerFunc(defMarker),
--	"diag":         makeMarkerFunc(diagMarker),
--	"hover":        makeMarkerFunc(hoverMarker),
--	"loc":          makeMarkerFunc(locMarker),
--	"rename":       makeMarkerFunc(renameMarker),
--	"renameerr":    makeMarkerFunc(renameErrMarker),
--	"suggestedfix": makeMarkerFunc(suggestedfixMarker),
+-// The provided fn should not mutate the test environment.
+-func actionMarkerFunc(fn any) func(marker) {
+-	ftype := reflect.TypeOf(fn)
+-	if ftype.NumIn() == 0 || ftype.In(0) != markerType {
+-		panic(fmt.Sprintf("action marker function %#v must accept marker as its first argument", ftype))
+-	}
+-	if ftype.NumOut() != 0 {
+-		panic(fmt.Sprintf("action marker function %#v cannot have results", ftype))
+-	}
+-
+-	return func(mark marker) {
+-		args := append([]any{mark}, mark.note.Args...)
+-		argValues, err := convertArgs(mark, ftype, args)
+-		if err != nil {
+-			mark.errorf("converting args: %v", err)
+-			return
+-		}
+-		reflect.ValueOf(fn).Call(argValues)
+-	}
+-}
+-
+-func convertArgs(mark marker, ftype reflect.Type, args []any) ([]reflect.Value, error) {
+-	var (
+-		argValues []reflect.Value
+-		pnext     int          // next param index
+-		p         reflect.Type // current param
+-	)
+-	for i, arg := range args {
+-		if i < ftype.NumIn() {
+-			p = ftype.In(pnext)
+-			pnext++
+-		} else if p == nil || !ftype.IsVariadic() {
+-			// The actual number of arguments expected by the mark varies, depending
+-			// on whether this is a value marker or an action marker.
+-			//
+-			// Since this error indicates a bug, probably OK to have an imprecise
+-			// error message here.
+-			return nil, fmt.Errorf("too many arguments to %s", mark.note.Name)
+-		}
+-		elemType := p
+-		if ftype.IsVariadic() && pnext == ftype.NumIn() {
+-			elemType = p.Elem()
+-		}
+-		var v reflect.Value
+-		if id, ok := arg.(expect.Identifier); ok && id == "_" {
+-			v = reflect.Zero(elemType)
+-		} else {
+-			a, err := convert(mark, arg, elemType)
+-			if err != nil {
+-				return nil, err
+-			}
+-			v = reflect.ValueOf(a)
+-		}
+-		argValues = append(argValues, v)
+-	}
+-	// Check that we have sufficient arguments. If the function is variadic, we
+-	// do not need arguments for the final parameter.
+-	if pnext < ftype.NumIn()-1 || pnext == ftype.NumIn()-1 && !ftype.IsVariadic() {
+-		// Same comment as above: OK to be vague here.
+-		return nil, fmt.Errorf("not enough arguments to %s", mark.note.Name)
+-	}
+-	return argValues, nil
+-}
+-
+-// is reports whether arg is a T.
+-func is[T any](arg any) bool {
+-	_, ok := arg.(T)
+-	return ok
+-}
+-
+-// Supported value marker functions. See [valueMarkerFunc] for more details.
+-var valueMarkerFuncs = map[string]func(marker){
+-	"loc":  valueMarkerFunc(locMarker),
+-	"item": valueMarkerFunc(completionItemMarker),
+-}
+-
+-// Supported action marker functions. See [actionMarkerFunc] for more details.
+-var actionMarkerFuncs = map[string]func(marker){
+-	"acceptcompletion": actionMarkerFunc(acceptCompletionMarker),
+-	"codeaction":       actionMarkerFunc(codeActionMarker),
+-	"codeactionerr":    actionMarkerFunc(codeActionErrMarker),
+-	"codelenses":       actionMarkerFunc(codeLensesMarker),
+-	"complete":         actionMarkerFunc(completeMarker),
+-	"def":              actionMarkerFunc(defMarker),
+-	"diag":             actionMarkerFunc(diagMarker),
+-	"foldingrange":     actionMarkerFunc(foldingRangeMarker),
+-	"format":           actionMarkerFunc(formatMarker),
+-	"highlight":        actionMarkerFunc(highlightMarker),
+-	"hover":            actionMarkerFunc(hoverMarker),
+-	"implementation":   actionMarkerFunc(implementationMarker),
+-	"rank":             actionMarkerFunc(rankMarker),
+-	"rankl":            actionMarkerFunc(ranklMarker),
+-	"refs":             actionMarkerFunc(refsMarker),
+-	"rename":           actionMarkerFunc(renameMarker),
+-	"renameerr":        actionMarkerFunc(renameErrMarker),
+-	"signature":        actionMarkerFunc(signatureMarker),
+-	"snippet":          actionMarkerFunc(snippetMarker),
+-	"suggestedfix":     actionMarkerFunc(suggestedfixMarker),
+-	"symbol":           actionMarkerFunc(symbolMarker),
+-	"typedef":          actionMarkerFunc(typedefMarker),
+-	"workspacesymbol":  actionMarkerFunc(workspaceSymbolMarker),
 -}
 -
 -// markerTest holds all the test data extracted from a test txtar archive.
@@ -60581,20 +67112,27 @@
 -// See the documentation for RunMarkerTests for more information on the archive
 -// format.
 -type markerTest struct {
--	name     string                 // relative path to the txtar file in the testdata dir
--	fset     *token.FileSet         // fileset used for parsing notes
--	content  []byte                 // raw test content
--	archive  *txtar.Archive         // original test archive
--	settings map[string]interface{} // gopls settings
--	env      map[string]string      // editor environment
--	files    map[string][]byte      // data files from the archive (excluding special files)
--	notes    []*expect.Note         // extracted notes from data files
--	golden   map[string]*Golden     // extracted golden content, by identifier name
+-	name         string                        // relative path to the txtar file in the testdata dir
+-	fset         *token.FileSet                // fileset used for parsing notes
+-	content      []byte                        // raw test content
+-	archive      *txtar.Archive                // original test archive
+-	settings     map[string]any                // gopls settings
+-	capabilities []byte                        // content of capabilities.json file
+-	env          map[string]string             // editor environment
+-	proxyFiles   map[string][]byte             // proxy content
+-	files        map[string][]byte             // data files from the archive (excluding special files)
+-	notes        []*expect.Note                // extracted notes from data files
+-	golden       map[expect.Identifier]*Golden // extracted golden content, by identifier name
 -
--	// flags holds flags extracted from the special "flags" archive file.
--	flags []string
+-	skipReason string   // the skip reason extracted from the "skip" archive file
+-	flags      []string // flags extracted from the special "flags" archive file.
+-
 -	// Parsed flags values.
--	minGoVersion string
+-	minGoVersion     string
+-	cgo              bool
+-	writeGoSum       []string // comma separated dirs to write go sum for
+-	skipGOOS         []string // comma separated GOOS values to skip
+-	ignoreExtraDiags bool
 -}
 -
 -// flagSet returns the flagset used for parsing the special "flags" file in the
@@ -60602,10 +67140,30 @@
 -func (t *markerTest) flagSet() *flag.FlagSet {
 -	flags := flag.NewFlagSet(t.name, flag.ContinueOnError)
 -	flags.StringVar(&t.minGoVersion, "min_go", "", "if set, the minimum go1.X version required for this test")
+-	flags.BoolVar(&t.cgo, "cgo", false, "if set, requires cgo (both the cgo tool and CGO_ENABLED=1)")
+-	flags.Var((*stringListValue)(&t.writeGoSum), "write_sumfile", "if set, write the sumfile for these directories")
+-	flags.Var((*stringListValue)(&t.skipGOOS), "skip_goos", "if set, skip this test on these GOOS values")
+-	flags.BoolVar(&t.ignoreExtraDiags, "ignore_extra_diags", false, "if set, suppress errors for unmatched diagnostics")
 -	return flags
 -}
 -
--func (t *markerTest) getGolden(id string) *Golden {
+-// stringListValue implements flag.Value.
+-type stringListValue []string
+-
+-func (l *stringListValue) Set(s string) error {
+-	if s != "" {
+-		for _, d := range strings.Split(s, ",") {
+-			*l = append(*l, strings.TrimSpace(d))
+-		}
+-	}
+-	return nil
+-}
+-
+-func (l stringListValue) String() string {
+-	return strings.Join([]string(l), ",")
+-}
+-
+-func (t *markerTest) getGolden(id expect.Identifier) *Golden {
 -	golden, ok := t.golden[id]
 -	// If there was no golden content for this identifier, we must create one
 -	// to handle the case where -update is set: we need a place to store
@@ -60627,7 +67185,7 @@
 -// When -update is set, golden captures the updated golden contents for later
 -// writing.
 -type Golden struct {
--	id      string
+-	id      expect.Identifier
 -	data    map[string][]byte // key "" => @id itself
 -	updated map[string][]byte
 -}
@@ -60670,9 +67228,6 @@
 -//
 -// See the documentation for RunMarkerTests for more details on the test data
 -// archive.
--//
--// TODO(rfindley): this test could sanity check the results. For example, it is
--// too easy to write "// @" instead of "//@", which we will happy skip silently.
 -func loadMarkerTests(dir string) ([]*markerTest, error) {
 -	var tests []*markerTest
 -	err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
@@ -60681,6 +67236,7 @@
 -			if err != nil {
 -				return err
 -			}
+-
 -			name := strings.TrimPrefix(path, dir+string(filepath.Separator))
 -			test, err := loadMarkerTest(name, content)
 -			if err != nil {
@@ -60695,16 +67251,28 @@
 -
 -func loadMarkerTest(name string, content []byte) (*markerTest, error) {
 -	archive := txtar.Parse(content)
+-	if len(archive.Files) == 0 {
+-		return nil, fmt.Errorf("txtar file has no '-- filename --' sections")
+-	}
+-	if bytes.Contains(archive.Comment, []byte("\n-- ")) {
+-		// This check is conservative, but the comment is only a comment.
+-		return nil, fmt.Errorf("ill-formed '-- filename --' header in comment")
+-	}
 -	test := &markerTest{
 -		name:    name,
 -		fset:    token.NewFileSet(),
 -		content: content,
 -		archive: archive,
 -		files:   make(map[string][]byte),
--		golden:  make(map[string]*Golden),
+-		golden:  make(map[expect.Identifier]*Golden),
 -	}
 -	for _, file := range archive.Files {
 -		switch {
+-		case file.Name == "skip":
+-			reason := strings.ReplaceAll(string(file.Data), "\n", " ")
+-			reason = strings.TrimSpace(reason)
+-			test.skipReason = reason
+-
 -		case file.Name == "flags":
 -			test.flags = strings.Fields(string(file.Data))
 -			if err := test.flagSet().Parse(test.flags); err != nil {
@@ -60716,12 +67284,14 @@
 -				return nil, err
 -			}
 -
+-		case file.Name == "capabilities.json":
+-			test.capabilities = file.Data // lazily unmarshalled by the editor
+-
 -		case file.Name == "env":
 -			test.env = make(map[string]string)
 -			fields := strings.Fields(string(file.Data))
 -			for _, field := range fields {
--				// TODO: use strings.Cut once we are on 1.18+.
--				key, value, ok := cut(field, "=")
+-				key, value, ok := strings.Cut(field, "=")
 -				if !ok {
 -					return nil, fmt.Errorf("env vars must be formatted as var=value, got %q", field)
 -				}
@@ -60729,7 +67299,8 @@
 -			}
 -
 -		case strings.HasPrefix(file.Name, "@"): // golden content
--			id, name, _ := cut(file.Name[len("@"):], "/")
+-			idstring, name, _ := strings.Cut(file.Name[len("@"):], "/")
+-			id := expect.Identifier(idstring)
 -			// Note that a file.Name of just "@id" gives (id, name) = ("id", "").
 -			if _, ok := test.golden[id]; !ok {
 -				test.golden[id] = &Golden{
@@ -60739,29 +67310,41 @@
 -			}
 -			test.golden[id].data[name] = file.Data
 -
+-		case strings.HasPrefix(file.Name, "proxy/"):
+-			name := file.Name[len("proxy/"):]
+-			if test.proxyFiles == nil {
+-				test.proxyFiles = make(map[string][]byte)
+-			}
+-			test.proxyFiles[name] = file.Data
+-
 -		default: // ordinary file content
 -			notes, err := expect.Parse(test.fset, file.Name, file.Data)
 -			if err != nil {
 -				return nil, fmt.Errorf("parsing notes in %q: %v", file.Name, err)
 -			}
+-
+-			// Reject common misspelling: "// @mark".
+-			// TODO(adonovan): permit "// @" within a string. Detect multiple spaces.
+-			if i := bytes.Index(file.Data, []byte("// @")); i >= 0 {
+-				line := 1 + bytes.Count(file.Data[:i], []byte("\n"))
+-				return nil, fmt.Errorf("%s:%d: unwanted space before marker (// @)", file.Name, line)
+-			}
+-
 -			test.notes = append(test.notes, notes...)
 -			test.files[file.Name] = file.Data
 -		}
+-
+-		// Print a warning if we see what looks like "-- filename --"
+-		// without the second "--". It's not necessarily wrong,
+-		// but it should almost never appear in our test inputs.
+-		if bytes.Contains(file.Data, []byte("\n-- ")) {
+-			log.Printf("ill-formed '-- filename --' header in %s?", file.Name)
+-		}
 -	}
 -
 -	return test, nil
 -}
 -
--// cut is a copy of strings.Cut.
--//
--// TODO: once we only support Go 1.18+, just use strings.Cut.
--func cut(s, sep string) (before, after string, found bool) {
--	if i := strings.Index(s, sep); i >= 0 {
--		return s[:i], s[i+len(sep):], true
--	}
--	return s, "", false
--}
--
 -// formatTest formats the test as a txtar archive.
 -func formatTest(test *markerTest) ([]byte, error) {
 -	arch := &txtar.Archive{
@@ -60771,7 +67354,7 @@
 -	updatedGolden := make(map[string][]byte)
 -	for id, g := range test.golden {
 -		for name, data := range g.updated {
--			filename := "@" + path.Join(id, name) // name may be ""
+-			filename := "@" + path.Join(string(id), name) // name may be ""
 -			updatedGolden[filename] = data
 -		}
 -	}
@@ -60781,11 +67364,13 @@
 -		switch file.Name {
 -		// Preserve configuration files exactly as they were. They must have parsed
 -		// if we got this far.
--		case "flags", "settings.json", "env":
+-		case "skip", "flags", "settings.json", "capabilities.json", "env":
 -			arch.Files = append(arch.Files, file)
 -		default:
 -			if _, ok := test.files[file.Name]; ok { // ordinary file
 -				arch.Files = append(arch.Files, file)
+-			} else if strings.HasPrefix(file.Name, "proxy/") { // proxy file
+-				arch.Files = append(arch.Files, file)
 -			} else if data, ok := updatedGolden[file.Name]; ok { // golden file
 -				arch.Files = append(arch.Files, txtar.File{Name: file.Name, Data: data})
 -				delete(updatedGolden, file.Name)
@@ -60811,16 +67396,22 @@
 -//
 -// TODO(rfindley): simplify and refactor the construction of testing
 -// environments across regtests, marker tests, and benchmarks.
--func newEnv(t *testing.T, cache *cache.Cache, files map[string][]byte, config fake.EditorConfig) *Env {
+-func newEnv(t *testing.T, cache *cache.Cache, files, proxyFiles map[string][]byte, writeGoSum []string, config fake.EditorConfig) *Env {
 -	sandbox, err := fake.NewSandbox(&fake.SandboxConfig{
--		RootDir: t.TempDir(),
--		GOPROXY: "https://proxy.golang.org",
--		Files:   files,
+-		RootDir:    t.TempDir(),
+-		Files:      files,
+-		ProxyFiles: proxyFiles,
 -	})
 -	if err != nil {
 -		t.Fatal(err)
 -	}
 -
+-	for _, dir := range writeGoSum {
+-		if err := sandbox.RunGoCommand(context.Background(), dir, "list", []string{"-mod=mod", "..."}, []string{"GOWORK=off"}, true); err != nil {
+-			t.Fatal(err)
+-		}
+-	}
+-
 -	// Put a debug instance in the context to prevent logging to stderr.
 -	// See associated TODO in runner.go: we should revisit this pattern.
 -	ctx := context.Background()
@@ -60848,22 +67439,53 @@
 -	}
 -}
 -
--// A markerFunc is a reflectively callable @mark implementation function.
--type markerFunc struct {
--	fn         reflect.Value  // the func to invoke
--	paramTypes []reflect.Type // parameter types, for zero values
--	converters []converter    // to convert non-blank arguments
--}
--
 -// A markerTestRun holds the state of one run of a marker test archive.
 -type markerTestRun struct {
--	test *markerTest
--	env  *Env
+-	test     *markerTest
+-	env      *Env
+-	settings map[string]any
 -
 -	// Collected information.
 -	// Each @diag/@suggestedfix marker eliminates an entry from diags.
--	locations map[expect.Identifier]protocol.Location
--	diags     map[protocol.Location][]protocol.Diagnostic
+-	values map[expect.Identifier]any
+-	diags  map[protocol.Location][]protocol.Diagnostic // diagnostics by position; location end == start
+-
+-	// Notes that weren't associated with a top-level marker func. They may be
+-	// consumed by another marker (e.g. @codelenses collects @codelens markers).
+-	// Any notes that aren't consumed are flagged as an error.
+-	extraNotes map[protocol.DocumentURI]map[string][]*expect.Note
+-}
+-
+-// sprintf returns a formatted string after applying pre-processing to
+-// arguments of the following types:
+-//   - token.Pos: formatted using (*markerTestRun).fmtPos
+-//   - protocol.Location: formatted using (*markerTestRun).fmtLoc
+-func (c *marker) sprintf(format string, args ...any) string {
+-	if false {
+-		_ = fmt.Sprintf(format, args...) // enable vet printf checker
+-	}
+-	var args2 []any
+-	for _, arg := range args {
+-		switch arg := arg.(type) {
+-		case token.Pos:
+-			args2 = append(args2, c.run.fmtPos(arg))
+-		case protocol.Location:
+-			args2 = append(args2, c.run.fmtLoc(arg))
+-		default:
+-			args2 = append(args2, arg)
+-		}
+-	}
+-	return fmt.Sprintf(format, args2...)
+-}
+-
+-// uri returns the URI of the file containing the marker.
+-func (mark marker) uri() protocol.DocumentURI {
+-	return mark.run.env.Sandbox.Workdir.URI(mark.run.test.fset.File(mark.note.Pos).Name())
+-}
+-
+-// path returns the relative path to the file containing the marker.
+-func (mark marker) path() string {
+-	return mark.run.env.Sandbox.Workdir.RelPath(mark.run.test.fset.File(mark.note.Pos).Name())
 -}
 -
 -// fmtLoc formats the given pos in the context of the test, using
@@ -60891,8 +67513,21 @@
 -// archive-relative paths for files and including the line number in the full
 -// archive file.
 -func (run *markerTestRun) fmtLoc(loc protocol.Location) string {
+-	formatted := run.fmtLocDetails(loc, true)
+-	if formatted == "" {
+-		run.env.T.Errorf("unable to find %s in test archive", loc)
+-		return "<invalid location>"
+-	}
+-	return formatted
+-}
+-
+-// See fmtLoc. If includeTxtPos is not set, the position in the full archive
+-// file is omitted.
+-//
+-// If the location cannot be found within the archive, fmtLocDetails returns "".
+-func (run *markerTestRun) fmtLocDetails(loc protocol.Location, includeTxtPos bool) string {
 -	if loc == (protocol.Location{}) {
--		return "<missing location>"
+-		return ""
 -	}
 -	lines := bytes.Count(run.test.archive.Comment, []byte("\n"))
 -	var name string
@@ -60906,8 +67541,7 @@
 -		lines += bytes.Count(f.Data, []byte("\n"))
 -	}
 -	if name == "" {
--		run.env.T.Errorf("unable to find %s in test archive", loc)
--		return "<invalid location>"
+-		return ""
 -	}
 -	m, err := run.env.Editor.Mapper(name)
 -	if err != nil {
@@ -60932,35 +67566,18 @@
 -		}
 -	}
 -
--	return fmt.Sprintf("%s:%s (%s:%s)", name, innerSpan, run.test.name, outerSpan)
--}
--
--// makeMarkerFunc uses reflection to create a markerFunc for the given func value.
--func makeMarkerFunc(fn interface{}) markerFunc {
--	mi := markerFunc{
--		fn: reflect.ValueOf(fn),
+-	if includeTxtPos {
+-		return fmt.Sprintf("%s:%s (%s:%s)", name, innerSpan, run.test.name, outerSpan)
+-	} else {
+-		return fmt.Sprintf("%s:%s", name, innerSpan)
 -	}
--	mtyp := mi.fn.Type()
--	if mtyp.NumIn() == 0 || mtyp.In(0) != markerType {
--		panic(fmt.Sprintf("marker function %#v must accept marker as its first argument", mi.fn))
--	}
--	if mtyp.NumOut() != 0 {
--		panic(fmt.Sprintf("marker function %#v must not have results", mi.fn))
--	}
--	for a := 1; a < mtyp.NumIn(); a++ {
--		in := mtyp.In(a)
--		mi.paramTypes = append(mi.paramTypes, in)
--		c := makeConverter(in)
--		mi.converters = append(mi.converters, c)
--	}
--	return mi
 -}
 -
 -// ---- converters ----
 -
 -// converter is the signature of argument converters.
 -// A converter should return an error rather than calling marker.errorf().
--type converter func(marker, interface{}) (interface{}, error)
+-type converter func(marker, any) (any, error)
 -
 -// Types with special conversions.
 -var (
@@ -60971,28 +67588,39 @@
 -	wantErrorType = reflect.TypeOf(wantError{})
 -)
 -
--func makeConverter(paramType reflect.Type) converter {
--	switch paramType {
--	case goldenType:
--		return goldenConverter
--	case locationType:
--		return locationConverter
--	case wantErrorType:
--		return wantErrorConverter
--	default:
--		return func(_ marker, arg interface{}) (interface{}, error) {
--			if argType := reflect.TypeOf(arg); argType != paramType {
--				return nil, fmt.Errorf("cannot convert type %s to %s", argType, paramType)
+-func convert(mark marker, arg any, paramType reflect.Type) (any, error) {
+-	if paramType == goldenType {
+-		id, ok := arg.(expect.Identifier)
+-		if !ok {
+-			return nil, fmt.Errorf("invalid input type %T: golden key must be an identifier", arg)
+-		}
+-		return mark.run.test.getGolden(id), nil
+-	}
+-	if id, ok := arg.(expect.Identifier); ok {
+-		if arg, ok := mark.run.values[id]; ok {
+-			if !reflect.TypeOf(arg).AssignableTo(paramType) {
+-				return nil, fmt.Errorf("cannot convert %v to %s", arg, paramType)
 -			}
 -			return arg, nil
 -		}
 -	}
+-	if reflect.TypeOf(arg).AssignableTo(paramType) {
+-		return arg, nil // no conversion required
+-	}
+-	switch paramType {
+-	case locationType:
+-		return convertLocation(mark, arg)
+-	case wantErrorType:
+-		return convertWantError(mark, arg)
+-	default:
+-		return nil, fmt.Errorf("cannot convert %v to %s", arg, paramType)
+-	}
 -}
 -
--// locationConverter converts a string argument into the protocol location
--// corresponding to the first position of the string in the line preceding the
--// note.
--func locationConverter(mark marker, arg interface{}) (interface{}, error) {
+-// convertLocation converts a string or regexp argument into the protocol
+-// location corresponding to the first position of the string (or first match
+-// of the regexp) in the line preceding the note.
+-func convertLocation(mark marker, arg any) (protocol.Location, error) {
 -	switch arg := arg.(type) {
 -	case string:
 -		startOff, preceding, m, err := linePreceding(mark.run, mark.note.Pos)
@@ -61001,20 +67629,14 @@
 -		}
 -		idx := bytes.Index(preceding, []byte(arg))
 -		if idx < 0 {
--			return nil, fmt.Errorf("substring %q not found in %q", arg, preceding)
+-			return protocol.Location{}, fmt.Errorf("substring %q not found in %q", arg, preceding)
 -		}
 -		off := startOff + idx
 -		return m.OffsetLocation(off, off+len(arg))
 -	case *regexp.Regexp:
 -		return findRegexpInLine(mark.run, mark.note.Pos, arg)
--	case expect.Identifier:
--		loc, ok := mark.run.locations[arg]
--		if !ok {
--			return nil, fmt.Errorf("no location named %q", arg)
--		}
--		return loc, nil
 -	default:
--		return nil, fmt.Errorf("cannot convert argument type %T to location (must be a string to match the preceding line)", arg)
+-		return protocol.Location{}, fmt.Errorf("cannot convert argument type %T to location (must be a string to match the preceding line)", arg)
 -	}
 -}
 -
@@ -61062,22 +67684,22 @@
 -	return startOff, m.Content[startOff:endOff], m, nil
 -}
 -
--// wantErrorConverter converts a string, regexp, or identifier
+-// convertWantError converts a string, regexp, or identifier
 -// argument into a wantError. The string is a substring of the
 -// expected error, the regexp is a pattern than matches the expected
 -// error, and the identifier is a golden file containing the expected
 -// error.
--func wantErrorConverter(mark marker, arg interface{}) (interface{}, error) {
+-func convertWantError(mark marker, arg any) (wantError, error) {
 -	switch arg := arg.(type) {
 -	case string:
 -		return wantError{substr: arg}, nil
 -	case *regexp.Regexp:
 -		return wantError{pattern: arg}, nil
 -	case expect.Identifier:
--		golden := mark.run.test.getGolden(string(arg))
+-		golden := mark.run.test.getGolden(arg)
 -		return wantError{golden: golden}, nil
 -	default:
--		return nil, fmt.Errorf("cannot convert %T to wantError (want: string, regexp, or identifier)", arg)
+-		return wantError{}, fmt.Errorf("cannot convert %T to wantError (want: string, regexp, or identifier)", arg)
 -	}
 -}
 -
@@ -61137,17 +67759,6 @@
 -	}
 -}
 -
--// goldenConverter converts an identifier into the Golden directory of content
--// prefixed by @<ident> in the test archive file.
--func goldenConverter(mark marker, arg interface{}) (interface{}, error) {
--	switch arg := arg.(type) {
--	case expect.Identifier:
--		return mark.run.test.getGolden(string(arg)), nil
--	default:
--		return nil, fmt.Errorf("invalid input type %T: golden key must be an identifier", arg)
--	}
--}
--
 -// checkChangedFiles compares the files changed by an operation with their expected (golden) state.
 -func checkChangedFiles(mark marker, changed map[string][]byte, golden *Golden) {
 -	// Check changed files match expectations.
@@ -61175,7 +67786,195 @@
 -
 -// ---- marker functions ----
 -
--// defMarker implements the @godef marker, running textDocument/definition at
+-// TODO(rfindley): consolidate documentation of these markers. They are already
+-// documented above, so much of the documentation here is redundant.
+-
+-// completionItem is a simplified summary of a completion item.
+-type completionItem struct {
+-	Label, Detail, Kind, Documentation string
+-}
+-
+-func completionItemMarker(mark marker, label string, other ...string) completionItem {
+-	if len(other) > 3 {
+-		mark.errorf("too many arguments to @item: expect at most 4")
+-	}
+-	item := completionItem{
+-		Label: label,
+-	}
+-	if len(other) > 0 {
+-		item.Detail = other[0]
+-	}
+-	if len(other) > 1 {
+-		item.Kind = other[1]
+-	}
+-	if len(other) > 2 {
+-		item.Documentation = other[2]
+-	}
+-	return item
+-}
+-
+-func rankMarker(mark marker, src protocol.Location, items ...completionItem) {
+-	list := mark.run.env.Completion(src)
+-	var got []string
+-	// Collect results that are present in items, preserving their order.
+-	for _, g := range list.Items {
+-		for _, w := range items {
+-			if g.Label == w.Label {
+-				got = append(got, g.Label)
+-				break
+-			}
+-		}
+-	}
+-	var want []string
+-	for _, w := range items {
+-		want = append(want, w.Label)
+-	}
+-	if diff := cmp.Diff(want, got); diff != "" {
+-		mark.errorf("completion rankings do not match (-want +got):\n%s", diff)
+-	}
+-}
+-
+-func ranklMarker(mark marker, src protocol.Location, labels ...string) {
+-	list := mark.run.env.Completion(src)
+-	var got []string
+-	// Collect results that are present in items, preserving their order.
+-	for _, g := range list.Items {
+-		for _, label := range labels {
+-			if g.Label == label {
+-				got = append(got, g.Label)
+-				break
+-			}
+-		}
+-	}
+-	if diff := cmp.Diff(labels, got); diff != "" {
+-		mark.errorf("completion rankings do not match (-want +got):\n%s", diff)
+-	}
+-}
+-
+-func snippetMarker(mark marker, src protocol.Location, item completionItem, want string) {
+-	list := mark.run.env.Completion(src)
+-	var (
+-		found bool
+-		got   string
+-		all   []string // for errors
+-	)
+-	items := filterBuiltinsAndKeywords(list.Items)
+-	for _, i := range items {
+-		all = append(all, i.Label)
+-		if i.Label == item.Label {
+-			found = true
+-			if i.TextEdit != nil {
+-				got = i.TextEdit.NewText
+-			}
+-			break
+-		}
+-	}
+-	if !found {
+-		mark.errorf("no completion item found matching %s (got: %v)", item.Label, all)
+-		return
+-	}
+-	if got != want {
+-		mark.errorf("snippets do not match: got %q, want %q", got, want)
+-	}
+-}
+-
+-// completeMarker implements the @complete marker, running
+-// textDocument/completion at the given src location and asserting that the
+-// results match the expected results.
+-func completeMarker(mark marker, src protocol.Location, want ...completionItem) {
+-	list := mark.run.env.Completion(src)
+-	items := filterBuiltinsAndKeywords(list.Items)
+-	var got []completionItem
+-	for i, item := range items {
+-		simplified := completionItem{
+-			Label:  item.Label,
+-			Detail: item.Detail,
+-			Kind:   fmt.Sprint(item.Kind),
+-		}
+-		if item.Documentation != nil {
+-			switch v := item.Documentation.Value.(type) {
+-			case string:
+-				simplified.Documentation = v
+-			case protocol.MarkupContent:
+-				simplified.Documentation = strings.TrimSpace(v.Value) // trim newlines
+-			}
+-		}
+-		// Support short-hand notation: if Detail, Kind, or Documentation are omitted from the
+-		// item, don't match them.
+-		if i < len(want) {
+-			if want[i].Detail == "" {
+-				simplified.Detail = ""
+-			}
+-			if want[i].Kind == "" {
+-				simplified.Kind = ""
+-			}
+-			if want[i].Documentation == "" {
+-				simplified.Documentation = ""
+-			}
+-		}
+-		got = append(got, simplified)
+-	}
+-	if len(want) == 0 {
+-		want = nil // got is nil if empty
+-	}
+-	if diff := cmp.Diff(want, got); diff != "" {
+-		mark.errorf("Completion(...) returned unexpect results (-want +got):\n%s", diff)
+-	}
+-}
+-
+-// filterBuiltinsAndKeywords filters out builtins and keywords from completion
+-// results.
+-//
+-// It over-approximates, and does not detect if builtins are shadowed.
+-func filterBuiltinsAndKeywords(items []protocol.CompletionItem) []protocol.CompletionItem {
+-	keep := 0
+-	for _, item := range items {
+-		if types.Universe.Lookup(item.Label) == nil && token.Lookup(item.Label) == token.IDENT {
+-			items[keep] = item
+-			keep++
+-		}
+-	}
+-	return items[:keep]
+-}
+-
+-// acceptCompletionMarker implements the @acceptCompletion marker, running
+-// textDocument/completion at the given src location and accepting the
+-// candidate with the given label. The resulting source must match the provided
+-// golden content.
+-func acceptCompletionMarker(mark marker, src protocol.Location, label string, golden *Golden) {
+-	list := mark.run.env.Completion(src)
+-	var selected *protocol.CompletionItem
+-	for _, item := range list.Items {
+-		if item.Label == label {
+-			selected = &item
+-			break
+-		}
+-	}
+-	if selected == nil {
+-		mark.errorf("Completion(...) did not return an item labeled %q", label)
+-		return
+-	}
+-	filename := mark.path()
+-	mapper, err := mark.run.env.Editor.Mapper(filename)
+-	if err != nil {
+-		mark.errorf("Editor.Mapper(%s) failed: %v", filename, err)
+-		return
+-	}
+-
+-	patched, _, err := source.ApplyProtocolEdits(mapper, append([]protocol.TextEdit{
+-		*selected.TextEdit,
+-	}, selected.AdditionalTextEdits...))
+-
+-	if err != nil {
+-		mark.errorf("ApplyProtocolEdits failed: %v", err)
+-		return
+-	}
+-	changes := map[string][]byte{filename: patched}
+-	// Check the file state.
+-	checkChangedFiles(mark, changes, golden)
+-}
+-
+-// defMarker implements the @def marker, running textDocument/definition at
 -// the given src location and asserting that there is exactly one resulting
 -// location, matching dst.
 -//
@@ -61188,6 +67987,115 @@
 -	}
 -}
 -
+-func typedefMarker(mark marker, src, dst protocol.Location) {
+-	got := mark.run.env.TypeDefinition(src)
+-	if got != dst {
+-		mark.errorf("type definition location does not match:\n\tgot: %s\n\twant %s",
+-			mark.run.fmtLoc(got), mark.run.fmtLoc(dst))
+-	}
+-}
+-
+-func foldingRangeMarker(mark marker, g *Golden) {
+-	env := mark.run.env
+-	ranges, err := mark.server().FoldingRange(env.Ctx, &protocol.FoldingRangeParams{
+-		TextDocument: protocol.TextDocumentIdentifier{URI: mark.uri()},
+-	})
+-	if err != nil {
+-		mark.errorf("foldingRange failed: %v", err)
+-		return
+-	}
+-	var edits []protocol.TextEdit
+-	insert := func(line, char uint32, text string) {
+-		pos := protocol.Position{Line: line, Character: char}
+-		edits = append(edits, protocol.TextEdit{
+-			Range: protocol.Range{
+-				Start: pos,
+-				End:   pos,
+-			},
+-			NewText: text,
+-		})
+-	}
+-	for i, rng := range ranges {
+-		insert(rng.StartLine, rng.StartCharacter, fmt.Sprintf("<%d kind=%q>", i, rng.Kind))
+-		insert(rng.EndLine, rng.EndCharacter, fmt.Sprintf("</%d>", i))
+-	}
+-	filename := mark.path()
+-	mapper, err := env.Editor.Mapper(filename)
+-	if err != nil {
+-		mark.errorf("Editor.Mapper(%s) failed: %v", filename, err)
+-		return
+-	}
+-	got, _, err := source.ApplyProtocolEdits(mapper, edits)
+-	if err != nil {
+-		mark.errorf("ApplyProtocolEdits failed: %v", err)
+-		return
+-	}
+-	want, _ := g.Get(mark.run.env.T, "", got)
+-	if diff := compare.Bytes(want, got); diff != "" {
+-		mark.errorf("foldingRange mismatch:\n%s", diff)
+-	}
+-}
+-
+-// formatMarker implements the @format marker.
+-func formatMarker(mark marker, golden *Golden) {
+-	edits, err := mark.server().Formatting(mark.run.env.Ctx, &protocol.DocumentFormattingParams{
+-		TextDocument: protocol.TextDocumentIdentifier{URI: mark.uri()},
+-	})
+-	var got []byte
+-	if err != nil {
+-		got = []byte(err.Error() + "\n") // all golden content is newline terminated
+-	} else {
+-		env := mark.run.env
+-		filename := mark.path()
+-		mapper, err := env.Editor.Mapper(filename)
+-		if err != nil {
+-			mark.errorf("Editor.Mapper(%s) failed: %v", filename, err)
+-		}
+-
+-		got, _, err = source.ApplyProtocolEdits(mapper, edits)
+-		if err != nil {
+-			mark.errorf("ApplyProtocolEdits failed: %v", err)
+-			return
+-		}
+-	}
+-
+-	want, ok := golden.Get(mark.run.env.T, "", got)
+-	if !ok {
+-		mark.errorf("missing golden file @%s", golden.id)
+-		return
+-	}
+-
+-	if diff := compare.Bytes(want, got); diff != "" {
+-		mark.errorf("golden file @%s does not match format results:\n%s", golden.id, diff)
+-	}
+-}
+-
+-func highlightMarker(mark marker, src protocol.Location, dsts ...protocol.Location) {
+-	highlights := mark.run.env.DocumentHighlight(src)
+-	var got []protocol.Range
+-	for _, h := range highlights {
+-		got = append(got, h.Range)
+-	}
+-
+-	var want []protocol.Range
+-	for _, d := range dsts {
+-		want = append(want, d.Range)
+-	}
+-
+-	sortRanges := func(s []protocol.Range) {
+-		sort.Slice(s, func(i, j int) bool {
+-			return protocol.CompareRange(s[i], s[j]) < 0
+-		})
+-	}
+-
+-	sortRanges(got)
+-	sortRanges(want)
+-
+-	if diff := cmp.Diff(want, got); diff != "" {
+-		mark.errorf("DocumentHighlight(%v) mismatch (-want +got):\n%s", src, diff)
+-	}
+-}
+-
 -// hoverMarker implements the @hover marker, running textDocument/hover at the
 -// given src location and asserting that the resulting hover is over the dst
 -// location (typically a span surrounding src), and that the markdown content
@@ -61218,32 +68126,37 @@
 -
 -// locMarker implements the @loc marker. It is executed before other
 -// markers, so that locations are available.
--func locMarker(mark marker, name expect.Identifier, loc protocol.Location) {
--	mark.run.locations[name] = loc
--}
+-func locMarker(mark marker, loc protocol.Location) protocol.Location { return loc }
 -
 -// diagMarker implements the @diag marker. It eliminates diagnostics from
 -// the observed set in mark.test.
 -func diagMarker(mark marker, loc protocol.Location, re *regexp.Regexp) {
--	if _, err := removeDiagnostic(mark, loc, re); err != nil {
--		mark.errorf("%v", err)
+-	if _, ok := removeDiagnostic(mark, loc, re); !ok {
+-		mark.errorf("no diagnostic at %v matches %q", loc, re)
 -	}
 -}
 -
--func removeDiagnostic(mark marker, loc protocol.Location, re *regexp.Regexp) (protocol.Diagnostic, error) {
+-// removeDiagnostic looks for a diagnostic matching loc at the given position.
+-//
+-// If found, it returns (diag, true), and eliminates the matched diagnostic
+-// from the unmatched set.
+-//
+-// If not found, it returns (protocol.Diagnostic{}, false).
+-func removeDiagnostic(mark marker, loc protocol.Location, re *regexp.Regexp) (protocol.Diagnostic, bool) {
+-	loc.Range.End = loc.Range.Start // diagnostics ignore end position.
 -	diags := mark.run.diags[loc]
 -	for i, diag := range diags {
 -		if re.MatchString(diag.Message) {
 -			mark.run.diags[loc] = append(diags[:i], diags[i+1:]...)
--			return diag, nil
+-			return diag, true
 -		}
 -	}
--	return protocol.Diagnostic{}, fmt.Errorf("no diagnostic matches %q", re)
+-	return protocol.Diagnostic{}, false
 -}
 -
 -// renameMarker implements the @rename(location, new, golden) marker.
--func renameMarker(mark marker, loc protocol.Location, newName expect.Identifier, golden *Golden) {
--	changed, err := rename(mark.run.env, loc, string(newName))
+-func renameMarker(mark marker, loc protocol.Location, newName string, golden *Golden) {
+-	changed, err := rename(mark.run.env, loc, newName)
 -	if err != nil {
 -		mark.errorf("rename failed: %v. (Use @renameerr for expected errors.)", err)
 -		return
@@ -61252,11 +68165,22 @@
 -}
 -
 -// renameErrMarker implements the @renamererr(location, new, error) marker.
--func renameErrMarker(mark marker, loc protocol.Location, newName expect.Identifier, wantErr wantError) {
--	_, err := rename(mark.run.env, loc, string(newName))
+-func renameErrMarker(mark marker, loc protocol.Location, newName string, wantErr wantError) {
+-	_, err := rename(mark.run.env, loc, newName)
 -	wantErr.check(mark, err)
 -}
 -
+-func signatureMarker(mark marker, src protocol.Location, want string) {
+-	got := mark.run.env.SignatureHelp(src)
+-	if got == nil || len(got.Signatures) != 1 {
+-		mark.errorf("signatureHelp = %v, want exactly 1 signature", got)
+-		return
+-	}
+-	if got := got.Signatures[0].Label; got != want {
+-		mark.errorf("signatureHelp: got %q, want %q", got, want)
+-	}
+-}
+-
 -// rename returns the new contents of the files that would be modified
 -// by renaming the identifier at loc to newName.
 -func rename(env *Env, loc protocol.Location, newName string) (map[string][]byte, error) {
@@ -61275,41 +68199,125 @@
 -		return nil, err
 -	}
 -
--	return applyDocumentChanges(env, editMap.DocumentChanges)
+-	fileChanges := make(map[string][]byte)
+-	if err := applyDocumentChanges(env, editMap.DocumentChanges, fileChanges); err != nil {
+-		return nil, fmt.Errorf("applying document changes: %v", err)
+-	}
+-	return fileChanges, nil
 -}
 -
--// applyDocumentChanges returns the effect of applying the document
--// changes to the contents of the Editor buffers. The actual editor
--// buffers are unchanged.
--func applyDocumentChanges(env *Env, changes []protocol.DocumentChanges) (map[string][]byte, error) {
--	result := make(map[string][]byte)
+-// applyDocumentChanges applies the given document changes to the editor buffer
+-// content, recording the resulting contents in the fileChanges map. It is an
+-// error for a change to an edit a file that is already present in the
+-// fileChanges map.
+-func applyDocumentChanges(env *Env, changes []protocol.DocumentChanges, fileChanges map[string][]byte) error {
+-	getMapper := func(path string) (*protocol.Mapper, error) {
+-		if _, ok := fileChanges[path]; ok {
+-			return nil, fmt.Errorf("internal error: %s is already edited", path)
+-		}
+-		return env.Editor.Mapper(path)
+-	}
+-
 -	for _, change := range changes {
 -		if change.RenameFile != nil {
 -			// rename
 -			oldFile := env.Sandbox.Workdir.URIToPath(change.RenameFile.OldURI)
--			newFile := env.Sandbox.Workdir.URIToPath(change.RenameFile.NewURI)
--			mapper, err := env.Editor.Mapper(oldFile)
+-			mapper, err := getMapper(oldFile)
 -			if err != nil {
--				return nil, err
+-				return err
 -			}
--			result[newFile] = mapper.Content
--
+-			newFile := env.Sandbox.Workdir.URIToPath(change.RenameFile.NewURI)
+-			fileChanges[newFile] = mapper.Content
 -		} else {
 -			// edit
 -			filename := env.Sandbox.Workdir.URIToPath(change.TextDocumentEdit.TextDocument.URI)
--			mapper, err := env.Editor.Mapper(filename)
+-			mapper, err := getMapper(filename)
 -			if err != nil {
--				return nil, err
+-				return err
 -			}
 -			patched, _, err := source.ApplyProtocolEdits(mapper, change.TextDocumentEdit.Edits)
 -			if err != nil {
--				return nil, err
+-				return err
 -			}
--			result[filename] = patched
+-			fileChanges[filename] = patched
 -		}
 -	}
 -
--	return result, nil
+-	return nil
+-}
+-
+-func codeActionMarker(mark marker, actionKind string, start, end protocol.Location, golden *Golden) {
+-	// Request the range from start.Start to end.End.
+-	loc := start
+-	loc.Range.End = end.Range.End
+-
+-	// Apply the fix it suggests.
+-	changed, err := codeAction(mark.run.env, loc.URI, loc.Range, actionKind, nil)
+-	if err != nil {
+-		mark.errorf("codeAction failed: %v", err)
+-		return
+-	}
+-
+-	// Check the file state.
+-	checkChangedFiles(mark, changed, golden)
+-}
+-
+-func codeActionErrMarker(mark marker, actionKind string, start, end protocol.Location, wantErr wantError) {
+-	loc := start
+-	loc.Range.End = end.Range.End
+-	_, err := codeAction(mark.run.env, loc.URI, loc.Range, actionKind, nil)
+-	wantErr.check(mark, err)
+-}
+-
+-// codeLensesMarker runs the @codelenses() marker, collecting @codelens marks
+-// in the current file and comparing with the result of the
+-// textDocument/codeLens RPC.
+-func codeLensesMarker(mark marker) {
+-	type codeLens struct {
+-		Range protocol.Range
+-		Title string
+-	}
+-
+-	lenses := mark.run.env.CodeLens(mark.path())
+-	var got []codeLens
+-	for _, lens := range lenses {
+-		title := ""
+-		if lens.Command != nil {
+-			title = lens.Command.Title
+-		}
+-		got = append(got, codeLens{lens.Range, title})
+-	}
+-
+-	var want []codeLens
+-	mark.consumeExtraNotes("codelens", actionMarkerFunc(func(mark marker, loc protocol.Location, title string) {
+-		want = append(want, codeLens{loc.Range, title})
+-	}))
+-
+-	for _, s := range [][]codeLens{got, want} {
+-		sort.Slice(s, func(i, j int) bool {
+-			li, lj := s[i], s[j]
+-			if c := protocol.CompareRange(li.Range, lj.Range); c != 0 {
+-				return c < 0
+-			}
+-			return li.Title < lj.Title
+-		})
+-	}
+-
+-	if diff := cmp.Diff(want, got); diff != "" {
+-		mark.errorf("codelenses: unexpected diff (-want +got):\n%s", diff)
+-	}
+-}
+-
+-// consumeExtraNotes runs the provided func for each extra note with the given
+-// name, and deletes all matching notes.
+-func (mark marker) consumeExtraNotes(name string, f func(marker)) {
+-	uri := mark.uri()
+-	notes := mark.run.extraNotes[uri][name]
+-	delete(mark.run.extraNotes[uri], name)
+-
+-	for _, note := range notes {
+-		f(marker{run: mark.run, note: note})
+-	}
 -}
 -
 -// suggestedfixMarker implements the @suggestedfix(location, regexp,
@@ -61317,15 +68325,16 @@
 -// the expectation of a diagnostic, but then it applies the first code
 -// action of the specified kind suggested by the matched diagnostic.
 -func suggestedfixMarker(mark marker, loc protocol.Location, re *regexp.Regexp, actionKind string, golden *Golden) {
+-	loc.Range.End = loc.Range.Start // diagnostics ignore end position.
 -	// Find and remove the matching diagnostic.
--	diag, err := removeDiagnostic(mark, loc, re)
--	if err != nil {
--		mark.errorf("%v", err)
+-	diag, ok := removeDiagnostic(mark, loc, re)
+-	if !ok {
+-		mark.errorf("no diagnostic at %v matches %q", loc, re)
 -		return
 -	}
 -
 -	// Apply the fix it suggests.
--	changed, err := suggestedfix(mark.run.env, loc, diag, actionKind)
+-	changed, err := codeAction(mark.run.env, loc.URI, diag.Range, actionKind, &diag)
 -	if err != nil {
 -		mark.errorf("suggestedfix failed: %v. (Use @suggestedfixerr for expected errors.)", err)
 -		return
@@ -61335,19 +68344,29 @@
 -	checkChangedFiles(mark, changed, golden)
 -}
 -
--func suggestedfix(env *Env, loc protocol.Location, diag protocol.Diagnostic, actionKind string) (map[string][]byte, error) {
--
+-// codeAction executes a textDocument/codeAction request for the specified
+-// location and kind. If diag is non-nil, it is used as the code action
+-// context.
+-//
+-// The resulting map contains resulting file contents after the code action is
+-// applied. Currently, this function does not support code actions that return
+-// edits directly; it only supports code action commands.
+-func codeAction(env *Env, uri protocol.DocumentURI, rng protocol.Range, actionKind string, diag *protocol.Diagnostic) (map[string][]byte, error) {
 -	// Request all code actions that apply to the diagnostic.
 -	// (The protocol supports filtering using Context.Only={actionKind}
 -	// but we can give a better error if we don't filter.)
--	actions, err := env.Editor.Server.CodeAction(env.Ctx, &protocol.CodeActionParams{
--		TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
--		Range:        diag.Range,
+-	params := &protocol.CodeActionParams{
+-		TextDocument: protocol.TextDocumentIdentifier{URI: uri},
+-		Range:        rng,
 -		Context: protocol.CodeActionContext{
--			Only:        nil, // => all kinds
--			Diagnostics: []protocol.Diagnostic{diag},
+-			Only: nil, // => all kinds
 -		},
--	})
+-	}
+-	if diag != nil {
+-		params.Context.Diagnostics = []protocol.Diagnostic{*diag}
+-	}
+-
+-	actions, err := env.Editor.Server.CodeAction(env.Ctx, params)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -61367,54 +68386,239 @@
 -	}
 -	action := candidates[0]
 -
+-	// Apply the codeAction.
+-	//
+-	// Spec:
+-	//  "If a code action provides an edit and a command, first the edit is
+-	//  executed and then the command."
+-	fileChanges := make(map[string][]byte)
 -	// An action may specify an edit and/or a command, to be
 -	// applied in that order. But since applyDocumentChanges(env,
 -	// action.Edit.DocumentChanges) doesn't compose, for now we
 -	// assert that all commands used in the @suggestedfix tests
 -	// return only a command.
--	if action.Edit.DocumentChanges != nil {
--		env.T.Errorf("internal error: discarding unexpected CodeAction{Kind=%s, Title=%q}.Edit.DocumentChanges", action.Kind, action.Title)
--	}
--	if action.Command == nil {
--		return nil, fmt.Errorf("missing CodeAction{Kind=%s, Title=%q}.Command", action.Kind, action.Title)
+-	if action.Edit != nil {
+-		if action.Edit.Changes != nil {
+-			env.T.Errorf("internal error: discarding unexpected CodeAction{Kind=%s, Title=%q}.Edit.Changes", action.Kind, action.Title)
+-		}
+-		if action.Edit.DocumentChanges != nil {
+-			if err := applyDocumentChanges(env, action.Edit.DocumentChanges, fileChanges); err != nil {
+-				return nil, fmt.Errorf("applying document changes: %v", err)
+-			}
+-		}
 -	}
 -
--	// This is a typical CodeAction command:
--	//
--	//   Title:     "Implement error"
--	//   Command:   gopls.apply_fix
--	//   Arguments: [{"Fix":"stub_methods","URI":".../a.go","Range":...}}]
--	//
--	// The client makes an ExecuteCommand RPC to the server,
--	// which dispatches it to the ApplyFix handler.
--	// ApplyFix dispatches to the "stub_methods" suggestedfix hook (the meat).
--	// The server then makes an ApplyEdit RPC to the client,
--	// whose Awaiter hook gathers the edits instead of applying them.
+-	if action.Command != nil {
+-		// This is a typical CodeAction command:
+-		//
+-		//   Title:     "Implement error"
+-		//   Command:   gopls.apply_fix
+-		//   Arguments: [{"Fix":"stub_methods","URI":".../a.go","Range":...}}]
+-		//
+-		// The client makes an ExecuteCommand RPC to the server,
+-		// which dispatches it to the ApplyFix handler.
+-		// ApplyFix dispatches to the "stub_methods" suggestedfix hook (the meat).
+-		// The server then makes an ApplyEdit RPC to the client,
+-		// whose Awaiter hook gathers the edits instead of applying them.
 -
--	_ = env.Awaiter.takeDocumentChanges() // reset (assuming Env is confined to this thread)
+-		_ = env.Awaiter.takeDocumentChanges() // reset (assuming Env is confined to this thread)
 -
--	if _, err := env.Editor.Server.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
--		Command:   action.Command.Command,
--		Arguments: action.Command.Arguments,
--	}); err != nil {
--		env.T.Fatalf("error converting command %q to edits: %v", action.Command.Command, err)
+-		if _, err := env.Editor.Server.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
+-			Command:   action.Command.Command,
+-			Arguments: action.Command.Arguments,
+-		}); err != nil {
+-			env.T.Fatalf("error converting command %q to edits: %v", action.Command.Command, err)
+-		}
+-
+-		if err := applyDocumentChanges(env, env.Awaiter.takeDocumentChanges(), fileChanges); err != nil {
+-			return nil, fmt.Errorf("applying document changes from command: %v", err)
+-		}
 -	}
 -
--	return applyDocumentChanges(env, env.Awaiter.takeDocumentChanges())
+-	return fileChanges, nil
 -}
 -
 -// TODO(adonovan): suggestedfixerr
+-
+-// refsMarker implements the @refs marker.
+-func refsMarker(mark marker, src protocol.Location, want ...protocol.Location) {
+-	refs := func(includeDeclaration bool, want []protocol.Location) error {
+-		got, err := mark.server().References(mark.run.env.Ctx, &protocol.ReferenceParams{
+-			TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(src),
+-			Context: protocol.ReferenceContext{
+-				IncludeDeclaration: includeDeclaration,
+-			},
+-		})
+-		if err != nil {
+-			return err
+-		}
+-
+-		return compareLocations(mark, got, want)
+-	}
+-
+-	for _, includeDeclaration := range []bool{false, true} {
+-		// Ignore first 'want' location if we didn't request the declaration.
+-		// TODO(adonovan): don't assume a single declaration:
+-		// there may be >1 if corresponding methods are considered.
+-		want := want
+-		if !includeDeclaration && len(want) > 0 {
+-			want = want[1:]
+-		}
+-		if err := refs(includeDeclaration, want); err != nil {
+-			mark.errorf("refs(includeDeclaration=%t) failed: %v",
+-				includeDeclaration, err)
+-		}
+-	}
+-}
+-
+-// implementationMarker implements the @implementation marker.
+-func implementationMarker(mark marker, src protocol.Location, want ...protocol.Location) {
+-	got, err := mark.server().Implementation(mark.run.env.Ctx, &protocol.ImplementationParams{
+-		TextDocumentPositionParams: protocol.LocationTextDocumentPositionParams(src),
+-	})
+-	if err != nil {
+-		mark.errorf("implementation at %s failed: %v", src, err)
+-		return
+-	}
+-	if err := compareLocations(mark, got, want); err != nil {
+-		mark.errorf("implementation: %v", err)
+-	}
+-}
+-
+-// symbolMarker implements the @symbol marker.
+-func symbolMarker(mark marker, golden *Golden) {
+-	// Retrieve information about all symbols in this file.
+-	symbols, err := mark.server().DocumentSymbol(mark.run.env.Ctx, &protocol.DocumentSymbolParams{
+-		TextDocument: protocol.TextDocumentIdentifier{URI: mark.uri()},
+-	})
+-	if err != nil {
+-		mark.errorf("DocumentSymbol request failed: %v", err)
+-		return
+-	}
+-
+-	// Format symbols one per line, sorted (in effect) by first column, a dotted name.
+-	var lines []string
+-	for _, symbol := range symbols {
+-		// Each result element is a union of (legacy)
+-		// SymbolInformation and (new) DocumentSymbol,
+-		// so we ascertain which one and then transcode.
+-		data, err := json.Marshal(symbol)
+-		if err != nil {
+-			mark.run.env.T.Fatal(err)
+-		}
+-		if _, ok := symbol.(map[string]any)["location"]; ok {
+-			// This case is not reached because Editor initialization
+-			// enables HierarchicalDocumentSymbolSupport.
+-			// TODO(adonovan): test this too.
+-			var sym protocol.SymbolInformation
+-			if err := json.Unmarshal(data, &sym); err != nil {
+-				mark.run.env.T.Fatal(err)
+-			}
+-			mark.errorf("fake Editor doesn't support SymbolInformation")
+-
+-		} else {
+-			var sym protocol.DocumentSymbol // new hierarchical hotness
+-			if err := json.Unmarshal(data, &sym); err != nil {
+-				mark.run.env.T.Fatal(err)
+-			}
+-
+-			// Print each symbol in the response tree.
+-			var visit func(sym protocol.DocumentSymbol, prefix []string)
+-			visit = func(sym protocol.DocumentSymbol, prefix []string) {
+-				var out strings.Builder
+-				out.WriteString(strings.Join(prefix, "."))
+-				fmt.Fprintf(&out, " %q", sym.Detail)
+-				if delta := sym.Range.End.Line - sym.Range.Start.Line; delta > 0 {
+-					fmt.Fprintf(&out, " +%d lines", delta)
+-				}
+-				lines = append(lines, out.String())
+-
+-				for _, child := range sym.Children {
+-					visit(child, append(prefix, child.Name))
+-				}
+-			}
+-			visit(sym, []string{sym.Name})
+-		}
+-	}
+-	sort.Strings(lines)
+-	lines = append(lines, "") // match trailing newline in .txtar file
+-	got := []byte(strings.Join(lines, "\n"))
+-
+-	// Compare with golden.
+-	want, ok := golden.Get(mark.run.env.T, "", got)
+-	if !ok {
+-		mark.errorf("%s: missing golden file @%s", mark.note.Name, golden.id)
+-	} else if diff := cmp.Diff(string(got), string(want)); diff != "" {
+-		mark.errorf("%s: unexpected output: got:\n%s\nwant:\n%s\ndiff:\n%s",
+-			mark.note.Name, got, want, diff)
+-	}
+-}
+-
+-// compareLocations returns an error message if got and want are not
+-// the same set of locations. The marker is used only for fmtLoc.
+-func compareLocations(mark marker, got, want []protocol.Location) error {
+-	toStrings := func(locs []protocol.Location) []string {
+-		strs := make([]string, len(locs))
+-		for i, loc := range locs {
+-			strs[i] = mark.run.fmtLoc(loc)
+-		}
+-		sort.Strings(strs)
+-		return strs
+-	}
+-	if diff := cmp.Diff(toStrings(want), toStrings(got)); diff != "" {
+-		return fmt.Errorf("incorrect result locations: (got %d, want %d):\n%s",
+-			len(got), len(want), diff)
+-	}
+-	return nil
+-}
+-
+-func workspaceSymbolMarker(mark marker, query string, golden *Golden) {
+-	params := &protocol.WorkspaceSymbolParams{
+-		Query: query,
+-	}
+-
+-	gotSymbols, err := mark.server().Symbol(mark.run.env.Ctx, params)
+-	if err != nil {
+-		mark.errorf("Symbol(%q) failed: %v", query, err)
+-		return
+-	}
+-	var got bytes.Buffer
+-	for _, s := range gotSymbols {
+-		// Omit the txtar position of the symbol location; otherwise edits to the
+-		// txtar archive lead to unexpected failures.
+-		loc := mark.run.fmtLocDetails(s.Location, false)
+-		// TODO(rfindley): can we do better here, by detecting if the location is
+-		// relative to GOROOT?
+-		if loc == "" {
+-			loc = "<unknown>"
+-		}
+-		fmt.Fprintf(&got, "%s %s %s\n", loc, s.Name, s.Kind)
+-	}
+-
+-	want, ok := golden.Get(mark.run.env.T, "", got.Bytes())
+-	if !ok {
+-		mark.errorf("missing golden file @%s", golden.id)
+-		return
+-	}
+-
+-	if diff := compare.Bytes(want, got.Bytes()); diff != "" {
+-		mark.errorf("Symbol(%q) mismatch:\n%s", query, diff)
+-	}
+-}
 diff -urN a/gopls/internal/lsp/regtest/options.go b/gopls/internal/lsp/regtest/options.go
 --- a/gopls/internal/lsp/regtest/options.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/options.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,105 +0,0 @@
++++ b/gopls/internal/lsp/regtest/options.go	1970-01-01 08:00:00
+@@ -1,134 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
 -package regtest
 -
--import "golang.org/x/tools/gopls/internal/lsp/fake"
+-import (
+-	"golang.org/x/tools/gopls/internal/lsp/fake"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
 -
 -type runConfig struct {
 -	editor    fake.EditorConfig
@@ -61423,6 +68627,18 @@
 -	skipHooks bool
 -}
 -
+-func defaultConfig() runConfig {
+-	return runConfig{
+-		editor: fake.EditorConfig{
+-			Settings: map[string]interface{}{
+-				// Shorten the diagnostic delay to speed up test execution (else we'd add
+-				// the default delay to each assertion about diagnostics)
+-				"diagnosticsDelay": "10ms",
+-			},
+-		},
+-	}
+-}
+-
 -// A RunOption augments the behavior of the test runner.
 -type RunOption interface {
 -	set(*runConfig)
@@ -61462,8 +68678,14 @@
 -	})
 -}
 -
--// Settings is a RunOption that sets user-provided configuration for the LSP
--// server.
+-// ClientName sets the LSP client name.
+-func ClientName(name string) RunOption {
+-	return optionSetter(func(opts *runConfig) {
+-		opts.editor.ClientName = name
+-	})
+-}
+-
+-// Settings sets user-provided configuration for the LSP server.
 -//
 -// As a special case, the env setting must not be provided via Settings: use
 -// EnvVars instead.
@@ -61513,10 +68735,18 @@
 -		opts.sandbox.InGoPath = true
 -	})
 -}
+-
+-// MessageResponder configures the editor to respond to
+-// window/showMessageRequest messages using the provided function.
+-func MessageResponder(f func(*protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error)) RunOption {
+-	return optionSetter(func(opts *runConfig) {
+-		opts.editor.MessageResponder = f
+-	})
+-}
 diff -urN a/gopls/internal/lsp/regtest/regtest.go b/gopls/internal/lsp/regtest/regtest.go
 --- a/gopls/internal/lsp/regtest/regtest.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/regtest.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,153 +0,0 @@
++++ b/gopls/internal/lsp/regtest/regtest.go	1970-01-01 08:00:00
+@@ -1,156 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -61527,7 +68757,6 @@
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"runtime"
 -	"testing"
@@ -61623,6 +68852,10 @@
 -		os.Exit(0)
 -	}
 -
+-	if !testenv.HasExec() {
+-		fmt.Printf("skipping all tests: exec not supported on %s\n", runtime.GOOS)
+-		os.Exit(0)
+-	}
 -	testenv.ExitIfSmallMachine()
 -
 -	// Disable GOPACKAGESDRIVER, as it can cause spurious test failures.
@@ -61648,7 +68881,7 @@
 -		}
 -	}
 -
--	dir, err := ioutil.TempDir("", "gopls-regtest-")
+-	dir, err := os.MkdirTemp("", "gopls-regtest-")
 -	if err != nil {
 -		panic(fmt.Errorf("creating regtest temp directory: %v", err))
 -	}
@@ -61672,8 +68905,8 @@
 -}
 diff -urN a/gopls/internal/lsp/regtest/runner.go b/gopls/internal/lsp/regtest/runner.go
 --- a/gopls/internal/lsp/regtest/runner.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/runner.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,437 +0,0 @@
++++ b/gopls/internal/lsp/regtest/runner.go	1970-01-01 08:00:00
+@@ -1,436 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -61685,7 +68918,6 @@
 -	"context"
 -	"fmt"
 -	"io"
--	"io/ioutil"
 -	"net"
 -	"os"
 -	"path/filepath"
@@ -61830,7 +69062,7 @@
 -
 -	for _, tc := range tests {
 -		tc := tc
--		var config runConfig
+-		config := defaultConfig()
 -		for _, opt := range opts {
 -			opt.set(&config)
 -		}
@@ -62046,7 +69278,7 @@
 -	}
 -
 -	r.startRemoteOnce.Do(func() {
--		socketDir, err := ioutil.TempDir(r.tempDir, "gopls-regtest-socket")
+-		socketDir, err := os.MkdirTemp(r.tempDir, "gopls-regtest-socket")
 -		if err != nil {
 -			r.remoteErr = err
 -			return
@@ -62113,8 +69345,8 @@
 -}
 diff -urN a/gopls/internal/lsp/regtest/wrappers.go b/gopls/internal/lsp/regtest/wrappers.go
 --- a/gopls/internal/lsp/regtest/wrappers.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/regtest/wrappers.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,489 +0,0 @@
++++ b/gopls/internal/lsp/regtest/wrappers.go	1970-01-01 08:00:00
+@@ -1,544 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -62272,9 +69504,20 @@
 -
 -// GoToDefinition goes to definition in the editor, calling t.Fatal on any
 -// error. It returns the path and position of the resulting jump.
+-//
+-// TODO(rfindley): rename this to just 'Definition'.
 -func (e *Env) GoToDefinition(loc protocol.Location) protocol.Location {
 -	e.T.Helper()
--	loc, err := e.Editor.GoToDefinition(e.Ctx, loc)
+-	loc, err := e.Editor.Definition(e.Ctx, loc)
+-	if err != nil {
+-		e.T.Fatal(err)
+-	}
+-	return loc
+-}
+-
+-func (e *Env) TypeDefinition(loc protocol.Location) protocol.Location {
+-	e.T.Helper()
+-	loc, err := e.Editor.TypeDefinition(e.Ctx, loc)
 -	if err != nil {
 -		e.T.Fatal(err)
 -	}
@@ -62362,7 +69605,7 @@
 -	if err := e.Editor.RunGenerate(e.Ctx, dir); err != nil {
 -		e.T.Fatal(err)
 -	}
--	e.Await(NoOutstandingWork())
+-	e.Await(NoOutstandingWork(IgnoreTelemetryPromptWork))
 -	// Ideally the fake.Workspace would handle all synthetic file watching, but
 -	// we help it out here as we need to wait for the generate command to
 -	// complete before checking the filesystem.
@@ -62373,7 +69616,7 @@
 -// directory.
 -func (e *Env) RunGoCommand(verb string, args ...string) {
 -	e.T.Helper()
--	if err := e.Sandbox.RunGoCommand(e.Ctx, "", verb, args, true); err != nil {
+-	if err := e.Sandbox.RunGoCommand(e.Ctx, "", verb, args, nil, true); err != nil {
 -		e.T.Fatal(err)
 -	}
 -}
@@ -62382,7 +69625,16 @@
 -// relative directory of the sandbox.
 -func (e *Env) RunGoCommandInDir(dir, verb string, args ...string) {
 -	e.T.Helper()
--	if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args, true); err != nil {
+-	if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args, nil, true); err != nil {
+-		e.T.Fatal(err)
+-	}
+-}
+-
+-// RunGoCommandInDirWithEnv is like RunGoCommand, but executes in the given
+-// relative directory of the sandbox with the given additional environment variables.
+-func (e *Env) RunGoCommandInDirWithEnv(dir string, env []string, verb string, args ...string) {
+-	e.T.Helper()
+-	if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args, env, true); err != nil {
 -		e.T.Fatal(err)
 -	}
 -}
@@ -62403,7 +69655,7 @@
 -func (e *Env) DumpGoSum(dir string) {
 -	e.T.Helper()
 -
--	if err := e.Sandbox.RunGoCommand(e.Ctx, dir, "list", []string{"-mod=mod", "..."}, true); err != nil {
+-	if err := e.Sandbox.RunGoCommand(e.Ctx, dir, "list", []string{"-mod=mod", "..."}, nil, true); err != nil {
 -		e.T.Fatal(err)
 -	}
 -	sumFile := path.Join(dir, "/go.sum")
@@ -62478,6 +69730,41 @@
 -	}
 -}
 -
+-// StartProfile starts a CPU profile with the given name, using the
+-// gopls.start_profile custom command. It calls t.Fatal on any error.
+-//
+-// The resulting stop function must be called to stop profiling (using the
+-// gopls.stop_profile custom command).
+-func (e *Env) StartProfile() (stop func() string) {
+-	// TODO(golang/go#61217): revisit the ergonomics of these command APIs.
+-	//
+-	// This would be a lot simpler if we generated params constructors.
+-	args, err := command.MarshalArgs(command.StartProfileArgs{})
+-	if err != nil {
+-		e.T.Fatal(err)
+-	}
+-	params := &protocol.ExecuteCommandParams{
+-		Command:   command.StartProfile.ID(),
+-		Arguments: args,
+-	}
+-	var result command.StartProfileResult
+-	e.ExecuteCommand(params, &result)
+-
+-	return func() string {
+-		stopArgs, err := command.MarshalArgs(command.StopProfileArgs{})
+-		if err != nil {
+-			e.T.Fatal(err)
+-		}
+-		stopParams := &protocol.ExecuteCommandParams{
+-			Command:   command.StopProfile.ID(),
+-			Arguments: stopArgs,
+-		}
+-		var result command.StopProfileResult
+-		e.ExecuteCommand(stopParams, &result)
+-		return result.File
+-	}
+-}
+-
 -// InlayHints calls textDocument/inlayHints for the given path, calling t.Fatal on
 -// any error.
 -func (e *Env) InlayHints(path string) []protocol.InlayHint {
@@ -62606,8 +69893,8 @@
 -}
 diff -urN a/gopls/internal/lsp/rename.go b/gopls/internal/lsp/rename.go
 --- a/gopls/internal/lsp/rename.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/rename.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,78 +0,0 @@
++++ b/gopls/internal/lsp/rename.go	1970-01-01 08:00:00
+@@ -1,86 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -62620,9 +69907,14 @@
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -)
 -
 -func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.rename", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -62636,9 +69928,9 @@
 -		return nil, err
 -	}
 -
--	var docChanges []protocol.DocumentChanges
+-	docChanges := []protocol.DocumentChanges{} // must be a slice
 -	for uri, e := range edits {
--		fh, err := snapshot.GetFile(ctx, uri)
+-		fh, err := snapshot.ReadFile(ctx, uri)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -62668,6 +69960,9 @@
 -// TODO(rfindley): why wouldn't we want to show an error to the user, if the
 -// user initiated a rename request at the cursor?
 -func (s *Server) prepareRename(ctx context.Context, params *protocol.PrepareRenameParams) (*protocol.PrepareRename2Gn, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.prepareRename", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -62688,7 +69983,7 @@
 -}
 diff -urN a/gopls/internal/lsp/reset_golden.sh b/gopls/internal/lsp/reset_golden.sh
 --- a/gopls/internal/lsp/reset_golden.sh	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/reset_golden.sh	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/reset_golden.sh	1970-01-01 08:00:00
 @@ -1,30 +0,0 @@
 -#!/bin/bash
 -#
@@ -62722,8 +70017,8 @@
 -go test ./test  -golden
 diff -urN a/gopls/internal/lsp/safetoken/safetoken.go b/gopls/internal/lsp/safetoken/safetoken.go
 --- a/gopls/internal/lsp/safetoken/safetoken.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/safetoken/safetoken.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,122 +0,0 @@
++++ b/gopls/internal/lsp/safetoken/safetoken.go	1970-01-01 08:00:00
+@@ -1,127 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -62817,6 +70112,11 @@
 -	return f.PositionFor(pos, false)
 -}
 -
+-// Line returns the line number for the given offset in the given file.
+-func Line(f *token.File, pos token.Pos) int {
+-	return Position(f, pos).Line
+-}
+-
 -// StartPosition converts a start Pos in the FileSet into a Position.
 -//
 -// Call this function only if start represents the start of a token or
@@ -62848,8 +70148,8 @@
 -}
 diff -urN a/gopls/internal/lsp/safetoken/safetoken_test.go b/gopls/internal/lsp/safetoken/safetoken_test.go
 --- a/gopls/internal/lsp/safetoken/safetoken_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/safetoken/safetoken_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,121 +0,0 @@
++++ b/gopls/internal/lsp/safetoken/safetoken_test.go	1970-01-01 08:00:00
+@@ -1,132 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -62924,10 +70224,20 @@
 -// suggests alternatives.
 -func TestGoplsSourceDoesNotCallTokenFileMethods(t *testing.T) {
 -	testenv.NeedsGoPackages(t)
+-	testenv.NeedsGo1Point(t, 18)
+-	testenv.NeedsLocalXTools(t)
 -
--	pkgs, err := packages.Load(&packages.Config{
+-	cfg := &packages.Config{
 -		Mode: packages.NeedName | packages.NeedModule | packages.NeedCompiledGoFiles | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax | packages.NeedImports | packages.NeedDeps,
--	}, "go/token", "golang.org/x/tools/gopls/...")
+-	}
+-	cfg.Env = os.Environ()
+-	cfg.Env = append(cfg.Env,
+-		"GOPACKAGESDRIVER=off",
+-		"GOWORK=off", // necessary for -mod=mod below
+-		"GOFLAGS=-mod=mod",
+-	)
+-
+-	pkgs, err := packages.Load(cfg, "go/token", "golang.org/x/tools/gopls/...")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -62950,6 +70260,7 @@
 -		oldMethod, _, _ := types.LookupFieldOrMethod(recv.Type(), true, recv.Pkg(), old)
 -		alternative[oldMethod] = new
 -	}
+-	setAlternative(File, "Line", "safetoken.Line")
 -	setAlternative(File, "Offset", "safetoken.Offset")
 -	setAlternative(File, "Position", "safetoken.Position")
 -	setAlternative(File, "PositionFor", "safetoken.Position")
@@ -62973,7 +70284,7 @@
 -}
 diff -urN a/gopls/internal/lsp/selection_range.go b/gopls/internal/lsp/selection_range.go
 --- a/gopls/internal/lsp/selection_range.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/selection_range.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/selection_range.go	1970-01-01 08:00:00
 @@ -1,69 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -63002,7 +70313,7 @@
 -// returned for each cursor to avoid multiple round-trips when the user is
 -// likely to issue this command multiple times in quick succession.
 -func (s *Server) selectionRange(ctx context.Context, params *protocol.SelectionRangeParams) ([]protocol.SelectionRange, error) {
--	ctx, done := event.Start(ctx, "lsp.Server.documentSymbol")
+-	ctx, done := event.Start(ctx, "lsp.Server.selectionRange")
 -	defer done()
 -
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
@@ -63046,8 +70357,8 @@
 -}
 diff -urN a/gopls/internal/lsp/semantic.go b/gopls/internal/lsp/semantic.go
 --- a/gopls/internal/lsp/semantic.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/semantic.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1003 +0,0 @@
++++ b/gopls/internal/lsp/semantic.go	1970-01-01 08:00:00
+@@ -1,999 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -63073,6 +70384,7 @@
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/template"
 -	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/typeparams"
 -)
 -
@@ -63087,25 +70399,22 @@
 -// semDebug should NEVER be true in checked-in code
 -const semDebug = false
 -
--func (s *Server) semanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
--	ret, err := s.computeSemanticTokens(ctx, p.TextDocument, nil)
+-func (s *Server) semanticTokensFull(ctx context.Context, params *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.semanticTokensFull", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
+-	ret, err := s.computeSemanticTokens(ctx, params.TextDocument, nil)
 -	return ret, err
 -}
 -
--func (s *Server) semanticTokensFullDelta(ctx context.Context, p *protocol.SemanticTokensDeltaParams) (interface{}, error) {
--	return nil, fmt.Errorf("implement SemanticTokensFullDelta")
--}
+-func (s *Server) semanticTokensRange(ctx context.Context, params *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.semanticTokensRange", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
 -
--func (s *Server) semanticTokensRange(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
--	ret, err := s.computeSemanticTokens(ctx, p.TextDocument, &p.Range)
+-	ret, err := s.computeSemanticTokens(ctx, params.TextDocument, &params.Range)
 -	return ret, err
 -}
 -
--func (s *Server) semanticTokensRefresh(ctx context.Context) error {
--	// in the code, but not in the protocol spec
--	return fmt.Errorf("implement SemanticTokensRefresh")
--}
--
 -func (s *Server) computeSemanticTokens(ctx context.Context, td protocol.TextDocumentIdentifier, rng *protocol.Range) (*protocol.SemanticTokens, error) {
 -	ans := protocol.SemanticTokens{
 -		Data: []uint32{},
@@ -63115,13 +70424,12 @@
 -	if !ok {
 -		return nil, err
 -	}
--	vv := snapshot.View()
--	if !vv.Options().SemanticTokens {
+-	if !snapshot.Options().SemanticTokens {
 -		// return an error, so if the option changes
 -		// the client won't remember the wrong answer
 -		return nil, fmt.Errorf("semantictokens are disabled")
 -	}
--	kind := snapshot.View().FileKind(fh)
+-	kind := snapshot.FileKind(fh)
 -	if kind == source.Tmpl {
 -		// this is a little cumbersome to avoid both exporting 'encoded' and its methods
 -		// and to avoid import cycles
@@ -63129,8 +70437,8 @@
 -			ctx:            ctx,
 -			metadataSource: snapshot,
 -			rng:            rng,
--			tokTypes:       s.session.Options().SemanticTypes,
--			tokMods:        s.session.Options().SemanticMods,
+-			tokTypes:       snapshot.Options().SemanticTypes,
+-			tokMods:        snapshot.Options().SemanticMods,
 -		}
 -		add := func(line, start uint32, len uint32) {
 -			e.add(line, start, len, tokMacro, nil)
@@ -63143,7 +70451,7 @@
 -	if kind != source.Go {
 -		return nil, nil
 -	}
--	pkg, pgf, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage)
+-	pkg, pgf, err := source.NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -63161,10 +70469,10 @@
 -		ti:             pkg.GetTypesInfo(),
 -		pkg:            pkg,
 -		fset:           pkg.FileSet(),
--		tokTypes:       s.session.Options().SemanticTypes,
--		tokMods:        s.session.Options().SemanticMods,
--		noStrings:      vv.Options().NoSemanticString,
--		noNumbers:      vv.Options().NoSemanticNumber,
+-		tokTypes:       snapshot.Options().SemanticTypes,
+-		tokMods:        snapshot.Options().SemanticMods,
+-		noStrings:      snapshot.Options().NoSemanticString,
+-		noNumbers:      snapshot.Options().NoSemanticNumber,
 -	}
 -	if err := e.init(); err != nil {
 -		// e.init should never return an error, unless there's some
@@ -63308,7 +70616,7 @@
 -// find the line in the source
 -func (e *encoded) srcLine(x ast.Node) string {
 -	file := e.pgf.Tok
--	line := file.Line(x.Pos())
+-	line := safetoken.Line(file, x.Pos())
 -	start, err := safetoken.Offset(file, file.LineStart(line))
 -	if err != nil {
 -		return ""
@@ -63889,17 +71197,16 @@
 -}
 -
 -func (e *encoded) init() error {
--	e.start = token.Pos(e.pgf.Tok.Base())
--	e.end = e.start + token.Pos(e.pgf.Tok.Size())
--	if e.rng == nil {
--		return nil
+-	if e.rng != nil {
+-		var err error
+-		e.start, e.end, err = e.pgf.RangePos(*e.rng)
+-		if err != nil {
+-			return fmt.Errorf("range span (%w) error for %s", err, e.pgf.File.Name)
+-		}
+-	} else {
+-		tok := e.pgf.Tok
+-		e.start, e.end = tok.Pos(0), tok.Pos(tok.Size()) // entire file
 -	}
--	span, err := e.pgf.Mapper.RangeSpan(*e.rng)
--	if err != nil {
--		return fmt.Errorf("range span (%w) error for %s", err, e.pgf.File.Name)
--	}
--	e.end = e.start + token.Pos(span.End().Offset())
--	e.start += token.Pos(span.Start().Offset())
 -	return nil
 -}
 -
@@ -64051,10 +71358,219 @@
 -		"deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary",
 -	}
 -)
+diff -urN a/gopls/internal/lsp/server.go b/gopls/internal/lsp/server.go
+--- a/gopls/internal/lsp/server.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/server.go	1970-01-01 08:00:00
+@@ -1,205 +0,0 @@
+-// Copyright 2018 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:generate go run ./helper -d protocol/tsserver.go -o server_gen.go -u .
+-
+-// Package lsp implements LSP for gopls.
+-package lsp
+-
+-import (
+-	"context"
+-	"fmt"
+-	"os"
+-	"sync"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
+-	"golang.org/x/tools/gopls/internal/lsp/progress"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/jsonrpc2"
+-)
+-
+-const concurrentAnalyses = 1
+-
+-// NewServer creates an LSP server and binds it to handle incoming client
+-// messages on the supplied stream.
+-func NewServer(session *cache.Session, client protocol.ClientCloser, options *source.Options) *Server {
+-	return &Server{
+-		diagnostics:           map[span.URI]*fileReports{},
+-		gcOptimizationDetails: make(map[source.PackageID]struct{}),
+-		watchedGlobPatterns:   nil, // empty
+-		changedFiles:          make(map[span.URI]struct{}),
+-		session:               session,
+-		client:                client,
+-		diagnosticsSema:       make(chan struct{}, concurrentAnalyses),
+-		progress:              progress.NewTracker(client),
+-		options:               options,
+-	}
+-}
+-
+-type serverState int
+-
+-const (
+-	serverCreated      = serverState(iota)
+-	serverInitializing // set once the server has received "initialize" request
+-	serverInitialized  // set once the server has received "initialized" request
+-	serverShutDown
+-)
+-
+-func (s serverState) String() string {
+-	switch s {
+-	case serverCreated:
+-		return "created"
+-	case serverInitializing:
+-		return "initializing"
+-	case serverInitialized:
+-		return "initialized"
+-	case serverShutDown:
+-		return "shutDown"
+-	}
+-	return fmt.Sprintf("(unknown state: %d)", int(s))
+-}
+-
+-// Server implements the protocol.Server interface.
+-type Server struct {
+-	client protocol.ClientCloser
+-
+-	stateMu sync.Mutex
+-	state   serverState
+-	// notifications generated before serverInitialized
+-	notifications []*protocol.ShowMessageParams
+-
+-	session *cache.Session
+-
+-	tempDir string
+-
+-	// changedFiles tracks files for which there has been a textDocument/didChange.
+-	changedFilesMu sync.Mutex
+-	changedFiles   map[span.URI]struct{}
+-
+-	// folders is only valid between initialize and initialized, and holds the
+-	// set of folders to build views for when we are ready
+-	pendingFolders []protocol.WorkspaceFolder
+-
+-	// watchedGlobPatterns is the set of glob patterns that we have requested
+-	// the client watch on disk. It will be updated as the set of directories
+-	// that the server should watch changes.
+-	// The map field may be reassigned but the map is immutable.
+-	watchedGlobPatternsMu  sync.Mutex
+-	watchedGlobPatterns    map[string]struct{}
+-	watchRegistrationCount int
+-
+-	diagnosticsMu sync.Mutex
+-	diagnostics   map[span.URI]*fileReports
+-
+-	// gcOptimizationDetails describes the packages for which we want
+-	// optimization details to be included in the diagnostics. The key is the
+-	// ID of the package.
+-	gcOptimizationDetailsMu sync.Mutex
+-	gcOptimizationDetails   map[source.PackageID]struct{}
+-
+-	// diagnosticsSema limits the concurrency of diagnostics runs, which can be
+-	// expensive.
+-	diagnosticsSema chan struct{}
+-
+-	progress *progress.Tracker
+-
+-	// When the workspace fails to load, we show its status through a progress
+-	// report with an error message.
+-	criticalErrorStatusMu sync.Mutex
+-	criticalErrorStatus   *progress.WorkDone
+-
+-	// Track an ongoing CPU profile created with the StartProfile command and
+-	// terminated with the StopProfile command.
+-	ongoingProfileMu sync.Mutex
+-	ongoingProfile   *os.File // if non-nil, an ongoing profile is writing to this file
+-
+-	// Track most recently requested options.
+-	optionsMu sync.Mutex
+-	options   *source.Options
+-}
+-
+-func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.workDoneProgressCancel")
+-	defer done()
+-
+-	return s.progress.Cancel(params.Token)
+-}
+-
+-func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.nonstandardRequest")
+-	defer done()
+-
+-	switch method {
+-	case "gopls/diagnoseFiles":
+-		paramMap := params.(map[string]interface{})
+-		// TODO(adonovan): opt: parallelize FileDiagnostics(URI...), either
+-		// by calling it in multiple goroutines or, better, by making
+-		// the relevant APIs accept a set of URIs/packages.
+-		for _, file := range paramMap["files"].([]interface{}) {
+-			snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind)
+-			defer release()
+-			if !ok {
+-				return nil, err
+-			}
+-
+-			fileID, diagnostics, err := s.diagnoseFile(ctx, snapshot, fh.URI())
+-			if err != nil {
+-				return nil, err
+-			}
+-			if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
+-				URI:         protocol.URIFromSpanURI(fh.URI()),
+-				Diagnostics: toProtocolDiagnostics(diagnostics),
+-				Version:     fileID.Version(),
+-			}); err != nil {
+-				return nil, err
+-			}
+-		}
+-		if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
+-			URI: "gopls://diagnostics-done",
+-		}); err != nil {
+-			return nil, err
+-		}
+-		return struct{}{}, nil
+-	}
+-	return nil, notImplemented(method)
+-}
+-
+-// fileDiagnostics reports diagnostics in the specified file,
+-// as used by the "gopls check" or "gopls fix" commands.
+-//
+-// TODO(adonovan): opt: this function is called in a loop from the
+-// "gopls/diagnoseFiles" nonstandard request handler. It would be more
+-// efficient to compute the set of packages and TypeCheck and
+-// Analyze them all at once. Or instead support textDocument/diagnostic
+-// (golang/go#60122).
+-func (s *Server) diagnoseFile(ctx context.Context, snapshot source.Snapshot, uri span.URI) (source.FileHandle, []*source.Diagnostic, error) {
+-	fh, err := snapshot.ReadFile(ctx, uri)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	pkg, _, err := source.NarrowestPackageForFile(ctx, snapshot, uri)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	pkgDiags, err := pkg.DiagnosticsForFile(ctx, snapshot, uri)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	adiags, err := source.Analyze(ctx, snapshot, map[source.PackageID]unit{pkg.Metadata().ID: {}}, nil /* progress tracker */)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	var td, ad []*source.Diagnostic // combine load/parse/type + analysis diagnostics
+-	source.CombineDiagnostics(pkgDiags, adiags[uri], &td, &ad)
+-	s.storeDiagnostics(snapshot, uri, typeCheckSource, td, true)
+-	s.storeDiagnostics(snapshot, uri, analysisSource, ad, true)
+-	return fh, append(td, ad...), nil
+-}
+-
+-func notImplemented(method string) error {
+-	return fmt.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method)
+-}
 diff -urN a/gopls/internal/lsp/server_gen.go b/gopls/internal/lsp/server_gen.go
 --- a/gopls/internal/lsp/server_gen.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/server_gen.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,301 +0,0 @@
++++ b/gopls/internal/lsp/server_gen.go	1970-01-01 08:00:00
+@@ -1,309 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -64213,6 +71729,10 @@
 -	return s.inlayHint(ctx, params)
 -}
 -
+-func (s *Server) InlineCompletion(context.Context, *protocol.InlineCompletionParams) (*protocol.Or_Result_textDocument_inlineCompletion, error) {
+-	return nil, notImplemented("InlineCompletion")
+-}
+-
 -func (s *Server) InlineValue(context.Context, *protocol.InlineValueParams) ([]protocol.InlineValue, error) {
 -	return nil, notImplemented("InlineValue")
 -}
@@ -64257,6 +71777,10 @@
 -	return nil, notImplemented("RangeFormatting")
 -}
 -
+-func (s *Server) RangesFormatting(context.Context, *protocol.DocumentRangesFormattingParams) ([]protocol.TextEdit, error) {
+-	return nil, notImplemented("RangesFormatting")
+-}
+-
 -func (s *Server) References(ctx context.Context, params *protocol.ReferenceParams) ([]protocol.Location, error) {
 -	return s.references(ctx, params)
 -}
@@ -64293,16 +71817,16 @@
 -	return s.selectionRange(ctx, params)
 -}
 -
--func (s *Server) SemanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
--	return s.semanticTokensFull(ctx, p)
+-func (s *Server) SemanticTokensFull(ctx context.Context, params *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
+-	return s.semanticTokensFull(ctx, params)
 -}
 -
--func (s *Server) SemanticTokensFullDelta(ctx context.Context, p *protocol.SemanticTokensDeltaParams) (interface{}, error) {
--	return s.semanticTokensFullDelta(ctx, p)
+-func (s *Server) SemanticTokensFullDelta(context.Context, *protocol.SemanticTokensDeltaParams) (interface{}, error) {
+-	return nil, notImplemented("SemanticTokensFullDelta")
 -}
 -
--func (s *Server) SemanticTokensRange(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
--	return s.semanticTokensRange(ctx, p)
+-func (s *Server) SemanticTokensRange(ctx context.Context, params *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
+-	return s.semanticTokensRange(ctx, params)
 -}
 -
 -func (s *Server) SetTrace(context.Context, *protocol.SetTraceParams) error {
@@ -64356,172 +71880,10 @@
 -func (s *Server) WorkDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
 -	return s.workDoneProgressCancel(ctx, params)
 -}
-diff -urN a/gopls/internal/lsp/server.go b/gopls/internal/lsp/server.go
---- a/gopls/internal/lsp/server.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/server.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,158 +0,0 @@
--// Copyright 2018 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--//go:generate go run ./helper -d protocol/tsserver.go -o server_gen.go -u .
--
--// Package lsp implements LSP for gopls.
--package lsp
--
--import (
--	"context"
--	"fmt"
--	"sync"
--
--	"golang.org/x/tools/gopls/internal/lsp/cache"
--	"golang.org/x/tools/gopls/internal/lsp/progress"
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/jsonrpc2"
--)
--
--const concurrentAnalyses = 1
--
--// NewServer creates an LSP server and binds it to handle incoming client
--// messages on on the supplied stream.
--func NewServer(session *cache.Session, client protocol.ClientCloser) *Server {
--	return &Server{
--		diagnostics:           map[span.URI]*fileReports{},
--		gcOptimizationDetails: make(map[source.PackageID]struct{}),
--		watchedGlobPatterns:   make(map[string]struct{}),
--		changedFiles:          make(map[span.URI]struct{}),
--		session:               session,
--		client:                client,
--		diagnosticsSema:       make(chan struct{}, concurrentAnalyses),
--		progress:              progress.NewTracker(client),
--		diagDebouncer:         newDebouncer(),
--	}
--}
--
--type serverState int
--
--const (
--	serverCreated      = serverState(iota)
--	serverInitializing // set once the server has received "initialize" request
--	serverInitialized  // set once the server has received "initialized" request
--	serverShutDown
--)
--
--func (s serverState) String() string {
--	switch s {
--	case serverCreated:
--		return "created"
--	case serverInitializing:
--		return "initializing"
--	case serverInitialized:
--		return "initialized"
--	case serverShutDown:
--		return "shutDown"
--	}
--	return fmt.Sprintf("(unknown state: %d)", int(s))
--}
--
--// Server implements the protocol.Server interface.
--type Server struct {
--	client protocol.ClientCloser
--
--	stateMu sync.Mutex
--	state   serverState
--	// notifications generated before serverInitialized
--	notifications []*protocol.ShowMessageParams
--
--	session *cache.Session
--
--	tempDir string
--
--	// changedFiles tracks files for which there has been a textDocument/didChange.
--	changedFilesMu sync.Mutex
--	changedFiles   map[span.URI]struct{}
--
--	// folders is only valid between initialize and initialized, and holds the
--	// set of folders to build views for when we are ready
--	pendingFolders []protocol.WorkspaceFolder
--
--	// watchedGlobPatterns is the set of glob patterns that we have requested
--	// the client watch on disk. It will be updated as the set of directories
--	// that the server should watch changes.
--	watchedGlobPatternsMu  sync.Mutex
--	watchedGlobPatterns    map[string]struct{}
--	watchRegistrationCount int
--
--	diagnosticsMu sync.Mutex
--	diagnostics   map[span.URI]*fileReports
--
--	// gcOptimizationDetails describes the packages for which we want
--	// optimization details to be included in the diagnostics. The key is the
--	// ID of the package.
--	gcOptimizationDetailsMu sync.Mutex
--	gcOptimizationDetails   map[source.PackageID]struct{}
--
--	// diagnosticsSema limits the concurrency of diagnostics runs, which can be
--	// expensive.
--	diagnosticsSema chan struct{}
--
--	progress *progress.Tracker
--
--	// diagDebouncer is used for debouncing diagnostics.
--	diagDebouncer *debouncer
--
--	// When the workspace fails to load, we show its status through a progress
--	// report with an error message.
--	criticalErrorStatusMu sync.Mutex
--	criticalErrorStatus   *progress.WorkDone
--}
--
--func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
--	return s.progress.Cancel(params.Token)
--}
--
--func (s *Server) nonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
--	switch method {
--	case "gopls/diagnoseFiles":
--		paramMap := params.(map[string]interface{})
--		// TODO(adonovan): opt: parallelize FileDiagnostics(URI...), either
--		// by calling it in multiple goroutines or, better, by making
--		// the relevant APIs accept a set of URIs/packages.
--		for _, file := range paramMap["files"].([]interface{}) {
--			snapshot, fh, ok, release, err := s.beginFileRequest(ctx, protocol.DocumentURI(file.(string)), source.UnknownKind)
--			defer release()
--			if !ok {
--				return nil, err
--			}
--
--			fileID, diagnostics, err := source.FileDiagnostics(ctx, snapshot, fh.URI())
--			if err != nil {
--				return nil, err
--			}
--			if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
--				URI:         protocol.URIFromSpanURI(fh.URI()),
--				Diagnostics: toProtocolDiagnostics(diagnostics),
--				Version:     fileID.Version(),
--			}); err != nil {
--				return nil, err
--			}
--		}
--		if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
--			URI: "gopls://diagnostics-done",
--		}); err != nil {
--			return nil, err
--		}
--		return struct{}{}, nil
--	}
--	return nil, notImplemented(method)
--}
--
--func notImplemented(method string) error {
--	return fmt.Errorf("%w: %q not yet implemented", jsonrpc2.ErrMethodNotFound, method)
--}
 diff -urN a/gopls/internal/lsp/signature_help.go b/gopls/internal/lsp/signature_help.go
 --- a/gopls/internal/lsp/signature_help.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/signature_help.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
++++ b/gopls/internal/lsp/signature_help.go	1970-01-01 08:00:00
+@@ -1,34 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -64538,6 +71900,9 @@
 -)
 -
 -func (s *Server) signatureHelp(ctx context.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) {
+-	ctx, done := event.Start(ctx, "lsp.Server.signatureHelp", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
 -	defer release()
 -	if !ok {
@@ -64555,7 +71920,7 @@
 -}
 diff -urN a/gopls/internal/lsp/snippet/snippet_builder.go b/gopls/internal/lsp/snippet/snippet_builder.go
 --- a/gopls/internal/lsp/snippet/snippet_builder.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/snippet/snippet_builder.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/snippet/snippet_builder.go	1970-01-01 08:00:00
 @@ -1,111 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -64670,7 +72035,7 @@
 -}
 diff -urN a/gopls/internal/lsp/snippet/snippet_builder_test.go b/gopls/internal/lsp/snippet/snippet_builder_test.go
 --- a/gopls/internal/lsp/snippet/snippet_builder_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/snippet/snippet_builder_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/snippet/snippet_builder_test.go	1970-01-01 08:00:00
 @@ -1,62 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -64736,7 +72101,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/add_import.go b/gopls/internal/lsp/source/add_import.go
 --- a/gopls/internal/lsp/source/add_import.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/add_import.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/add_import.go	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -64766,8 +72131,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/api_json.go b/gopls/internal/lsp/source/api_json.go
 --- a/gopls/internal/lsp/source/api_json.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/api_json.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1118 +0,0 @@
++++ b/gopls/internal/lsp/source/api_json.go	1970-01-01 08:00:00
+@@ -1,1263 +0,0 @@
 -// Code generated by "golang.org/x/tools/gopls/doc/generate"; DO NOT EDIT.
 -
 -package source
@@ -64917,6 +72282,13 @@
 -				Hierarchy: "ui.completion",
 -			},
 -			{
+-				Name:      "completeFunctionCalls",
+-				Type:      "bool",
+-				Doc:       "completeFunctionCalls enables function call completion.\n\nWhen completing a statement, or when a function return type matches the\nexpected of the expression being completed, completion may suggest call\nexpressions (i.e. may include parentheses).\n",
+-				Default:   "true",
+-				Hierarchy: "ui.completion",
+-			},
+-			{
 -				Name: "importShortcut",
 -				Type: "enum",
 -				Doc:  "importShortcut specifies whether import statements should link to\ndocumentation or go to definitions.\n",
@@ -64965,6 +72337,23 @@
 -				Hierarchy: "ui.navigation",
 -			},
 -			{
+-				Name: "symbolScope",
+-				Type: "enum",
+-				Doc:  "symbolScope controls which packages are searched for workspace/symbol\nrequests. The default value, \"workspace\", searches only workspace\npackages. The legacy behavior, \"all\", causes all loaded packages to be\nsearched, including dependencies; this is more expensive and may return\nunwanted results.\n",
+-				EnumValues: []EnumValue{
+-					{
+-						Value: "\"all\"",
+-						Doc:   "`\"all\"` matches symbols in any loaded package, including\ndependencies.\n",
+-					},
+-					{
+-						Value: "\"workspace\"",
+-						Doc:   "`\"workspace\"` matches symbols in workspace packages only.\n",
+-					},
+-				},
+-				Default:   "\"all\"",
+-				Hierarchy: "ui.navigation",
+-			},
+-			{
 -				Name: "analyses",
 -				Type: "map[string]bool",
 -				Doc:  "analyses specify analyses that the user would like to enable or disable.\nA map of the names of analysis passes that should be enabled/disabled.\nA full list of analyzers that gopls uses can be found in\n[analyzers.md](https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md).\n\nExample Usage:\n\n```json5\n...\n\"analyses\": {\n  \"unreachable\": false, // Disable the unreachable analyzer.\n  \"unusedparams\": true  // Enable the unusedparams analyzer.\n}\n...\n```\n",
@@ -64972,6 +72361,11 @@
 -					ValueType: "bool",
 -					Keys: []EnumKey{
 -						{
+-							Name:    "\"appends\"",
+-							Doc:     "check for missing values after append\n\nThis checker reports calls to append that pass\nno values to be appended to the slice.\n\n\ts := []string{\"a\", \"b\", \"c\"}\n\t_ = append(s)\n\nSuch calls are always no-ops and often indicate an\nunderlying mistake.",
+-							Default: "true",
+-						},
+-						{
 -							Name:    "\"asmdecl\"",
 -							Doc:     "report mismatches between assembly files and Go declarations",
 -							Default: "true",
@@ -65022,13 +72416,23 @@
 -							Default: "true",
 -						},
 -						{
+-							Name:    "\"defers\"",
+-							Doc:     "report common mistakes in defer statements\n\nThe defers analyzer reports a diagnostic when a defer statement would\nresult in a non-deferred call to time.Since, as experience has shown\nthat this is nearly always a mistake.\n\nFor example:\n\n\tstart := time.Now()\n\t...\n\tdefer recordLatency(time.Since(start)) // error: call to time.Since is not deferred\n\nThe correct code is:\n\n\tdefer func() { recordLatency(time.Since(start)) }()",
+-							Default: "true",
+-						},
+-						{
+-							Name:    "\"deprecated\"",
+-							Doc:     "check for use of deprecated identifiers\n\nThe deprecated analyzer looks for deprecated symbols and package imports.\n\nSee https://go.dev/wiki/Deprecated to learn about Go's convention\nfor documenting and signaling deprecated identifiers.",
+-							Default: "true",
+-						},
+-						{
 -							Name:    "\"directive\"",
 -							Doc:     "check Go toolchain directives such as //go:debug\n\nThis analyzer checks for problems with known Go toolchain directives\nin all Go source files in a package directory, even those excluded by\n//go:build constraints, and all non-Go source files too.\n\nFor //go:debug (see https://go.dev/doc/godebug), the analyzer checks\nthat the directives are placed only in Go source files, only above the\npackage comment, and only in package main or *_test.go files.\n\nSupport for other known directives may be added in the future.\n\nThis analyzer does not check //go:build, which is handled by the\nbuildtag analyzer.\n",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"embed\"",
--							Doc:     "check for //go:embed directive import\n\nThis analyzer checks that the embed package is imported when source code contains //go:embed comment directives.\nThe embed package must be imported for //go:embed directives to function.import _ \"embed\".",
+-							Doc:     "check //go:embed directive usage\n\nThis analyzer checks that the embed package is imported if //go:embed\ndirectives are present, providing a suggested fix to add the import if\nit is missing.\n\nThis analyzer also checks that //go:embed directives precede the\ndeclaration of a single variable.",
 -							Default: "true",
 -						},
 -						{
@@ -65048,17 +72452,12 @@
 -						},
 -						{
 -							Name:    "\"ifaceassert\"",
--							Doc:     "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.\n",
--							Default: "true",
--						},
--						{
--							Name:    "\"infertypeargs\"",
--							Doc:     "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n",
+-							Doc:     "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"loopclosure\"",
--							Doc:     "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n    for _, v := range list {\n        defer func() {\n            use(v) // incorrect\n        }()\n    }\n\nOne fix is to create a new variable for each iteration of the loop:\n\n    for _, v := range list {\n        v := v // new var per iteration\n        defer func() {\n            use(v) // ok\n        }()\n    }\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n    for _, v := range elem {\n        go func() {\n            use(v)  // incorrect, and a data race\n        }()\n    }\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n    func Test(t *testing.T) {\n        for _, test := range tests {\n            t.Run(test.name, func(t *testing.T) {\n                t.Parallel()\n                use(test) // incorrect, and a data race\n            })\n        }\n    }\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines",
+-							Doc:     "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n\tfor _, v := range list {\n\t    defer func() {\n\t        use(v) // incorrect\n\t    }()\n\t}\n\nOne fix is to create a new variable for each iteration of the loop:\n\n\tfor _, v := range list {\n\t    v := v // new var per iteration\n\t    defer func() {\n\t        use(v) // ok\n\t    }()\n\t}\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n\tfor _, v := range elem {\n\t    go func() {\n\t        use(v)  // incorrect, and a data race\n\t    }()\n\t}\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n\tfunc Test(t *testing.T) {\n\t    for _, test := range tests {\n\t        t.Run(test.name, func(t *testing.T) {\n\t            t.Parallel()\n\t            use(test) // incorrect, and a data race\n\t        })\n\t    }\n\t}\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines",
 -							Default: "true",
 -						},
 -						{
@@ -65073,17 +72472,17 @@
 -						},
 -						{
 -							Name:    "\"nilness\"",
--							Doc:     "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}\n",
+-							Doc:     "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}",
 -							Default: "false",
 -						},
 -						{
 -							Name:    "\"printf\"",
--							Doc:     "check consistency of Printf format strings and arguments\n\nThe check applies to known functions (for example, those in package fmt)\nas well as any detected wrappers of known functions.\n\nA function that wants to avail itself of printf checking but is not\nfound by this analyzer's heuristics (for example, due to use of\ndynamic calls) can insert a bogus call:\n\n\tif false {\n\t\t_ = fmt.Sprintf(format, args...) // enable printf checking\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.\n",
+-							Doc:     "check consistency of Printf format strings and arguments\n\nThe check applies to calls of the formatting functions such as\n[fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of\nthose functions.\n\nIn this example, the %d format operator requires an integer operand:\n\n\tfmt.Printf(\"%d\", \"hello\") // fmt.Printf format %d has arg \"hello\" of wrong type string\n\nSee the documentation of the fmt package for the complete set of\nformat operators and their operand types.\n\nTo enable printf checking on a function that is not found by this\nanalyzer's heuristics (for example, because control is obscured by\ndynamic method calls), insert a bogus call:\n\n\tfunc MyPrintf(format string, args ...any) {\n\t\tif false {\n\t\t\t_ = fmt.Sprintf(format, args...) // enable printf checker\n\t\t}\n\t\t...\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"shadow\"",
--							Doc:     "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}\n",
+-							Doc:     "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}",
 -							Default: "false",
 -						},
 -						{
@@ -65107,18 +72506,23 @@
 -							Default: "true",
 -						},
 -						{
+-							Name:    "\"slog\"",
+-							Doc:     "check for invalid structured logging calls\n\nThe slog checker looks for calls to functions from the log/slog\npackage that take alternating key-value pairs. It reports calls\nwhere an argument in a key position is neither a string nor a\nslog.Attr, and where a final key is missing its value.\nFor example,it would report\n\n\tslog.Warn(\"message\", 11, \"k\") // slog.Warn arg \"11\" should be a string or a slog.Attr\n\nand\n\n\tslog.Info(\"message\", \"k1\", v1, \"k2\") // call to slog.Info missing a final value",
+-							Default: "true",
+-						},
+-						{
 -							Name:    "\"sortslice\"",
 -							Doc:     "check the argument type of sort.Slice\n\nsort.Slice requires an argument of a slice type. Check that\nthe interface{} value passed to sort.Slice is actually a slice.",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"stdmethods\"",
--							Doc:     "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n        func (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo\n",
+-							Doc:     "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n\tfunc (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"stringintconv\"",
--							Doc:     "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.\n",
+-							Doc:     "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.",
 -							Default: "true",
 -						},
 -						{
@@ -65128,17 +72532,17 @@
 -						},
 -						{
 -							Name:    "\"testinggoroutine\"",
--							Doc:     "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n    go func() {\n        t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n    }()\n}\n",
+-							Doc:     "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\n\tfunc TestFoo(t *testing.T) {\n\t    go func() {\n\t        t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n\t    }()\n\t}",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"tests\"",
--							Doc:     "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.",
+-							Doc:     "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark, Fuzzing and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"timeformat\"",
--							Doc:     "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.\n",
+-							Doc:     "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.",
 -							Default: "true",
 -						},
 -						{
@@ -65158,17 +72562,17 @@
 -						},
 -						{
 -							Name:    "\"unusedparams\"",
--							Doc:     "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or are underscored\n- functions in test files\n- functions with empty bodies or those with just a return stmt",
+-							Doc:     "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or have the name '_' (the blank identifier)\n- functions in test files\n- functions with empty bodies or those with just a return stmt",
 -							Default: "false",
 -						},
 -						{
 -							Name:    "\"unusedresult\"",
--							Doc:     "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side effects,\nso it is always a mistake to discard the result. This analyzer reports\ncalls to certain functions in which the result of the call is ignored.\n\nThe set of functions may be controlled using flags.",
+-							Doc:     "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side\neffects, so it is always a mistake to discard the result. Other\nfunctions may return an error that must not be ignored, or a cleanup\noperation that must be called. This analyzer reports calls to\nfunctions like these when the result of the call is ignored.\n\nThe set of functions may be controlled using flags.",
 -							Default: "true",
 -						},
 -						{
 -							Name:    "\"unusedwrite\"",
--							Doc:     "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input {  // v is a copy\n\t\t\tv.x = i  // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() {  // t is a copy\n\t\tt.x = i  // unused write to field x\n\t}\n",
+-							Doc:     "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\n\tfunc f(input []T) {\n\t\tfor i, v := range input {  // v is a copy\n\t\t\tv.x = i  // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\n\tfunc (t T) f() {  // t is a copy\n\t\tt.x = i  // unused write to field x\n\t}",
 -							Default: "false",
 -						},
 -						{
@@ -65207,6 +72611,11 @@
 -							Default: "true",
 -						},
 -						{
+-							Name:    "\"infertypeargs\"",
+-							Doc:     "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n",
+-							Default: "true",
+-						},
+-						{
 -							Name:    "\"stubmethods\"",
 -							Doc:     "stub methods analyzer\n\nThis analyzer generates method stubs for concrete types\nin order to implement a target interface",
 -							Default: "true",
@@ -65279,11 +72688,18 @@
 -				Name:      "diagnosticsDelay",
 -				Type:      "time.Duration",
 -				Doc:       "diagnosticsDelay controls the amount of time that gopls waits\nafter the most recent file modification before computing deep diagnostics.\nSimple diagnostics (parsing and type-checking) are always run immediately\non recently modified packages.\n\nThis option must be set to a valid duration string, for example `\"250ms\"`.\n",
--				Default:   "\"250ms\"",
+-				Default:   "\"1s\"",
 -				Status:    "advanced",
 -				Hierarchy: "ui.diagnostic",
 -			},
 -			{
+-				Name:      "analysisProgressReporting",
+-				Type:      "bool",
+-				Doc:       "analysisProgressReporting controls whether gopls sends progress\nnotifications when construction of its index of analysis facts is taking a\nlong time. Cancelling these notifications will cancel the indexing task,\nthough it will restart after the next change in the workspace.\n\nWhen a package is opened for the first time and heavyweight analyses such as\nstaticcheck are enabled, it can take a while to construct the index of\nanalysis facts for all its dependencies. The index is cached in the\nfilesystem, so subsequent analysis should be faster.\n",
+-				Default:   "true",
+-				Hierarchy: "ui.diagnostic",
+-			},
+-			{
 -				Name: "hints",
 -				Type: "map[string]bool",
 -				Doc:  "hints specify inlay hints that users want to see. A full list of hints\nthat gopls uses can be found in\n[inlayHints.md](https://github.com/golang/tools/blob/master/gopls/doc/inlayHints.md).\n",
@@ -65441,6 +72857,12 @@
 -			ArgDoc:  "{\n\t// ImportPath is the target import path that should\n\t// be added to the URI file\n\t\"ImportPath\": string,\n\t// URI is the file that the ImportPath should be\n\t// added to\n\t\"URI\": string,\n}",
 -		},
 -		{
+-			Command: "gopls.add_telemetry_counters",
+-			Title:   "update the given telemetry counters.",
+-			Doc:     "Gopls will prepend \"fwd/\" to all the counters updated using this command\nto avoid conflicts with other counters gopls collects.",
+-			ArgDoc:  "{\n\t// Names and Values must have the same length.\n\t\"Names\": []string,\n\t\"Values\": []int64,\n}",
+-		},
+-		{
 -			Command: "gopls.apply_fix",
 -			Title:   "Apply a fix",
 -			Doc:     "Applies a fix to a region of source code.",
@@ -65463,7 +72885,7 @@
 -			Title:     "Get known vulncheck result",
 -			Doc:       "Fetch the result of latest vulnerability check (`govulncheck`).",
 -			ArgDoc:    "{\n\t// The file URI.\n\t\"URI\": string,\n}",
--			ResultDoc: "map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/govulncheck.Result",
+-			ResultDoc: "map[golang.org/x/tools/gopls/internal/lsp/protocol.DocumentURI]*golang.org/x/tools/gopls/internal/vulncheck.Result",
 -		},
 -		{
 -			Command: "gopls.gc_details",
@@ -65498,10 +72920,15 @@
 -			ResultDoc: "{\n\t// Packages is a list of packages relative\n\t// to the URIArg passed by the command request.\n\t// In other words, it omits paths that are already\n\t// imported or cannot be imported due to compiler\n\t// restrictions.\n\t\"Packages\": []string,\n}",
 -		},
 -		{
+-			Command: "gopls.maybe_prompt_for_telemetry",
+-			Title:   "checks for the right conditions, and then prompts",
+-			Doc:     "the user to ask if they want to enable Go telemetry uploading. If the user\nresponds 'Yes', the telemetry mode is set to \"on\".",
+-		},
+-		{
 -			Command:   "gopls.mem_stats",
 -			Title:     "fetch memory statistics",
 -			Doc:       "Call runtime.GC multiple times and return memory statistics as reported by\nruntime.MemStats.\n\nThis command is used for benchmarking, and may change in the future.",
--			ResultDoc: "{\n\t\"HeapAlloc\": uint64,\n\t\"HeapInUse\": uint64,\n}",
+-			ResultDoc: "{\n\t\"HeapAlloc\": uint64,\n\t\"HeapInUse\": uint64,\n\t\"TotalAlloc\": uint64,\n}",
 -		},
 -		{
 -			Command: "gopls.regenerate_cgo",
@@ -65513,7 +72940,7 @@
 -			Command: "gopls.remove_dependency",
 -			Title:   "Remove a dependency",
 -			Doc:     "Removes a dependency from the go.mod file of a module.",
--			ArgDoc:  "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The module path to remove.\n\t\"ModulePath\": string,\n\t\"OnlyDiagnostic\": bool,\n}",
+-			ArgDoc:  "{\n\t// The go.mod file URI.\n\t\"URI\": string,\n\t// The module path to remove.\n\t\"ModulePath\": string,\n\t// If the module is tidied apart from the one unused diagnostic, we can\n\t// run `go get module@none`, and then run `go mod tidy`. Otherwise, we\n\t// must make textual edits.\n\t\"OnlyDiagnostic\": bool,\n}",
 -		},
 -		{
 -			Command: "gopls.reset_go_mod_diagnostics",
@@ -65522,8 +72949,14 @@
 -			ArgDoc:  "{\n\t\"URIArg\": {\n\t\t\"URI\": string,\n\t},\n\t// Optional: source of the diagnostics to reset.\n\t// If not set, all resettable go.mod diagnostics will be cleared.\n\t\"DiagnosticSource\": string,\n}",
 -		},
 -		{
+-			Command: "gopls.run_go_work_command",
+-			Title:   "run `go work [args...]`, and apply the resulting go.work",
+-			Doc:     "edits to the current go.work file.",
+-			ArgDoc:  "{\n\t\"ViewID\": string,\n\t\"InitFirst\": bool,\n\t\"Args\": []string,\n}",
+-		},
+-		{
 -			Command:   "gopls.run_govulncheck",
--			Title:     "Run govulncheck.",
+-			Title:     "Run vulncheck.",
 -			Doc:       "Run vulnerability check (`govulncheck`).",
 -			ArgDoc:    "{\n\t// Any document in the directory from which govulncheck will run.\n\t\"URI\": string,\n\t// Package pattern. E.g. \"\", \".\", \"./...\".\n\t\"Pattern\": string,\n}",
 -			ResultDoc: "{\n\t// Token holds the progress token for LSP workDone reporting of the vulncheck\n\t// invocation.\n\t\"Token\": interface{},\n}",
@@ -65538,8 +72971,22 @@
 -			Command:   "gopls.start_debugging",
 -			Title:     "Start the gopls debug server",
 -			Doc:       "Start the gopls debug server if it isn't running, and return the debug\naddress.",
--			ArgDoc:    "{\n\t// Optional: the address (including port) for the debug server to listen on.\n\t// If not provided, the debug server will bind to \"localhost:0\", and the\n\t// full debug URL will be contained in the result.\n\t// \n\t// If there is more than one gopls instance along the serving path (i.e. you\n\t// are using a daemon), each gopls instance will attempt to start debugging.\n\t// If Addr specifies a port, only the daemon will be able to bind to that\n\t// port, and each intermediate gopls instance will fail to start debugging.\n\t// For this reason it is recommended not to specify a port (or equivalently,\n\t// to specify \":0\").\n\t// \n\t// If the server was already debugging this field has no effect, and the\n\t// result will contain the previously configured debug URL(s).\n\t\"Addr\": string,\n}",
--			ResultDoc: "{\n\t// The URLs to use to access the debug servers, for all gopls instances in\n\t// the serving path. For the common case of a single gopls instance (i.e. no\n\t// daemon), this will be exactly one address.\n\t// \n\t// In the case of one or more gopls instances forwarding the LSP to a daemon,\n\t// URLs will contain debug addresses for each server in the serving path, in\n\t// serving order. The daemon debug address will be the last entry in the\n\t// slice. If any intermediate gopls instance fails to start debugging, no\n\t// error will be returned but the debug URL for that server in the URLs slice\n\t// will be empty.\n\t\"URLs\": []string,\n}",
+-			ArgDoc:    "{\n\t// Optional: the address (including port) for the debug server to listen on.\n\t// If not provided, the debug server will bind to \"localhost:0\", and the\n\t// full debug URL will be contained in the result.\n\t//\n\t// If there is more than one gopls instance along the serving path (i.e. you\n\t// are using a daemon), each gopls instance will attempt to start debugging.\n\t// If Addr specifies a port, only the daemon will be able to bind to that\n\t// port, and each intermediate gopls instance will fail to start debugging.\n\t// For this reason it is recommended not to specify a port (or equivalently,\n\t// to specify \":0\").\n\t//\n\t// If the server was already debugging this field has no effect, and the\n\t// result will contain the previously configured debug URL(s).\n\t\"Addr\": string,\n}",
+-			ResultDoc: "{\n\t// The URLs to use to access the debug servers, for all gopls instances in\n\t// the serving path. For the common case of a single gopls instance (i.e. no\n\t// daemon), this will be exactly one address.\n\t//\n\t// In the case of one or more gopls instances forwarding the LSP to a daemon,\n\t// URLs will contain debug addresses for each server in the serving path, in\n\t// serving order. The daemon debug address will be the last entry in the\n\t// slice. If any intermediate gopls instance fails to start debugging, no\n\t// error will be returned but the debug URL for that server in the URLs slice\n\t// will be empty.\n\t\"URLs\": []string,\n}",
+-		},
+-		{
+-			Command:   "gopls.start_profile",
+-			Title:     "start capturing a profile of gopls' execution.",
+-			Doc:       "Start a new pprof profile. Before using the resulting file, profiling must\nbe stopped with a corresponding call to StopProfile.\n\nThis command is intended for internal use only, by the gopls benchmark\nrunner.",
+-			ArgDoc:    "struct{}",
+-			ResultDoc: "struct{}",
+-		},
+-		{
+-			Command:   "gopls.stop_profile",
+-			Title:     "stop an ongoing profile.",
+-			Doc:       "This command is intended for internal use only, by the gopls benchmark\nrunner.",
+-			ArgDoc:    "struct{}",
+-			ResultDoc: "{\n\t// File is the profile file name.\n\t\"File\": string,\n}",
 -		},
 -		{
 -			Command: "gopls.test",
@@ -65577,6 +73024,12 @@
 -			Doc:     "Runs `go mod vendor` for a module.",
 -			ArgDoc:  "{\n\t// The file URI.\n\t\"URI\": string,\n}",
 -		},
+-		{
+-			Command:   "gopls.workspace_stats",
+-			Title:     "fetch workspace statistics",
+-			Doc:       "Query statistics about workspace builds, modules, packages, and files.\n\nThis command is intended for internal use only, by the gopls stats\ncommand.",
+-			ResultDoc: "{\n\t\"Files\": {\n\t\t\"Total\": int,\n\t\t\"Largest\": int,\n\t\t\"Errs\": int,\n\t},\n\t\"Views\": []{\n\t\t\"GoCommandVersion\": string,\n\t\t\"AllPackages\": {\n\t\t\t\"Packages\": int,\n\t\t\t\"LargestPackage\": int,\n\t\t\t\"CompiledGoFiles\": int,\n\t\t\t\"Modules\": int,\n\t\t},\n\t\t\"WorkspacePackages\": {\n\t\t\t\"Packages\": int,\n\t\t\t\"LargestPackage\": int,\n\t\t\t\"CompiledGoFiles\": int,\n\t\t\t\"Modules\": int,\n\t\t},\n\t\t\"Diagnostics\": int,\n\t},\n}",
+-		},
 -	},
 -	Lenses: []*LensJSON{
 -		{
@@ -65596,7 +73049,7 @@
 -		},
 -		{
 -			Lens:  "run_govulncheck",
--			Title: "Run govulncheck.",
+-			Title: "Run vulncheck.",
 -			Doc:   "Run vulnerability check (`govulncheck`).",
 -		},
 -		{
@@ -65622,120 +73075,154 @@
 -	},
 -	Analyzers: []*AnalyzerJSON{
 -		{
+-			Name:    "appends",
+-			Doc:     "check for missing values after append\n\nThis checker reports calls to append that pass\nno values to be appended to the slice.\n\n\ts := []string{\"a\", \"b\", \"c\"}\n\t_ = append(s)\n\nSuch calls are always no-ops and often indicate an\nunderlying mistake.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/appends",
+-			Default: true,
+-		},
+-		{
 -			Name:    "asmdecl",
 -			Doc:     "report mismatches between assembly files and Go declarations",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/asmdecl",
 -			Default: true,
 -		},
 -		{
 -			Name:    "assign",
 -			Doc:     "check for useless assignments\n\nThis checker reports assignments of the form x = x or a[i] = a[i].\nThese are almost always useless, and even when they aren't they are\nusually a mistake.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/assign",
 -			Default: true,
 -		},
 -		{
 -			Name:    "atomic",
 -			Doc:     "check for common mistakes using the sync/atomic package\n\nThe atomic checker looks for assignment statements of the form:\n\n\tx = atomic.AddUint64(&x, 1)\n\nwhich are not atomic.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomic",
 -			Default: true,
 -		},
 -		{
 -			Name:    "atomicalign",
 -			Doc:     "check for non-64-bits-aligned arguments to sync/atomic functions",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/atomicalign",
 -			Default: true,
 -		},
 -		{
 -			Name:    "bools",
 -			Doc:     "check for common mistakes involving boolean operators",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/bools",
 -			Default: true,
 -		},
 -		{
 -			Name:    "buildtag",
 -			Doc:     "check //go:build and // +build directives",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildtag",
 -			Default: true,
 -		},
 -		{
 -			Name:    "cgocall",
 -			Doc:     "detect some violations of the cgo pointer passing rules\n\nCheck for invalid cgo pointer passing.\nThis looks for code that uses cgo to call C code passing values\nwhose types are almost always invalid according to the cgo pointer\nsharing rules.\nSpecifically, it warns about attempts to pass a Go chan, map, func,\nor slice to C, either directly, or via a pointer, array, or struct.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/cgocall",
 -			Default: true,
 -		},
 -		{
 -			Name:    "composites",
 -			Doc:     "check for unkeyed composite literals\n\nThis analyzer reports a diagnostic for composite literals of struct\ntypes imported from another package that do not use the field-keyed\nsyntax. Such literals are fragile because the addition of a new field\n(even if unexported) to the struct will cause compilation to fail.\n\nAs an example,\n\n\terr = &net.DNSConfigError{err}\n\nshould be replaced by:\n\n\terr = &net.DNSConfigError{Err: err}\n",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/composite",
 -			Default: true,
 -		},
 -		{
 -			Name:    "copylocks",
 -			Doc:     "check for locks erroneously passed by value\n\nInadvertently copying a value containing a lock, such as sync.Mutex or\nsync.WaitGroup, may cause both copies to malfunction. Generally such\nvalues should be referred to through a pointer.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/copylocks",
 -			Default: true,
 -		},
 -		{
 -			Name:    "deepequalerrors",
 -			Doc:     "check for calls of reflect.DeepEqual on error values\n\nThe deepequalerrors checker looks for calls of the form:\n\n    reflect.DeepEqual(err1, err2)\n\nwhere err1 and err2 are errors. Using reflect.DeepEqual to compare\nerrors is discouraged.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/deepequalerrors",
+-			Default: true,
+-		},
+-		{
+-			Name:    "defers",
+-			Doc:     "report common mistakes in defer statements\n\nThe defers analyzer reports a diagnostic when a defer statement would\nresult in a non-deferred call to time.Since, as experience has shown\nthat this is nearly always a mistake.\n\nFor example:\n\n\tstart := time.Now()\n\t...\n\tdefer recordLatency(time.Since(start)) // error: call to time.Since is not deferred\n\nThe correct code is:\n\n\tdefer func() { recordLatency(time.Since(start)) }()",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/defers",
+-			Default: true,
+-		},
+-		{
+-			Name:    "deprecated",
+-			Doc:     "check for use of deprecated identifiers\n\nThe deprecated analyzer looks for deprecated symbols and package imports.\n\nSee https://go.dev/wiki/Deprecated to learn about Go's convention\nfor documenting and signaling deprecated identifiers.",
 -			Default: true,
 -		},
 -		{
 -			Name:    "directive",
 -			Doc:     "check Go toolchain directives such as //go:debug\n\nThis analyzer checks for problems with known Go toolchain directives\nin all Go source files in a package directory, even those excluded by\n//go:build constraints, and all non-Go source files too.\n\nFor //go:debug (see https://go.dev/doc/godebug), the analyzer checks\nthat the directives are placed only in Go source files, only above the\npackage comment, and only in package main or *_test.go files.\n\nSupport for other known directives may be added in the future.\n\nThis analyzer does not check //go:build, which is handled by the\nbuildtag analyzer.\n",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/directive",
 -			Default: true,
 -		},
 -		{
 -			Name:    "embed",
--			Doc:     "check for //go:embed directive import\n\nThis analyzer checks that the embed package is imported when source code contains //go:embed comment directives.\nThe embed package must be imported for //go:embed directives to function.import _ \"embed\".",
+-			Doc:     "check //go:embed directive usage\n\nThis analyzer checks that the embed package is imported if //go:embed\ndirectives are present, providing a suggested fix to add the import if\nit is missing.\n\nThis analyzer also checks that //go:embed directives precede the\ndeclaration of a single variable.",
 -			Default: true,
 -		},
 -		{
 -			Name:    "errorsas",
 -			Doc:     "report passing non-pointer or non-error values to errors.As\n\nThe errorsas analysis reports calls to errors.As where the type\nof the second argument is not a pointer to a type implementing error.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/errorsas",
 -			Default: true,
 -		},
 -		{
 -			Name: "fieldalignment",
 -			Doc:  "find structs that would use less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to use less memory, and provides\na suggested edit with the most compact order.\n\nNote that there are two different diagnostics reported. One checks struct size,\nand the other reports \"pointer bytes\" used. Pointer bytes is how many bytes of the\nobject that the garbage collector has to potentially scan for pointers, for example:\n\n\tstruct { uint32; string }\n\nhave 16 pointer bytes because the garbage collector has to scan up through the string's\ninner pointer.\n\n\tstruct { string; *uint32 }\n\nhas 24 pointer bytes because it has to scan further through the *uint32.\n\n\tstruct { string; uint32 }\n\nhas 8 because it can stop immediately after the string pointer.\n\nBe aware that the most compact order is not always the most efficient.\nIn rare cases it may cause two variables each updated by its own goroutine\nto occupy the same CPU cache line, inducing a form of memory contention\nknown as \"false sharing\" that slows down both goroutines.\n",
+-			URL:  "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment",
 -		},
 -		{
 -			Name:    "httpresponse",
 -			Doc:     "check for mistakes using HTTP responses\n\nA common mistake when using the net/http package is to defer a function\ncall to close the http.Response Body before checking the error that\ndetermines whether the response is valid:\n\n\tresp, err := http.Head(url)\n\tdefer resp.Body.Close()\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\t// (defer statement belongs here)\n\nThis checker helps uncover latent nil dereference bugs by reporting a\ndiagnostic for such mistakes.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/httpresponse",
 -			Default: true,
 -		},
 -		{
 -			Name:    "ifaceassert",
--			Doc:     "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.\n",
--			Default: true,
--		},
--		{
--			Name:    "infertypeargs",
--			Doc:     "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n",
+-			Doc:     "detect impossible interface-to-interface type assertions\n\nThis checker flags type assertions v.(T) and corresponding type-switch cases\nin which the static type V of v is an interface that cannot possibly implement\nthe target interface T. This occurs when V and T contain methods with the same\nname but different signatures. Example:\n\n\tvar v interface {\n\t\tRead()\n\t}\n\t_ = v.(io.Reader)\n\nThe Read method in v has a different signature than the Read method in\nio.Reader, so this assertion cannot succeed.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/ifaceassert",
 -			Default: true,
 -		},
 -		{
 -			Name:    "loopclosure",
--			Doc:     "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n    for _, v := range list {\n        defer func() {\n            use(v) // incorrect\n        }()\n    }\n\nOne fix is to create a new variable for each iteration of the loop:\n\n    for _, v := range list {\n        v := v // new var per iteration\n        defer func() {\n            use(v) // ok\n        }()\n    }\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n    for _, v := range elem {\n        go func() {\n            use(v)  // incorrect, and a data race\n        }()\n    }\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n    func Test(t *testing.T) {\n        for _, test := range tests {\n            t.Run(test.name, func(t *testing.T) {\n                t.Parallel()\n                use(test) // incorrect, and a data race\n            })\n        }\n    }\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines",
+-			Doc:     "check references to loop variables from within nested functions\n\nThis analyzer reports places where a function literal references the\niteration variable of an enclosing loop, and the loop calls the function\nin such a way (e.g. with go or defer) that it may outlive the loop\niteration and possibly observe the wrong value of the variable.\n\nIn this example, all the deferred functions run after the loop has\ncompleted, so all observe the final value of v.\n\n\tfor _, v := range list {\n\t    defer func() {\n\t        use(v) // incorrect\n\t    }()\n\t}\n\nOne fix is to create a new variable for each iteration of the loop:\n\n\tfor _, v := range list {\n\t    v := v // new var per iteration\n\t    defer func() {\n\t        use(v) // ok\n\t    }()\n\t}\n\nThe next example uses a go statement and has a similar problem.\nIn addition, it has a data race because the loop updates v\nconcurrent with the goroutines accessing it.\n\n\tfor _, v := range elem {\n\t    go func() {\n\t        use(v)  // incorrect, and a data race\n\t    }()\n\t}\n\nA fix is the same as before. The checker also reports problems\nin goroutines started by golang.org/x/sync/errgroup.Group.\nA hard-to-spot variant of this form is common in parallel tests:\n\n\tfunc Test(t *testing.T) {\n\t    for _, test := range tests {\n\t        t.Run(test.name, func(t *testing.T) {\n\t            t.Parallel()\n\t            use(test) // incorrect, and a data race\n\t        })\n\t    }\n\t}\n\nThe t.Parallel() call causes the rest of the function to execute\nconcurrent with the loop.\n\nThe analyzer reports references only in the last statement,\nas it is not deep enough to understand the effects of subsequent\nstatements that might render the reference benign.\n(\"Last statement\" is defined recursively in compound\nstatements such as if, switch, and select.)\n\nSee: https://golang.org/doc/go_faq.html#closures_and_goroutines",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/loopclosure",
 -			Default: true,
 -		},
 -		{
 -			Name:    "lostcancel",
 -			Doc:     "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel",
 -			Default: true,
 -		},
 -		{
 -			Name:    "nilfunc",
 -			Doc:     "check for useless comparisons between functions and nil\n\nA useless comparison is one like f == nil as opposed to f() == nil.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilfunc",
 -			Default: true,
 -		},
 -		{
 -			Name: "nilness",
--			Doc:  "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}\n",
+-			Doc:  "check for redundant or impossible nil comparisons\n\nThe nilness checker inspects the control-flow graph of each function in\na package and reports nil pointer dereferences, degenerate nil\npointers, and panics with nil values. A degenerate comparison is of the form\nx==nil or x!=nil where x is statically known to be nil or non-nil. These are\noften a mistake, especially in control flow related to errors. Panics with nil\nvalues are checked because they are not detectable by\n\n\tif r := recover(); r != nil {\n\nThis check reports conditions such as:\n\n\tif f == nil { // impossible condition (f is a function)\n\t}\n\nand:\n\n\tp := &v\n\t...\n\tif p != nil { // tautological condition\n\t}\n\nand:\n\n\tif p == nil {\n\t\tprint(*p) // nil dereference\n\t}\n\nand:\n\n\tif p == nil {\n\t\tpanic(p)\n\t}",
+-			URL:  "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/nilness",
 -		},
 -		{
 -			Name:    "printf",
--			Doc:     "check consistency of Printf format strings and arguments\n\nThe check applies to known functions (for example, those in package fmt)\nas well as any detected wrappers of known functions.\n\nA function that wants to avail itself of printf checking but is not\nfound by this analyzer's heuristics (for example, due to use of\ndynamic calls) can insert a bogus call:\n\n\tif false {\n\t\t_ = fmt.Sprintf(format, args...) // enable printf checking\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.\n",
+-			Doc:     "check consistency of Printf format strings and arguments\n\nThe check applies to calls of the formatting functions such as\n[fmt.Printf] and [fmt.Sprintf], as well as any detected wrappers of\nthose functions.\n\nIn this example, the %d format operator requires an integer operand:\n\n\tfmt.Printf(\"%d\", \"hello\") // fmt.Printf format %d has arg \"hello\" of wrong type string\n\nSee the documentation of the fmt package for the complete set of\nformat operators and their operand types.\n\nTo enable printf checking on a function that is not found by this\nanalyzer's heuristics (for example, because control is obscured by\ndynamic method calls), insert a bogus call:\n\n\tfunc MyPrintf(format string, args ...any) {\n\t\tif false {\n\t\t\t_ = fmt.Sprintf(format, args...) // enable printf checker\n\t\t}\n\t\t...\n\t}\n\nThe -funcs flag specifies a comma-separated list of names of additional\nknown formatting functions or methods. If the name contains a period,\nit must denote a specific function using one of the following forms:\n\n\tdir/pkg.Function\n\tdir/pkg.Type.Method\n\t(*dir/pkg.Type).Method\n\nOtherwise the name is interpreted as a case-insensitive unqualified\nidentifier such as \"errorf\". Either way, if a listed name ends in f, the\nfunction is assumed to be Printf-like, taking a format string before the\nargument list. Otherwise it is assumed to be Print-like, taking a list\nof arguments with no format string.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/printf",
 -			Default: true,
 -		},
 -		{
 -			Name: "shadow",
--			Doc:  "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}\n",
+-			Doc:  "check for possible unintended shadowing of variables\n\nThis analyzer check for shadowed variables.\nA shadowed variable is a variable declared in an inner scope\nwith the same name and type as a variable in an outer scope,\nand where the outer variable is mentioned after the inner one\nis declared.\n\n(This definition can be refined; the module generates too many\nfalse positives and is not yet enabled by default.)\n\nFor example:\n\n\tfunc BadRead(f *os.File, buf []byte) error {\n\t\tvar err error\n\t\tfor {\n\t\t\tn, err := f.Read(buf) // shadows the function variable 'err'\n\t\t\tif err != nil {\n\t\t\t\tbreak // causes return of wrong value\n\t\t\t}\n\t\t\tfoo(buf)\n\t\t}\n\t\treturn err\n\t}",
+-			URL:  "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shadow",
 -		},
 -		{
 -			Name:    "shift",
 -			Doc:     "check for shifts that equal or exceed the width of the integer",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/shift",
 -			Default: true,
 -		},
 -		{
@@ -65754,67 +73241,85 @@
 -			Default: true,
 -		},
 -		{
+-			Name:    "slog",
+-			Doc:     "check for invalid structured logging calls\n\nThe slog checker looks for calls to functions from the log/slog\npackage that take alternating key-value pairs. It reports calls\nwhere an argument in a key position is neither a string nor a\nslog.Attr, and where a final key is missing its value.\nFor example,it would report\n\n\tslog.Warn(\"message\", 11, \"k\") // slog.Warn arg \"11\" should be a string or a slog.Attr\n\nand\n\n\tslog.Info(\"message\", \"k1\", v1, \"k2\") // call to slog.Info missing a final value",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/slog",
+-			Default: true,
+-		},
+-		{
 -			Name:    "sortslice",
 -			Doc:     "check the argument type of sort.Slice\n\nsort.Slice requires an argument of a slice type. Check that\nthe interface{} value passed to sort.Slice is actually a slice.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/sortslice",
 -			Default: true,
 -		},
 -		{
 -			Name:    "stdmethods",
--			Doc:     "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n        func (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo\n",
+-			Doc:     "check signature of methods of well-known interfaces\n\nSometimes a type may be intended to satisfy an interface but may fail to\ndo so because of a mistake in its method signature.\nFor example, the result of this WriteTo method should be (int64, error),\nnot error, to satisfy io.WriterTo:\n\n\ttype myWriterTo struct{...}\n\tfunc (myWriterTo) WriteTo(w io.Writer) error { ... }\n\nThis check ensures that each method whose name matches one of several\nwell-known interface methods from the standard library has the correct\nsignature for that interface.\n\nChecked method names include:\n\n\tFormat GobEncode GobDecode MarshalJSON MarshalXML\n\tPeek ReadByte ReadFrom ReadRune Scan Seek\n\tUnmarshalJSON UnreadByte UnreadRune WriteByte\n\tWriteTo",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdmethods",
 -			Default: true,
 -		},
 -		{
 -			Name:    "stringintconv",
--			Doc:     "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.\n",
+-			Doc:     "check for string(int) conversions\n\nThis checker flags conversions of the form string(x) where x is an integer\n(but not byte or rune) type. Such conversions are discouraged because they\nreturn the UTF-8 representation of the Unicode code point x, and not a decimal\nstring representation of x as one might expect. Furthermore, if x denotes an\ninvalid code point, the conversion cannot be statically rejected.\n\nFor conversions that intend on using the code point, consider replacing them\nwith string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the\nstring representation of the value in the desired base.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/stringintconv",
 -			Default: true,
 -		},
 -		{
 -			Name:    "structtag",
 -			Doc:     "check that struct field tags conform to reflect.StructTag.Get\n\nAlso report certain struct tags (json, xml) used with unexported fields.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/structtag",
 -			Default: true,
 -		},
 -		{
 -			Name:    "testinggoroutine",
--			Doc:     "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\nfunc TestFoo(t *testing.T) {\n    go func() {\n        t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n    }()\n}\n",
+-			Doc:     "report calls to (*testing.T).Fatal from goroutines started by a test.\n\nFunctions that abruptly terminate a test, such as the Fatal, Fatalf, FailNow, and\nSkip{,f,Now} methods of *testing.T, must be called from the test goroutine itself.\nThis checker detects calls to these functions that occur within a goroutine\nstarted by the test. For example:\n\n\tfunc TestFoo(t *testing.T) {\n\t    go func() {\n\t        t.Fatal(\"oops\") // error: (*T).Fatal called from non-test goroutine\n\t    }()\n\t}",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/testinggoroutine",
 -			Default: true,
 -		},
 -		{
 -			Name:    "tests",
--			Doc:     "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.",
+-			Doc:     "check for common mistaken usages of tests and examples\n\nThe tests checker walks Test, Benchmark, Fuzzing and Example functions checking\nmalformed names, wrong signatures and examples documenting non-existent\nidentifiers.\n\nPlease see the documentation for package testing in golang.org/pkg/testing\nfor the conventions that are enforced for Tests, Benchmarks, and Examples.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/tests",
 -			Default: true,
 -		},
 -		{
 -			Name:    "timeformat",
--			Doc:     "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.\n",
+-			Doc:     "check for calls of (time.Time).Format or time.Parse with 2006-02-01\n\nThe timeformat checker looks for time formats with the 2006-02-01 (yyyy-dd-mm)\nformat. Internationally, \"yyyy-dd-mm\" does not occur in common calendar date\nstandards, and so it is more likely that 2006-01-02 (yyyy-mm-dd) was intended.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/timeformat",
 -			Default: true,
 -		},
 -		{
 -			Name:    "unmarshal",
 -			Doc:     "report passing non-pointer or non-interface values to unmarshal\n\nThe unmarshal analysis reports calls to functions such as json.Unmarshal\nin which the argument type is not a pointer or an interface.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unmarshal",
 -			Default: true,
 -		},
 -		{
 -			Name:    "unreachable",
 -			Doc:     "check for unreachable code\n\nThe unreachable analyzer finds statements that execution can never reach\nbecause they are preceded by an return statement, a call to panic, an\ninfinite loop, or similar constructs.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unreachable",
 -			Default: true,
 -		},
 -		{
 -			Name:    "unsafeptr",
 -			Doc:     "check for invalid conversions of uintptr to unsafe.Pointer\n\nThe unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer\nto convert integers to pointers. A conversion from uintptr to\nunsafe.Pointer is invalid if it implies that there is a uintptr-typed\nword in memory that holds a pointer value, because that word will be\ninvisible to stack copying and to the garbage collector.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unsafeptr",
 -			Default: true,
 -		},
 -		{
 -			Name: "unusedparams",
--			Doc:  "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or are underscored\n- functions in test files\n- functions with empty bodies or those with just a return stmt",
+-			Doc:  "check for unused parameters of functions\n\nThe unusedparams analyzer checks functions to see if there are\nany parameters that are not being used.\n\nTo reduce false positives it ignores:\n- methods\n- parameters that do not have a name or have the name '_' (the blank identifier)\n- functions in test files\n- functions with empty bodies or those with just a return stmt",
 -		},
 -		{
 -			Name:    "unusedresult",
--			Doc:     "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side effects,\nso it is always a mistake to discard the result. This analyzer reports\ncalls to certain functions in which the result of the call is ignored.\n\nThe set of functions may be controlled using flags.",
+-			Doc:     "check for unused results of calls to some functions\n\nSome functions like fmt.Errorf return a result and have no side\neffects, so it is always a mistake to discard the result. Other\nfunctions may return an error that must not be ignored, or a cleanup\noperation that must be called. This analyzer reports calls to\nfunctions like these when the result of the call is ignored.\n\nThe set of functions may be controlled using flags.",
+-			URL:     "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedresult",
 -			Default: true,
 -		},
 -		{
 -			Name: "unusedwrite",
--			Doc:  "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\tfunc f(input []T) {\n\t\tfor i, v := range input {  // v is a copy\n\t\t\tv.x = i  // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\tfunc (t T) f() {  // t is a copy\n\t\tt.x = i  // unused write to field x\n\t}\n",
+-			Doc:  "checks for unused writes\n\nThe analyzer reports instances of writes to struct fields and\narrays that are never read. Specifically, when a struct object\nor an array is copied, its elements are copied implicitly by\nthe compiler, and any element write to this copy does nothing\nwith the original object.\n\nFor example:\n\n\ttype T struct { x int }\n\n\tfunc f(input []T) {\n\t\tfor i, v := range input {  // v is a copy\n\t\t\tv.x = i  // unused write to field x\n\t\t}\n\t}\n\nAnother example is about non-pointer receiver:\n\n\ttype T struct { x int }\n\n\tfunc (t T) f() {  // t is a copy\n\t\tt.x = i  // unused write to field x\n\t}",
+-			URL:  "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/unusedwrite",
 -		},
 -		{
 -			Name: "useany",
@@ -65850,6 +73355,11 @@
 -			Default: true,
 -		},
 -		{
+-			Name:    "infertypeargs",
+-			Doc:     "check for unnecessary type arguments in call expressions\n\nExplicit type arguments may be omitted from call expressions if they can be\ninferred from function arguments, or from other type arguments:\n\n\tfunc f[T any](T) {}\n\t\n\tfunc _() {\n\t\tf[string](\"foo\") // string could be inferred\n\t}\n",
+-			Default: true,
+-		},
+-		{
 -			Name:    "stubmethods",
 -			Doc:     "stub methods analyzer\n\nThis analyzer generates method stubs for concrete types\nin order to implement a target interface",
 -			Default: true,
@@ -65888,7 +73398,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/call_hierarchy.go b/gopls/internal/lsp/source/call_hierarchy.go
 --- a/gopls/internal/lsp/source/call_hierarchy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/call_hierarchy.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/call_hierarchy.go	1970-01-01 08:00:00
 @@ -1,311 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -65906,10 +73416,10 @@
 -	"path/filepath"
 -
 -	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
 -)
@@ -65919,7 +73429,7 @@
 -	ctx, done := event.Start(ctx, "source.PrepareCallHierarchy")
 -	defer done()
 -
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -65999,7 +73509,7 @@
 -// enclosingNodeCallItem creates a CallHierarchyItem representing the function call at loc.
 -func enclosingNodeCallItem(ctx context.Context, snapshot Snapshot, pkgPath PackagePath, loc protocol.Location) (protocol.CallHierarchyItem, error) {
 -	// Parse the file containing the reference.
--	fh, err := snapshot.GetFile(ctx, loc.URI.SpanURI())
+-	fh, err := snapshot.ReadFile(ctx, loc.URI.SpanURI())
 -	if err != nil {
 -		return protocol.CallHierarchyItem{}, err
 -	}
@@ -66074,7 +73584,7 @@
 -	ctx, done := event.Start(ctx, "source.OutgoingCalls")
 -	defer done()
 -
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -66113,7 +73623,7 @@
 -	}
 -
 -	// Use TypecheckFull as we want to inspect the body of the function declaration.
--	declPkg, declPGF, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage)
+-	declPkg, declPGF, err := NarrowestPackageForFile(ctx, snapshot, uri)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -66203,7 +73713,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/code_lens.go b/gopls/internal/lsp/source/code_lens.go
 --- a/gopls/internal/lsp/source/code_lens.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/code_lens.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/code_lens.go	1970-01-01 08:00:00
 @@ -1,248 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -66243,9 +73753,13 @@
 -)
 -
 -func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.CodeLens, error) {
--	codeLens := make([]protocol.CodeLens, 0)
+-	var codeLens []protocol.CodeLens
 -
--	fns, err := TestsAndBenchmarks(ctx, snapshot, fh)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
+-	if err != nil {
+-		return nil, err
+-	}
+-	fns, err := TestsAndBenchmarks(ctx, snapshot, pkg, pgf)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -66301,16 +73815,12 @@
 -	Benchmarks []testFn
 -}
 -
--func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, fh FileHandle) (testFns, error) {
+-func TestsAndBenchmarks(ctx context.Context, snapshot Snapshot, pkg Package, pgf *ParsedGoFile) (testFns, error) {
 -	var out testFns
 -
--	if !strings.HasSuffix(fh.URI().Filename(), "_test.go") {
+-	if !strings.HasSuffix(pgf.URI.Filename(), "_test.go") {
 -		return out, nil
 -	}
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
--	if err != nil {
--		return out, err
--	}
 -
 -	for _, d := range pgf.File.Decls {
 -		fn, ok := d.(*ast.FuncDecl)
@@ -66455,7 +73965,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/comment.go b/gopls/internal/lsp/source/comment.go
 --- a/gopls/internal/lsp/source/comment.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/comment.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/comment.go	1970-01-01 08:00:00
 @@ -1,384 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -66843,7 +74353,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/comment_go118_test.go b/gopls/internal/lsp/source/comment_go118_test.go
 --- a/gopls/internal/lsp/source/comment_go118_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/comment_go118_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/comment_go118_test.go	1970-01-01 08:00:00
 @@ -1,371 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -67218,7 +74728,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/comment_go119.go b/gopls/internal/lsp/source/comment_go119.go
 --- a/gopls/internal/lsp/source/comment_go119.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/comment_go119.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/comment_go119.go	1970-01-01 08:00:00
 @@ -1,56 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -67278,7 +74788,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/builtin.go b/gopls/internal/lsp/source/completion/builtin.go
 --- a/gopls/internal/lsp/source/completion/builtin.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/builtin.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/builtin.go	1970-01-01 08:00:00
 @@ -1,147 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -67429,8 +74939,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/completion.go b/gopls/internal/lsp/source/completion/completion.go
 --- a/gopls/internal/lsp/source/completion/completion.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/completion.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3252 +0,0 @@
++++ b/gopls/internal/lsp/source/completion/completion.go	1970-01-01 08:00:00
+@@ -1,3279 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -67440,12 +74950,12 @@
 -package completion
 -
 -import (
--	"bytes"
 -	"context"
 -	"fmt"
 -	"go/ast"
 -	"go/constant"
 -	"go/parser"
+-	"go/printer"
 -	"go/scanner"
 -	"go/token"
 -	"go/types"
@@ -67460,6 +74970,7 @@
 -
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/ast/astutil"
+-	goplsastutil "golang.org/x/tools/gopls/internal/astutil"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/snippet"
@@ -67536,15 +75047,16 @@
 -
 -// completionOptions holds completion specific configuration.
 -type completionOptions struct {
--	unimported        bool
--	documentation     bool
--	fullDocumentation bool
--	placeholders      bool
--	literal           bool
--	snippets          bool
--	postfix           bool
--	matcher           source.Matcher
--	budget            time.Duration
+-	unimported            bool
+-	documentation         bool
+-	fullDocumentation     bool
+-	placeholders          bool
+-	literal               bool
+-	snippets              bool
+-	postfix               bool
+-	matcher               source.Matcher
+-	budget                time.Duration
+-	completeFunctionCalls bool
 -}
 -
 -// Snippet is a convenience returns the snippet if available, otherwise
@@ -67633,7 +75145,7 @@
 -	// completionCallbacks is a list of callbacks to collect completions that
 -	// require expensive operations. This includes operations where we search
 -	// through the entire module cache.
--	completionCallbacks []func(opts *imports.Options) error
+-	completionCallbacks []func(context.Context, *imports.Options) error
 -
 -	// surrounding describes the identifier surrounding the position.
 -	surrounding *Selection
@@ -67666,6 +75178,11 @@
 -
 -	// startTime is when we started processing this completion request. It does
 -	// not include any time the request spent in the queue.
+-	//
+-	// Note: in CL 503016, startTime move to *after* type checking, but it was
+-	// subsequently determined that it was better to keep setting it *before*
+-	// type checking, so that the completion budget best approximates the user
+-	// experience. See golang/go#62665 for more details.
 -	startTime time.Time
 -
 -	// scopes contains all scopes defined by nodes in our path,
@@ -67738,10 +75255,6 @@
 -	mapper             *protocol.Mapper
 -}
 -
--func (p Selection) Content() string {
--	return p.content
--}
--
 -func (p Selection) Range() (protocol.Range, error) {
 -	return p.mapper.PosRange(p.tokFile, p.start, p.end)
 -}
@@ -67879,7 +75392,7 @@
 -
 -	startTime := time.Now()
 -
--	pkg, pgf, err := source.PackageForFile(ctx, snapshot, fh.URI(), source.NarrowestPackage)
+-	pkg, pgf, err := source.NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil || pgf.File.Package == token.NoPos {
 -		// If we can't parse this file or find position for the package
 -		// keyword, it may be missing a package declaration. Try offering
@@ -67893,6 +75406,7 @@
 -		}
 -		return items, surrounding, nil
 -	}
+-
 -	pos, err := pgf.PositionPos(protoPos)
 -	if err != nil {
 -		return nil, nil, err
@@ -67950,7 +75464,7 @@
 -	scopes := source.CollectScopes(pkg.GetTypesInfo(), path, pos)
 -	scopes = append(scopes, pkg.GetTypes().Scope(), types.Universe)
 -
--	opts := snapshot.View().Options()
+-	opts := snapshot.Options()
 -	c := &completer{
 -		pkg:      pkg,
 -		snapshot: snapshot,
@@ -67973,15 +75487,16 @@
 -			enabled: opts.DeepCompletion,
 -		},
 -		opts: &completionOptions{
--			matcher:           opts.Matcher,
--			unimported:        opts.CompleteUnimported,
--			documentation:     opts.CompletionDocumentation && opts.HoverKind != source.NoDocumentation,
--			fullDocumentation: opts.HoverKind == source.FullDocumentation,
--			placeholders:      opts.UsePlaceholders,
--			literal:           opts.LiteralCompletions && opts.InsertTextFormat == protocol.SnippetTextFormat,
--			budget:            opts.CompletionBudget,
--			snippets:          opts.InsertTextFormat == protocol.SnippetTextFormat,
--			postfix:           opts.ExperimentalPostfixCompletions,
+-			matcher:               opts.Matcher,
+-			unimported:            opts.CompleteUnimported,
+-			documentation:         opts.CompletionDocumentation && opts.HoverKind != source.NoDocumentation,
+-			fullDocumentation:     opts.HoverKind == source.FullDocumentation,
+-			placeholders:          opts.UsePlaceholders,
+-			literal:               opts.LiteralCompletions && opts.InsertTextFormat == protocol.SnippetTextFormat,
+-			budget:                opts.CompletionBudget,
+-			snippets:              opts.InsertTextFormat == protocol.SnippetTextFormat,
+-			postfix:               opts.ExperimentalPostfixCompletions,
+-			completeFunctionCalls: opts.CompleteFunctionCalls,
 -		},
 -		// default to a matcher that always matches
 -		matcher:        prefixMatcher(""),
@@ -67991,20 +75506,27 @@
 -		scopes:         scopes,
 -	}
 -
--	var cancel context.CancelFunc
--	if c.opts.budget == 0 {
--		ctx, cancel = context.WithCancel(ctx)
--	} else {
--		// timeoutDuration is the completion budget remaining. If less than
--		// 10ms, set to 10ms
--		timeoutDuration := time.Until(c.startTime.Add(c.opts.budget))
--		if timeoutDuration < 10*time.Millisecond {
--			timeoutDuration = 10 * time.Millisecond
--		}
--		ctx, cancel = context.WithTimeout(ctx, timeoutDuration)
--	}
+-	ctx, cancel := context.WithCancel(ctx)
 -	defer cancel()
 -
+-	// Compute the deadline for this operation. Deadline is relative to the
+-	// search operation, not the entire completion RPC, as the work up until this
+-	// point depends significantly on how long it took to type-check, which in
+-	// turn depends on the timing of the request relative to other operations on
+-	// the snapshot. Including that work in the budget leads to inconsistent
+-	// results (and realistically, if type-checking took 200ms already, the user
+-	// is unlikely to be significantly more bothered by e.g. another 100ms of
+-	// search).
+-	//
+-	// Don't overload the context with this deadline, as we don't want to
+-	// conflate user cancellation (=fail the operation) with our time limit
+-	// (=stop searching and succeed with partial results).
+-	var deadline *time.Time
+-	if c.opts.budget > 0 {
+-		d := startTime.Add(c.opts.budget)
+-		deadline = &d
+-	}
+-
 -	if surrounding := c.containingIdent(pgf.Src); surrounding != nil {
 -		c.setSurrounding(surrounding)
 -	}
@@ -68017,17 +75539,30 @@
 -	}
 -
 -	// Deep search collected candidates and their members for more candidates.
--	c.deepSearch(ctx)
+-	c.deepSearch(ctx, 1, deadline)
+-
+-	// At this point we have a sufficiently complete set of results, and want to
+-	// return as close to the completion budget as possible. Previously, we
+-	// avoided cancelling the context because it could result in partial results
+-	// for e.g. struct fields. At this point, we have a minimal valid set of
+-	// candidates, and so truncating due to context cancellation is acceptable.
+-	if c.opts.budget > 0 {
+-		timeoutDuration := time.Until(c.startTime.Add(c.opts.budget))
+-		ctx, cancel = context.WithTimeout(ctx, timeoutDuration)
+-		defer cancel()
+-	}
 -
 -	for _, callback := range c.completionCallbacks {
--		if err := c.snapshot.RunProcessEnvFunc(ctx, callback); err != nil {
--			return nil, nil, err
+-		if deadline == nil || time.Now().Before(*deadline) {
+-			if err := c.snapshot.RunProcessEnvFunc(ctx, callback); err != nil {
+-				return nil, nil, err
+-			}
 -		}
 -	}
 -
 -	// Search candidates populated by expensive operations like
 -	// unimportedMembers etc. for more completion items.
--	c.deepSearch(ctx)
+-	c.deepSearch(ctx, 0, deadline)
 -
 -	// Statement candidates offer an entire statement in certain contexts, as
 -	// opposed to a single object. Add statement candidates last because they
@@ -68046,7 +75581,7 @@
 -		if !(importSpec.Path.Pos() <= c.pos && c.pos <= importSpec.Path.End()) {
 -			continue
 -		}
--		return c.populateImportCompletions(ctx, importSpec)
+-		return c.populateImportCompletions(importSpec)
 -	}
 -
 -	// Inside comments, offer completions for the name of the relevant symbol.
@@ -68091,7 +75626,11 @@
 -	//   recv.‸(arg)
 -	case *ast.TypeAssertExpr:
 -		// Create a fake selector expression.
--		return c.selector(ctx, &ast.SelectorExpr{X: n.X})
+-		//
+-		// The name "_" is the convention used by go/parser to represent phantom
+-		// selectors.
+-		sel := &ast.Ident{NamePos: n.X.End() + token.Pos(len(".")), Name: "_"}
+-		return c.selector(ctx, &ast.SelectorExpr{X: n.X, Sel: sel})
 -	case *ast.SelectorExpr:
 -		return c.selector(ctx, n)
 -	// At the file scope, only keywords are allowed.
@@ -68195,7 +75734,7 @@
 -// Completions for "golang.org/" yield its subdirectories
 -// (i.e. "golang.org/x/"). The user is meant to accept completion suggestions
 -// until they reach a complete import path.
--func (c *completer) populateImportCompletions(ctx context.Context, searchImport *ast.ImportSpec) error {
+-func (c *completer) populateImportCompletions(searchImport *ast.ImportSpec) error {
 -	if !strings.HasPrefix(searchImport.Path.Value, `"`) {
 -		return nil
 -	}
@@ -68316,7 +75855,7 @@
 -		})
 -	}
 -
--	c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
+-	c.completionCallbacks = append(c.completionCallbacks, func(ctx context.Context, opts *imports.Options) error {
 -		return imports.GetImportPaths(ctx, searchImports, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env)
 -	})
 -	return nil
@@ -68345,14 +75884,14 @@
 -	// comment itself.
 -	c.opts.documentation = false
 -
--	commentLine := file.Line(comment.End())
+-	commentLine := safetoken.Line(file, comment.End())
 -
 -	// comment is valid, set surrounding as word boundaries around cursor
 -	c.setSurroundingForComment(comment)
 -
 -	// Using the next line pos, grab and parse the exported symbol on that line
 -	for _, n := range c.file.Decls {
--		declLine := file.Line(n.Pos())
+-		declLine := safetoken.Line(file, n.Pos())
 -		// if the comment is not in, directly above or on the same line as a declaration
 -		if declLine != commentLine && declLine != commentLine+1 &&
 -			!(n.Pos() <= comment.Pos() && comment.End() <= n.End()) {
@@ -68567,7 +76106,6 @@
 -		// Imported declaration with missing type information.
 -		// Fall through to shallow completion of unimported package members.
 -		// Match candidate packages by path.
--		// TODO(adonovan): simplify by merging with else case and matching on name only?
 -		filter = func(m *source.Metadata) bool {
 -			return strings.TrimPrefix(string(m.PkgPath), "vendor/") == imp.Path()
 -		}
@@ -68604,27 +76142,47 @@
 -	// not assume global Pos/Object realms and then use export
 -	// data instead of the quick parse approach taken here.
 -
--	// First, we search among packages in the workspace.
+-	// First, we search among packages in the forward transitive
+-	// closure of the workspace.
 -	// We'll use a fast parse to extract package members
 -	// from those that match the name/path criterion.
 -	all, err := c.snapshot.AllMetadata(ctx)
 -	if err != nil {
 -		return err
 -	}
--	var paths []string
--	known := make(map[source.PackagePath][]*source.Metadata) // may include test variant
+-	known := make(map[source.PackagePath]*source.Metadata)
 -	for _, m := range all {
--		if m.IsIntermediateTestVariant() || m.Name == "main" || !filter(m) {
+-		if m.Name == "main" {
+-			continue // not importable
+-		}
+-		if m.IsIntermediateTestVariant() {
 -			continue
 -		}
--		known[m.PkgPath] = append(known[m.PkgPath], m)
--		paths = append(paths, string(m.PkgPath))
+-		// The only test variant we admit is "p [p.test]"
+-		// when we are completing within "p_test [p.test]",
+-		// as in that case we would like to offer completions
+-		// of the test variants' additional symbols.
+-		if m.ForTest != "" && c.pkg.Metadata().PkgPath != m.ForTest+"_test" {
+-			continue
+-		}
+-		if !filter(m) {
+-			continue
+-		}
+-		// Prefer previous entry unless this one is its test variant.
+-		if m.ForTest != "" || known[m.PkgPath] == nil {
+-			known[m.PkgPath] = m
+-		}
+-	}
+-
+-	paths := make([]string, 0, len(known))
+-	for path := range known {
+-		paths = append(paths, string(path))
 -	}
 -
 -	// Rank import paths as goimports would.
 -	var relevances map[string]float64
 -	if len(paths) > 0 {
--		if err := c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
+-		if err := c.snapshot.RunProcessEnvFunc(ctx, func(ctx context.Context, opts *imports.Options) error {
 -			var err error
 -			relevances, err = imports.ScoreImportPaths(ctx, opts.Env, paths)
 -			return err
@@ -68638,18 +76196,20 @@
 -
 -	// quickParse does a quick parse of a single file of package m,
 -	// extracts exported package members and adds candidates to c.items.
--	var itemsMu sync.Mutex // guards c.items
--	var enough int32       // atomic bool
+-	// TODO(rfindley): synchronizing access to c here does not feel right.
+-	// Consider adding a concurrency-safe API for completer.
+-	var cMu sync.Mutex // guards c.items and c.matcher
+-	var enough int32   // atomic bool
 -	quickParse := func(uri span.URI, m *source.Metadata) error {
 -		if atomic.LoadInt32(&enough) != 0 {
 -			return nil
 -		}
 -
--		fh, err := c.snapshot.GetFile(ctx, uri)
+-		fh, err := c.snapshot.ReadFile(ctx, uri)
 -		if err != nil {
 -			return err
 -		}
--		content, err := fh.Read()
+-		content, err := fh.Content()
 -		if err != nil {
 -			return err
 -		}
@@ -68659,18 +76219,27 @@
 -				return
 -			}
 -
--			if !id.IsExported() ||
--				sel.Sel.Name != "_" && !strings.HasPrefix(id.Name, sel.Sel.Name) {
--				return // not a match
+-			if !id.IsExported() {
+-				return
+-			}
+-
+-			cMu.Lock()
+-			score := c.matcher.Score(id.Name)
+-			cMu.Unlock()
+-
+-			if sel.Sel.Name != "_" && score == 0 {
+-				return // not a match; avoid constructing the completion item below
 -			}
 -
 -			// The only detail is the kind and package: `var (from "example.com/foo")`
 -			// TODO(adonovan): pretty-print FuncDecl.FuncType or TypeSpec.Type?
+-			// TODO(adonovan): should this score consider the actual c.matcher.Score
+-			// of the item? How does this compare with the deepState.enqueue path?
 -			item := CompletionItem{
 -				Label:      id.Name,
 -				Detail:     fmt.Sprintf("%s (from %q)", strings.ToLower(tok.String()), m.PkgPath),
 -				InsertText: id.Name,
--				Score:      unimportedScore(relevances[path]),
+-				Score:      float64(score) * unimportedScore(relevances[path]),
 -			}
 -			switch tok {
 -			case token.FUNC:
@@ -68694,33 +76263,44 @@
 -
 -			// For functions, add a parameter snippet.
 -			if fn != nil {
+-				paramList := func(list *ast.FieldList) []string {
+-					var params []string
+-					if list != nil {
+-						var cfg printer.Config // slight overkill
+-						param := func(name string, typ ast.Expr) {
+-							var buf strings.Builder
+-							buf.WriteString(name)
+-							buf.WriteByte(' ')
+-							cfg.Fprint(&buf, token.NewFileSet(), typ)
+-							params = append(params, buf.String())
+-						}
+-
+-						for _, field := range list.List {
+-							if field.Names != nil {
+-								for _, name := range field.Names {
+-									param(name.Name, field.Type)
+-								}
+-							} else {
+-								param("_", field.Type)
+-							}
+-						}
+-					}
+-					return params
+-				}
+-
+-				tparams := paramList(fn.Type.TypeParams)
+-				params := paramList(fn.Type.Params)
 -				var sn snippet.Builder
--				sn.WriteText(id.Name)
--				sn.WriteText("(")
--				var nparams int
--				for _, field := range fn.Type.Params.List {
--					if field.Names != nil {
--						nparams += len(field.Names)
--					} else {
--						nparams++
--					}
--				}
--				for i := 0; i < nparams; i++ {
--					if i > 0 {
--						sn.WriteText(", ")
--					}
--					sn.WritePlaceholder(nil)
--				}
--				sn.WriteText(")")
+-				c.functionCallSnippet(id.Name, tparams, params, &sn)
 -				item.snippet = &sn
 -			}
 -
--			itemsMu.Lock()
+-			cMu.Lock()
 -			c.items = append(c.items, item)
 -			if len(c.items) >= unimportedMemberTarget {
 -				atomic.StoreInt32(&enough, 1)
 -			}
--			itemsMu.Unlock()
+-			cMu.Unlock()
 -		})
 -		return nil
 -	}
@@ -68728,14 +76308,12 @@
 -	// Extract the package-level candidates using a quick parse.
 -	var g errgroup.Group
 -	for _, path := range paths {
--		for _, m := range known[source.PackagePath(path)] {
--			m := m
--			for _, uri := range m.CompiledGoFiles {
--				uri := uri
--				g.Go(func() error {
--					return quickParse(uri, m)
--				})
--			}
+-		m := known[source.PackagePath(path)]
+-		for _, uri := range m.CompiledGoFiles {
+-			uri := uri
+-			g.Go(func() error {
+-				return quickParse(uri, m)
+-			})
 -		}
 -	}
 -	if err := g.Wait(); err != nil {
@@ -68746,6 +76324,10 @@
 -	ctx, cancel := context.WithCancel(ctx)
 -	var mu sync.Mutex
 -	add := func(pkgExport imports.PackageExport) {
+-		if ignoreUnimportedCompletion(pkgExport.Fix) {
+-			return
+-		}
+-
 -		mu.Lock()
 -		defer mu.Unlock()
 -		// TODO(adonovan): what if the actual package has a vendor/ prefix?
@@ -68771,7 +76353,7 @@
 -		}
 -	}
 -
--	c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
+-	c.completionCallbacks = append(c.completionCallbacks, func(ctx context.Context, opts *imports.Options) error {
 -		defer cancel()
 -		return imports.GetPackageExports(ctx, add, id.Name, c.filename, c.pkg.GetTypes().Name(), opts.Env)
 -	})
@@ -68797,6 +76379,13 @@
 -	}
 -}
 -
+-// ignoreUnimportedCompletion reports whether an unimported completion
+-// resulting in the given import should be ignored.
+-func ignoreUnimportedCompletion(fix *imports.ImportFix) bool {
+-	// golang/go#60062: don't add unimported completion to golang.org/toolchain.
+-	return fix != nil && strings.HasPrefix(fix.StmtInfo.ImportPath, "golang.org/toolchain")
+-}
+-
 -func (c *completer) methodsAndFields(typ types.Type, addressable bool, imp *importInfo, cb func(candidate)) {
 -	mset := c.methodSetCache[methodSetKey{typ, addressable}]
 -	if mset == nil {
@@ -69040,7 +76629,7 @@
 -
 -	count := 0
 -
--	// Search packages across the entire workspace.
+-	// Search the forward transitive closure of the workspace.
 -	all, err := c.snapshot.AllMetadata(ctx)
 -	if err != nil {
 -		return err
@@ -69064,7 +76653,7 @@
 -	// Rank candidates using goimports' algorithm.
 -	var relevances map[string]float64
 -	if len(paths) != 0 {
--		if err := c.snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
+-		if err := c.snapshot.RunProcessEnvFunc(ctx, func(ctx context.Context, opts *imports.Options) error {
 -			var err error
 -			relevances, err = imports.ScoreImportPaths(ctx, opts.Env, paths)
 -			return err
@@ -69109,6 +76698,9 @@
 -
 -	var mu sync.Mutex
 -	add := func(pkg imports.ImportFix) {
+-		if ignoreUnimportedCompletion(&pkg) {
+-			return
+-		}
 -		mu.Lock()
 -		defer mu.Unlock()
 -		if _, ok := seen[pkg.IdentName]; ok {
@@ -69137,7 +76729,7 @@
 -		})
 -		count++
 -	}
--	c.completionCallbacks = append(c.completionCallbacks, func(opts *imports.Options) error {
+-	c.completionCallbacks = append(c.completionCallbacks, func(ctx context.Context, opts *imports.Options) error {
 -		defer cancel()
 -		return imports.GetAllCandidates(ctx, add, prefix, c.filename, c.pkg.GetTypes().Name(), opts.Env)
 -	})
@@ -70606,7 +78198,7 @@
 -// quick partial parse. fn is non-nil only for function declarations.
 -// The AST position information is garbage.
 -func forEachPackageMember(content []byte, f func(tok token.Token, id *ast.Ident, fn *ast.FuncDecl)) {
--	purged := purgeFuncBodies(content)
+-	purged := goplsastutil.PurgeFuncBodies(content)
 -	file, _ := parser.ParseFile(token.NewFileSet(), "", purged, 0)
 -	for _, decl := range file.Decls {
 -		switch decl := decl.(type) {
@@ -70628,65 +78220,10 @@
 -		}
 -	}
 -}
--
--// purgeFuncBodies returns a copy of src in which the contents of each
--// outermost {...} region except struct and interface types have been
--// deleted. It does not preserve newlines. This reduces the amount of
--// work required to parse the top-level declarations.
--func purgeFuncBodies(src []byte) []byte {
--	// Destroy the content of any {...}-bracketed regions that are
--	// not immediately preceded by a "struct" or "interface"
--	// token.  That includes function bodies, composite literals,
--	// switch/select bodies, and all blocks of statements.
--	// This will lead to non-void functions that don't have return
--	// statements, which of course is a type error, but that's ok.
--
--	var out bytes.Buffer
--	file := token.NewFileSet().AddFile("", -1, len(src))
--	var sc scanner.Scanner
--	sc.Init(file, src, nil, 0)
--	var prev token.Token
--	var cursor int         // last consumed src offset
--	var braces []token.Pos // stack of unclosed braces or -1 for struct/interface type
--	for {
--		pos, tok, _ := sc.Scan()
--		if tok == token.EOF {
--			break
--		}
--		switch tok {
--		case token.COMMENT:
--			// TODO(adonovan): opt: skip, to save an estimated 20% of time.
--
--		case token.LBRACE:
--			if prev == token.STRUCT || prev == token.INTERFACE {
--				pos = -1
--			}
--			braces = append(braces, pos)
--
--		case token.RBRACE:
--			if last := len(braces) - 1; last >= 0 {
--				top := braces[last]
--				braces = braces[:last]
--				if top < 0 {
--					// struct/interface type: leave alone
--				} else if len(braces) == 0 { // toplevel only
--					// Delete {...} body.
--					start, _ := safetoken.Offset(file, top)
--					end, _ := safetoken.Offset(file, pos)
--					out.Write(src[cursor : start+len("{")])
--					cursor = end
--				}
--			}
--		}
--		prev = tok
--	}
--	out.Write(src[cursor:])
--	return out.Bytes()
--}
 diff -urN a/gopls/internal/lsp/source/completion/deep_completion.go b/gopls/internal/lsp/source/completion/deep_completion.go
 --- a/gopls/internal/lsp/source/completion/deep_completion.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/deep_completion.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,362 +0,0 @@
++++ b/gopls/internal/lsp/source/completion/deep_completion.go	1970-01-01 08:00:00
+@@ -1,378 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -70802,7 +78339,7 @@
 -// deepSearch searches a candidate and its subordinate objects for completion
 -// items if deep completion is enabled and adds the valid candidates to
 -// completion items.
--func (c *completer) deepSearch(ctx context.Context) {
+-func (c *completer) deepSearch(ctx context.Context, minDepth int, deadline *time.Time) {
 -	defer func() {
 -		// We can return early before completing the search, so be sure to
 -		// clear out our queues to not impact any further invocations.
@@ -70810,7 +78347,25 @@
 -		c.deepState.nextQueue = c.deepState.nextQueue[:0]
 -	}()
 -
+-	depth := 0 // current depth being processed
+-	// Stop reports whether we should stop the search immediately.
+-	stop := func() bool {
+-		// Context cancellation indicates that the actual completion operation was
+-		// cancelled, so ignore minDepth and deadline.
+-		select {
+-		case <-ctx.Done():
+-			return true
+-		default:
+-		}
+-		// Otherwise, only stop if we've searched at least minDepth and reached the deadline.
+-		return depth > minDepth && deadline != nil && time.Now().After(*deadline)
+-	}
+-
 -	for len(c.deepState.nextQueue) > 0 {
+-		depth++
+-		if stop() {
+-			return
+-		}
 -		c.deepState.thisQueue, c.deepState.nextQueue = c.deepState.nextQueue, c.deepState.thisQueue[:0]
 -
 -	outer:
@@ -70859,17 +78414,15 @@
 -
 -			c.deepState.candidateCount++
 -			if c.opts.budget > 0 && c.deepState.candidateCount%100 == 0 {
--				spent := float64(time.Since(c.startTime)) / float64(c.opts.budget)
--				select {
--				case <-ctx.Done():
+-				if stop() {
 -					return
--				default:
--					// If we are almost out of budgeted time, no further elements
--					// should be added to the queue. This ensures remaining time is
--					// used for processing current queue.
--					if !c.deepState.queueClosed && spent >= 0.85 {
--						c.deepState.queueClosed = true
--					}
+-				}
+-				spent := float64(time.Since(c.startTime)) / float64(c.opts.budget)
+-				// If we are almost out of budgeted time, no further elements
+-				// should be added to the queue. This ensures remaining time is
+-				// used for processing current queue.
+-				if !c.deepState.queueClosed && spent >= 0.85 {
+-					c.deepState.queueClosed = true
 -				}
 -			}
 -
@@ -71051,7 +78604,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/deep_completion_test.go b/gopls/internal/lsp/source/completion/deep_completion_test.go
 --- a/gopls/internal/lsp/source/completion/deep_completion_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/deep_completion_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/deep_completion_test.go	1970-01-01 08:00:00
 @@ -1,33 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -71088,7 +78641,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/definition.go b/gopls/internal/lsp/source/completion/definition.go
 --- a/gopls/internal/lsp/source/completion/definition.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/definition.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/definition.go	1970-01-01 08:00:00
 @@ -1,160 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -71252,8 +78805,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/format.go b/gopls/internal/lsp/source/completion/format.go
 --- a/gopls/internal/lsp/source/completion/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,338 +0,0 @@
++++ b/gopls/internal/lsp/source/completion/format.go	1970-01-01 08:00:00
+@@ -1,345 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -71439,11 +78992,18 @@
 -	if cand.convertTo != nil {
 -		typeName := types.TypeString(cand.convertTo, c.qf)
 -
--		switch cand.convertTo.(type) {
+-		switch t := cand.convertTo.(type) {
 -		// We need extra parens when casting to these types. For example,
 -		// we need "(*int)(foo)", not "*int(foo)".
 -		case *types.Pointer, *types.Signature:
 -			typeName = "(" + typeName + ")"
+-		case *types.Basic:
+-			// If the types are incompatible (as determined by typeMatches), then we
+-			// must need a conversion here. However, if the target type is untyped,
+-			// don't suggest converting to e.g. "untyped float" (golang/go#62141).
+-			if t.Info()&types.IsUntyped != 0 {
+-				typeName = types.TypeString(types.Default(cand.convertTo), c.qf)
+-			}
 -		}
 -
 -		prefix = typeName + "(" + prefix
@@ -71512,9 +79072,9 @@
 -	// TODO(rfindley): It doesn't look like this does the right thing for
 -	// multi-line comments.
 -	if strings.HasPrefix(comment.Text(), "Deprecated") {
--		if c.snapshot.View().Options().CompletionTags {
+-		if c.snapshot.Options().CompletionTags {
 -			item.Tags = []protocol.CompletionItemTag{protocol.ComplDeprecated}
--		} else if c.snapshot.View().Options().CompletionDeprecated {
+-		} else if c.snapshot.Options().CompletionDeprecated {
 -			item.Deprecated = true
 -		}
 -	}
@@ -71594,7 +79154,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/fuzz.go b/gopls/internal/lsp/source/completion/fuzz.go
 --- a/gopls/internal/lsp/source/completion/fuzz.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/fuzz.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/fuzz.go	1970-01-01 08:00:00
 @@ -1,142 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -71740,7 +79300,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/keywords.go b/gopls/internal/lsp/source/completion/keywords.go
 --- a/gopls/internal/lsp/source/completion/keywords.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/keywords.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/keywords.go	1970-01-01 08:00:00
 @@ -1,154 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -71898,7 +79458,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/labels.go b/gopls/internal/lsp/source/completion/labels.go
 --- a/gopls/internal/lsp/source/completion/labels.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/labels.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/labels.go	1970-01-01 08:00:00
 @@ -1,112 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -72014,7 +79574,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/literal.go b/gopls/internal/lsp/source/completion/literal.go
 --- a/gopls/internal/lsp/source/completion/literal.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/literal.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/literal.go	1970-01-01 08:00:00
 @@ -1,592 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -72610,7 +80170,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/package.go b/gopls/internal/lsp/source/completion/package.go
 --- a/gopls/internal/lsp/source/completion/package.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/package.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/package.go	1970-01-01 08:00:00
 @@ -1,351 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -72722,7 +80282,7 @@
 -	// appear on any line of the file as long as it's the first code expression
 -	// in the file.
 -	lines := strings.Split(string(pgf.Src), "\n")
--	cursorLine := tok.Line(cursor)
+-	cursorLine := safetoken.Line(tok, cursor)
 -	if cursorLine <= 0 || cursorLine > len(lines) {
 -		return nil, fmt.Errorf("invalid line number")
 -	}
@@ -72817,7 +80377,7 @@
 -// file. This also includes test packages for these packages (<pkg>_test) and
 -// the directory name itself.
 -func packageSuggestions(ctx context.Context, snapshot source.Snapshot, fileURI span.URI, prefix string) (packages []candidate, err error) {
--	active, err := snapshot.ActiveMetadata(ctx)
+-	active, err := snapshot.WorkspaceMetadata(ctx)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -72965,7 +80525,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/package_test.go b/gopls/internal/lsp/source/completion/package_test.go
 --- a/gopls/internal/lsp/source/completion/package_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/package_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/package_test.go	1970-01-01 08:00:00
 @@ -1,81 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -73050,8 +80610,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/postfix_snippets.go b/gopls/internal/lsp/source/completion/postfix_snippets.go
 --- a/gopls/internal/lsp/source/completion/postfix_snippets.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/postfix_snippets.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,471 +0,0 @@
++++ b/gopls/internal/lsp/source/completion/postfix_snippets.go	1970-01-01 08:00:00
+@@ -1,481 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -73071,6 +80631,7 @@
 -	"text/template"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/snippet"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/internal/event"
@@ -73247,6 +80808,14 @@
 -	body: `{{if and (eq .Kind "slice") (eq (.TypeName .ElemType) "string") -}}
 -{{.Import "strings"}}.Join({{.X}}, "{{.Cursor}}")
 -{{- end}}`,
+-}, {
+-	label:   "ifnotnil",
+-	details: "if expr != nil",
+-	body: `{{if and (or (eq .Kind "pointer") (eq .Kind "chan") (eq .Kind "signature") (eq .Kind "interface") (eq .Kind "map") (eq .Kind "slice")) .StmtOK -}}
+-if {{.X}} != nil {{"{"}}
+-	{{.Cursor}}
+-{{"}"}}
+-{{- end}}`,
 -}}
 -
 -// Cursor indicates where the client's cursor should end up after the
@@ -73264,6 +80833,7 @@
 -		return "", fmt.Errorf("couldn't import %q: %w", path, err)
 -	}
 -	a.edits = append(a.edits, edits...)
+-
 -	return name, nil
 -}
 -
@@ -73394,7 +80964,7 @@
 -				//
 -				// detect that "foo." makes up the entire statement since the
 -				// apparent selector spans lines.
--				stmtOK = tokFile.Line(c.pos) < tokFile.Line(p.TokPos)
+-				stmtOK = safetoken.Line(tokFile, c.pos) < safetoken.Line(tokFile, p.TokPos)
 -			}
 -			break
 -		}
@@ -73416,8 +80986,8 @@
 -	//
 -	// and adjust afterDot so that we don't mistakenly delete the
 -	// newline thinking "bar" is part of our selector.
--	if startLine := tokFile.Line(sel.Pos()); startLine != tokFile.Line(afterDot) {
--		if tokFile.Line(c.pos) != startLine {
+-	if startLine := safetoken.Line(tokFile, sel.Pos()); startLine != safetoken.Line(tokFile, afterDot) {
+-		if safetoken.Line(tokFile, c.pos) != startLine {
 -			return
 -		}
 -		afterDot = c.pos
@@ -73525,7 +81095,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/printf.go b/gopls/internal/lsp/source/completion/printf.go
 --- a/gopls/internal/lsp/source/completion/printf.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/printf.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/printf.go	1970-01-01 08:00:00
 @@ -1,172 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -73701,7 +81271,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/printf_test.go b/gopls/internal/lsp/source/completion/printf_test.go
 --- a/gopls/internal/lsp/source/completion/printf_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/printf_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/printf_test.go	1970-01-01 08:00:00
 @@ -1,72 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -73777,8 +81347,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/snippet.go b/gopls/internal/lsp/source/completion/snippet.go
 --- a/gopls/internal/lsp/source/completion/snippet.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/snippet.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,116 +0,0 @@
++++ b/gopls/internal/lsp/source/completion/snippet.go	1970-01-01 08:00:00
+@@ -1,121 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -73832,6 +81402,11 @@
 -
 -// functionCallSnippet calculates the snippet for function calls.
 -func (c *completer) functionCallSnippet(name string, tparams, params []string, snip *snippet.Builder) {
+-	if !c.opts.completeFunctionCalls {
+-		snip.WriteText(name)
+-		return
+-	}
+-
 -	// If there is no suffix then we need to reuse existing call parens
 -	// "()" if present. If there is an identifier suffix then we always
 -	// need to include "()" since we don't overwrite the suffix.
@@ -73897,7 +81472,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/statements.go b/gopls/internal/lsp/source/completion/statements.go
 --- a/gopls/internal/lsp/source/completion/statements.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/statements.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/statements.go	1970-01-01 08:00:00
 @@ -1,361 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -74262,7 +81837,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/util.go b/gopls/internal/lsp/source/completion/util.go
 --- a/gopls/internal/lsp/source/completion/util.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/util.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/util.go	1970-01-01 08:00:00
 @@ -1,344 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -74610,7 +82185,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/completion/util_test.go b/gopls/internal/lsp/source/completion/util_test.go
 --- a/gopls/internal/lsp/source/completion/util_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/completion/util_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/completion/util_test.go	1970-01-01 08:00:00
 @@ -1,28 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -74642,8 +82217,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/definition.go b/gopls/internal/lsp/source/definition.go
 --- a/gopls/internal/lsp/source/definition.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/definition.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,229 +0,0 @@
++++ b/gopls/internal/lsp/source/definition.go	1970-01-01 08:00:00
+@@ -1,261 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -74652,14 +82227,15 @@
 -
 -import (
 -	"context"
+-	"errors"
 -	"fmt"
 -	"go/ast"
 -	"go/token"
 -	"go/types"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -)
 -
@@ -74668,7 +82244,7 @@
 -	ctx, done := event.Start(ctx, "source.Definition")
 -	defer done()
 -
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -74704,31 +82280,67 @@
 -		return []protocol.Location{loc}, nil
 -	}
 -
+-	// Handle the case where the cursor is in a linkname directive.
+-	locations, err := LinknameDefinition(ctx, snapshot, fh, position)
+-	if !errors.Is(err, ErrNoLinkname) {
+-		return locations, err
+-	}
+-
+-	// Handle the case where the cursor is in an embed directive.
+-	locations, err = EmbedDefinition(pgf.Mapper, position)
+-	if !errors.Is(err, ErrNoEmbed) {
+-		return locations, err
+-	}
+-
 -	// The general case: the cursor is on an identifier.
 -	_, obj, _ := referencedObject(pkg, pgf, pos)
 -	if obj == nil {
 -		return nil, nil
 -	}
 -
--	// Handle built-in identifiers.
--	if obj.Parent() == types.Universe {
--		builtin, err := snapshot.BuiltinFile(ctx)
--		if err != nil {
--			return nil, err
+-	// Handle objects with no position: builtin, unsafe.
+-	if !obj.Pos().IsValid() {
+-		var pgf *ParsedGoFile
+-		if obj.Parent() == types.Universe {
+-			// pseudo-package "builtin"
+-			builtinPGF, err := snapshot.BuiltinFile(ctx)
+-			if err != nil {
+-				return nil, err
+-			}
+-			pgf = builtinPGF
+-
+-		} else if obj.Pkg() == types.Unsafe {
+-			// package "unsafe"
+-			unsafe := snapshot.Metadata("unsafe")
+-			if unsafe == nil {
+-				return nil, fmt.Errorf("no metadata for package 'unsafe'")
+-			}
+-			uri := unsafe.GoFiles[0]
+-			fh, err := snapshot.ReadFile(ctx, uri)
+-			if err != nil {
+-				return nil, err
+-			}
+-			pgf, err = snapshot.ParseGo(ctx, fh, ParseFull&^SkipObjectResolution)
+-			if err != nil {
+-				return nil, err
+-			}
+-
+-		} else {
+-			return nil, bug.Errorf("internal error: no position for %v", obj.Name())
 -		}
--		// Note that builtinObj is an ast.Object, not types.Object :)
--		builtinObj := builtin.File.Scope.Lookup(obj.Name())
--		if builtinObj == nil {
--			// Every builtin should have documentation.
--			return nil, bug.Errorf("internal error: no builtin object for %s", obj.Name())
+-		// Inv: pgf ∈ {builtin,unsafe}.go
+-
+-		// Use legacy (go/ast) object resolution.
+-		astObj := pgf.File.Scope.Lookup(obj.Name())
+-		if astObj == nil {
+-			// Every built-in should have documentation syntax.
+-			return nil, bug.Errorf("internal error: no object for %s", obj.Name())
 -		}
--		decl, ok := builtinObj.Decl.(ast.Node)
+-		decl, ok := astObj.Decl.(ast.Node)
 -		if !ok {
 -			return nil, bug.Errorf("internal error: no declaration for %s", obj.Name())
 -		}
--		// The builtin package isn't in the dependency graph, so the usual
--		// utilities won't work here.
--		loc, err := builtin.PosLocation(decl.Pos(), decl.Pos()+token.Pos(len(obj.Name())))
+-		loc, err := pgf.PosLocation(decl.Pos(), decl.Pos()+token.Pos(len(obj.Name())))
 -		if err != nil {
 -			return nil, err
 -		}
@@ -74736,16 +82348,11 @@
 -	}
 -
 -	// Finally, map the object position.
--	var locs []protocol.Location
--	if !obj.Pos().IsValid() {
--		return nil, bug.Errorf("internal error: no position for %v", obj.Name())
--	}
 -	loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, obj.Pos(), adjustedObjEnd(obj))
 -	if err != nil {
 -		return nil, err
 -	}
--	locs = append(locs, loc)
--	return locs, nil
+-	return []protocol.Location{loc}, nil
 -}
 -
 -// referencedObject returns the identifier and object referenced at the
@@ -74829,7 +82436,7 @@
 -
 -	var locs []protocol.Location
 -	for _, f := range impMetadata.CompiledGoFiles {
--		fh, err := s.GetFile(ctx, f)
+-		fh, err := s.ReadFile(ctx, f)
 -		if err != nil {
 -			if ctx.Err() != nil {
 -				return nil, ctx.Err()
@@ -74862,11 +82469,11 @@
 -func mapPosition(ctx context.Context, fset *token.FileSet, s FileSource, start, end token.Pos) (protocol.Location, error) {
 -	file := fset.File(start)
 -	uri := span.URIFromPath(file.Name())
--	fh, err := s.GetFile(ctx, uri)
+-	fh, err := s.ReadFile(ctx, uri)
 -	if err != nil {
 -		return protocol.Location{}, err
 -	}
--	content, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return protocol.Location{}, err
 -	}
@@ -74875,8 +82482,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/diagnostics.go b/gopls/internal/lsp/source/diagnostics.go
 --- a/gopls/internal/lsp/source/diagnostics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/diagnostics.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,138 +0,0 @@
++++ b/gopls/internal/lsp/source/diagnostics.go	1970-01-01 08:00:00
+@@ -1,187 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -74885,7 +82492,10 @@
 -
 -import (
 -	"context"
+-	"encoding/json"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/progress"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/span"
 -)
@@ -74898,22 +82508,22 @@
 -}
 -
 -// Analyze reports go/analysis-framework diagnostics in the specified package.
--func Analyze(ctx context.Context, snapshot Snapshot, pkgid PackageID, includeConvenience bool) (map[span.URI][]*Diagnostic, error) {
+-//
+-// If the provided tracker is non-nil, it may be used to provide notifications
+-// of the ongoing analysis pass.
+-func Analyze(ctx context.Context, snapshot Snapshot, pkgIDs map[PackageID]unit, tracker *progress.Tracker) (map[span.URI][]*Diagnostic, error) {
 -	// Exit early if the context has been canceled. This also protects us
 -	// from a race on Options, see golang/go#36699.
 -	if ctx.Err() != nil {
 -		return nil, ctx.Err()
 -	}
 -
--	options := snapshot.View().Options()
+-	options := snapshot.Options()
 -	categories := []map[string]*Analyzer{
 -		options.DefaultAnalyzers,
 -		options.StaticcheckAnalyzers,
 -		options.TypeErrorAnalyzers,
 -	}
--	if includeConvenience { // e.g. for codeAction
--		categories = append(categories, options.ConvenienceAnalyzers) // e.g. fillstruct
--	}
 -
 -	var analyzers []*Analyzer
 -	for _, cat := range categories {
@@ -74922,7 +82532,7 @@
 -		}
 -	}
 -
--	analysisDiagnostics, err := snapshot.Analyze(ctx, pkgid, analyzers)
+-	analysisDiagnostics, err := snapshot.Analyze(ctx, pkgIDs, analyzers, tracker)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -74935,38 +82545,6 @@
 -	return reports, nil
 -}
 -
--// FileDiagnostics reports diagnostics in the specified file,
--// as used by the "gopls check" command.
--//
--// TODO(adonovan): factor in common with (*Server).codeAction, which
--// executes { PackageForFile; Analyze } too?
--//
--// TODO(adonovan): opt: this function is called in a loop from the
--// "gopls/diagnoseFiles" nonstandard request handler. It would be more
--// efficient to compute the set of packages and TypeCheck and
--// Analyze them all at once.
--func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (FileHandle, []*Diagnostic, error) {
--	fh, err := snapshot.GetFile(ctx, uri)
--	if err != nil {
--		return nil, nil, err
--	}
--	pkg, _, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage)
--	if err != nil {
--		return nil, nil, err
--	}
--	pkgDiags, err := pkg.DiagnosticsForFile(ctx, snapshot, uri)
--	if err != nil {
--		return nil, nil, err
--	}
--	adiags, err := Analyze(ctx, snapshot, pkg.Metadata().ID, false)
--	if err != nil {
--		return nil, nil, err
--	}
--	var fileDiags []*Diagnostic // combine load/parse/type + analysis diagnostics
--	CombineDiagnostics(pkgDiags, adiags[uri], &fileDiags, &fileDiags)
--	return fh, fileDiags, nil
--}
--
 -// CombineDiagnostics combines and filters list/parse/type diagnostics from
 -// tdiags with adiags, and appends the two lists to *outT and *outA,
 -// respectively.
@@ -75015,10 +82593,287 @@
 -
 -	*outT = append(*outT, tdiags...)
 -}
+-
+-// quickFixesJSON is a JSON-serializable list of quick fixes
+-// to be saved in the protocol.Diagnostic.Data field.
+-type quickFixesJSON struct {
+-	// TODO(rfindley): pack some sort of identifier here for later
+-	// lookup/validation?
+-	Fixes []protocol.CodeAction
+-}
+-
+-// BundleQuickFixes attempts to bundle sd.SuggestedFixes into the
+-// sd.BundledFixes field, so that it can be round-tripped through the client.
+-// It returns false if the quick-fixes cannot be bundled.
+-func BundleQuickFixes(sd *Diagnostic) bool {
+-	if len(sd.SuggestedFixes) == 0 {
+-		return true
+-	}
+-	var actions []protocol.CodeAction
+-	for _, fix := range sd.SuggestedFixes {
+-		if fix.Edits != nil {
+-			// For now, we only support bundled code actions that execute commands.
+-			//
+-			// In order to cleanly support bundled edits, we'd have to guarantee that
+-			// the edits were generated on the current snapshot. But this naively
+-			// implies that every fix would have to include a snapshot ID, which
+-			// would require us to republish all diagnostics on each new snapshot.
+-			//
+-			// TODO(rfindley): in order to avoid this additional chatter, we'd need
+-			// to build some sort of registry or other mechanism on the snapshot to
+-			// check whether a diagnostic is still valid.
+-			return false
+-		}
+-		action := protocol.CodeAction{
+-			Title:   fix.Title,
+-			Kind:    fix.ActionKind,
+-			Command: fix.Command,
+-		}
+-		actions = append(actions, action)
+-	}
+-	fixes := quickFixesJSON{
+-		Fixes: actions,
+-	}
+-	data, err := json.Marshal(fixes)
+-	if err != nil {
+-		bug.Reportf("marshalling quick fixes: %v", err)
+-		return false
+-	}
+-	msg := json.RawMessage(data)
+-	sd.BundledFixes = &msg
+-	return true
+-}
+-
+-// BundledQuickFixes extracts any bundled codeActions from the
+-// diag.Data field.
+-func BundledQuickFixes(diag protocol.Diagnostic) []protocol.CodeAction {
+-	if diag.Data == nil {
+-		return nil
+-	}
+-	var fix quickFixesJSON
+-	if err := json.Unmarshal(*diag.Data, &fix); err != nil {
+-		bug.Reportf("unmarshalling quick fix: %v", err)
+-		return nil
+-	}
+-
+-	var actions []protocol.CodeAction
+-	for _, action := range fix.Fixes {
+-		// See BundleQuickFixes: for now we only support bundling commands.
+-		if action.Edit != nil {
+-			bug.Reportf("bundled fix %q includes workspace edits", action.Title)
+-			continue
+-		}
+-		// associate the action with the incoming diagnostic
+-		// (Note that this does not mutate the fix.Fixes slice).
+-		action.Diagnostics = []protocol.Diagnostic{diag}
+-		actions = append(actions, action)
+-	}
+-
+-	return actions
+-}
+diff -urN a/gopls/internal/lsp/source/embeddirective.go b/gopls/internal/lsp/source/embeddirective.go
+--- a/gopls/internal/lsp/source/embeddirective.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/embeddirective.go	1970-01-01 08:00:00
+@@ -1,195 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package source
+-
+-import (
+-	"errors"
+-	"fmt"
+-	"io/fs"
+-	"path/filepath"
+-	"strconv"
+-	"strings"
+-	"unicode"
+-	"unicode/utf8"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
+-
+-// ErrNoEmbed is returned by EmbedDefinition when no embed
+-// directive is found at a particular position.
+-// As such it indicates that other definitions could be worth checking.
+-var ErrNoEmbed = errors.New("no embed directive found")
+-
+-var errStopWalk = errors.New("stop walk")
+-
+-// EmbedDefinition finds a file matching the embed directive at pos in the mapped file.
+-// If there is no embed directive at pos, returns ErrNoEmbed.
+-// If multiple files match the embed pattern, one is picked at random.
+-func EmbedDefinition(m *protocol.Mapper, pos protocol.Position) ([]protocol.Location, error) {
+-	pattern, _ := parseEmbedDirective(m, pos)
+-	if pattern == "" {
+-		return nil, ErrNoEmbed
+-	}
+-
+-	// Find the first matching file.
+-	var match string
+-	dir := filepath.Dir(m.URI.Filename())
+-	err := filepath.WalkDir(dir, func(abs string, d fs.DirEntry, e error) error {
+-		if e != nil {
+-			return e
+-		}
+-		rel, err := filepath.Rel(dir, abs)
+-		if err != nil {
+-			return err
+-		}
+-		ok, err := filepath.Match(pattern, rel)
+-		if err != nil {
+-			return err
+-		}
+-		if ok && !d.IsDir() {
+-			match = abs
+-			return errStopWalk
+-		}
+-		return nil
+-	})
+-	if err != nil && !errors.Is(err, errStopWalk) {
+-		return nil, err
+-	}
+-	if match == "" {
+-		return nil, fmt.Errorf("%q does not match any files in %q", pattern, dir)
+-	}
+-
+-	loc := protocol.Location{
+-		URI: protocol.URIFromPath(match),
+-		Range: protocol.Range{
+-			Start: protocol.Position{Line: 0, Character: 0},
+-		},
+-	}
+-	return []protocol.Location{loc}, nil
+-}
+-
+-// parseEmbedDirective attempts to parse a go:embed directive argument at pos.
+-// If successful it return the directive argument and its range, else zero values are returned.
+-func parseEmbedDirective(m *protocol.Mapper, pos protocol.Position) (string, protocol.Range) {
+-	lineStart, err := m.PositionOffset(protocol.Position{Line: pos.Line, Character: 0})
+-	if err != nil {
+-		return "", protocol.Range{}
+-	}
+-	lineEnd, err := m.PositionOffset(protocol.Position{Line: pos.Line + 1, Character: 0})
+-	if err != nil {
+-		return "", protocol.Range{}
+-	}
+-
+-	text := string(m.Content[lineStart:lineEnd])
+-	if !strings.HasPrefix(text, "//go:embed") {
+-		return "", protocol.Range{}
+-	}
+-	text = text[len("//go:embed"):]
+-	offset := lineStart + len("//go:embed")
+-
+-	// Find the first pattern in text that covers the offset of the pos we are looking for.
+-	findOffset, err := m.PositionOffset(pos)
+-	if err != nil {
+-		return "", protocol.Range{}
+-	}
+-	patterns, err := parseGoEmbed(text, offset)
+-	if err != nil {
+-		return "", protocol.Range{}
+-	}
+-	for _, p := range patterns {
+-		if p.startOffset <= findOffset && findOffset <= p.endOffset {
+-			// Found our match.
+-			rng, err := m.OffsetRange(p.startOffset, p.endOffset)
+-			if err != nil {
+-				return "", protocol.Range{}
+-			}
+-			return p.pattern, rng
+-		}
+-	}
+-
+-	return "", protocol.Range{}
+-}
+-
+-type fileEmbed struct {
+-	pattern     string
+-	startOffset int
+-	endOffset   int
+-}
+-
+-// parseGoEmbed patterns that come after the directive.
+-//
+-// Copied and adapted from go/build/read.go.
+-// Replaced token.Position with start/end offset (including quotes if present).
+-func parseGoEmbed(args string, offset int) ([]fileEmbed, error) {
+-	trimBytes := func(n int) {
+-		offset += n
+-		args = args[n:]
+-	}
+-	trimSpace := func() {
+-		trim := strings.TrimLeftFunc(args, unicode.IsSpace)
+-		trimBytes(len(args) - len(trim))
+-	}
+-
+-	var list []fileEmbed
+-	for trimSpace(); args != ""; trimSpace() {
+-		var path string
+-		pathOffset := offset
+-	Switch:
+-		switch args[0] {
+-		default:
+-			i := len(args)
+-			for j, c := range args {
+-				if unicode.IsSpace(c) {
+-					i = j
+-					break
+-				}
+-			}
+-			path = args[:i]
+-			trimBytes(i)
+-
+-		case '`':
+-			var ok bool
+-			path, _, ok = strings.Cut(args[1:], "`")
+-			if !ok {
+-				return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+-			}
+-			trimBytes(1 + len(path) + 1)
+-
+-		case '"':
+-			i := 1
+-			for ; i < len(args); i++ {
+-				if args[i] == '\\' {
+-					i++
+-					continue
+-				}
+-				if args[i] == '"' {
+-					q, err := strconv.Unquote(args[:i+1])
+-					if err != nil {
+-						return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
+-					}
+-					path = q
+-					trimBytes(i + 1)
+-					break Switch
+-				}
+-			}
+-			if i >= len(args) {
+-				return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+-			}
+-		}
+-
+-		if args != "" {
+-			r, _ := utf8.DecodeRuneInString(args)
+-			if !unicode.IsSpace(r) {
+-				return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+-			}
+-		}
+-		list = append(list, fileEmbed{
+-			pattern:     path,
+-			startOffset: pathOffset,
+-			endOffset:   offset,
+-		})
+-	}
+-	return list, nil
+-}
 diff -urN a/gopls/internal/lsp/source/extract.go b/gopls/internal/lsp/source/extract.go
 --- a/gopls/internal/lsp/source/extract.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/extract.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1331 +0,0 @@
++++ b/gopls/internal/lsp/source/extract.go	1970-01-01 08:00:00
+@@ -1,1352 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -75039,12 +82894,12 @@
 -
 -	"golang.org/x/tools/go/analysis"
 -	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/internal/analysisinternal"
--	"golang.org/x/tools/internal/bug"
 -)
 -
--func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, _ *types.Package, info *types.Info) (*analysis.SuggestedFix, error) {
+-func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) {
 -	tokFile := fset.File(file.Pos())
 -	expr, path, ok, err := CanExtractVariable(start, end, file)
 -	if !ok {
@@ -75057,14 +82912,14 @@
 -	// TODO: stricter rules for selectorExpr.
 -	case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.SliceExpr,
 -		*ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr:
--		lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, info, "x", 0)
+-		lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, pkg, info, "x", 0)
 -		lhsNames = append(lhsNames, lhsName)
 -	case *ast.CallExpr:
 -		tup, ok := info.TypeOf(expr).(*types.Tuple)
 -		if !ok {
 -			// If the call expression only has one return value, we can treat it the
 -			// same as our standard extract variable case.
--			lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, info, "x", 0)
+-			lhsName, _ := generateAvailableIdentifier(expr.Pos(), file, path, pkg, info, "x", 0)
 -			lhsNames = append(lhsNames, lhsName)
 -			break
 -		}
@@ -75072,7 +82927,7 @@
 -		for i := 0; i < tup.Len(); i++ {
 -			// Generate a unique variable for each return value.
 -			var lhsName string
--			lhsName, idx = generateAvailableIdentifier(expr.Pos(), file, path, info, "x", idx)
+-			lhsName, idx = generateAvailableIdentifier(expr.Pos(), file, path, pkg, info, "x", idx)
 -			lhsNames = append(lhsNames, lhsName)
 -		}
 -	default:
@@ -75153,7 +83008,7 @@
 -// formatting (i.e. the proper indentation). To do so, we observe the indentation on the
 -// line of code on which the insertion occurs.
 -func calculateIndentation(content []byte, tok *token.File, insertBeforeStmt ast.Node) (string, error) {
--	line := tok.Line(insertBeforeStmt.Pos())
+-	line := safetoken.Line(tok, insertBeforeStmt.Pos())
 -	lineOffset, stmtOffset, err := safetoken.Offsets(tok, tok.LineStart(line), insertBeforeStmt.Pos())
 -	if err != nil {
 -		return "", err
@@ -75163,10 +83018,16 @@
 -
 -// generateAvailableIdentifier adjusts the new function name until there are no collisions in scope.
 -// Possible collisions include other function and variable names. Returns the next index to check for prefix.
--func generateAvailableIdentifier(pos token.Pos, file *ast.File, path []ast.Node, info *types.Info, prefix string, idx int) (string, int) {
+-func generateAvailableIdentifier(pos token.Pos, file *ast.File, path []ast.Node, pkg *types.Package, info *types.Info, prefix string, idx int) (string, int) {
 -	scopes := CollectScopes(info, path, pos)
+-	scopes = append(scopes, pkg.Scope())
 -	return generateIdentifier(idx, prefix, func(name string) bool {
--		return file.Scope.Lookup(name) != nil || !isValidName(name, scopes)
+-		for _, scope := range scopes {
+-			if scope != nil && scope.Lookup(name) != nil {
+-				return true
+-			}
+-		}
+-		return false
 -	})
 -}
 -
@@ -75182,19 +83043,6 @@
 -	return name, idx + 1
 -}
 -
--// isValidName checks for variable collision in scope.
--func isValidName(name string, scopes []*types.Scope) bool {
--	for _, scope := range scopes {
--		if scope == nil {
--			continue
--		}
--		if scope.Lookup(name) != nil {
--			return false
--		}
--	}
--	return true
--}
--
 -// returnVariable keeps track of the information we need to properly introduce a new variable
 -// that we will return in the extracted function.
 -type returnVariable struct {
@@ -75391,6 +83239,8 @@
 -		}
 -	}
 -
+-	reorderParams(params, paramTypes)
+-
 -	// Find the function literal that encloses the selection. The enclosing function literal
 -	// may not be the enclosing function declaration (i.e. 'outer'). For example, in the
 -	// following block:
@@ -75555,7 +83405,7 @@
 -		funName = name
 -	} else {
 -		name = "newFunction"
--		funName, _ = generateAvailableIdentifier(start, file, path, info, name, 0)
+-		funName, _ = generateAvailableIdentifier(start, file, path, pkg, info, name, 0)
 -	}
 -	extractedFunCall := generateFuncCall(hasNonNestedReturn, hasReturnValues, params,
 -		append(returns, getNames(retVars)...), funName, sym, receiverName)
@@ -75659,6 +83509,33 @@
 -	}, nil
 -}
 -
+-// isSelector reports if e is the selector expr <x>, <sel>.
+-func isSelector(e ast.Expr, x, sel string) bool {
+-	selectorExpr, ok := e.(*ast.SelectorExpr)
+-	if !ok {
+-		return false
+-	}
+-	ident, ok := selectorExpr.X.(*ast.Ident)
+-	if !ok {
+-		return false
+-	}
+-	return ident.Name == x && selectorExpr.Sel.Name == sel
+-}
+-
+-// reorderParams reorders the given parameters in-place to follow common Go conventions.
+-func reorderParams(params []ast.Expr, paramTypes []*ast.Field) {
+-	// Move Context parameter (if any) to front.
+-	for i, t := range paramTypes {
+-		if isSelector(t.Type, "context", "Context") {
+-			p, t := params[i], paramTypes[i]
+-			copy(params[1:], params[:i])
+-			copy(paramTypes[1:], paramTypes[:i])
+-			params[0], paramTypes[0] = p, t
+-			break
+-		}
+-	}
+-}
+-
 -// adjustRangeForCommentsAndWhiteSpace adjusts the given range to exclude unnecessary leading or
 -// trailing whitespace characters from selection as well as leading or trailing comments.
 -// In the following example, each line of the if statement is indented once. There are also two
@@ -76158,7 +84035,7 @@
 -	var cond *ast.Ident
 -	if !hasNonNestedReturns {
 -		// Generate information for the added bool value.
--		name, _ := generateAvailableIdentifier(pos, file, path, info, "shouldReturn", 0)
+-		name, _ := generateAvailableIdentifier(pos, file, path, pkg, info, "shouldReturn", 0)
 -		cond = &ast.Ident{Name: name}
 -		retVars = append(retVars, &returnVariable{
 -			name:    cond,
@@ -76180,8 +84057,7 @@
 -				return nil, nil, fmt.Errorf("nil AST expression")
 -			}
 -			var name string
--			name, idx = generateAvailableIdentifier(pos, file,
--				path, info, "returnValue", idx)
+-			name, idx = generateAvailableIdentifier(pos, file, path, pkg, info, "returnValue", idx)
 -			retVars = append(retVars, &returnVariable{
 -				name:    ast.NewIdent(name),
 -				decl:    &ast.Field{Type: expr},
@@ -76352,8 +84228,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/fix.go b/gopls/internal/lsp/source/fix.go
 --- a/gopls/internal/lsp/source/fix.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/fix.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,138 +0,0 @@
++++ b/gopls/internal/lsp/source/fix.go	1970-01-01 08:00:00
+@@ -1,195 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -76368,11 +84244,13 @@
 -	"go/types"
 -
 -	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/analysis/embeddirective"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/undeclaredname"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/internal/imports"
 -)
 -
 -type (
@@ -76389,29 +84267,37 @@
 -	singleFileFixFunc func(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error)
 -)
 -
+-// These strings identify kinds of suggested fix, both in Analyzer.Fix
+-// and in the ApplyFix subcommand (see ExecuteCommand and ApplyFixArgs.Fix).
 -const (
--	FillStruct      = "fill_struct"
--	StubMethods     = "stub_methods"
--	UndeclaredName  = "undeclared_name"
--	ExtractVariable = "extract_variable"
--	ExtractFunction = "extract_function"
--	ExtractMethod   = "extract_method"
+-	FillStruct        = "fill_struct"
+-	StubMethods       = "stub_methods"
+-	UndeclaredName    = "undeclared_name"
+-	ExtractVariable   = "extract_variable"
+-	ExtractFunction   = "extract_function"
+-	ExtractMethod     = "extract_method"
+-	InlineCall        = "inline_call"
+-	InvertIfCondition = "invert_if_condition"
+-	AddEmbedImport    = "add_embed_import"
 -)
 -
 -// suggestedFixes maps a suggested fix command id to its handler.
 -var suggestedFixes = map[string]SuggestedFixFunc{
--	FillStruct:      singleFile(fillstruct.SuggestedFix),
--	UndeclaredName:  singleFile(undeclaredname.SuggestedFix),
--	ExtractVariable: singleFile(extractVariable),
--	ExtractFunction: singleFile(extractFunction),
--	ExtractMethod:   singleFile(extractMethod),
--	StubMethods:     stubSuggestedFixFunc,
+-	FillStruct:        singleFile(fillstruct.SuggestedFix),
+-	UndeclaredName:    singleFile(undeclaredname.SuggestedFix),
+-	ExtractVariable:   singleFile(extractVariable),
+-	InlineCall:        inlineCall,
+-	ExtractFunction:   singleFile(extractFunction),
+-	ExtractMethod:     singleFile(extractMethod),
+-	InvertIfCondition: singleFile(invertIfCondition),
+-	StubMethods:       stubSuggestedFixFunc,
+-	AddEmbedImport:    addEmbedImport,
 -}
 -
 -// singleFile calls analyzers that expect inputs for a single file
 -func singleFile(sf singleFileFixFunc) SuggestedFixFunc {
 -	return func(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
--		pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-		pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -		if err != nil {
 -			return nil, nil, err
 -		}
@@ -76456,7 +84342,7 @@
 -		if !end.IsValid() {
 -			end = edit.Pos
 -		}
--		fh, err := snapshot.GetFile(ctx, span.URIFromPath(tokFile.Name()))
+-		fh, err := snapshot.ReadFile(ctx, span.URIFromPath(tokFile.Name()))
 -		if err != nil {
 -			return nil, err
 -		}
@@ -76472,7 +84358,7 @@
 -			}
 -			editsPerFile[fh.URI()] = te
 -		}
--		content, err := fh.Read()
+-		content, err := fh.Content()
 -		if err != nil {
 -			return nil, err
 -		}
@@ -76492,10 +84378,57 @@
 -	}
 -	return edits, nil
 -}
+-
+-// fixedByImportingEmbed returns true if diag can be fixed by addEmbedImport.
+-func fixedByImportingEmbed(diag *Diagnostic) bool {
+-	if diag == nil {
+-		return false
+-	}
+-	return diag.Message == embeddirective.MissingImportMessage
+-}
+-
+-// addEmbedImport adds a missing embed "embed" import with blank name.
+-func addEmbedImport(ctx context.Context, snapshot Snapshot, fh FileHandle, rng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
+-	if err != nil {
+-		return nil, nil, fmt.Errorf("narrow pkg: %w", err)
+-	}
+-
+-	// Like source.AddImport, but with _ as Name and using our pgf.
+-	protoEdits, err := ComputeOneImportFixEdits(snapshot, pgf, &imports.ImportFix{
+-		StmtInfo: imports.ImportInfo{
+-			ImportPath: "embed",
+-			Name:       "_",
+-		},
+-		FixType: imports.AddImport,
+-	})
+-	if err != nil {
+-		return nil, nil, fmt.Errorf("compute edits: %w", err)
+-	}
+-
+-	var edits []analysis.TextEdit
+-	for _, e := range protoEdits {
+-		start, end, err := pgf.RangePos(e.Range)
+-		if err != nil {
+-			return nil, nil, fmt.Errorf("map range: %w", err)
+-		}
+-		edits = append(edits, analysis.TextEdit{
+-			Pos:     start,
+-			End:     end,
+-			NewText: []byte(e.NewText),
+-		})
+-	}
+-
+-	fix := &analysis.SuggestedFix{
+-		Message:   "Add embed import",
+-		TextEdits: edits,
+-	}
+-	return pkg.FileSet(), fix, nil
+-}
 diff -urN a/gopls/internal/lsp/source/folding_range.go b/gopls/internal/lsp/source/folding_range.go
 --- a/gopls/internal/lsp/source/folding_range.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/folding_range.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,193 +0,0 @@
++++ b/gopls/internal/lsp/source/folding_range.go	1970-01-01 08:00:00
+@@ -1,194 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -76509,8 +84442,9 @@
 -	"sort"
 -	"strings"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -)
 -
 -// FoldingRangeInfo holds range and kind info of folding for an ast.Node
@@ -76622,7 +84556,7 @@
 -		return nil
 -	}
 -	// in line folding mode, do not fold if the start and end lines are the same.
--	if lineFoldingOnly && pgf.Tok.Line(start) == pgf.Tok.Line(end) {
+-	if lineFoldingOnly && safetoken.Line(pgf.Tok, start) == safetoken.Line(pgf.Tok, end) {
 -		return nil
 -	}
 -	mrng, err := pgf.PosMappedRange(start, end)
@@ -76647,8 +84581,8 @@
 -		// as an example, the example below should *not* fold:
 -		// var x = [2]string{"d",
 -		// "e" }
--		if tokFile.Line(open) == tokFile.Line(start) ||
--			tokFile.Line(close) == tokFile.Line(end) {
+-		if safetoken.Line(tokFile, open) == safetoken.Line(tokFile, start) ||
+-			safetoken.Line(tokFile, close) == safetoken.Line(tokFile, end) {
 -			return token.NoPos, token.NoPos
 -		}
 -
@@ -76663,7 +84597,7 @@
 -func commentsFoldingRange(pgf *ParsedGoFile) (comments []*FoldingRangeInfo) {
 -	tokFile := pgf.Tok
 -	for _, commentGrp := range pgf.File.Comments {
--		startGrpLine, endGrpLine := tokFile.Line(commentGrp.Pos()), tokFile.Line(commentGrp.End())
+-		startGrpLine, endGrpLine := safetoken.Line(tokFile, commentGrp.Pos()), safetoken.Line(tokFile, commentGrp.End())
 -		if startGrpLine == endGrpLine {
 -			// Don't fold single line comments.
 -			continue
@@ -76671,7 +84605,7 @@
 -
 -		firstComment := commentGrp.List[0]
 -		startPos, endLinePos := firstComment.Pos(), firstComment.End()
--		startCmmntLine, endCmmntLine := tokFile.Line(startPos), tokFile.Line(endLinePos)
+-		startCmmntLine, endCmmntLine := safetoken.Line(tokFile, startPos), safetoken.Line(tokFile, endLinePos)
 -		if startCmmntLine != endCmmntLine {
 -			// If the first comment spans multiple lines, then we want to have the
 -			// folding range start at the end of the first line.
@@ -76691,8 +84625,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/format.go b/gopls/internal/lsp/source/format.go
 --- a/gopls/internal/lsp/source/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,391 +0,0 @@
++++ b/gopls/internal/lsp/source/format.go	1970-01-01 08:00:00
+@@ -1,388 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -76716,6 +84650,7 @@
 -	"golang.org/x/tools/internal/diff"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/imports"
+-	"golang.org/x/tools/internal/tokeninternal"
 -)
 -
 -// Format formats a file with a given range.
@@ -76748,7 +84683,7 @@
 -	// This should be acceptable for all users, who likely be prompted to rebuild
 -	// the LSP server on each Go release.
 -	buf := &bytes.Buffer{}
--	fset := FileSetFor(pgf.Tok)
+-	fset := tokeninternal.FileSetFor(pgf.Tok)
 -	if err := format.Node(buf, fset, pgf.File); err != nil {
 -		return nil, err
 -	}
@@ -76756,7 +84691,7 @@
 -
 -	// Apply additional formatting, if any is supported. Currently, the only
 -	// supported additional formatter is gofumpt.
--	if format := snapshot.View().Options().GofumptFormat; snapshot.View().Options().Gofumpt && format != nil {
+-	if format := snapshot.Options().GofumptFormat; snapshot.Options().Gofumpt && format != nil {
 -		// gofumpt can customize formatting based on language version and module
 -		// path, if available.
 -		//
@@ -76766,9 +84701,9 @@
 -		// Can this, for example, result in inconsistent formatting across saves,
 -		// due to pending calls to packages.Load?
 -		var langVersion, modulePath string
--		mds, err := snapshot.MetadataForFile(ctx, fh.URI())
--		if err == nil && len(mds) > 0 {
--			if mi := mds[0].Module; mi != nil {
+-		meta, err := NarrowestMetadataForFile(ctx, snapshot, fh.URI())
+-		if err == nil {
+-			if mi := meta.Module; mi != nil {
 -				langVersion = mi.GoVersion
 -				modulePath = mi.Path
 -			}
@@ -76786,7 +84721,7 @@
 -	_, done := event.Start(ctx, "source.formatSource")
 -	defer done()
 -
--	data, err := fh.Read()
+-	data, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -76802,16 +84737,12 @@
 -// In addition to returning the result of applying all edits,
 -// it returns a list of fixes that could be applied to the file, with the
 -// corresponding TextEdits that would be needed to apply that fix.
--func AllImportsFixes(ctx context.Context, snapshot Snapshot, fh FileHandle) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) {
+-func AllImportsFixes(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) {
 -	ctx, done := event.Start(ctx, "source.AllImportsFixes")
 -	defer done()
 -
--	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
--	if err != nil {
--		return nil, nil, err
--	}
--	if err := snapshot.RunProcessEnvFunc(ctx, func(opts *imports.Options) error {
--		allFixEdits, editsPerFix, err = computeImportEdits(snapshot, pgf, opts)
+-	if err := snapshot.RunProcessEnvFunc(ctx, func(ctx context.Context, opts *imports.Options) error {
+-		allFixEdits, editsPerFix, err = computeImportEdits(ctx, snapshot, pgf, opts)
 -		return err
 -	}); err != nil {
 -		return nil, nil, fmt.Errorf("AllImportsFixes: %v", err)
@@ -76821,11 +84752,11 @@
 -
 -// computeImportEdits computes a set of edits that perform one or all of the
 -// necessary import fixes.
--func computeImportEdits(snapshot Snapshot, pgf *ParsedGoFile, options *imports.Options) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) {
+-func computeImportEdits(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, options *imports.Options) (allFixEdits []protocol.TextEdit, editsPerFix []*ImportFix, err error) {
 -	filename := pgf.URI.Filename()
 -
 -	// Build up basic information about the original file.
--	allFixes, err := imports.FixImports(filename, pgf.Src, options)
+-	allFixes, err := imports.FixImports(ctx, filename, pgf.Src, options)
 -	if err != nil {
 -		return nil, nil, err
 -	}
@@ -76853,7 +84784,7 @@
 -// ComputeOneImportFixEdits returns text edits for a single import fix.
 -func ComputeOneImportFixEdits(snapshot Snapshot, pgf *ParsedGoFile, fix *imports.ImportFix) ([]protocol.TextEdit, error) {
 -	options := &imports.Options{
--		LocalPrefix: snapshot.View().Options().Local,
+-		LocalPrefix: snapshot.Options().Local,
 -		// Defaults.
 -		AllErrors:  true,
 -		Comments:   true,
@@ -76892,7 +84823,7 @@
 -	if fixedData == nil || fixedData[len(fixedData)-1] != '\n' {
 -		fixedData = append(fixedData, '\n') // ApplyFixes may miss the newline, go figure.
 -	}
--	edits := snapshot.View().Options().ComputeEdits(left, string(fixedData))
+-	edits := snapshot.Options().ComputeEdits(left, string(fixedData))
 -	return protocolEditsFromSource([]byte(left), edits)
 -}
 -
@@ -76932,7 +84863,7 @@
 -		// specifically, in the text of a comment, it will strip out \r\n line
 -		// endings in favor of \n. To account for these differences, we try to
 -		// return a position on the next line whenever possible.
--		switch line := tok.Line(tok.Pos(offset)); {
+-		switch line := safetoken.Line(tok, tok.Pos(offset)); {
 -		case line < tok.LineCount():
 -			nextLineOffset, err := safetoken.Offset(tok, tok.LineStart(line+1))
 -			if err != nil {
@@ -77002,7 +84933,7 @@
 -	_, done := event.Start(ctx, "source.computeTextEdits")
 -	defer done()
 -
--	edits := snapshot.View().Options().ComputeEdits(string(pgf.Src), formatted)
+-	edits := snapshot.Options().ComputeEdits(string(pgf.Src), formatted)
 -	return ToProtocolEdits(pgf.Mapper, edits)
 -}
 -
@@ -77030,7 +84961,7 @@
 -	return result, nil
 -}
 -
--// ToProtocolEdits converts diff.Edits to LSP TextEdits.
+-// ToProtocolEdits converts diff.Edits to a non-nil slice of LSP TextEdits.
 -// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEditArray
 -func ToProtocolEdits(m *protocol.Mapper, edits []diff.Edit) ([]protocol.TextEdit, error) {
 -	// LSP doesn't require TextEditArray to be sorted:
@@ -77086,7 +85017,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/format_test.go b/gopls/internal/lsp/source/format_test.go
 --- a/gopls/internal/lsp/source/format_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/format_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/format_test.go	1970-01-01 08:00:00
 @@ -1,75 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -77165,7 +85096,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/gc_annotations.go b/gopls/internal/lsp/source/gc_annotations.go
 --- a/gopls/internal/lsp/source/gc_annotations.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/gc_annotations.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/gc_annotations.go	1970-01-01 08:00:00
 @@ -1,221 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -77178,7 +85109,6 @@
 -	"context"
 -	"encoding/json"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"strings"
@@ -77214,7 +85144,7 @@
 -	if err := os.MkdirAll(outDir, 0700); err != nil {
 -		return nil, err
 -	}
--	tmpFile, err := ioutil.TempFile(os.TempDir(), "gopls-x")
+-	tmpFile, err := os.CreateTemp(os.TempDir(), "gopls-x")
 -	if err != nil {
 -		return nil, err
 -	}
@@ -77244,7 +85174,7 @@
 -		return nil, err
 -	}
 -	reports := make(map[span.URI][]*Diagnostic)
--	opts := snapshot.View().Options()
+-	opts := snapshot.Options()
 -	var parseError error
 -	for _, fn := range files {
 -		uri, diagnostics, err := parseDetailsFile(fn, opts)
@@ -77268,7 +85198,7 @@
 -}
 -
 -func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnostic, error) {
--	buf, err := ioutil.ReadFile(filename)
+-	buf, err := os.ReadFile(filename)
 -	if err != nil {
 -		return "", nil, err
 -	}
@@ -77298,6 +85228,7 @@
 -		if err := dec.Decode(d); err != nil {
 -			return "", nil, err
 -		}
+-		d.Tags = []protocol.DiagnosticTag{} // must be an actual slice
 -		msg := d.Code.(string)
 -		if msg != "" {
 -			msg = fmt.Sprintf("%s(%s)", msg, d.Message)
@@ -77390,8 +85321,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/highlight.go b/gopls/internal/lsp/source/highlight.go
 --- a/gopls/internal/lsp/source/highlight.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/highlight.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,484 +0,0 @@
++++ b/gopls/internal/lsp/source/highlight.go	1970-01-01 08:00:00
+@@ -1,480 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -77404,7 +85335,6 @@
 -	"go/ast"
 -	"go/token"
 -	"go/types"
--	"strings"
 -
 -	"golang.org/x/tools/go/ast/astutil"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
@@ -77417,7 +85347,7 @@
 -
 -	// We always want fully parsed files for highlight, regardless
 -	// of whether the file belongs to a workspace package.
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, fmt.Errorf("getting package for Highlight: %w", err)
 -	}
@@ -77461,10 +85391,27 @@
 -	result := make(map[posRange]struct{})
 -	switch node := path[0].(type) {
 -	case *ast.BasicLit:
+-		// Import path string literal?
 -		if len(path) > 1 {
--			if _, ok := path[1].(*ast.ImportSpec); ok {
--				err := highlightImportUses(path, info, result)
--				return result, err
+-			if imp, ok := path[1].(*ast.ImportSpec); ok {
+-				highlight := func(n ast.Node) {
+-					result[posRange{start: n.Pos(), end: n.End()}] = struct{}{}
+-				}
+-
+-				// Highlight the import itself...
+-				highlight(imp)
+-
+-				// ...and all references to it in the file.
+-				if pkgname, ok := ImportedPkgName(info, imp); ok {
+-					ast.Inspect(file, func(n ast.Node) bool {
+-						if id, ok := n.(*ast.Ident); ok &&
+-							info.Uses[id] == pkgname {
+-							highlight(id)
+-						}
+-						return true
+-					})
+-				}
+-				return result, nil
 -			}
 -		}
 -		highlightFuncControlFlow(path, result)
@@ -77813,73 +85760,53 @@
 -	})
 -}
 -
--func highlightImportUses(path []ast.Node, info *types.Info, result map[posRange]struct{}) error {
--	basicLit, ok := path[0].(*ast.BasicLit)
--	if !ok {
--		return fmt.Errorf("highlightImportUses called with an ast.Node of type %T", basicLit)
--	}
--	ast.Inspect(path[len(path)-1], func(node ast.Node) bool {
--		if imp, ok := node.(*ast.ImportSpec); ok && imp.Path == basicLit {
--			result[posRange{start: node.Pos(), end: node.End()}] = struct{}{}
--			return false
--		}
--		n, ok := node.(*ast.Ident)
--		if !ok {
--			return true
--		}
--		obj, ok := info.ObjectOf(n).(*types.PkgName)
--		if !ok {
--			return true
--		}
--		if !strings.Contains(basicLit.Value, obj.Name()) {
--			return true
--		}
--		result[posRange{start: n.Pos(), end: n.End()}] = struct{}{}
--		return false
--	})
--	return nil
--}
--
 -func highlightIdentifier(id *ast.Ident, file *ast.File, info *types.Info, result map[posRange]struct{}) {
--	// TODO(rfindley): idObj may be nil. Note that returning early in this case
--	// causes tests to fail (because the nObj == idObj check below was succeeded
--	// for nil == nil!)
--	//
--	// Revisit this. If ObjectOf is nil, there are type errors, and it seems
--	// reasonable for identifier highlighting not to work.
--	idObj := info.ObjectOf(id)
--	pkgObj, isImported := idObj.(*types.PkgName)
--	ast.Inspect(file, func(node ast.Node) bool {
--		if imp, ok := node.(*ast.ImportSpec); ok && isImported {
--			highlightImport(pkgObj, imp, result)
+-	highlight := func(n ast.Node) {
+-		result[posRange{start: n.Pos(), end: n.End()}] = struct{}{}
+-	}
+-
+-	// obj may be nil if the Ident is undefined.
+-	// In this case, the behavior expected by tests is
+-	// to match other undefined Idents of the same name.
+-	obj := info.ObjectOf(id)
+-
+-	ast.Inspect(file, func(n ast.Node) bool {
+-		switch n := n.(type) {
+-		case *ast.Ident:
+-			if n.Name == id.Name && info.ObjectOf(n) == obj {
+-				highlight(n)
+-			}
+-
+-		case *ast.ImportSpec:
+-			pkgname, ok := ImportedPkgName(info, n)
+-			if ok && pkgname == obj {
+-				if n.Name != nil {
+-					highlight(n.Name)
+-				} else {
+-					highlight(n)
+-				}
+-			}
 -		}
--		n, ok := node.(*ast.Ident)
--		if !ok {
--			return true
--		}
--		if n.Name != id.Name {
--			return false
--		}
--		if nObj := info.ObjectOf(n); nObj == idObj {
--			result[posRange{start: n.Pos(), end: n.End()}] = struct{}{}
--		}
--		return false
+-		return true
 -	})
 -}
 -
--func highlightImport(obj *types.PkgName, imp *ast.ImportSpec, result map[posRange]struct{}) {
--	if imp.Name != nil || imp.Path == nil {
--		return
+-// ImportedPkgName returns the PkgName object declared by an ImportSpec.
+-// TODO(adonovan): make this a method of types.Info.
+-func ImportedPkgName(info *types.Info, imp *ast.ImportSpec) (*types.PkgName, bool) {
+-	var obj types.Object
+-	if imp.Name != nil {
+-		obj = info.Defs[imp.Name]
+-	} else {
+-		obj = info.Implicits[imp]
 -	}
--	if !strings.Contains(imp.Path.Value, obj.Name()) {
--		return
--	}
--	result[posRange{start: imp.Path.Pos(), end: imp.Path.End()}] = struct{}{}
+-	pkgname, ok := obj.(*types.PkgName)
+-	return pkgname, ok
 -}
 diff -urN a/gopls/internal/lsp/source/hover.go b/gopls/internal/lsp/source/hover.go
 --- a/gopls/internal/lsp/source/hover.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/hover.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,951 +0,0 @@
++++ b/gopls/internal/lsp/source/hover.go	1970-01-01 08:00:00
+@@ -1,1069 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -77896,6 +85823,8 @@
 -	"go/format"
 -	"go/token"
 -	"go/types"
+-	"io/fs"
+-	"path/filepath"
 -	"strconv"
 -	"strings"
 -	"time"
@@ -77904,11 +85833,12 @@
 -	"golang.org/x/text/unicode/runenames"
 -	"golang.org/x/tools/go/ast/astutil"
 -	"golang.org/x/tools/go/types/typeutil"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/typeparams"
 -)
 -
@@ -77952,13 +85882,13 @@
 -	if h == nil {
 -		return nil, nil
 -	}
--	hover, err := formatHover(h, snapshot.View().Options())
+-	hover, err := formatHover(h, snapshot.Options())
 -	if err != nil {
 -		return nil, err
 -	}
 -	return &protocol.Hover{
 -		Contents: protocol.MarkupContent{
--			Kind:  snapshot.View().Options().PreferredContentFormat,
+-			Kind:  snapshot.Options().PreferredContentFormat,
 -			Value: hover,
 -		},
 -		Range: rng,
@@ -77969,7 +85899,7 @@
 -// hovering at the position, it returns _, nil, nil: an error is only returned
 -// if the position is valid but we fail to compute hover information.
 -func hover(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) (protocol.Range, *HoverJSON, error) {
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return protocol.Range{}, nil, err
 -	}
@@ -78002,6 +85932,28 @@
 -		}
 -	}
 -
+-	// Handle hovering over embed directive argument.
+-	pattern, embedRng := parseEmbedDirective(pgf.Mapper, pp)
+-	if pattern != "" {
+-		return hoverEmbed(fh, embedRng, pattern)
+-	}
+-
+-	// Handle linkname directive by overriding what to look for.
+-	var linkedRange *protocol.Range // range referenced by linkname directive, or nil
+-	if pkgPath, name, offset := parseLinkname(ctx, snapshot, fh, pp); pkgPath != "" && name != "" {
+-		// rng covering 2nd linkname argument: pkgPath.name.
+-		rng, err := pgf.PosRange(pgf.Tok.Pos(offset), pgf.Tok.Pos(offset+len(pkgPath)+len(".")+len(name)))
+-		if err != nil {
+-			return protocol.Range{}, nil, fmt.Errorf("range over linkname arg: %w", err)
+-		}
+-		linkedRange = &rng
+-
+-		pkg, pgf, pos, err = findLinkname(ctx, snapshot, PackagePath(pkgPath), name)
+-		if err != nil {
+-			return protocol.Range{}, nil, fmt.Errorf("find linkname: %w", err)
+-		}
+-	}
+-
 -	// The general case: compute hover information for the object referenced by
 -	// the identifier at pos.
 -	ident, obj, selectedType := referencedObject(pkg, pgf, pos)
@@ -78009,9 +85961,15 @@
 -		return protocol.Range{}, nil, nil // no object to hover
 -	}
 -
--	rng, err := pgf.NodeRange(ident)
--	if err != nil {
--		return protocol.Range{}, nil, err
+-	// Unless otherwise specified, rng covers the ident being hovered.
+-	var rng protocol.Range
+-	if linkedRange != nil {
+-		rng = *linkedRange
+-	} else {
+-		rng, err = pgf.NodeRange(ident)
+-		if err != nil {
+-			return protocol.Range{}, nil, err
+-		}
 -	}
 -
 -	// By convention, we qualify hover information relative to the package
@@ -78024,7 +85982,7 @@
 -	// There's not much useful information to provide.
 -	if selectedType != nil {
 -		fakeObj := types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), selectedType)
--		signature := objectString(fakeObj, qf, nil)
+-		signature := types.ObjectString(fakeObj, qf)
 -		return rng, &HoverJSON{
 -			Signature:  signature,
 -			SingleLine: signature,
@@ -78049,10 +86007,14 @@
 -	docText := comment.Text()
 -
 -	// By default, types.ObjectString provides a reasonable signature.
--	signature := objectString(obj, qf, nil)
+-	signature := objectString(obj, qf, declPos, declPGF.Tok, spec)
+-	singleLineSignature := signature
+-
 -	// TODO(rfindley): we could do much better for inferred signatures.
 -	if inferred := inferredSignature(pkg.GetTypesInfo(), ident); inferred != nil {
--		signature = objectString(obj, qf, inferred)
+-		if s := inferredSignatureString(obj, qf, inferred); s != "" {
+-			signature = s
+-		}
 -	}
 -
 -	// For "objects defined by a type spec", the signature produced by
@@ -78077,7 +86039,7 @@
 -		spec2.Comment = nil
 -		var b strings.Builder
 -		b.WriteString("type ")
--		fset := FileSetFor(declPGF.Tok)
+-		fset := tokeninternal.FileSetFor(declPGF.Tok)
 -		if err := format.Node(&b, fset, &spec2); err != nil {
 -			return protocol.Range{}, nil, err
 -		}
@@ -78095,7 +86057,7 @@
 -				if (m.Obj().Exported() || m.Obj().Pkg() == pkg.GetTypes()) && len(m.Index()) == 1 {
 -					b.WriteString(sep)
 -					sep = "\n"
--					b.WriteString(objectString(m.Obj(), qf, nil))
+-					b.WriteString(types.ObjectString(m.Obj(), qf))
 -				}
 -			}
 -		}
@@ -78202,7 +86164,7 @@
 -	return rng, &HoverJSON{
 -		Synopsis:          doc.Synopsis(docText),
 -		FullDocumentation: docText,
--		SingleLine:        objectString(obj, qf, nil),
+-		SingleLine:        singleLineSignature,
 -		SymbolName:        linkName,
 -		Signature:         signature,
 -		LinkPath:          linkPath,
@@ -78219,8 +86181,6 @@
 -		return nil, err
 -	}
 -
--	// TODO(rfindley): add a test for jump to definition of error.Error (which is
--	// probably failing, considering it lacks special handling).
 -	if obj.Name() == "Error" {
 -		signature := obj.String()
 -		return &HoverJSON{
@@ -78306,7 +86266,7 @@
 -	// Find the first file with a package doc comment.
 -	var comment *ast.CommentGroup
 -	for _, f := range impMetadata.CompiledGoFiles {
--		fh, err := snapshot.GetFile(ctx, f)
+-		fh, err := snapshot.ReadFile(ctx, f)
 -		if err != nil {
 -			if ctx.Err() != nil {
 -				return protocol.Range{}, nil, ctx.Err()
@@ -78364,8 +86324,11 @@
 -//
 -//	'∑', U+2211, N-ARY SUMMATION
 -func hoverLit(pgf *ParsedGoFile, lit *ast.BasicLit, pos token.Pos) (protocol.Range, *HoverJSON, error) {
--	var r rune
--	var start, end token.Pos
+-	var (
+-		value      string    // if non-empty, a constant value to format in hover
+-		r          rune      // if non-zero, format a description of this rune in hover
+-		start, end token.Pos // hover span
+-	)
 -	// Extract a rune from the current position.
 -	// 'Ω', "...Ω...", or 0x03A9 => 'Ω', U+03A9, GREEK CAPITAL LETTER OMEGA
 -	switch lit.Kind {
@@ -78381,23 +86344,34 @@
 -			return protocol.Range{}, nil, fmt.Errorf("rune error")
 -		}
 -		start, end = lit.Pos(), lit.End()
--	case token.INT:
--		// TODO(rfindley): add support for hex/octal/binary->int conversion here.
 -
--		// It's an integer, scan only if it is a hex literal whose bitsize in
--		// ranging from 8 to 32.
--		if !(strings.HasPrefix(lit.Value, "0x") && len(lit.Value[2:]) >= 2 && len(lit.Value[2:]) <= 8) {
+-	case token.INT:
+-		// Short literals (e.g. 99 decimal, 07 octal) are uninteresting.
+-		if len(lit.Value) < 3 {
 -			return protocol.Range{}, nil, nil
 -		}
--		v, err := strconv.ParseUint(lit.Value[2:], 16, 32)
--		if err != nil {
--			return protocol.Range{}, nil, fmt.Errorf("parsing int: %v", err)
+-
+-		v := constant.MakeFromLiteral(lit.Value, lit.Kind, 0)
+-		if v.Kind() != constant.Int {
+-			return protocol.Range{}, nil, nil
 -		}
--		r = rune(v)
--		if r == utf8.RuneError {
--			return protocol.Range{}, nil, fmt.Errorf("rune error")
+-
+-		switch lit.Value[:2] {
+-		case "0x", "0X":
+-			// As a special case, try to recognize hexadecimal literals as runes if
+-			// they are within the range of valid unicode values.
+-			if v, ok := constant.Int64Val(v); ok && v > 0 && v <= utf8.MaxRune && utf8.ValidRune(rune(v)) {
+-				r = rune(v)
+-			}
+-			fallthrough
+-		case "0o", "0O", "0b", "0B":
+-			// Format the decimal value of non-decimal literals.
+-			value = v.ExactString()
+-			start, end = lit.Pos(), lit.End()
+-		default:
+-			return protocol.Range{}, nil, nil
 -		}
--		start, end = lit.Pos(), lit.End()
+-
 -	case token.STRING:
 -		// It's a string, scan only if it contains a unicode escape sequence under or before the
 -		// current cursor position.
@@ -78432,38 +86406,88 @@
 -			}
 -		}
 -	}
--	if r == 0 {
+-
+-	if value == "" && r == 0 { // nothing to format
 -		return protocol.Range{}, nil, nil
 -	}
+-
 -	rng, err := pgf.PosRange(start, end)
 -	if err != nil {
 -		return protocol.Range{}, nil, err
 -	}
 -
--	var desc string
--	runeName := runenames.Name(r)
--	if len(runeName) > 0 && runeName[0] == '<' {
--		// Check if the rune looks like an HTML tag. If so, trim the surrounding <>
--		// characters to work around https://github.com/microsoft/vscode/issues/124042.
--		runeName = strings.TrimRight(runeName[1:], ">")
+-	var b strings.Builder
+-	if value != "" {
+-		b.WriteString(value)
 -	}
--	if strconv.IsPrint(r) {
--		desc = fmt.Sprintf("'%s', U+%04X, %s", string(r), uint32(r), runeName)
--	} else {
--		desc = fmt.Sprintf("U+%04X, %s", uint32(r), runeName)
+-	if r != 0 {
+-		runeName := runenames.Name(r)
+-		if len(runeName) > 0 && runeName[0] == '<' {
+-			// Check if the rune looks like an HTML tag. If so, trim the surrounding <>
+-			// characters to work around https://github.com/microsoft/vscode/issues/124042.
+-			runeName = strings.TrimRight(runeName[1:], ">")
+-		}
+-		if b.Len() > 0 {
+-			b.WriteString(", ")
+-		}
+-		if strconv.IsPrint(r) {
+-			fmt.Fprintf(&b, "'%c', ", r)
+-		}
+-		fmt.Fprintf(&b, "U+%04X, %s", r, runeName)
 -	}
+-	hover := b.String()
 -	return rng, &HoverJSON{
--		Synopsis:          desc,
--		FullDocumentation: desc,
+-		Synopsis:          hover,
+-		FullDocumentation: hover,
 -	}, nil
 -}
 -
--// objectString is a wrapper around the types.ObjectString function.
--// It handles adding more information to the object string.
--//
--// TODO(rfindley): this function does too much. We should lift the special
--// handling to callsites.
--func objectString(obj types.Object, qf types.Qualifier, inferred *types.Signature) string {
+-// hoverEmbed computes hover information for a filepath.Match pattern.
+-// Assumes that the pattern is relative to the location of fh.
+-func hoverEmbed(fh FileHandle, rng protocol.Range, pattern string) (protocol.Range, *HoverJSON, error) {
+-	s := &strings.Builder{}
+-
+-	dir := filepath.Dir(fh.URI().Filename())
+-	var matches []string
+-	err := filepath.WalkDir(dir, func(abs string, d fs.DirEntry, e error) error {
+-		if e != nil {
+-			return e
+-		}
+-		rel, err := filepath.Rel(dir, abs)
+-		if err != nil {
+-			return err
+-		}
+-		ok, err := filepath.Match(pattern, rel)
+-		if err != nil {
+-			return err
+-		}
+-		if ok && !d.IsDir() {
+-			matches = append(matches, rel)
+-		}
+-		return nil
+-	})
+-	if err != nil {
+-		return protocol.Range{}, nil, err
+-	}
+-
+-	for _, m := range matches {
+-		// TODO: Renders each file as separate markdown paragraphs.
+-		// If forcing (a single) newline is possible it might be more clear.
+-		fmt.Fprintf(s, "%s\n\n", m)
+-	}
+-
+-	json := &HoverJSON{
+-		Signature:         fmt.Sprintf("Embedding %q", pattern),
+-		Synopsis:          s.String(),
+-		FullDocumentation: s.String(),
+-	}
+-	return rng, json, nil
+-}
+-
+-// inferredSignatureString is a wrapper around the types.ObjectString function
+-// that adds more information to inferred signatures. It will return an empty string
+-// if the passed types.Object is not a signature.
+-func inferredSignatureString(obj types.Object, qf types.Qualifier, inferred *types.Signature) string {
 -	// If the signature type was inferred, prefer the inferred signature with a
 -	// comment showing the generic signature.
 -	if sig, _ := obj.Type().(*types.Signature); sig != nil && typeparams.ForSignature(sig).Len() > 0 && inferred != nil {
@@ -78478,22 +86502,65 @@
 -		str += "// " + types.TypeString(sig, qf)
 -		return str
 -	}
+-	return ""
+-}
+-
+-// objectString is a wrapper around the types.ObjectString function.
+-// It handles adding more information to the object string.
+-// If spec is non-nil, it may be used to format additional declaration
+-// syntax, and file must be the token.File describing its positions.
+-func objectString(obj types.Object, qf types.Qualifier, declPos token.Pos, file *token.File, spec ast.Spec) string {
 -	str := types.ObjectString(obj, qf)
+-
 -	switch obj := obj.(type) {
 -	case *types.Const:
--		str = fmt.Sprintf("%s = %s", str, obj.Val())
+-		var (
+-			declaration = obj.Val().String() // default formatted declaration
+-			comment     = ""                 // if non-empty, a clarifying comment
+-		)
 -
--		// Try to add a formatted duration as an inline comment
--		typ, ok := obj.Type().(*types.Named)
--		if !ok {
--			break
--		}
--		pkg := typ.Obj().Pkg()
--		if pkg.Path() == "time" && typ.Obj().Name() == "Duration" {
--			if d, ok := constant.Int64Val(obj.Val()); ok {
--				str += " // " + time.Duration(d).String()
+-		// Try to use the original declaration.
+-		switch obj.Val().Kind() {
+-		case constant.String:
+-			// Usually the original declaration of a string doesn't carry much information.
+-			// Also strings can be very long. So, just use the constant's value.
+-
+-		default:
+-			if spec, _ := spec.(*ast.ValueSpec); spec != nil {
+-				for i, name := range spec.Names {
+-					if declPos == name.Pos() {
+-						if i < len(spec.Values) {
+-							originalDeclaration := FormatNodeFile(file, spec.Values[i])
+-							if originalDeclaration != declaration {
+-								comment = declaration
+-								declaration = originalDeclaration
+-							}
+-						}
+-						break
+-					}
+-				}
 -			}
 -		}
+-
+-		// Special formatting cases.
+-		switch typ := obj.Type().(type) {
+-		case *types.Named:
+-			// Try to add a formatted duration as an inline comment.
+-			pkg := typ.Obj().Pkg()
+-			if pkg.Path() == "time" && typ.Obj().Name() == "Duration" {
+-				if d, ok := constant.Int64Val(obj.Val()); ok {
+-					comment = time.Duration(d).String()
+-				}
+-			}
+-		}
+-		if comment == declaration {
+-			comment = ""
+-		}
+-
+-		str += " = " + declaration
+-		if comment != "" {
+-			str += " // " + comment
+-		}
 -	}
 -	return str
 -}
@@ -78566,7 +86633,7 @@
 -	}
 -
 -	uri := span.URIFromPath(f.Name())
--	fh, err := snapshot.GetFile(ctx, uri)
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, 0, err
 -	}
@@ -78589,28 +86656,6 @@
 -	return pgf, fullPos, nil
 -}
 -
--// extractFieldList recursively tries to extract a field list.
--// If it is not found, nil is returned.
--func extractFieldList(specType ast.Expr) *ast.FieldList {
--	switch t := specType.(type) {
--	case *ast.StructType:
--		return t.Fields
--	case *ast.InterfaceType:
--		return t.Methods
--	case *ast.ArrayType:
--		return extractFieldList(t.Elt)
--	case *ast.MapType:
--		// Map value has a greater chance to be a struct
--		if fields := extractFieldList(t.Value); fields != nil {
--			return fields
--		}
--		return extractFieldList(t.Key)
--	case *ast.ChanType:
--		return extractFieldList(t.Value)
--	}
--	return nil
--}
--
 -func formatHover(h *HoverJSON, options *Options) (string, error) {
 -	signature := formatSignature(h, options)
 -
@@ -78833,7 +86878,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/identifier.go b/gopls/internal/lsp/source/identifier.go
 --- a/gopls/internal/lsp/source/identifier.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/identifier.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/identifier.go	1970-01-01 08:00:00
 @@ -1,174 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -78893,7 +86938,7 @@
 -
 -// typeToObject returns the relevant type name for the given type, after
 -// unwrapping pointers, arrays, slices, channels, and function signatures with
--// a single non-error result.
+-// a single non-error result, and ignoring built-in named types.
 -func typeToObject(typ types.Type) *types.TypeName {
 -	switch typ := typ.(type) {
 -	case *types.Named:
@@ -78916,7 +86961,7 @@
 -		for i := 0; i < results.Len(); i++ {
 -			obj := typeToObject(results.At(i).Type())
 -			if obj == nil || hasErrorType(obj) {
--				// Skip builtins.
+-				// Skip builtins. TODO(rfindley): should comparable be handled here as well?
 -				continue
 -			}
 -			if res != nil {
@@ -79011,7 +87056,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/identifier_test.go b/gopls/internal/lsp/source/identifier_test.go
 --- a/gopls/internal/lsp/source/identifier_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/identifier_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/identifier_test.go	1970-01-01 08:00:00
 @@ -1,103 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -79118,8 +87163,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/implementation.go b/gopls/internal/lsp/source/implementation.go
 --- a/gopls/internal/lsp/source/implementation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/implementation.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,482 +0,0 @@
++++ b/gopls/internal/lsp/source/implementation.go	1970-01-01 08:00:00
+@@ -1,495 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -79139,6 +87184,7 @@
 -	"sync"
 -
 -	"golang.org/x/sync/errgroup"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
@@ -79152,7 +87198,6 @@
 -//
 -// TODO(adonovan):
 -// - Audit to ensure robustness in face of type errors.
--// - Support 'error' and 'error.Error', which were also lacking from the old implementation.
 -// - Eliminate false positives due to 'tricky' cases of the global algorithm.
 -// - Ensure we have test coverage of:
 -//      type aliases
@@ -79172,7 +87217,7 @@
 -	ctx, done := event.Start(ctx, "source.Implementation")
 -	defer done()
 -
--	locs, err := implementations2(ctx, snapshot, f, pp)
+-	locs, err := implementations(ctx, snapshot, f, pp)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -79192,60 +87237,37 @@
 -	return locs, nil
 -}
 -
--func implementations2(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) ([]protocol.Location, error) {
--
--	// Type-check the query package, find the query identifier,
--	// and locate the type or method declaration it refers to.
--	declPosn, err := typeDeclPosition(ctx, snapshot, fh.URI(), pp)
+-func implementations(ctx context.Context, snapshot Snapshot, fh FileHandle, pp protocol.Position) ([]protocol.Location, error) {
+-	obj, pkg, err := implementsObj(ctx, snapshot, fh.URI(), pp)
 -	if err != nil {
 -		return nil, err
 -	}
 -
--	// Type-check the declaring package (incl. variants) for use
--	// by the "local" search, which uses type information to
--	// enumerate all types within the package that satisfy the
--	// query type, even those defined local to a function.
--	declURI := span.URIFromPath(declPosn.Filename)
--	declMetas, err := snapshot.MetadataForFile(ctx, declURI)
--	if err != nil {
--		return nil, err
+-	var localPkgs []Package
+-	if obj.Pos().IsValid() { // no local package for error or error.Error
+-		declPosn := safetoken.StartPosition(pkg.FileSet(), obj.Pos())
+-		// Type-check the declaring package (incl. variants) for use
+-		// by the "local" search, which uses type information to
+-		// enumerate all types within the package that satisfy the
+-		// query type, even those defined local to a function.
+-		declURI := span.URIFromPath(declPosn.Filename)
+-		declMetas, err := snapshot.MetadataForFile(ctx, declURI)
+-		if err != nil {
+-			return nil, err
+-		}
+-		RemoveIntermediateTestVariants(&declMetas)
+-		if len(declMetas) == 0 {
+-			return nil, fmt.Errorf("no packages for file %s", declURI)
+-		}
+-		ids := make([]PackageID, len(declMetas))
+-		for i, m := range declMetas {
+-			ids[i] = m.ID
+-		}
+-		localPkgs, err = snapshot.TypeCheck(ctx, ids...)
+-		if err != nil {
+-			return nil, err
+-		}
 -	}
--	if len(declMetas) == 0 {
--		return nil, fmt.Errorf("no packages for file %s", declURI)
--	}
--	ids := make([]PackageID, len(declMetas))
--	for i, m := range declMetas {
--		ids[i] = m.ID
--	}
--	localPkgs, err := snapshot.TypeCheck(ctx, ids...)
--	if err != nil {
--		return nil, err
--	}
--	// The narrowest package will do, since the local search is based
--	// on position and the global search is based on fingerprint.
--	// (Neither is based on object identity.)
--	declPkg := localPkgs[0]
--	declFile, err := declPkg.File(declURI)
--	if err != nil {
--		return nil, err // "can't happen"
--	}
--
--	// Find declaration of corresponding object
--	// in this package based on (URI, offset).
--	pos, err := safetoken.Pos(declFile.Tok, declPosn.Offset)
--	if err != nil {
--		return nil, err
--	}
--	// TODO(adonovan): simplify: use objectsAt?
--	path := pathEnclosingObjNode(declFile.File, pos)
--	if path == nil {
--		return nil, ErrNoIdentFound // checked earlier
--	}
--	id, ok := path[0].(*ast.Ident)
--	if !ok {
--		return nil, ErrNoIdentFound // checked earlier
--	}
--	obj := declPkg.GetTypesInfo().ObjectOf(id) // may be nil
 -
 -	// Is the selected identifier a type name or method?
 -	// (For methods, report the corresponding method names.)
@@ -79262,7 +87284,7 @@
 -		}
 -	}
 -	if queryType == nil {
--		return nil, fmt.Errorf("%s is not a type or method", id.Name)
+-		return nil, bug.Errorf("%s is not a type or method", obj.Name()) // should have been handled by implementsObj
 -	}
 -
 -	// Compute the method-set fingerprint used as a key to the global search.
@@ -79273,8 +87295,9 @@
 -		return nil, nil
 -	}
 -
--	// The global search needs to look at every package in the workspace;
--	// see package ./methodsets.
+-	// The global search needs to look at every package in the
+-	// forward transitive closure of the workspace; see package
+-	// ./methodsets.
 -	//
 -	// For now we do all the type checking before beginning the search.
 -	// TODO(adonovan): opt: search in parallel topological order
@@ -79285,16 +87308,22 @@
 -	if err != nil {
 -		return nil, err
 -	}
+-	RemoveIntermediateTestVariants(&globalMetas)
 -	globalIDs := make([]PackageID, 0, len(globalMetas))
+-
+-	var pkgPath PackagePath
+-	if obj.Pkg() != nil { // nil for error
+-		pkgPath = PackagePath(obj.Pkg().Path())
+-	}
 -	for _, m := range globalMetas {
--		if m.PkgPath == declPkg.Metadata().PkgPath {
+-		if m.PkgPath == pkgPath {
 -			continue // declaring package is handled by local implementation
 -		}
 -		globalIDs = append(globalIDs, m.ID)
 -	}
 -	indexes, err := snapshot.MethodSets(ctx, globalIDs...)
 -	if err != nil {
--		return nil, err
+-		return nil, fmt.Errorf("querying method sets: %v", err)
 -	}
 -
 -	// Search local and global packages in parallel.
@@ -79349,11 +87378,11 @@
 -// which requires reading the file.
 -func offsetToLocation(ctx context.Context, snapshot Snapshot, filename string, start, end int) (protocol.Location, error) {
 -	uri := span.URIFromPath(filename)
--	fh, err := snapshot.GetFile(ctx, uri)
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		return protocol.Location{}, err // cancelled, perhaps
 -	}
--	content, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return protocol.Location{}, err // nonexistent or deleted ("can't happen")
 -	}
@@ -79361,18 +87390,19 @@
 -	return m.OffsetLocation(start, end)
 -}
 -
--// typeDeclPosition returns the position of the declaration of the
--// type (or one of its methods) referred to at (uri, ppos).
--func typeDeclPosition(ctx context.Context, snapshot Snapshot, uri span.URI, ppos protocol.Position) (token.Position, error) {
--	var noPosn token.Position
--
--	pkg, pgf, err := PackageForFile(ctx, snapshot, uri, WidestPackage)
+-// implementsObj returns the object to query for implementations, which is a
+-// type name or method.
+-//
+-// The returned Package is the narrowest package containing ppos, which is the
+-// package using the resulting obj but not necessarily the declaring package.
+-func implementsObj(ctx context.Context, snapshot Snapshot, uri span.URI, ppos protocol.Position) (types.Object, Package, error) {
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, uri)
 -	if err != nil {
--		return noPosn, err
+-		return nil, nil, err
 -	}
 -	pos, err := pgf.PositionPos(ppos)
 -	if err != nil {
--		return noPosn, err
+-		return nil, nil, err
 -	}
 -
 -	// This function inherits the limitation of its predecessor in
@@ -79387,11 +87417,11 @@
 -	// TODO(adonovan): simplify: use objectsAt?
 -	path := pathEnclosingObjNode(pgf.File, pos)
 -	if path == nil {
--		return noPosn, ErrNoIdentFound
+-		return nil, nil, ErrNoIdentFound
 -	}
 -	id, ok := path[0].(*ast.Ident)
 -	if !ok {
--		return noPosn, ErrNoIdentFound
+-		return nil, nil, ErrNoIdentFound
 -	}
 -
 -	// Is the object a type or method? Reject other kinds.
@@ -79407,18 +87437,17 @@
 -		// ok
 -	case *types.Func:
 -		if obj.Type().(*types.Signature).Recv() == nil {
--			return noPosn, fmt.Errorf("%s is a function, not a method", id.Name)
+-			return nil, nil, fmt.Errorf("%s is a function, not a method", id.Name)
 -		}
 -	case nil:
--		return noPosn, fmt.Errorf("%s denotes unknown object", id.Name)
+-		return nil, nil, fmt.Errorf("%s denotes unknown object", id.Name)
 -	default:
 -		// e.g. *types.Var -> "var".
 -		kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
--		return noPosn, fmt.Errorf("%s is a %s, not a type", id.Name, kind)
+-		return nil, nil, fmt.Errorf("%s is a %s, not a type", id.Name, kind)
 -	}
 -
--	declPosn := safetoken.StartPosition(pkg.FileSet(), obj.Pos())
--	return declPosn, nil
+-	return obj, pkg, nil
 -}
 -
 -// localImplementations searches within pkg for declarations of all
@@ -79507,9 +87536,38 @@
 -		locs = append(locs, loc)
 -	}
 -
+-	// Special case: for types that satisfy error, report builtin.go (see #59527).
+-	if types.Implements(queryType, errorInterfaceType) {
+-		loc, err := errorLocation(ctx, snapshot)
+-		if err != nil {
+-			return nil, err
+-		}
+-		locs = append(locs, loc)
+-	}
+-
 -	return locs, nil
 -}
 -
+-var errorInterfaceType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+-
+-// errorLocation returns the location of the 'error' type in builtin.go.
+-func errorLocation(ctx context.Context, snapshot Snapshot) (protocol.Location, error) {
+-	pgf, err := snapshot.BuiltinFile(ctx)
+-	if err != nil {
+-		return protocol.Location{}, err
+-	}
+-	for _, decl := range pgf.File.Decls {
+-		if decl, ok := decl.(*ast.GenDecl); ok {
+-			for _, spec := range decl.Specs {
+-				if spec, ok := spec.(*ast.TypeSpec); ok && spec.Name.Name == "error" {
+-					return pgf.NodeLocation(spec.Name)
+-				}
+-			}
+-		}
+-	}
+-	return protocol.Location{}, fmt.Errorf("built-in error type not found")
+-}
+-
 -// concreteImplementsIntf returns true if a is an interface type implemented by
 -// concrete type b, or vice versa.
 -func concreteImplementsIntf(a, b types.Type) bool {
@@ -79529,7 +87587,7 @@
 -	// to report (e.g.) "ArrayList[T] implements List[T]", but
 -	// GenericAssignableTo doesn't work correctly on pointers to
 -	// generic named types. Thus the legacy implementation and the
--	// "local" part of implementation2 fail to report generics.
+-	// "local" part of implementations fail to report generics.
 -	// The global algorithm based on subsets does the right thing.
 -	return types.AssignableTo(a, b)
 -}
@@ -79604,7 +87662,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/inlay_hint.go b/gopls/internal/lsp/source/inlay_hint.go
 --- a/gopls/internal/lsp/source/inlay_hint.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/inlay_hint.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/inlay_hint.go	1970-01-01 08:00:00
 @@ -1,394 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -79690,13 +87748,13 @@
 -	ctx, done := event.Start(ctx, "source.InlayHint")
 -	defer done()
 -
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, fmt.Errorf("getting file for InlayHint: %w", err)
 -	}
 -
 -	// Collect a list of the inlay hints that are enabled.
--	inlayHintOptions := snapshot.View().Options().InlayHintOptions
+-	inlayHintOptions := snapshot.Options().InlayHintOptions
 -	var enabledHints []InlayHintFunc
 -	for hint, enabled := range inlayHintOptions.Hints {
 -		if !enabled {
@@ -79765,7 +87823,7 @@
 -		if param.Name() == "" {
 -			continue
 -		}
--		// Skip the parameter name hint if the arg matches the
+-		// Skip the parameter name hint if the arg matches
 -		// the parameter name.
 -		if i, ok := v.(*ast.Ident); ok && i.Name == param.Name() {
 -			continue
@@ -80000,10 +88058,424 @@
 -	}
 -	return []protocol.InlayHintLabelPart{label}
 -}
+diff -urN a/gopls/internal/lsp/source/inline.go b/gopls/internal/lsp/source/inline.go
+--- a/gopls/internal/lsp/source/inline.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/inline.go	1970-01-01 08:00:00
+@@ -1,138 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package source
+-
+-// This file defines the refactor.inline code action.
+-
+-import (
+-	"context"
+-	"fmt"
+-	"go/ast"
+-	"go/token"
+-	"go/types"
+-	"runtime/debug"
+-
+-	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/go/types/typeutil"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/diff"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/refactor/inline"
+-)
+-
+-// EnclosingStaticCall returns the innermost function call enclosing
+-// the selected range, along with the callee.
+-func EnclosingStaticCall(pkg Package, pgf *ParsedGoFile, rng protocol.Range) (*ast.CallExpr, *types.Func, error) {
+-	start, end, err := pgf.RangePos(rng)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	path, _ := astutil.PathEnclosingInterval(pgf.File, start, end)
+-
+-	var call *ast.CallExpr
+-loop:
+-	for _, n := range path {
+-		switch n := n.(type) {
+-		case *ast.FuncLit:
+-			break loop
+-		case *ast.CallExpr:
+-			call = n
+-			break loop
+-		}
+-	}
+-	if call == nil {
+-		return nil, nil, fmt.Errorf("no enclosing call")
+-	}
+-	if safetoken.Line(pgf.Tok, call.Lparen) != safetoken.Line(pgf.Tok, start) {
+-		return nil, nil, fmt.Errorf("enclosing call is not on this line")
+-	}
+-	fn := typeutil.StaticCallee(pkg.GetTypesInfo(), call)
+-	if fn == nil {
+-		return nil, nil, fmt.Errorf("not a static call to a Go function")
+-	}
+-	return call, fn, nil
+-}
+-
+-func inlineCall(ctx context.Context, snapshot Snapshot, fh FileHandle, rng protocol.Range) (_ *token.FileSet, _ *analysis.SuggestedFix, err error) {
+-	// Find enclosing static call.
+-	callerPkg, callerPGF, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	call, fn, err := EnclosingStaticCall(callerPkg, callerPGF, rng)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-
+-	// Locate callee by file/line and analyze it.
+-	calleePosn := safetoken.StartPosition(callerPkg.FileSet(), fn.Pos())
+-	calleePkg, calleePGF, err := NarrowestPackageForFile(ctx, snapshot, span.URIFromPath(calleePosn.Filename))
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	var calleeDecl *ast.FuncDecl
+-	for _, decl := range calleePGF.File.Decls {
+-		if decl, ok := decl.(*ast.FuncDecl); ok {
+-			posn := safetoken.StartPosition(calleePkg.FileSet(), decl.Name.Pos())
+-			if posn.Line == calleePosn.Line && posn.Column == calleePosn.Column {
+-				calleeDecl = decl
+-				break
+-			}
+-		}
+-	}
+-	if calleeDecl == nil {
+-		return nil, nil, fmt.Errorf("can't find callee")
+-	}
+-
+-	// The inliner assumes that input is well-typed,
+-	// but that is frequently not the case within gopls.
+-	// Until we are able to harden the inliner,
+-	// report panics as errors to avoid crashing the server.
+-	bad := func(p Package) bool { return len(p.GetParseErrors())+len(p.GetTypeErrors()) > 0 }
+-	if bad(calleePkg) || bad(callerPkg) {
+-		defer func() {
+-			if x := recover(); x != nil {
+-				err = bug.Errorf("inlining failed unexpectedly: %v\nstack: %v",
+-					x, debug.Stack())
+-			}
+-		}()
+-	}
+-
+-	// Users can consult the gopls event log to see
+-	// why a particular inlining strategy was chosen.
+-	logf := func(format string, args ...any) {
+-		event.Log(ctx, "inliner: "+fmt.Sprintf(format, args...))
+-	}
+-
+-	callee, err := inline.AnalyzeCallee(logf, calleePkg.FileSet(), calleePkg.GetTypes(), calleePkg.GetTypesInfo(), calleeDecl, calleePGF.Src)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-
+-	// Inline the call.
+-	caller := &inline.Caller{
+-		Fset:    callerPkg.FileSet(),
+-		Types:   callerPkg.GetTypes(),
+-		Info:    callerPkg.GetTypesInfo(),
+-		File:    callerPGF.File,
+-		Call:    call,
+-		Content: callerPGF.Src,
+-	}
+-
+-	got, err := inline.Inline(logf, caller, callee)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-
+-	// Suggest the fix.
+-	return callerPkg.FileSet(), &analysis.SuggestedFix{
+-		Message:   fmt.Sprintf("inline call of %v", callee),
+-		TextEdits: diffToTextEdits(callerPGF.Tok, diff.Bytes(callerPGF.Src, got)),
+-	}, nil
+-}
+diff -urN a/gopls/internal/lsp/source/invertifcondition.go b/gopls/internal/lsp/source/invertifcondition.go
+--- a/gopls/internal/lsp/source/invertifcondition.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/invertifcondition.go	1970-01-01 08:00:00
+@@ -1,268 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package source
+-
+-import (
+-	"fmt"
+-	"go/ast"
+-	"go/token"
+-	"go/types"
+-	"strings"
+-
+-	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
+-	"golang.org/x/tools/internal/typeparams"
+-)
+-
+-// invertIfCondition is a singleFileFixFunc that inverts an if/else statement
+-func invertIfCondition(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, _ *types.Package, _ *types.Info) (*analysis.SuggestedFix, error) {
+-	ifStatement, _, err := CanInvertIfCondition(file, start, end)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	var replaceElse analysis.TextEdit
+-
+-	endsWithReturn, err := endsWithReturn(ifStatement.Else)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	if endsWithReturn {
+-		// Replace the whole else part with an empty line and an unindented
+-		// version of the original if body
+-		sourcePos := safetoken.StartPosition(fset, ifStatement.Pos())
+-
+-		indent := sourcePos.Column - 1
+-		if indent < 0 {
+-			indent = 0
+-		}
+-
+-		standaloneBodyText := ifBodyToStandaloneCode(fset, ifStatement.Body, src)
+-		replaceElse = analysis.TextEdit{
+-			Pos:     ifStatement.Body.Rbrace + 1, // 1 == len("}")
+-			End:     ifStatement.End(),
+-			NewText: []byte("\n\n" + strings.Repeat("\t", indent) + standaloneBodyText),
+-		}
+-	} else {
+-		// Replace the else body text with the if body text
+-		bodyStart := safetoken.StartPosition(fset, ifStatement.Body.Lbrace)
+-		bodyEnd := safetoken.EndPosition(fset, ifStatement.Body.Rbrace+1) // 1 == len("}")
+-		bodyText := src[bodyStart.Offset:bodyEnd.Offset]
+-		replaceElse = analysis.TextEdit{
+-			Pos:     ifStatement.Else.Pos(),
+-			End:     ifStatement.Else.End(),
+-			NewText: bodyText,
+-		}
+-	}
+-
+-	// Replace the if text with the else text
+-	elsePosInSource := safetoken.StartPosition(fset, ifStatement.Else.Pos())
+-	elseEndInSource := safetoken.EndPosition(fset, ifStatement.Else.End())
+-	elseText := src[elsePosInSource.Offset:elseEndInSource.Offset]
+-	replaceBodyWithElse := analysis.TextEdit{
+-		Pos:     ifStatement.Body.Pos(),
+-		End:     ifStatement.Body.End(),
+-		NewText: elseText,
+-	}
+-
+-	// Replace the if condition with its inverse
+-	inverseCondition, err := invertCondition(fset, ifStatement.Cond, src)
+-	if err != nil {
+-		return nil, err
+-	}
+-	replaceConditionWithInverse := analysis.TextEdit{
+-		Pos:     ifStatement.Cond.Pos(),
+-		End:     ifStatement.Cond.End(),
+-		NewText: inverseCondition,
+-	}
+-
+-	// Return a SuggestedFix with just that TextEdit in there
+-	return &analysis.SuggestedFix{
+-		TextEdits: []analysis.TextEdit{
+-			replaceConditionWithInverse,
+-			replaceBodyWithElse,
+-			replaceElse,
+-		},
+-	}, nil
+-}
+-
+-func endsWithReturn(elseBranch ast.Stmt) (bool, error) {
+-	elseBlock, isBlockStatement := elseBranch.(*ast.BlockStmt)
+-	if !isBlockStatement {
+-		return false, fmt.Errorf("Unable to figure out whether this ends with return: %T", elseBranch)
+-	}
+-
+-	if len(elseBlock.List) == 0 {
+-		// Empty blocks don't end in returns
+-		return false, nil
+-	}
+-
+-	lastStatement := elseBlock.List[len(elseBlock.List)-1]
+-
+-	_, lastStatementIsReturn := lastStatement.(*ast.ReturnStmt)
+-	return lastStatementIsReturn, nil
+-}
+-
+-// Turn { fmt.Println("Hello") } into just fmt.Println("Hello"), with one less
+-// level of indentation.
+-//
+-// The first line of the result will not be indented, but all of the following
+-// lines will.
+-func ifBodyToStandaloneCode(fset *token.FileSet, ifBody *ast.BlockStmt, src []byte) string {
+-	// Get the whole body (without the surrounding braces) as a string
+-	bodyStart := safetoken.StartPosition(fset, ifBody.Lbrace+1) // 1 == len("}")
+-	bodyEnd := safetoken.EndPosition(fset, ifBody.Rbrace)
+-	bodyWithoutBraces := string(src[bodyStart.Offset:bodyEnd.Offset])
+-	bodyWithoutBraces = strings.TrimSpace(bodyWithoutBraces)
+-
+-	// Unindent
+-	bodyWithoutBraces = strings.ReplaceAll(bodyWithoutBraces, "\n\t", "\n")
+-
+-	return bodyWithoutBraces
+-}
+-
+-func invertCondition(fset *token.FileSet, cond ast.Expr, src []byte) ([]byte, error) {
+-	condStart := safetoken.StartPosition(fset, cond.Pos())
+-	condEnd := safetoken.EndPosition(fset, cond.End())
+-	oldText := string(src[condStart.Offset:condEnd.Offset])
+-
+-	switch expr := cond.(type) {
+-	case *ast.Ident, *ast.ParenExpr, *ast.CallExpr, *ast.StarExpr, *ast.IndexExpr, *typeparams.IndexListExpr, *ast.SelectorExpr:
+-		newText := "!" + oldText
+-		if oldText == "true" {
+-			newText = "false"
+-		} else if oldText == "false" {
+-			newText = "true"
+-		}
+-
+-		return []byte(newText), nil
+-
+-	case *ast.UnaryExpr:
+-		if expr.Op != token.NOT {
+-			// This should never happen
+-			return dumbInvert(fset, cond, src), nil
+-		}
+-
+-		inverse := expr.X
+-		if p, isParen := inverse.(*ast.ParenExpr); isParen {
+-			// We got !(x), remove the parentheses with the ! so we get just "x"
+-			inverse = p.X
+-
+-			start := safetoken.StartPosition(fset, inverse.Pos())
+-			end := safetoken.EndPosition(fset, inverse.End())
+-			if start.Line != end.Line {
+-				// The expression is multi-line, so we can't remove the parentheses
+-				inverse = expr.X
+-			}
+-		}
+-
+-		start := safetoken.StartPosition(fset, inverse.Pos())
+-		end := safetoken.EndPosition(fset, inverse.End())
+-		textWithoutNot := src[start.Offset:end.Offset]
+-
+-		return textWithoutNot, nil
+-
+-	case *ast.BinaryExpr:
+-		// These inversions are unsound for floating point NaN, but that's ok.
+-		negations := map[token.Token]string{
+-			token.EQL: "!=",
+-			token.LSS: ">=",
+-			token.GTR: "<=",
+-			token.NEQ: "==",
+-			token.LEQ: ">",
+-			token.GEQ: "<",
+-		}
+-
+-		negation, negationFound := negations[expr.Op]
+-		if !negationFound {
+-			return invertAndOr(fset, expr, src)
+-		}
+-
+-		xPosInSource := safetoken.StartPosition(fset, expr.X.Pos())
+-		opPosInSource := safetoken.StartPosition(fset, expr.OpPos)
+-		yPosInSource := safetoken.StartPosition(fset, expr.Y.Pos())
+-
+-		textBeforeOp := string(src[xPosInSource.Offset:opPosInSource.Offset])
+-
+-		oldOpWithTrailingWhitespace := string(src[opPosInSource.Offset:yPosInSource.Offset])
+-		newOpWithTrailingWhitespace := negation + oldOpWithTrailingWhitespace[len(expr.Op.String()):]
+-
+-		textAfterOp := string(src[yPosInSource.Offset:condEnd.Offset])
+-
+-		return []byte(textBeforeOp + newOpWithTrailingWhitespace + textAfterOp), nil
+-	}
+-
+-	return dumbInvert(fset, cond, src), nil
+-}
+-
+-// dumbInvert is a fallback, inverting cond into !(cond).
+-func dumbInvert(fset *token.FileSet, expr ast.Expr, src []byte) []byte {
+-	start := safetoken.StartPosition(fset, expr.Pos())
+-	end := safetoken.EndPosition(fset, expr.End())
+-	text := string(src[start.Offset:end.Offset])
+-	return []byte("!(" + text + ")")
+-}
+-
+-func invertAndOr(fset *token.FileSet, expr *ast.BinaryExpr, src []byte) ([]byte, error) {
+-	if expr.Op != token.LAND && expr.Op != token.LOR {
+-		// Neither AND nor OR, don't know how to invert this
+-		return dumbInvert(fset, expr, src), nil
+-	}
+-
+-	oppositeOp := "&&"
+-	if expr.Op == token.LAND {
+-		oppositeOp = "||"
+-	}
+-
+-	xEndInSource := safetoken.EndPosition(fset, expr.X.End())
+-	opPosInSource := safetoken.StartPosition(fset, expr.OpPos)
+-	whitespaceAfterBefore := src[xEndInSource.Offset:opPosInSource.Offset]
+-
+-	invertedBefore, err := invertCondition(fset, expr.X, src)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	invertedAfter, err := invertCondition(fset, expr.Y, src)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	yPosInSource := safetoken.StartPosition(fset, expr.Y.Pos())
+-
+-	oldOpWithTrailingWhitespace := string(src[opPosInSource.Offset:yPosInSource.Offset])
+-	newOpWithTrailingWhitespace := oppositeOp + oldOpWithTrailingWhitespace[len(expr.Op.String()):]
+-
+-	return []byte(string(invertedBefore) + string(whitespaceAfterBefore) + newOpWithTrailingWhitespace + string(invertedAfter)), nil
+-}
+-
+-// CanInvertIfCondition reports whether we can do invert-if-condition on the
+-// code in the given range
+-func CanInvertIfCondition(file *ast.File, start, end token.Pos) (*ast.IfStmt, bool, error) {
+-	path, _ := astutil.PathEnclosingInterval(file, start, end)
+-	for _, node := range path {
+-		stmt, isIfStatement := node.(*ast.IfStmt)
+-		if !isIfStatement {
+-			continue
+-		}
+-
+-		if stmt.Else == nil {
+-			// Can't invert conditions without else clauses
+-			return nil, false, fmt.Errorf("else clause required")
+-		}
+-
+-		if _, hasElseIf := stmt.Else.(*ast.IfStmt); hasElseIf {
+-			// Can't invert conditions with else-if clauses, unclear what that
+-			// would look like
+-			return nil, false, fmt.Errorf("else-if not supported")
+-		}
+-
+-		return stmt, true, nil
+-	}
+-
+-	return nil, false, fmt.Errorf("not an if statement")
+-}
 diff -urN a/gopls/internal/lsp/source/known_packages.go b/gopls/internal/lsp/source/known_packages.go
 --- a/gopls/internal/lsp/source/known_packages.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/known_packages.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,140 +0,0 @@
++++ b/gopls/internal/lsp/source/known_packages.go	1970-01-01 08:00:00
+@@ -1,134 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -80012,7 +88484,6 @@
 -
 -import (
 -	"context"
--	"fmt"
 -	"go/parser"
 -	"go/token"
 -	"sort"
@@ -80034,19 +88505,14 @@
 -	// This algorithm is expressed in terms of Metadata, not Packages,
 -	// so it doesn't cause or wait for type checking.
 -
--	// Find a Metadata containing the file.
--	metas, err := snapshot.MetadataForFile(ctx, fh.URI())
+-	current, err := NarrowestMetadataForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err // e.g. context cancelled
 -	}
--	if len(metas) == 0 {
--		return nil, fmt.Errorf("no loaded package contain file %s", fh.URI())
--	}
--	current := metas[0] // pick one arbitrarily (they should all have the same package path)
 -
 -	// Parse the file's imports so we can compute which
 -	// PackagePaths are imported by this specific file.
--	src, err := fh.Read()
+-	src, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -80063,7 +88529,7 @@
 -		}
 -	}
 -
--	// Now find candidates among known packages.
+-	// Now find candidates among all known packages.
 -	knownPkgs, err := snapshot.AllMetadata(ctx)
 -	if err != nil {
 -		return nil, err
@@ -80097,7 +88563,7 @@
 -	}
 -
 -	// Augment the set by invoking the goimports algorithm.
--	if err := snapshot.RunProcessEnvFunc(ctx, func(o *imports.Options) error {
+-	if err := snapshot.RunProcessEnvFunc(ctx, func(ctx context.Context, o *imports.Options) error {
 -		ctx, cancel := context.WithTimeout(ctx, time.Millisecond*80)
 -		defer cancel()
 -		var seenMu sync.Mutex
@@ -80146,8 +88612,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/linkname.go b/gopls/internal/lsp/source/linkname.go
 --- a/gopls/internal/lsp/source/linkname.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/linkname.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,136 +0,0 @@
++++ b/gopls/internal/lsp/source/linkname.go	1970-01-01 08:00:00
+@@ -1,156 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -80173,65 +88639,88 @@
 -
 -// LinknameDefinition finds the definition of the linkname directive in fh at pos.
 -// If there is no linkname directive at pos, returns ErrNoLinkname.
--func LinknameDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) ([]protocol.Location, error) {
--	pkgPath, name := parseLinkname(ctx, snapshot, fh, pos)
+-func LinknameDefinition(ctx context.Context, snapshot Snapshot, fh FileHandle, from protocol.Position) ([]protocol.Location, error) {
+-	pkgPath, name, _ := parseLinkname(ctx, snapshot, fh, from)
 -	if pkgPath == "" {
 -		return nil, ErrNoLinkname
 -	}
--	return findLinkname(ctx, snapshot, fh, pos, PackagePath(pkgPath), name)
+-
+-	_, pgf, pos, err := findLinkname(ctx, snapshot, PackagePath(pkgPath), name)
+-	if err != nil {
+-		return nil, fmt.Errorf("find linkname: %w", err)
+-	}
+-	loc, err := pgf.PosLocation(pos, pos+token.Pos(len(name)))
+-	if err != nil {
+-		return nil, fmt.Errorf("location of linkname: %w", err)
+-	}
+-	return []protocol.Location{loc}, nil
 -}
 -
 -// parseLinkname attempts to parse a go:linkname declaration at the given pos.
--// If successful, it returns the package path and object name referenced by the second
--// argument of the linkname directive.
+-// If successful, it returns
+-// - package path referenced
+-// - object name referenced
+-// - byte offset in fh of the start of the link target
+-// of the linkname directives 2nd argument.
 -//
--// If the position is not in the second argument of a go:linkname directive, or parsing fails, it returns "", "".
--func parseLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (pkgPath, name string) {
+-// If the position is not in the second argument of a go:linkname directive,
+-// or parsing fails, it returns "", "", 0.
+-func parseLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (pkgPath, name string, targetOffset int) {
+-	// TODO(adonovan): opt: parsing isn't necessary here.
+-	// We're only looking for a line comment.
 -	pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
 -	if err != nil {
--		return "", ""
+-		return "", "", 0
 -	}
 -
--	span, err := pgf.Mapper.PositionPoint(pos)
+-	offset, err := pgf.Mapper.PositionOffset(pos)
 -	if err != nil {
--		return "", ""
+-		return "", "", 0
 -	}
--	atLine := span.Line()
--	atColumn := span.Column()
 -
 -	// Looking for pkgpath in '//go:linkname f pkgpath.g'.
 -	// (We ignore 1-arg linkname directives.)
--	directive, column := findLinknameOnLine(pgf, atLine)
+-	directive, end := findLinknameAtOffset(pgf, offset)
 -	parts := strings.Fields(directive)
 -	if len(parts) != 3 {
--		return "", ""
+-		return "", "", 0
 -	}
 -
 -	// Inside 2nd arg [start, end]?
--	end := column + len(directive)
+-	// (Assumes no trailing spaces.)
 -	start := end - len(parts[2])
--	if !(start <= atColumn && atColumn <= end) {
--		return "", ""
+-	if !(start <= offset && offset <= end) {
+-		return "", "", 0
 -	}
 -	linkname := parts[2]
 -
 -	// Split the pkg path from the name.
 -	dot := strings.LastIndexByte(linkname, '.')
 -	if dot < 0 {
--		return "", ""
+-		return "", "", 0
 -	}
--	return linkname[:dot], linkname[dot+1:]
+-
+-	return linkname[:dot], linkname[dot+1:], start
 -}
 -
--// findLinknameOnLine returns the first linkname directive on line and the column it starts at.
--// Returns "", 0 if no linkname directive is found on the line.
--func findLinknameOnLine(pgf *ParsedGoFile, line int) (string, int) {
+-// findLinknameAtOffset returns the first linkname directive on line and its end offset.
+-// Returns "", 0 if the offset is not in a linkname directive.
+-func findLinknameAtOffset(pgf *ParsedGoFile, offset int) (string, int) {
 -	for _, grp := range pgf.File.Comments {
 -		for _, com := range grp.List {
 -			if strings.HasPrefix(com.Text, "//go:linkname") {
 -				p := safetoken.Position(pgf.Tok, com.Pos())
--				if p.Line == line {
--					return com.Text, p.Column
+-
+-				// Sometimes source code (typically tests) has another
+-				// comment after the directive, trim that away.
+-				text := com.Text
+-				if i := strings.LastIndex(text, "//"); i != 0 {
+-					text = strings.TrimSpace(text[:i])
+-				}
+-
+-				end := p.Offset + len(text)
+-				if p.Offset <= offset && offset < end {
+-					return text, end
 -				}
 -			}
 -		}
@@ -80241,16 +88730,16 @@
 -
 -// findLinkname searches dependencies of packages containing fh for an object
 -// with linker name matching the given package path and name.
--func findLinkname(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position, pkgPath PackagePath, name string) ([]protocol.Location, error) {
+-func findLinkname(ctx context.Context, snapshot Snapshot, pkgPath PackagePath, name string) (Package, *ParsedGoFile, token.Pos, error) {
 -	// Typically the linkname refers to a forward dependency
 -	// or a reverse dependency, but in general it may refer
--	// to any package in the workspace.
+-	// to any package that is linked with this one.
 -	var pkgMeta *Metadata
 -	metas, err := snapshot.AllMetadata(ctx)
 -	if err != nil {
--		return nil, err
+-		return nil, nil, token.NoPos, err
 -	}
--	metas = RemoveIntermediateTestVariants(metas)
+-	RemoveIntermediateTestVariants(&metas)
 -	for _, meta := range metas {
 -		if meta.PkgPath == pkgPath {
 -			pkgMeta = meta
@@ -80258,36 +88747,33 @@
 -		}
 -	}
 -	if pkgMeta == nil {
--		return nil, fmt.Errorf("cannot find package %q", pkgPath)
+-		return nil, nil, token.NoPos, fmt.Errorf("cannot find package %q", pkgPath)
 -	}
 -
 -	// When found, type check the desired package (snapshot.TypeCheck in TypecheckFull mode),
 -	pkgs, err := snapshot.TypeCheck(ctx, pkgMeta.ID)
 -	if err != nil {
--		return nil, err
+-		return nil, nil, token.NoPos, err
 -	}
 -	pkg := pkgs[0]
 -
 -	obj := pkg.GetTypes().Scope().Lookup(name)
 -	if obj == nil {
--		return nil, fmt.Errorf("package %q does not define %s", pkgPath, name)
+-		return nil, nil, token.NoPos, fmt.Errorf("package %q does not define %s", pkgPath, name)
 -	}
 -
 -	objURI := safetoken.StartPosition(pkg.FileSet(), obj.Pos())
 -	pgf, err := pkg.File(span.URIFromPath(objURI.Filename))
 -	if err != nil {
--		return nil, err
+-		return nil, nil, token.NoPos, err
 -	}
--	loc, err := pgf.PosLocation(obj.Pos(), obj.Pos()+token.Pos(len(name)))
--	if err != nil {
--		return nil, err
--	}
--	return []protocol.Location{loc}, nil
+-
+-	return pkg, pgf, obj.Pos(), nil
 -}
 diff -urN a/gopls/internal/lsp/source/methodsets/methodsets.go b/gopls/internal/lsp/source/methodsets/methodsets.go
 --- a/gopls/internal/lsp/source/methodsets/methodsets.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/methodsets/methodsets.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,508 +0,0 @@
++++ b/gopls/internal/lsp/source/methodsets/methodsets.go	1970-01-01 08:00:00
+@@ -1,490 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -80299,7 +88785,7 @@
 -// This package provides only the "global" (all workspace) search; the
 -// "local" search within a given package uses a different
 -// implementation based on type-checker data structures for a single
--// package plus variants; see ../implementation2.go.
+-// package plus variants; see ../implementation.go.
 -// The local algorithm is more precise as it tests function-local types too.
 -//
 -// A global index of function-local types is challenging since they
@@ -80334,20 +88820,17 @@
 -// single 64-bit mask is quite effective. See CL 452060 for details.
 -
 -import (
--	"bytes"
--	"encoding/gob"
 -	"fmt"
 -	"go/token"
 -	"go/types"
 -	"hash/crc32"
--	"log"
 -	"strconv"
 -	"strings"
 -
 -	"golang.org/x/tools/go/types/objectpath"
+-	"golang.org/x/tools/gopls/internal/lsp/frob"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/internal/typeparams"
--	"golang.org/x/tools/internal/typesinternal"
 -)
 -
 -// An Index records the non-empty method sets of all package-level
@@ -80360,27 +88843,13 @@
 -// Decode decodes the given gob-encoded data as an Index.
 -func Decode(data []byte) *Index {
 -	var pkg gobPackage
--	mustDecode(data, &pkg)
+-	packageCodec.Decode(data, &pkg)
 -	return &Index{pkg}
 -}
 -
 -// Encode encodes the receiver as gob-encoded data.
 -func (index *Index) Encode() []byte {
--	return mustEncode(index.pkg)
--}
--
--func mustEncode(x interface{}) []byte {
--	var buf bytes.Buffer
--	if err := gob.NewEncoder(&buf).Encode(x); err != nil {
--		log.Fatalf("internal error encoding %T: %v", x, err)
--	}
--	return buf.Bytes()
--}
--
--func mustDecode(data []byte, ptr interface{}) {
--	if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil {
--		log.Fatalf("internal error decoding %T: %v", ptr, err)
--	}
+-	return packageCodec.Encode(index.pkg)
 -}
 -
 -// NewIndex returns a new index of method-set information for all
@@ -80522,7 +88991,7 @@
 -		return gobPosition{b.string(posn.Filename), posn.Offset, len(obj.Name())}
 -	}
 -
--	objectpathFor := typesinternal.NewObjectpathFunc()
+-	objectpathFor := new(objectpath.Encoder).For
 -
 -	// setindexInfo sets the (Posn, PkgPath, ObjectPath) fields for each method declaration.
 -	setIndexInfo := func(m *gobMethod, method *types.Func) {
@@ -80642,8 +89111,8 @@
 -			if tname.Pkg() != nil {
 -				buf.WriteString(strconv.Quote(tname.Pkg().Path()))
 -				buf.WriteByte('.')
--			} else if tname.Name() != "error" {
--				panic(tname) // error is the only named type with no package
+-			} else if tname.Name() != "error" && tname.Name() != "comparable" {
+-				panic(tname) // error and comparable the only named types with no package
 -			}
 -			buf.WriteString(tname.Name())
 -
@@ -80761,9 +89230,8 @@
 -
 -// -- serial format of index --
 -
--// The cost of gob encoding and decoding for most packages in x/tools
--// is under 50us, with occasional peaks of around 1-3ms.
--// The encoded indexes are around 1KB-50KB.
+-// (The name says gob but in fact we use frob.)
+-var packageCodec = frob.CodecFor[gobPackage]()
 -
 -// A gobPackage records the method set of each package-level type for a single package.
 -type gobPackage struct {
@@ -80798,8 +89266,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/options.go b/gopls/internal/lsp/source/options.go
 --- a/gopls/internal/lsp/source/options.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/options.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1631 +0,0 @@
++++ b/gopls/internal/lsp/source/options.go	1970-01-01 08:00:00
+@@ -1,1797 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -80818,6 +89286,7 @@
 -	"time"
 -
 -	"golang.org/x/tools/go/analysis"
+-	"golang.org/x/tools/go/analysis/passes/appends"
 -	"golang.org/x/tools/go/analysis/passes/asmdecl"
 -	"golang.org/x/tools/go/analysis/passes/assign"
 -	"golang.org/x/tools/go/analysis/passes/atomic"
@@ -80828,6 +89297,7 @@
 -	"golang.org/x/tools/go/analysis/passes/composite"
 -	"golang.org/x/tools/go/analysis/passes/copylock"
 -	"golang.org/x/tools/go/analysis/passes/deepequalerrors"
+-	"golang.org/x/tools/go/analysis/passes/defers"
 -	"golang.org/x/tools/go/analysis/passes/directive"
 -	"golang.org/x/tools/go/analysis/passes/errorsas"
 -	"golang.org/x/tools/go/analysis/passes/fieldalignment"
@@ -80840,6 +89310,7 @@
 -	"golang.org/x/tools/go/analysis/passes/printf"
 -	"golang.org/x/tools/go/analysis/passes/shadow"
 -	"golang.org/x/tools/go/analysis/passes/shift"
+-	"golang.org/x/tools/go/analysis/passes/slog"
 -	"golang.org/x/tools/go/analysis/passes/sortslice"
 -	"golang.org/x/tools/go/analysis/passes/stdmethods"
 -	"golang.org/x/tools/go/analysis/passes/stringintconv"
@@ -80852,6 +89323,7 @@
 -	"golang.org/x/tools/go/analysis/passes/unsafeptr"
 -	"golang.org/x/tools/go/analysis/passes/unusedresult"
 -	"golang.org/x/tools/go/analysis/passes/unusedwrite"
+-	"golang.org/x/tools/gopls/internal/lsp/analysis/deprecated"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/embeddirective"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/fillreturns"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/fillstruct"
@@ -80880,7 +89352,7 @@
 -// DefaultOptions is the options that are used for Gopls execution independent
 -// of any externally provided configuration (LSP initialization, command
 -// invocation, etc.).
--func DefaultOptions() *Options {
+-func DefaultOptions(overrides ...func(*Options)) *Options {
 -	optionsOnce.Do(func() {
 -		var commands []string
 -		for _, c := range command.Commands {
@@ -80904,6 +89376,7 @@
 -						protocol.SourceOrganizeImports: true,
 -						protocol.QuickFix:              true,
 -						protocol.RefactorRewrite:       true,
+-						protocol.RefactorInline:        true,
 -						protocol.RefactorExtract:       true,
 -					},
 -					Mod: {
@@ -80926,14 +89399,15 @@
 -				},
 -				UIOptions: UIOptions{
 -					DiagnosticOptions: DiagnosticOptions{
--						DiagnosticsDelay: 250 * time.Millisecond,
 -						Annotations: map[Annotation]bool{
 -							Bounds: true,
 -							Escape: true,
 -							Inline: true,
 -							Nil:    true,
 -						},
--						Vulncheck: ModeVulncheckOff,
+-						Vulncheck:                 ModeVulncheckOff,
+-						DiagnosticsDelay:          1 * time.Second,
+-						AnalysisProgressReporting: true,
 -					},
 -					InlayHintOptions: InlayHintOptions{},
 -					DocumentationOptions: DocumentationOptions{
@@ -80945,11 +89419,13 @@
 -						ImportShortcut: BothShortcuts,
 -						SymbolMatcher:  SymbolFastFuzzy,
 -						SymbolStyle:    DynamicSymbols,
+-						SymbolScope:    AllSymbolScope,
 -					},
 -					CompletionOptions: CompletionOptions{
 -						Matcher:                        Fuzzy,
 -						CompletionBudget:               100 * time.Millisecond,
 -						ExperimentalPostfixCompletions: true,
+-						CompleteFunctionCalls:          true,
 -					},
 -					Codelenses: map[string]bool{
 -						string(command.Generate):          true,
@@ -80963,13 +89439,17 @@
 -				},
 -			},
 -			InternalOptions: InternalOptions{
--				LiteralCompletions:      true,
--				TempModfile:             true,
--				CompleteUnimported:      true,
--				CompletionDocumentation: true,
--				DeepCompletion:          true,
--				ChattyDiagnostics:       true,
--				NewDiff:                 "both",
+-				LiteralCompletions:          true,
+-				TempModfile:                 true,
+-				CompleteUnimported:          true,
+-				CompletionDocumentation:     true,
+-				DeepCompletion:              true,
+-				ChattyDiagnostics:           true,
+-				NewDiff:                     "new",
+-				SubdirWatchPatterns:         SubdirWatchPatternsAuto,
+-				ReportAnalysisProgressAfter: 5 * time.Second,
+-				TelemetryPrompt:             false,
+-				LinkifyShowMessage:          false,
 -			},
 -			Hooks: Hooks{
 -				// TODO(adonovan): switch to new diff.Strings implementation.
@@ -80983,7 +89463,13 @@
 -			},
 -		}
 -	})
--	return defaultOptions
+-	options := defaultOptions.Clone()
+-	for _, override := range overrides {
+-		if override != nil {
+-			override(options)
+-		}
+-	}
+-	return options
 -}
 -
 -// Options holds various configuration that affects Gopls execution, organized
@@ -80996,9 +89482,26 @@
 -	Hooks
 -}
 -
+-// IsAnalyzerEnabled reports whether an analyzer with the given name is
+-// enabled.
+-//
+-// TODO(rfindley): refactor to simplify this function. We no longer need the
+-// different categories of analyzer.
+-func (opts *Options) IsAnalyzerEnabled(name string) bool {
+-	for _, amap := range []map[string]*Analyzer{opts.DefaultAnalyzers, opts.TypeErrorAnalyzers, opts.ConvenienceAnalyzers, opts.StaticcheckAnalyzers} {
+-		for _, analyzer := range amap {
+-			if analyzer.Analyzer.Name == name && analyzer.IsEnabled(opts) {
+-				return true
+-			}
+-		}
+-	}
+-	return false
+-}
+-
 -// ClientOptions holds LSP-specific configuration that is provided by the
 -// client.
 -type ClientOptions struct {
+-	ClientInfo                                 *protocol.Msg_XInitializeParams_clientInfo
 -	InsertTextFormat                           protocol.InsertTextFormat
 -	ConfigurationSupported                     bool
 -	DynamicConfigurationSupported              bool
@@ -81156,6 +89659,13 @@
 -	// ExperimentalPostfixCompletions enables artificial method snippets
 -	// such as "someSlice.sort!".
 -	ExperimentalPostfixCompletions bool `status:"experimental"`
+-
+-	// CompleteFunctionCalls enables function call completion.
+-	//
+-	// When completing a statement, or when a function return type matches the
+-	// expected of the expression being completed, completion may suggest call
+-	// expressions (i.e. may include parentheses).
+-	CompleteFunctionCalls bool
 -}
 -
 -type DocumentationOptions struct {
@@ -81227,6 +89737,17 @@
 -	//
 -	// This option must be set to a valid duration string, for example `"250ms"`.
 -	DiagnosticsDelay time.Duration `status:"advanced"`
+-
+-	// AnalysisProgressReporting controls whether gopls sends progress
+-	// notifications when construction of its index of analysis facts is taking a
+-	// long time. Cancelling these notifications will cancel the indexing task,
+-	// though it will restart after the next change in the workspace.
+-	//
+-	// When a package is opened for the first time and heavyweight analyses such as
+-	// staticcheck are enabled, it can take a while to construct the index of
+-	// analysis facts for all its dependencies. The index is cached in the
+-	// filesystem, so subsequent analysis should be faster.
+-	AnalysisProgressReporting bool
 -}
 -
 -type InlayHintOptions struct {
@@ -81256,6 +89777,13 @@
 -	// }
 -	// ```
 -	SymbolStyle SymbolStyle `status:"advanced"`
+-
+-	// SymbolScope controls which packages are searched for workspace/symbol
+-	// requests. The default value, "workspace", searches only workspace
+-	// packages. The legacy behavior, "all", causes all loaded packages to be
+-	// searched, including dependencies; this is more expensive and may return
+-	// unwanted results.
+-	SymbolScope SymbolScope
 -}
 -
 -// UserOptions holds custom Gopls configuration (not part of the LSP) that is
@@ -81330,6 +89858,9 @@
 -// average user. These may be settings used by tests or outdated settings that
 -// will soon be deprecated. Some of these settings may not even be configurable
 -// by the user.
+-//
+-// TODO(rfindley): even though these settings are not intended for
+-// modification, some of them should be surfaced in our documentation.
 -type InternalOptions struct {
 -	// LiteralCompletions controls whether literal candidates such as
 -	// "&someStruct{}" are offered. Tests disable this flag to simplify
@@ -81393,8 +89924,58 @@
 -	// file change. If unset, gopls only reports diagnostics when they change, or
 -	// when a file is opened or closed.
 -	ChattyDiagnostics bool
+-
+-	// SubdirWatchPatterns configures the file watching glob patterns registered
+-	// by gopls.
+-	//
+-	// Some clients (namely VS Code) do not send workspace/didChangeWatchedFile
+-	// notifications for files contained in a directory when that directory is
+-	// deleted:
+-	// https://github.com/microsoft/vscode/issues/109754
+-	//
+-	// In this case, gopls would miss important notifications about deleted
+-	// packages. To work around this, gopls registers a watch pattern for each
+-	// directory containing Go files.
+-	//
+-	// Unfortunately, other clients experience performance problems with this
+-	// many watch patterns, so there is no single behavior that works well for
+-	// all clients.
+-	//
+-	// The "subdirWatchPatterns" setting allows configuring this behavior. Its
+-	// default value of "auto" attempts to guess the correct behavior based on
+-	// the client name. We'd love to avoid this specialization, but as described
+-	// above there is no single value that works for all clients.
+-	//
+-	// If any LSP client does not behave well with the default value (for
+-	// example, if like VS Code it drops file notifications), please file an
+-	// issue.
+-	SubdirWatchPatterns SubdirWatchPatterns
+-
+-	// ReportAnalysisProgressAfter sets the duration for gopls to wait before starting
+-	// progress reporting for ongoing go/analysis passes.
+-	//
+-	// It is intended to be used for testing only.
+-	ReportAnalysisProgressAfter time.Duration
+-
+-	// TelemetryPrompt controls whether gopls prompts about enabling Go telemetry.
+-	//
+-	// Once the prompt is answered, gopls doesn't ask again, but TelemetryPrompt
+-	// can prevent the question from ever being asked in the first place.
+-	TelemetryPrompt bool
+-
+-	// LinkifyShowMessage controls whether the client wants gopls
+-	// to linkify links in showMessage. e.g. [go.dev](https://go.dev).
+-	LinkifyShowMessage bool
 -}
 -
+-type SubdirWatchPatterns string
+-
+-const (
+-	SubdirWatchPatternsOn   SubdirWatchPatterns = "on"
+-	SubdirWatchPatternsOff  SubdirWatchPatterns = "off"
+-	SubdirWatchPatternsAuto SubdirWatchPatterns = "auto"
+-)
+-
 -type ImportShortcut string
 -
 -const (
@@ -81419,6 +90000,8 @@
 -	CaseSensitive   Matcher = "CaseSensitive"
 -)
 -
+-// A SymbolMatcher controls the matching of symbols for workspace/symbol
+-// requests.
 -type SymbolMatcher string
 -
 -const (
@@ -81428,6 +90011,7 @@
 -	SymbolCaseSensitive   SymbolMatcher = "CaseSensitive"
 -)
 -
+-// A SymbolStyle controls the formatting of symbols in workspace/symbol results.
 -type SymbolStyle string
 -
 -const (
@@ -81444,6 +90028,17 @@
 -	DynamicSymbols SymbolStyle = "Dynamic"
 -)
 -
+-// A SymbolScope controls the search scope for workspace/symbol requests.
+-type SymbolScope string
+-
+-const (
+-	// WorkspaceSymbolScope matches symbols in workspace packages only.
+-	WorkspaceSymbolScope SymbolScope = "workspace"
+-	// AllSymbolScope matches symbols in any loaded package, including
+-	// dependencies.
+-	AllSymbolScope SymbolScope = "all"
+-)
+-
 -type HoverKind string
 -
 -const (
@@ -81522,7 +90117,8 @@
 -	return results
 -}
 -
--func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
+-func (o *Options) ForClientCapabilities(clientName *protocol.Msg_XInitializeParams_clientInfo, caps protocol.ClientCapabilities) {
+-	o.ClientInfo = clientName
 -	// Check if the client supports snippets in completion items.
 -	if caps.Workspace.WorkspaceEdit != nil {
 -		o.SupportedResourceOperations = caps.Workspace.WorkspaceEdit.ResourceOperations
@@ -81771,6 +90367,14 @@
 -			o.SymbolStyle = SymbolStyle(s)
 -		}
 -
+-	case "symbolScope":
+-		if s, ok := result.asOneOf(
+-			string(WorkspaceSymbolScope),
+-			string(AllSymbolScope),
+-		); ok {
+-			o.SymbolScope = SymbolScope(s)
+-		}
+-
 -	case "hoverKind":
 -		if s, ok := result.asOneOf(
 -			string(NoDocumentation),
@@ -81860,6 +90464,8 @@
 -					" rebuild gopls with a more recent version of Go", result.Name, runtime.Version())
 -			}
 -		}
+-	case "completeFunctionCalls":
+-		result.setBool(&o.CompleteFunctionCalls)
 -
 -	case "semanticTokens":
 -		result.setBool(&o.SemanticTokens)
@@ -81903,6 +90509,9 @@
 -	case "diagnosticsDelay":
 -		result.setDuration(&o.DiagnosticsDelay)
 -
+-	case "analysisProgressReporting":
+-		result.setBool(&o.AnalysisProgressReporting)
+-
 -	case "experimentalWatchedFileDelay":
 -		result.deprecated("")
 -
@@ -81931,6 +90540,23 @@
 -	case "chattyDiagnostics":
 -		result.setBool(&o.ChattyDiagnostics)
 -
+-	case "subdirWatchPatterns":
+-		if s, ok := result.asOneOf(
+-			string(SubdirWatchPatternsOn),
+-			string(SubdirWatchPatternsOff),
+-			string(SubdirWatchPatternsAuto),
+-		); ok {
+-			o.SubdirWatchPatterns = SubdirWatchPatterns(s)
+-		}
+-
+-	case "reportAnalysisProgressAfter":
+-		result.setDuration(&o.ReportAnalysisProgressAfter)
+-
+-	case "telemetryPrompt":
+-		result.setBool(&o.TelemetryPrompt)
+-	case "linkifyShowMessage":
+-		result.setBool(&o.LinkifyShowMessage)
+-
 -	// Replaced settings.
 -	case "experimentalDisabledAnalyses":
 -		result.deprecated("analyses")
@@ -81990,14 +90616,6 @@
 -	return e.msg
 -}
 -
--// softErrorf reports an error that does not affect the functionality of gopls
--// (a warning in the UI).
--// The formatted message will be shown to the user unmodified.
--func (r *OptionResult) softErrorf(format string, values ...interface{}) {
--	msg := fmt.Sprintf(format, values...)
--	r.Error = &SoftError{msg}
--}
--
 -// deprecated reports the current setting as deprecated. If 'replacement' is
 -// non-nil, it is suggested to the user.
 -func (r *OptionResult) deprecated(replacement string) {
@@ -82166,7 +90784,8 @@
 -func typeErrorAnalyzers() map[string]*Analyzer {
 -	return map[string]*Analyzer{
 -		fillreturns.Analyzer.Name: {
--			Analyzer:   fillreturns.Analyzer,
+-			Analyzer: fillreturns.Analyzer,
+-			// TODO(rfindley): is SourceFixAll even necessary here? Is that not implied?
 -			ActionKind: []protocol.CodeActionKind{protocol.SourceFixAll, protocol.QuickFix},
 -			Enabled:    true,
 -		},
@@ -82190,6 +90809,8 @@
 -	}
 -}
 -
+-// TODO(golang/go#61559): remove convenience analyzers now that they are not
+-// used from the analysis framework.
 -func convenienceAnalyzers() map[string]*Analyzer {
 -	return map[string]*Analyzer{
 -		fillstruct.Analyzer.Name: {
@@ -82199,10 +90820,14 @@
 -			ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite},
 -		},
 -		stubmethods.Analyzer.Name: {
--			Analyzer:   stubmethods.Analyzer,
--			ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite},
--			Fix:        StubMethods,
+-			Analyzer: stubmethods.Analyzer,
+-			Fix:      StubMethods,
+-			Enabled:  true,
+-		},
+-		infertypeargs.Analyzer.Name: {
+-			Analyzer:   infertypeargs.Analyzer,
 -			Enabled:    true,
+-			ActionKind: []protocol.CodeActionKind{protocol.RefactorRewrite},
 -		},
 -	}
 -}
@@ -82210,6 +90835,7 @@
 -func defaultAnalyzers() map[string]*Analyzer {
 -	return map[string]*Analyzer{
 -		// The traditional vet suite:
+-		appends.Analyzer.Name:       {Analyzer: appends.Analyzer, Enabled: true},
 -		asmdecl.Analyzer.Name:       {Analyzer: asmdecl.Analyzer, Enabled: true},
 -		assign.Analyzer.Name:        {Analyzer: assign.Analyzer, Enabled: true},
 -		atomic.Analyzer.Name:        {Analyzer: atomic.Analyzer, Enabled: true},
@@ -82218,6 +90844,8 @@
 -		cgocall.Analyzer.Name:       {Analyzer: cgocall.Analyzer, Enabled: true},
 -		composite.Analyzer.Name:     {Analyzer: composite.Analyzer, Enabled: true},
 -		copylock.Analyzer.Name:      {Analyzer: copylock.Analyzer, Enabled: true},
+-		defers.Analyzer.Name:        {Analyzer: defers.Analyzer, Enabled: true},
+-		deprecated.Analyzer.Name:    {Analyzer: deprecated.Analyzer, Enabled: true, Severity: protocol.SeverityHint, Tag: []protocol.DiagnosticTag{protocol.Deprecated}},
 -		directive.Analyzer.Name:     {Analyzer: directive.Analyzer, Enabled: true},
 -		errorsas.Analyzer.Name:      {Analyzer: errorsas.Analyzer, Enabled: true},
 -		httpresponse.Analyzer.Name:  {Analyzer: httpresponse.Analyzer, Enabled: true},
@@ -82227,6 +90855,7 @@
 -		nilfunc.Analyzer.Name:       {Analyzer: nilfunc.Analyzer, Enabled: true},
 -		printf.Analyzer.Name:        {Analyzer: printf.Analyzer, Enabled: true},
 -		shift.Analyzer.Name:         {Analyzer: shift.Analyzer, Enabled: true},
+-		slog.Analyzer.Name:          {Analyzer: slog.Analyzer, Enabled: true},
 -		stdmethods.Analyzer.Name:    {Analyzer: stdmethods.Analyzer, Enabled: true},
 -		stringintconv.Analyzer.Name: {Analyzer: stringintconv.Analyzer, Enabled: true},
 -		structtag.Analyzer.Name:     {Analyzer: structtag.Analyzer, Enabled: true},
@@ -82247,9 +90876,13 @@
 -		unusedparams.Analyzer.Name:     {Analyzer: unusedparams.Analyzer, Enabled: false},
 -		unusedwrite.Analyzer.Name:      {Analyzer: unusedwrite.Analyzer, Enabled: false},
 -		useany.Analyzer.Name:           {Analyzer: useany.Analyzer, Enabled: false},
--		infertypeargs.Analyzer.Name:    {Analyzer: infertypeargs.Analyzer, Enabled: true},
--		embeddirective.Analyzer.Name:   {Analyzer: embeddirective.Analyzer, Enabled: true},
 -		timeformat.Analyzer.Name:       {Analyzer: timeformat.Analyzer, Enabled: true},
+-		embeddirective.Analyzer.Name: {
+-			Analyzer:        embeddirective.Analyzer,
+-			Enabled:         true,
+-			Fix:             AddEmbedImport,
+-			fixesDiagnostic: fixedByImportingEmbed,
+-		},
 -
 -		// gofmt -s suite:
 -		simplifycompositelit.Analyzer.Name: {
@@ -82407,6 +91040,7 @@
 -type AnalyzerJSON struct {
 -	Name    string
 -	Doc     string
+-	URL     string
 -	Default bool
 -}
 -
@@ -82433,7 +91067,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/options_test.go b/gopls/internal/lsp/source/options_test.go
 --- a/gopls/internal/lsp/source/options_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/options_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/options_test.go	1970-01-01 08:00:00
 @@ -1,206 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -82641,10 +91275,110 @@
 -		}
 -	}
 -}
+diff -urN a/gopls/internal/lsp/source/origin.go b/gopls/internal/lsp/source/origin.go
+--- a/gopls/internal/lsp/source/origin.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/origin.go	1970-01-01 08:00:00
+@@ -1,26 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build !go1.19
+-// +build !go1.19
+-
+-package source
+-
+-import "go/types"
+-
+-// containsOrigin reports whether the provided object set contains an object
+-// with the same origin as the provided obj (which may be a synthetic object
+-// created during instantiation).
+-func containsOrigin(objSet map[types.Object]bool, obj types.Object) bool {
+-	if obj == nil {
+-		return objSet[obj]
+-	}
+-	// In Go 1.18, we can't use the types.Var.Origin and types.Func.Origin methods.
+-	for target := range objSet {
+-		if target.Pkg() == obj.Pkg() && target.Pos() == obj.Pos() && target.Name() == obj.Name() {
+-			return true
+-		}
+-	}
+-	return false
+-}
+diff -urN a/gopls/internal/lsp/source/origin_119.go b/gopls/internal/lsp/source/origin_119.go
+--- a/gopls/internal/lsp/source/origin_119.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/origin_119.go	1970-01-01 08:00:00
+@@ -1,33 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.19
+-// +build go1.19
+-
+-package source
+-
+-import "go/types"
+-
+-// containsOrigin reports whether the provided object set contains an object
+-// with the same origin as the provided obj (which may be a synthetic object
+-// created during instantiation).
+-func containsOrigin(objSet map[types.Object]bool, obj types.Object) bool {
+-	objOrigin := origin(obj)
+-	for target := range objSet {
+-		if origin(target) == objOrigin {
+-			return true
+-		}
+-	}
+-	return false
+-}
+-
+-func origin(obj types.Object) types.Object {
+-	switch obj := obj.(type) {
+-	case *types.Var:
+-		return obj.Origin()
+-	case *types.Func:
+-		return obj.Origin()
+-	}
+-	return obj
+-}
+diff -urN a/gopls/internal/lsp/source/parsemode_go116.go b/gopls/internal/lsp/source/parsemode_go116.go
+--- a/gopls/internal/lsp/source/parsemode_go116.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/parsemode_go116.go	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build !go1.17
+-// +build !go1.17
+-
+-package source
+-
+-import "go/parser"
+-
+-// The parser.SkipObjectResolution mode flag is not supported before Go 1.17.
+-const SkipObjectResolution parser.Mode = 0
+diff -urN a/gopls/internal/lsp/source/parsemode_go117.go b/gopls/internal/lsp/source/parsemode_go117.go
+--- a/gopls/internal/lsp/source/parsemode_go117.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/parsemode_go117.go	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.17
+-// +build go1.17
+-
+-package source
+-
+-import "go/parser"
+-
+-const SkipObjectResolution = parser.SkipObjectResolution
 diff -urN a/gopls/internal/lsp/source/references.go b/gopls/internal/lsp/source/references.go
 --- a/gopls/internal/lsp/source/references.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/references.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,582 +0,0 @@
++++ b/gopls/internal/lsp/source/references.go	1970-01-01 08:00:00
+@@ -1,692 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -82672,11 +91406,11 @@
 -
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/types/objectpath"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -)
 -
@@ -82707,7 +91441,7 @@
 -// definitions before uses) to the object denoted by the identifier at
 -// the given file/position, searching the entire workspace.
 -func references(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, includeDeclaration bool) ([]reference, error) {
--	ctx, done := event.Start(ctx, "source.References2")
+-	ctx, done := event.Start(ctx, "source.references")
 -	defer done()
 -
 -	// Is the cursor within the package name declaration?
@@ -82789,9 +91523,23 @@
 -		if err != nil {
 -			return nil, err
 -		}
+-
+-		// Restrict search to workspace packages.
+-		workspace, err := snapshot.WorkspaceMetadata(ctx)
+-		if err != nil {
+-			return nil, err
+-		}
+-		workspaceMap := make(map[PackageID]*Metadata, len(workspace))
+-		for _, m := range workspace {
+-			workspaceMap[m.ID] = m
+-		}
+-
 -		for _, rdep := range rdeps {
+-			if _, ok := workspaceMap[rdep.ID]; !ok {
+-				continue
+-			}
 -			for _, uri := range rdep.CompiledGoFiles {
--				fh, err := snapshot.GetFile(ctx, uri)
+-				fh, err := snapshot.ReadFile(ctx, uri)
 -				if err != nil {
 -					return nil, err
 -				}
@@ -82818,9 +91566,9 @@
 -	// The widest package (possibly a test variant) has the
 -	// greatest number of files and thus we choose it for the
 -	// "internal" references.
--	widest := metas[len(metas)-1]
+-	widest := metas[len(metas)-1] // may include _test.go files
 -	for _, uri := range widest.CompiledGoFiles {
--		fh, err := snapshot.GetFile(ctx, uri)
+-		fh, err := snapshot.ReadFile(ctx, uri)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -82851,12 +91599,13 @@
 -	// declaration (e.g. because the _test.go files can change the
 -	// meaning of a field or method selection), but the narrower
 -	// package reports the more broadly referenced object.
--	pkg, pgf, err := PackageForFile(ctx, snapshot, uri, NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, uri)
 -	if err != nil {
 -		return nil, err
 -	}
 -
 -	// Find the selected object (declaration or reference).
+-	// For struct{T}, we choose the field (Def) over the type (Use).
 -	pos, err := pgf.PositionPos(pp)
 -	if err != nil {
 -		return nil, err
@@ -82879,14 +91628,14 @@
 -
 -	// nil, error, error.Error, iota, or other built-in?
 -	if obj.Pkg() == nil {
--		// For some reason, existing tests require that iota has no references,
--		// nor an error. TODO(adonovan): do something more principled.
--		if obj.Name() == "iota" {
--			return nil, nil
--		}
--
 -		return nil, fmt.Errorf("references to builtin %q are not supported", obj.Name())
 -	}
+-	if !obj.Pos().IsValid() {
+-		if obj.Pkg().Path() != "unsafe" {
+-			bug.Reportf("references: object %v has no position", obj)
+-		}
+-		return nil, fmt.Errorf("references to unsafe.%s are not supported", obj.Name())
+-	}
 -
 -	// Find metadata of all packages containing the object's defining file.
 -	// This may include the query pkg, and possibly other variants.
@@ -82899,14 +91648,16 @@
 -	if len(variants) == 0 {
 -		return nil, fmt.Errorf("no packages for file %q", declURI) // can't happen
 -	}
+-	// (variants must include ITVs for reverse dependency computation below.)
 -
 -	// Is object exported?
 -	// If so, compute scope and targets of the global search.
 -	var (
--		globalScope   = make(map[PackageID]*Metadata)
+-		globalScope   = make(map[PackageID]*Metadata) // (excludes ITVs)
 -		globalTargets map[PackagePath]map[objectpath.Path]unit
+-		expansions    = make(map[PackageID]unit) // packages that caused search expansion
 -	)
--	// TODO(adonovan): what about generic functions. Need to consider both
+-	// TODO(adonovan): what about generic functions? Need to consider both
 -	// uninstantiated and instantiated. The latter have no objectpath. Use Origin?
 -	if path, err := objectpath.For(obj); err == nil && obj.Exported() {
 -		pkgPath := variants[0].PkgPath // (all variants have same package path)
@@ -82914,6 +91665,47 @@
 -			pkgPath: {path: {}}, // primary target
 -		}
 -
+-		// Compute set of (non-ITV) workspace packages.
+-		// We restrict references to this subset.
+-		workspace, err := snapshot.WorkspaceMetadata(ctx)
+-		if err != nil {
+-			return nil, err
+-		}
+-		workspaceMap := make(map[PackageID]*Metadata, len(workspace))
+-		workspaceIDs := make([]PackageID, 0, len(workspace))
+-		for _, m := range workspace {
+-			workspaceMap[m.ID] = m
+-			workspaceIDs = append(workspaceIDs, m.ID)
+-		}
+-
+-		// addRdeps expands the global scope to include the
+-		// reverse dependencies of the specified package.
+-		addRdeps := func(id PackageID, transitive bool) error {
+-			rdeps, err := snapshot.ReverseDependencies(ctx, id, transitive)
+-			if err != nil {
+-				return err
+-			}
+-			for rdepID, rdep := range rdeps {
+-				// Skip non-workspace packages.
+-				//
+-				// This means we also skip any expansion of the
+-				// search that might be caused by a non-workspace
+-				// package, possibly causing us to miss references
+-				// to the expanded target set from workspace packages.
+-				//
+-				// TODO(adonovan): don't skip those expansions.
+-				// The challenge is how to so without type-checking
+-				// a lot of non-workspace packages not covered by
+-				// the initial workspace load.
+-				if _, ok := workspaceMap[rdepID]; !ok {
+-					continue
+-				}
+-
+-				globalScope[rdepID] = rdep
+-			}
+-			return nil
+-		}
+-
 -		// How far need we search?
 -		// For package-level objects, we need only search the direct importers.
 -		// For fields and methods, we must search transitively.
@@ -82921,15 +91713,11 @@
 -
 -		// The scope is the union of rdeps of each variant.
 -		// (Each set is disjoint so there's no benefit to
--		// to combining the metadata graph traversals.)
+-		// combining the metadata graph traversals.)
 -		for _, m := range variants {
--			rdeps, err := snapshot.ReverseDependencies(ctx, m.ID, transitive)
--			if err != nil {
+-			if err := addRdeps(m.ID, transitive); err != nil {
 -				return nil, err
 -			}
--			for id, rdep := range rdeps {
--				globalScope[id] = rdep
--			}
 -		}
 -
 -		// Is object a method?
@@ -82938,8 +91726,11 @@
 -		// all methods that correspond to it through interface
 -		// satisfaction, and the scope includes the rdeps of
 -		// the package that declares each corresponding type.
+-		//
+-		// 'expansions' records the packages that declared
+-		// such types.
 -		if recv := effectiveReceiver(obj); recv != nil {
--			if err := expandMethodSearch(ctx, snapshot, obj.(*types.Func), recv, globalScope, globalTargets); err != nil {
+-			if err := expandMethodSearch(ctx, snapshot, workspaceIDs, obj.(*types.Func), recv, addRdeps, globalTargets, expansions); err != nil {
 -				return nil, err
 -			}
 -		}
@@ -82973,6 +91764,7 @@
 -	var group errgroup.Group
 -
 -	// Compute local references for each variant.
+-	// The target objects are identified by (URI, offset).
 -	for _, m := range variants {
 -		// We want the ordinary importable package,
 -		// plus any test-augmented variants, since
@@ -82988,7 +91780,73 @@
 -		}
 -		m := m
 -		group.Go(func() error {
--			return localReferences(ctx, snapshot, declURI, declPosn.Offset, m, report)
+-			// TODO(adonovan): opt: batch these TypeChecks.
+-			pkgs, err := snapshot.TypeCheck(ctx, m.ID)
+-			if err != nil {
+-				return err
+-			}
+-			pkg := pkgs[0]
+-
+-			// Find the declaration of the corresponding
+-			// object in this package based on (URI, offset).
+-			pgf, err := pkg.File(declURI)
+-			if err != nil {
+-				return err
+-			}
+-			pos, err := safetoken.Pos(pgf.Tok, declPosn.Offset)
+-			if err != nil {
+-				return err
+-			}
+-			objects, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
+-			if err != nil {
+-				return err // unreachable? (probably caught earlier)
+-			}
+-
+-			// Report the locations of the declaration(s).
+-			// TODO(adonovan): what about for corresponding methods? Add tests.
+-			for _, node := range objects {
+-				report(mustLocation(pgf, node), true)
+-			}
+-
+-			// Convert targets map to set.
+-			targets := make(map[types.Object]bool)
+-			for obj := range objects {
+-				targets[obj] = true
+-			}
+-
+-			return localReferences(pkg, targets, true, report)
+-		})
+-	}
+-
+-	// Also compute local references within packages that declare
+-	// corresponding methods (see above), which expand the global search.
+-	// The target objects are identified by (PkgPath, objectpath).
+-	for id := range expansions {
+-		id := id
+-		group.Go(func() error {
+-			// TODO(adonovan): opt: batch these TypeChecks.
+-			pkgs, err := snapshot.TypeCheck(ctx, id)
+-			if err != nil {
+-				return err
+-			}
+-			pkg := pkgs[0]
+-
+-			targets := make(map[types.Object]bool)
+-			for objpath := range globalTargets[pkg.Metadata().PkgPath] {
+-				obj, err := objectpath.Object(pkg.GetTypes(), objpath)
+-				if err != nil {
+-					// No such object, because it was
+-					// declared only in the test variant.
+-					continue
+-				}
+-				targets[obj] = true
+-			}
+-
+-			// Don't include corresponding types or methods
+-			// since expansions did that already, and we don't
+-			// want (e.g.) concrete -> interface -> concrete.
+-			const correspond = false
+-			return localReferences(pkg, targets, correspond, report)
 -		})
 -	}
 -
@@ -83017,30 +91875,28 @@
 -}
 -
 -// expandMethodSearch expands the scope and targets of a global search
--// for an exported method to include all methods that correspond to
--// it through interface satisfaction.
+-// for an exported method to include all methods in the workspace
+-// that correspond to it through interface satisfaction.
+-//
+-// Each package that declares a corresponding type is added to
+-// expansions so that we can also find local references to the type
+-// within the package, which of course requires type checking.
+-//
+-// The scope is expanded by a sequence of calls (not concurrent) to addRdeps.
 -//
 -// recv is the method's effective receiver type, for method-set computations.
--func expandMethodSearch(ctx context.Context, snapshot Snapshot, method *types.Func, recv types.Type, scope map[PackageID]*Metadata, targets map[PackagePath]map[objectpath.Path]unit) error {
+-func expandMethodSearch(ctx context.Context, snapshot Snapshot, workspaceIDs []PackageID, method *types.Func, recv types.Type, addRdeps func(id PackageID, transitive bool) error, targets map[PackagePath]map[objectpath.Path]unit, expansions map[PackageID]unit) error {
 -	// Compute the method-set fingerprint used as a key to the global search.
 -	key, hasMethods := methodsets.KeyOf(recv)
 -	if !hasMethods {
 -		return bug.Errorf("KeyOf(%s)={} yet %s is a method", recv, method)
 -	}
--	metas, err := snapshot.AllMetadata(ctx)
--	if err != nil {
--		return err
--	}
--	allIDs := make([]PackageID, 0, len(metas))
--	for _, m := range metas {
--		allIDs = append(allIDs, m.ID)
--	}
 -	// Search the methodset index of each package in the workspace.
--	indexes, err := snapshot.MethodSets(ctx, allIDs...)
+-	indexes, err := snapshot.MethodSets(ctx, workspaceIDs...)
 -	if err != nil {
 -		return err
 -	}
--	var mu sync.Mutex // guards scope and targets
+-	var mu sync.Mutex // guards addRdeps, targets, expansions
 -	var group errgroup.Group
 -	for i, index := range indexes {
 -		i := i
@@ -83052,17 +91908,21 @@
 -				return nil
 -			}
 -
--			// Expand global search scope to include rdeps of this pkg.
--			rdeps, err := snapshot.ReverseDependencies(ctx, allIDs[i], true)
--			if err != nil {
--				return err
--			}
+-			// We have discovered one or more corresponding types.
+-			id := workspaceIDs[i]
+-
 -			mu.Lock()
 -			defer mu.Unlock()
--			for _, rdep := range rdeps {
--				scope[rdep.ID] = rdep
+-
+-			// Expand global search scope to include rdeps of this pkg.
+-			if err := addRdeps(id, true); err != nil {
+-				return err
 -			}
 -
+-			// Mark this package so that we search within it for
+-			// local references to the additional types/methods.
+-			expansions[id] = unit{}
+-
 -			// Add each corresponding method the to set of global search targets.
 -			for _, res := range results {
 -				methodPkg := PackagePath(res.PkgPath)
@@ -83079,55 +91939,32 @@
 -	return group.Wait()
 -}
 -
--// localReferences reports each reference to the object
--// declared at the specified URI/offset within its enclosing package m.
--func localReferences(ctx context.Context, snapshot Snapshot, declURI span.URI, declOffset int, m *Metadata, report func(loc protocol.Location, isDecl bool)) error {
--	pkgs, err := snapshot.TypeCheck(ctx, m.ID)
--	if err != nil {
--		return err
--	}
--	pkg := pkgs[0] // narrowest
--
--	// Find declaration of corresponding object
--	// in this package based on (URI, offset).
--	pgf, err := pkg.File(declURI)
--	if err != nil {
--		return err
--	}
--	pos, err := safetoken.Pos(pgf.Tok, declOffset)
--	if err != nil {
--		return err
--	}
--	targets, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
--	if err != nil {
--		return err // unreachable? (probably caught earlier)
--	}
--
--	// Report the locations of the declaration(s).
--	// TODO(adonovan): what about for corresponding methods? Add tests.
--	for _, node := range targets {
--		report(mustLocation(pgf, node), true)
--	}
--
--	// If we're searching for references to a method, broaden the
--	// search to include references to corresponding methods of
--	// mutually assignable receiver types.
+-// localReferences traverses syntax and reports each reference to one
+-// of the target objects, or (if correspond is set) an object that
+-// corresponds to one of them via interface satisfaction.
+-func localReferences(pkg Package, targets map[types.Object]bool, correspond bool, report func(loc protocol.Location, isDecl bool)) error {
+-	// If we're searching for references to a method optionally
+-	// broaden the search to include references to corresponding
+-	// methods of mutually assignable receiver types.
 -	// (We use a slice, but objectsAt never returns >1 methods.)
 -	var methodRecvs []types.Type
 -	var methodName string // name of an arbitrary target, iff a method
--	for obj := range targets {
--		if t := effectiveReceiver(obj); t != nil {
--			methodRecvs = append(methodRecvs, t)
--			methodName = obj.Name()
+-	if correspond {
+-		for obj := range targets {
+-			if t := effectiveReceiver(obj); t != nil {
+-				methodRecvs = append(methodRecvs, t)
+-				methodName = obj.Name()
+-			}
 -		}
 -	}
 -
 -	// matches reports whether obj either is or corresponds to a target.
 -	// (Correspondence is defined as usual for interface methods.)
 -	matches := func(obj types.Object) bool {
--		if targets[obj] != nil {
+-		if containsOrigin(targets, obj) {
 -			return true
--		} else if methodRecvs != nil && obj.Name() == methodName {
+-		}
+-		if methodRecvs != nil && obj.Name() == methodName {
 -			if orecv := effectiveReceiver(obj); orecv != nil {
 -				for _, mrecv := range methodRecvs {
 -					if concreteImplementsIntf(orecv, mrecv) {
@@ -83195,6 +92032,13 @@
 -				targets[obj] = leaf
 -			}
 -		} else {
+-			// Note: prior to go1.21, go/types issue #60372 causes the position
+-			// a field Var T created for struct{*p.T} to be recorded at the
+-			// start of the field type ("*") not the location of the T.
+-			// This affects references and other gopls operations (issue #60369).
+-			// TODO(adonovan): delete this comment when we drop support for go1.20.
+-
+-			// For struct{T}, we prefer the defined field Var over the used TypeName.
 -			obj := info.ObjectOf(leaf)
 -			if obj == nil {
 -				return nil, nil, fmt.Errorf("%w for %q", errNoObjectFound, leaf.Name)
@@ -83219,17 +92063,1298 @@
 -// mustLocation reports the location interval a syntax node,
 -// which must belong to m.File.
 -//
--// Safe for use only by references2 and implementations2.
+-// Safe for use only by references and implementations.
 -func mustLocation(pgf *ParsedGoFile, n ast.Node) protocol.Location {
 -	loc, err := pgf.NodeLocation(n)
 -	if err != nil {
--		panic(err) // can't happen in references2 or implementations2
+-		panic(err) // can't happen in references or implementations
 -	}
 -	return loc
 -}
+diff -urN a/gopls/internal/lsp/source/rename.go b/gopls/internal/lsp/source/rename.go
+--- a/gopls/internal/lsp/source/rename.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/rename.go	1970-01-01 08:00:00
+@@ -1,1277 +0,0 @@
+-// Copyright 2019 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package source
+-
+-// TODO(adonovan):
+-//
+-// - method of generic concrete type -> arbitrary instances of same
+-//
+-// - make satisfy work across packages.
+-//
+-// - tests, tests, tests:
+-//   - play with renamings in the k8s tree.
+-//   - generics
+-//   - error cases (e.g. conflicts)
+-//   - renaming a symbol declared in the module cache
+-//     (currently proceeds with half of the renaming!)
+-//   - make sure all tests have both a local and a cross-package analogue.
+-//   - look at coverage
+-//   - special cases: embedded fields, interfaces, test variants,
+-//     function-local things with uppercase names;
+-//     packages with type errors (currently 'satisfy' rejects them),
+-//     package with missing imports;
+-//
+-// - measure performance in k8s.
+-//
+-// - The original gorename tool assumed well-typedness, but the gopls feature
+-//   does no such check (which actually makes it much more useful).
+-//   Audit to ensure it is safe on ill-typed code.
+-//
+-// - Generics support was no doubt buggy before but incrementalization
+-//   may have exacerbated it. If the problem were just about objects,
+-//   defs and uses it would be fairly simple, but type assignability
+-//   comes into play in the 'satisfy' check for method renamings.
+-//   De-instantiating Vector[int] to Vector[T] changes its type.
+-//   We need to come up with a theory for the satisfy check that
+-//   works with generics, and across packages. We currently have no
+-//   simple way to pass types between packages (think: objectpath for
+-//   types), though presumably exportdata could be pressed into service.
+-//
+-// - FileID-based de-duplication of edits to different URIs for the same file.
+-
+-import (
+-	"context"
+-	"errors"
+-	"fmt"
+-	"go/ast"
+-	"go/token"
+-	"go/types"
+-	"path"
+-	"path/filepath"
+-	"regexp"
+-	"sort"
+-	"strconv"
+-	"strings"
+-
+-	"golang.org/x/mod/modfile"
+-	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/go/types/objectpath"
+-	"golang.org/x/tools/go/types/typeutil"
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/safetoken"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/diff"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/typeparams"
+-	"golang.org/x/tools/refactor/satisfy"
+-)
+-
+-// A renamer holds state of a single call to renameObj, which renames
+-// an object (or several coupled objects) within a single type-checked
+-// syntax package.
+-type renamer struct {
+-	pkg                Package               // the syntax package in which the renaming is applied
+-	objsToUpdate       map[types.Object]bool // records progress of calls to check
+-	hadConflicts       bool
+-	conflicts          []string
+-	from, to           string
+-	satisfyConstraints map[satisfy.Constraint]bool
+-	msets              typeutil.MethodSetCache
+-	changeMethods      bool
+-}
+-
+-// A PrepareItem holds the result of a "prepare rename" operation:
+-// the source range and value of a selected identifier.
+-type PrepareItem struct {
+-	Range protocol.Range
+-	Text  string
+-}
+-
+-// PrepareRename searches for a valid renaming at position pp.
+-//
+-// The returned usererr is intended to be displayed to the user to explain why
+-// the prepare fails. Probably we could eliminate the redundancy in returning
+-// two errors, but for now this is done defensively.
+-func PrepareRename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) (_ *PrepareItem, usererr, err error) {
+-	ctx, done := event.Start(ctx, "source.PrepareRename")
+-	defer done()
+-
+-	// Is the cursor within the package name declaration?
+-	if pgf, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp); err != nil {
+-		return nil, err, err
+-	} else if inPackageName {
+-		item, err := prepareRenamePackageName(ctx, snapshot, pgf)
+-		return item, err, err
+-	}
+-
+-	// Ordinary (non-package) renaming.
+-	//
+-	// Type-check the current package, locate the reference at the position,
+-	// validate the object, and report its name and range.
+-	//
+-	// TODO(adonovan): in all cases below, we return usererr=nil,
+-	// which means we return (nil, nil) at the protocol
+-	// layer. This seems like a bug, or at best an exploitation of
+-	// knowledge of VSCode-specific behavior. Can we avoid that?
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, f.URI())
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	pos, err := pgf.PositionPos(pp)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	targets, node, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	var obj types.Object
+-	for obj = range targets {
+-		break // pick one arbitrarily
+-	}
+-	if err := checkRenamable(obj); err != nil {
+-		return nil, nil, err
+-	}
+-	rng, err := pgf.NodeRange(node)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-	if _, isImport := node.(*ast.ImportSpec); isImport {
+-		// We're not really renaming the import path.
+-		rng.End = rng.Start
+-	}
+-	return &PrepareItem{
+-		Range: rng,
+-		Text:  obj.Name(),
+-	}, nil, nil
+-}
+-
+-func prepareRenamePackageName(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile) (*PrepareItem, error) {
+-	// Does the client support file renaming?
+-	fileRenameSupported := false
+-	for _, op := range snapshot.Options().SupportedResourceOperations {
+-		if op == protocol.Rename {
+-			fileRenameSupported = true
+-			break
+-		}
+-	}
+-	if !fileRenameSupported {
+-		return nil, errors.New("can't rename package: LSP client does not support file renaming")
+-	}
+-
+-	// Check validity of the metadata for the file's containing package.
+-	meta, err := NarrowestMetadataForFile(ctx, snapshot, pgf.URI)
+-	if err != nil {
+-		return nil, err
+-	}
+-	if meta.Name == "main" {
+-		return nil, fmt.Errorf("can't rename package \"main\"")
+-	}
+-	if strings.HasSuffix(string(meta.Name), "_test") {
+-		return nil, fmt.Errorf("can't rename x_test packages")
+-	}
+-	if meta.Module == nil {
+-		return nil, fmt.Errorf("can't rename package: missing module information for package %q", meta.PkgPath)
+-	}
+-	if meta.Module.Path == string(meta.PkgPath) {
+-		return nil, fmt.Errorf("can't rename package: package path %q is the same as module path %q", meta.PkgPath, meta.Module.Path)
+-	}
+-
+-	// Return the location of the package declaration.
+-	rng, err := pgf.NodeRange(pgf.File.Name)
+-	if err != nil {
+-		return nil, err
+-	}
+-	return &PrepareItem{
+-		Range: rng,
+-		Text:  string(meta.Name),
+-	}, nil
+-}
+-
+-func checkRenamable(obj types.Object) error {
+-	switch obj := obj.(type) {
+-	case *types.Var:
+-		if obj.Embedded() {
+-			return fmt.Errorf("can't rename embedded fields: rename the type directly or name the field")
+-		}
+-	case *types.Builtin, *types.Nil:
+-		return fmt.Errorf("%s is built in and cannot be renamed", obj.Name())
+-	}
+-	if obj.Pkg() == nil || obj.Pkg().Path() == "unsafe" {
+-		// e.g. error.Error, unsafe.Pointer
+-		return fmt.Errorf("%s is built in and cannot be renamed", obj.Name())
+-	}
+-	if obj.Name() == "_" {
+-		return errors.New("can't rename \"_\"")
+-	}
+-	return nil
+-}
+-
+-// Rename returns a map of TextEdits for each file modified when renaming a
+-// given identifier within a package and a boolean value of true for renaming
+-// package and false otherwise.
+-func Rename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]protocol.TextEdit, bool, error) {
+-	ctx, done := event.Start(ctx, "source.Rename")
+-	defer done()
+-
+-	if !isValidIdentifier(newName) {
+-		return nil, false, fmt.Errorf("invalid identifier to rename: %q", newName)
+-	}
+-
+-	// Cursor within package name declaration?
+-	_, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp)
+-	if err != nil {
+-		return nil, false, err
+-	}
+-
+-	var editMap map[span.URI][]diff.Edit
+-	if inPackageName {
+-		editMap, err = renamePackageName(ctx, snapshot, f, PackageName(newName))
+-	} else {
+-		editMap, err = renameOrdinary(ctx, snapshot, f, pp, newName)
+-	}
+-	if err != nil {
+-		return nil, false, err
+-	}
+-
+-	// Convert edits to protocol form.
+-	result := make(map[span.URI][]protocol.TextEdit)
+-	for uri, edits := range editMap {
+-		// Sort and de-duplicate edits.
+-		//
+-		// Overlapping edits may arise in local renamings (due
+-		// to type switch implicits) and globals ones (due to
+-		// processing multiple package variants).
+-		//
+-		// We assume renaming produces diffs that are all
+-		// replacements (no adjacent insertions that might
+-		// become reordered) and that are either identical or
+-		// non-overlapping.
+-		diff.SortEdits(edits)
+-		filtered := edits[:0]
+-		for i, edit := range edits {
+-			if i == 0 || edit != filtered[len(filtered)-1] {
+-				filtered = append(filtered, edit)
+-			}
+-		}
+-		edits = filtered
+-
+-		// TODO(adonovan): the logic above handles repeat edits to the
+-		// same file URI (e.g. as a member of package p and p_test) but
+-		// is not sufficient to handle file-system level aliasing arising
+-		// from symbolic or hard links. For that, we should use a
+-		// robustio-FileID-keyed map.
+-		// See https://go.dev/cl/457615 for example.
+-		// This really occurs in practice, e.g. kubernetes has
+-		// vendor/k8s.io/kubectl -> ../../staging/src/k8s.io/kubectl.
+-		fh, err := snapshot.ReadFile(ctx, uri)
+-		if err != nil {
+-			return nil, false, err
+-		}
+-		data, err := fh.Content()
+-		if err != nil {
+-			return nil, false, err
+-		}
+-		m := protocol.NewMapper(uri, data)
+-		protocolEdits, err := ToProtocolEdits(m, edits)
+-		if err != nil {
+-			return nil, false, err
+-		}
+-		result[uri] = protocolEdits
+-	}
+-
+-	return result, inPackageName, nil
+-}
+-
+-// renameOrdinary renames an ordinary (non-package) name throughout the workspace.
+-func renameOrdinary(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]diff.Edit, error) {
+-	// Type-check the referring package and locate the object(s).
+-	//
+-	// Unlike NarrowestPackageForFile, this operation prefers the
+-	// widest variant as, for non-exported identifiers, it is the
+-	// only package we need. (In case you're wondering why
+-	// 'references' doesn't also want the widest variant: it
+-	// computes the union across all variants.)
+-	var targets map[types.Object]ast.Node
+-	var pkg Package
+-	{
+-		metas, err := snapshot.MetadataForFile(ctx, f.URI())
+-		if err != nil {
+-			return nil, err
+-		}
+-		RemoveIntermediateTestVariants(&metas)
+-		if len(metas) == 0 {
+-			return nil, fmt.Errorf("no package metadata for file %s", f.URI())
+-		}
+-		widest := metas[len(metas)-1] // widest variant may include _test.go files
+-		pkgs, err := snapshot.TypeCheck(ctx, widest.ID)
+-		if err != nil {
+-			return nil, err
+-		}
+-		pkg = pkgs[0]
+-		pgf, err := pkg.File(f.URI())
+-		if err != nil {
+-			return nil, err // "can't happen"
+-		}
+-		pos, err := pgf.PositionPos(pp)
+-		if err != nil {
+-			return nil, err
+-		}
+-		objects, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
+-		if err != nil {
+-			return nil, err
+-		}
+-		targets = objects
+-	}
+-
+-	// Pick a representative object arbitrarily.
+-	// (All share the same name, pos, and kind.)
+-	var obj types.Object
+-	for obj = range targets {
+-		break
+-	}
+-	if obj.Name() == newName {
+-		return nil, fmt.Errorf("old and new names are the same: %s", newName)
+-	}
+-	if err := checkRenamable(obj); err != nil {
+-		return nil, err
+-	}
+-
+-	// Find objectpath, if object is exported ("" otherwise).
+-	var declObjPath objectpath.Path
+-	if obj.Exported() {
+-		// objectpath.For requires the origin of a generic function or type, not an
+-		// instantiation (a bug?). Unfortunately we can't call Func.Origin as this
+-		// is not available in go/types@go1.18. So we take a scenic route.
+-		//
+-		// Note that unlike Funcs, TypeNames are always canonical (they are "left"
+-		// of the type parameters, unlike methods).
+-		switch obj.(type) { // avoid "obj :=" since cases reassign the var
+-		case *types.TypeName:
+-			if _, ok := obj.Type().(*typeparams.TypeParam); ok {
+-				// As with capitalized function parameters below, type parameters are
+-				// local.
+-				goto skipObjectPath
+-			}
+-		case *types.Func:
+-			obj = funcOrigin(obj.(*types.Func))
+-		case *types.Var:
+-			// TODO(adonovan): do vars need the origin treatment too? (issue #58462)
+-
+-			// Function parameter and result vars that are (unusually)
+-			// capitalized are technically exported, even though they
+-			// cannot be referenced, because they may affect downstream
+-			// error messages. But we can safely treat them as local.
+-			//
+-			// This is not merely an optimization: the renameExported
+-			// operation gets confused by such vars. It finds them from
+-			// objectpath, the classifies them as local vars, but as
+-			// they came from export data they lack syntax and the
+-			// correct scope tree (issue #61294).
+-			if !obj.(*types.Var).IsField() && !isPackageLevel(obj) {
+-				goto skipObjectPath
+-			}
+-		}
+-		if path, err := objectpath.For(obj); err == nil {
+-			declObjPath = path
+-		}
+-	skipObjectPath:
+-	}
+-
+-	// Nonexported? Search locally.
+-	if declObjPath == "" {
+-		var objects []types.Object
+-		for obj := range targets {
+-			objects = append(objects, obj)
+-		}
+-		editMap, _, err := renameObjects(ctx, snapshot, newName, pkg, objects...)
+-		return editMap, err
+-	}
+-
+-	// Exported: search globally.
+-	//
+-	// For exported package-level var/const/func/type objects, the
+-	// search scope is just the direct importers.
+-	//
+-	// For exported fields and methods, the scope is the
+-	// transitive rdeps. (The exportedness of the field's struct
+-	// or method's receiver is irrelevant.)
+-	transitive := false
+-	switch obj.(type) {
+-	case *types.TypeName:
+-		// Renaming an exported package-level type
+-		// requires us to inspect all transitive rdeps
+-		// in the event that the type is embedded.
+-		//
+-		// TODO(adonovan): opt: this is conservative
+-		// but inefficient. Instead, expand the scope
+-		// of the search only if we actually encounter
+-		// an embedding of the type, and only then to
+-		// the rdeps of the embedding package.
+-		if obj.Parent() == obj.Pkg().Scope() {
+-			transitive = true
+-		}
+-
+-	case *types.Var:
+-		if obj.(*types.Var).IsField() {
+-			transitive = true // field
+-		}
+-
+-		// TODO(adonovan): opt: process only packages that
+-		// contain a reference (xrefs) to the target field.
+-
+-	case *types.Func:
+-		if obj.Type().(*types.Signature).Recv() != nil {
+-			transitive = true // method
+-		}
+-
+-		// It's tempting to optimize by skipping
+-		// packages that don't contain a reference to
+-		// the method in the xrefs index, but we still
+-		// need to apply the satisfy check to those
+-		// packages to find assignment statements that
+-		// might expands the scope of the renaming.
+-	}
+-
+-	// Type-check all the packages to inspect.
+-	declURI := span.URIFromPath(pkg.FileSet().File(obj.Pos()).Name())
+-	pkgs, err := typeCheckReverseDependencies(ctx, snapshot, declURI, transitive)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	// Apply the renaming to the (initial) object.
+-	declPkgPath := PackagePath(obj.Pkg().Path())
+-	return renameExported(ctx, snapshot, pkgs, declPkgPath, declObjPath, newName)
+-}
+-
+-// funcOrigin is a go1.18-portable implementation of (*types.Func).Origin.
+-func funcOrigin(fn *types.Func) *types.Func {
+-	// Method?
+-	if fn.Type().(*types.Signature).Recv() != nil {
+-		return typeparams.OriginMethod(fn)
+-	}
+-
+-	// Package-level function?
+-	// (Assume the origin has the same position.)
+-	gen := fn.Pkg().Scope().Lookup(fn.Name())
+-	if gen != nil && gen.Pos() == fn.Pos() {
+-		return gen.(*types.Func)
+-	}
+-
+-	return fn
+-}
+-
+-// typeCheckReverseDependencies returns the type-checked packages for
+-// the reverse dependencies of all packages variants containing
+-// file declURI. The packages are in some topological order.
+-//
+-// It includes all variants (even intermediate test variants) for the
+-// purposes of computing reverse dependencies, but discards ITVs for
+-// the actual renaming work.
+-//
+-// (This neglects obscure edge cases where a _test.go file changes the
+-// selectors used only in an ITV, but life is short. Also sin must be
+-// punished.)
+-func typeCheckReverseDependencies(ctx context.Context, snapshot Snapshot, declURI span.URI, transitive bool) ([]Package, error) {
+-	variants, err := snapshot.MetadataForFile(ctx, declURI)
+-	if err != nil {
+-		return nil, err
+-	}
+-	// variants must include ITVs for the reverse dependency
+-	// computation, but they are filtered out before we typecheck.
+-	allRdeps := make(map[PackageID]*Metadata)
+-	for _, variant := range variants {
+-		rdeps, err := snapshot.ReverseDependencies(ctx, variant.ID, transitive)
+-		if err != nil {
+-			return nil, err
+-		}
+-		allRdeps[variant.ID] = variant // include self
+-		for id, meta := range rdeps {
+-			allRdeps[id] = meta
+-		}
+-	}
+-	var ids []PackageID
+-	for id, meta := range allRdeps {
+-		if meta.IsIntermediateTestVariant() {
+-			continue
+-		}
+-		ids = append(ids, id)
+-	}
+-
+-	// Sort the packages into some topological order of the
+-	// (unfiltered) metadata graph.
+-	SortPostOrder(snapshot, ids)
+-
+-	// Dependencies must be visited first since they can expand
+-	// the search set. Ideally we would process the (filtered) set
+-	// of packages in the parallel postorder of the snapshot's
+-	// (unfiltered) metadata graph, but this is quite tricky
+-	// without a good graph abstraction.
+-	//
+-	// For now, we visit packages sequentially in order of
+-	// ascending height, like an inverted breadth-first search.
+-	//
+-	// Type checking is by far the dominant cost, so
+-	// overlapping it with renaming may not be worthwhile.
+-	return snapshot.TypeCheck(ctx, ids...)
+-}
+-
+-// SortPostOrder sorts the IDs so that if x depends on y, then y appears before x.
+-func SortPostOrder(meta MetadataSource, ids []PackageID) {
+-	postorder := make(map[PackageID]int)
+-	order := 0
+-	var visit func(PackageID)
+-	visit = func(id PackageID) {
+-		if _, ok := postorder[id]; !ok {
+-			postorder[id] = -1 // break recursion
+-			if m := meta.Metadata(id); m != nil {
+-				for _, depID := range m.DepsByPkgPath {
+-					visit(depID)
+-				}
+-			}
+-			order++
+-			postorder[id] = order
+-		}
+-	}
+-	for _, id := range ids {
+-		visit(id)
+-	}
+-	sort.Slice(ids, func(i, j int) bool {
+-		return postorder[ids[i]] < postorder[ids[j]]
+-	})
+-}
+-
+-// renameExported renames the object denoted by (pkgPath, objPath)
+-// within the specified packages, along with any other objects that
+-// must be renamed as a consequence. The slice of packages must be
+-// topologically ordered.
+-func renameExported(ctx context.Context, snapshot Snapshot, pkgs []Package, declPkgPath PackagePath, declObjPath objectpath.Path, newName string) (map[span.URI][]diff.Edit, error) {
+-
+-	// A target is a name for an object that is stable across types.Packages.
+-	type target struct {
+-		pkg PackagePath
+-		obj objectpath.Path
+-	}
+-
+-	// Populate the initial set of target objects.
+-	// This set may grow as we discover the consequences of each renaming.
+-	//
+-	// TODO(adonovan): strictly, each cone of reverse dependencies
+-	// of a single variant should have its own target map that
+-	// monotonically expands as we go up the import graph, because
+-	// declarations in test files can alter the set of
+-	// package-level names and change the meaning of field and
+-	// method selectors. So if we parallelize the graph
+-	// visitation (see above), we should also compute the targets
+-	// as a union of dependencies.
+-	//
+-	// Or we could decide that the logic below is fast enough not
+-	// to need parallelism. In small measurements so far the
+-	// type-checking step is about 95% and the renaming only 5%.
+-	targets := map[target]bool{{declPkgPath, declObjPath}: true}
+-
+-	// Apply the renaming operation to each package.
+-	allEdits := make(map[span.URI][]diff.Edit)
+-	for _, pkg := range pkgs {
+-
+-		// Resolved target objects within package pkg.
+-		var objects []types.Object
+-		for t := range targets {
+-			p := pkg.DependencyTypes(t.pkg)
+-			if p == nil {
+-				continue // indirect dependency of no consequence
+-			}
+-			obj, err := objectpath.Object(p, t.obj)
+-			if err != nil {
+-				// Possibly a method or an unexported type
+-				// that is not reachable through export data?
+-				// See https://github.com/golang/go/issues/60789.
+-				//
+-				// TODO(adonovan): it seems unsatisfactory that Object
+-				// should return an error for a "valid" path. Perhaps
+-				// we should define such paths as invalid and make
+-				// objectpath.For compute reachability?
+-				// Would that be a compatible change?
+-				continue
+-			}
+-			objects = append(objects, obj)
+-		}
+-		if len(objects) == 0 {
+-			continue // no targets of consequence to this package
+-		}
+-
+-		// Apply the renaming.
+-		editMap, moreObjects, err := renameObjects(ctx, snapshot, newName, pkg, objects...)
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		// It is safe to concatenate the edits as they are non-overlapping
+-		// (or identical, in which case they will be de-duped by Rename).
+-		for uri, edits := range editMap {
+-			allEdits[uri] = append(allEdits[uri], edits...)
+-		}
+-
+-		// Expand the search set?
+-		for obj := range moreObjects {
+-			objpath, err := objectpath.For(obj)
+-			if err != nil {
+-				continue // not exported
+-			}
+-			target := target{PackagePath(obj.Pkg().Path()), objpath}
+-			targets[target] = true
+-
+-			// TODO(adonovan): methods requires dynamic
+-			// programming of the product targets x
+-			// packages as any package might add a new
+-			// target (from a foward dep) as a
+-			// consequence, and any target might imply a
+-			// new set of rdeps. See golang/go#58461.
+-		}
+-	}
+-
+-	return allEdits, nil
+-}
+-
+-// renamePackageName renames package declarations, imports, and go.mod files.
+-func renamePackageName(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) {
+-	// Rename the package decl and all imports.
+-	renamingEdits, err := renamePackage(ctx, s, f, newName)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	// Update the last component of the file's enclosing directory.
+-	oldBase := filepath.Dir(f.URI().Filename())
+-	newPkgDir := filepath.Join(filepath.Dir(oldBase), string(newName))
+-
+-	// Update any affected replace directives in go.mod files.
+-	// TODO(adonovan): extract into its own function.
+-	//
+-	// Get all workspace modules.
+-	// TODO(adonovan): should this operate on all go.mod files,
+-	// irrespective of whether they are included in the workspace?
+-	modFiles := s.ModFiles()
+-	for _, m := range modFiles {
+-		fh, err := s.ReadFile(ctx, m)
+-		if err != nil {
+-			return nil, err
+-		}
+-		pm, err := s.ParseMod(ctx, fh)
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		modFileDir := filepath.Dir(pm.URI.Filename())
+-		affectedReplaces := []*modfile.Replace{}
+-
+-		// Check if any replace directives need to be fixed
+-		for _, r := range pm.File.Replace {
+-			if !strings.HasPrefix(r.New.Path, "/") && !strings.HasPrefix(r.New.Path, "./") && !strings.HasPrefix(r.New.Path, "../") {
+-				continue
+-			}
+-
+-			replacedPath := r.New.Path
+-			if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") {
+-				replacedPath = filepath.Join(modFileDir, r.New.Path)
+-			}
+-
+-			// TODO: Is there a risk of converting a '\' delimited replacement to a '/' delimited replacement?
+-			if !strings.HasPrefix(filepath.ToSlash(replacedPath)+"/", filepath.ToSlash(oldBase)+"/") {
+-				continue // not affected by the package renaming
+-			}
+-
+-			affectedReplaces = append(affectedReplaces, r)
+-		}
+-
+-		if len(affectedReplaces) == 0 {
+-			continue
+-		}
+-		copied, err := modfile.Parse("", pm.Mapper.Content, nil)
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		for _, r := range affectedReplaces {
+-			replacedPath := r.New.Path
+-			if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") {
+-				replacedPath = filepath.Join(modFileDir, r.New.Path)
+-			}
+-
+-			suffix := strings.TrimPrefix(replacedPath, string(oldBase))
+-
+-			newReplacedPath, err := filepath.Rel(modFileDir, newPkgDir+suffix)
+-			if err != nil {
+-				return nil, err
+-			}
+-
+-			newReplacedPath = filepath.ToSlash(newReplacedPath)
+-
+-			if !strings.HasPrefix(newReplacedPath, "/") && !strings.HasPrefix(newReplacedPath, "../") {
+-				newReplacedPath = "./" + newReplacedPath
+-			}
+-
+-			if err := copied.AddReplace(r.Old.Path, "", newReplacedPath, ""); err != nil {
+-				return nil, err
+-			}
+-		}
+-
+-		copied.Cleanup()
+-		newContent, err := copied.Format()
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		// Calculate the edits to be made due to the change.
+-		edits := s.Options().ComputeEdits(string(pm.Mapper.Content), string(newContent))
+-		renamingEdits[pm.URI] = append(renamingEdits[pm.URI], edits...)
+-	}
+-
+-	return renamingEdits, nil
+-}
+-
+-// renamePackage computes all workspace edits required to rename the package
+-// described by the given metadata, to newName, by renaming its package
+-// directory.
+-//
+-// It updates package clauses and import paths for the renamed package as well
+-// as any other packages affected by the directory renaming among all packages
+-// known to the snapshot.
+-func renamePackage(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) {
+-	if strings.HasSuffix(string(newName), "_test") {
+-		return nil, fmt.Errorf("cannot rename to _test package")
+-	}
+-
+-	// We need metadata for the relevant package and module paths.
+-	// These should be the same for all packages containing the file.
+-	meta, err := NarrowestMetadataForFile(ctx, s, f.URI())
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	oldPkgPath := meta.PkgPath
+-	if meta.Module == nil {
+-		return nil, fmt.Errorf("cannot rename package: missing module information for package %q", meta.PkgPath)
+-	}
+-	modulePath := PackagePath(meta.Module.Path)
+-	if modulePath == oldPkgPath {
+-		return nil, fmt.Errorf("cannot rename package: module path %q is the same as the package path, so renaming the package directory would have no effect", modulePath)
+-	}
+-
+-	newPathPrefix := path.Join(path.Dir(string(oldPkgPath)), string(newName))
+-
+-	// We must inspect all packages, not just direct importers,
+-	// because we also rename subpackages, which may be unrelated.
+-	// (If the renamed package imports a subpackage it may require
+-	// edits to both its package and import decls.)
+-	allMetadata, err := s.AllMetadata(ctx)
+-	if err != nil {
+-		return nil, err
+-	}
+-
+-	// Rename package and import declarations in all relevant packages.
+-	edits := make(map[span.URI][]diff.Edit)
+-	for _, m := range allMetadata {
+-		// Special case: x_test packages for the renamed package will not have the
+-		// package path as a dir prefix, but still need their package clauses
+-		// renamed.
+-		if m.PkgPath == oldPkgPath+"_test" {
+-			if err := renamePackageClause(ctx, m, s, newName+"_test", edits); err != nil {
+-				return nil, err
+-			}
+-			continue
+-		}
+-
+-		// Subtle: check this condition before checking for valid module info
+-		// below, because we should not fail this operation if unrelated packages
+-		// lack module info.
+-		if !strings.HasPrefix(string(m.PkgPath)+"/", string(oldPkgPath)+"/") {
+-			continue // not affected by the package renaming
+-		}
+-
+-		if m.Module == nil {
+-			// This check will always fail under Bazel.
+-			return nil, fmt.Errorf("cannot rename package: missing module information for package %q", m.PkgPath)
+-		}
+-
+-		if modulePath != PackagePath(m.Module.Path) {
+-			continue // don't edit imports if nested package and renaming package have different module paths
+-		}
+-
+-		// Renaming a package consists of changing its import path and package name.
+-		suffix := strings.TrimPrefix(string(m.PkgPath), string(oldPkgPath))
+-		newPath := newPathPrefix + suffix
+-
+-		pkgName := m.Name
+-		if m.PkgPath == oldPkgPath {
+-			pkgName = PackageName(newName)
+-
+-			if err := renamePackageClause(ctx, m, s, newName, edits); err != nil {
+-				return nil, err
+-			}
+-		}
+-
+-		imp := ImportPath(newPath) // TODO(adonovan): what if newPath has vendor/ prefix?
+-		if err := renameImports(ctx, s, m, imp, pkgName, edits); err != nil {
+-			return nil, err
+-		}
+-	}
+-
+-	return edits, nil
+-}
+-
+-// renamePackageClause computes edits renaming the package clause of files in
+-// the package described by the given metadata, to newName.
+-//
+-// Edits are written into the edits map.
+-func renamePackageClause(ctx context.Context, m *Metadata, snapshot Snapshot, newName PackageName, edits map[span.URI][]diff.Edit) error {
+-	// Rename internal references to the package in the renaming package.
+-	for _, uri := range m.CompiledGoFiles {
+-		fh, err := snapshot.ReadFile(ctx, uri)
+-		if err != nil {
+-			return err
+-		}
+-		f, err := snapshot.ParseGo(ctx, fh, ParseHeader)
+-		if err != nil {
+-			return err
+-		}
+-		if f.File.Name == nil {
+-			continue // no package declaration
+-		}
+-
+-		edit, err := posEdit(f.Tok, f.File.Name.Pos(), f.File.Name.End(), string(newName))
+-		if err != nil {
+-			return err
+-		}
+-		edits[f.URI] = append(edits[f.URI], edit)
+-	}
+-
+-	return nil
+-}
+-
+-// renameImports computes the set of edits to imports resulting from renaming
+-// the package described by the given metadata, to a package with import path
+-// newPath and name newName.
+-//
+-// Edits are written into the edits map.
+-func renameImports(ctx context.Context, snapshot Snapshot, m *Metadata, newPath ImportPath, newName PackageName, allEdits map[span.URI][]diff.Edit) error {
+-	rdeps, err := snapshot.ReverseDependencies(ctx, m.ID, false) // find direct importers
+-	if err != nil {
+-		return err
+-	}
+-
+-	// Pass 1: rename import paths in import declarations.
+-	needsTypeCheck := make(map[PackageID][]span.URI)
+-	for _, rdep := range rdeps {
+-		if rdep.IsIntermediateTestVariant() {
+-			continue // for renaming, these variants are redundant
+-		}
+-
+-		for _, uri := range rdep.CompiledGoFiles {
+-			fh, err := snapshot.ReadFile(ctx, uri)
+-			if err != nil {
+-				return err
+-			}
+-			f, err := snapshot.ParseGo(ctx, fh, ParseHeader)
+-			if err != nil {
+-				return err
+-			}
+-			if f.File.Name == nil {
+-				continue // no package declaration
+-			}
+-			for _, imp := range f.File.Imports {
+-				if rdep.DepsByImpPath[UnquoteImportPath(imp)] != m.ID {
+-					continue // not the import we're looking for
+-				}
+-
+-				// If the import does not explicitly specify
+-				// a local name, then we need to invoke the
+-				// type checker to locate references to update.
+-				//
+-				// TODO(adonovan): is this actually true?
+-				// Renaming an import with a local name can still
+-				// cause conflicts: shadowing of built-ins, or of
+-				// package-level decls in the same or another file.
+-				if imp.Name == nil {
+-					needsTypeCheck[rdep.ID] = append(needsTypeCheck[rdep.ID], uri)
+-				}
+-
+-				// Create text edit for the import path (string literal).
+-				edit, err := posEdit(f.Tok, imp.Path.Pos(), imp.Path.End(), strconv.Quote(string(newPath)))
+-				if err != nil {
+-					return err
+-				}
+-				allEdits[uri] = append(allEdits[uri], edit)
+-			}
+-		}
+-	}
+-
+-	// If the imported package's name hasn't changed,
+-	// we don't need to rename references within each file.
+-	if newName == m.Name {
+-		return nil
+-	}
+-
+-	// Pass 2: rename local name (types.PkgName) of imported
+-	// package throughout one or more files of the package.
+-	ids := make([]PackageID, 0, len(needsTypeCheck))
+-	for id := range needsTypeCheck {
+-		ids = append(ids, id)
+-	}
+-	pkgs, err := snapshot.TypeCheck(ctx, ids...)
+-	if err != nil {
+-		return err
+-	}
+-	for i, id := range ids {
+-		pkg := pkgs[i]
+-		for _, uri := range needsTypeCheck[id] {
+-			f, err := pkg.File(uri)
+-			if err != nil {
+-				return err
+-			}
+-			for _, imp := range f.File.Imports {
+-				if imp.Name != nil {
+-					continue // has explicit local name
+-				}
+-				if rdeps[id].DepsByImpPath[UnquoteImportPath(imp)] != m.ID {
+-					continue // not the import we're looking for
+-				}
+-
+-				pkgname := pkg.GetTypesInfo().Implicits[imp].(*types.PkgName)
+-
+-				pkgScope := pkg.GetTypes().Scope()
+-				fileScope := pkg.GetTypesInfo().Scopes[f.File]
+-
+-				localName := string(newName)
+-				try := 0
+-
+-				// Keep trying with fresh names until one succeeds.
+-				//
+-				// TODO(adonovan): fix: this loop is not sufficient to choose a name
+-				// that is guaranteed to be conflict-free; renameObj may still fail.
+-				// So the retry loop should be around renameObj, and we shouldn't
+-				// bother with scopes here.
+-				for fileScope.Lookup(localName) != nil || pkgScope.Lookup(localName) != nil {
+-					try++
+-					localName = fmt.Sprintf("%s%d", newName, try)
+-				}
+-
+-				// renameObj detects various conflicts, including:
+-				// - new name conflicts with a package-level decl in this file;
+-				// - new name hides a package-level decl in another file that
+-				//   is actually referenced in this file;
+-				// - new name hides a built-in that is actually referenced
+-				//   in this file;
+-				// - a reference in this file to the old package name would
+-				//   become shadowed by an intervening declaration that
+-				//   uses the new name.
+-				// It returns the edits if no conflict was detected.
+-				editMap, _, err := renameObjects(ctx, snapshot, localName, pkg, pkgname)
+-				if err != nil {
+-					return err
+-				}
+-
+-				// If the chosen local package name matches the package's
+-				// new name, delete the change that would have inserted
+-				// an explicit local name, which is always the lexically
+-				// first change.
+-				if localName == string(newName) {
+-					edits, ok := editMap[uri]
+-					if !ok {
+-						return fmt.Errorf("internal error: no changes for %s", uri)
+-					}
+-					diff.SortEdits(edits)
+-					editMap[uri] = edits[1:]
+-				}
+-				for uri, edits := range editMap {
+-					allEdits[uri] = append(allEdits[uri], edits...)
+-				}
+-			}
+-		}
+-	}
+-	return nil
+-}
+-
+-// renameObjects computes the edits to the type-checked syntax package pkg
+-// required to rename a set of target objects to newName.
+-//
+-// It also returns the set of objects that were found (due to
+-// corresponding methods and embedded fields) to require renaming as a
+-// consequence of the requested renamings.
+-//
+-// It returns an error if the renaming would cause a conflict.
+-func renameObjects(ctx context.Context, snapshot Snapshot, newName string, pkg Package, targets ...types.Object) (map[span.URI][]diff.Edit, map[types.Object]bool, error) {
+-	r := renamer{
+-		pkg:          pkg,
+-		objsToUpdate: make(map[types.Object]bool),
+-		from:         targets[0].Name(),
+-		to:           newName,
+-	}
+-
+-	// A renaming initiated at an interface method indicates the
+-	// intention to rename abstract and concrete methods as needed
+-	// to preserve assignability.
+-	// TODO(adonovan): pull this into the caller.
+-	for _, obj := range targets {
+-		if obj, ok := obj.(*types.Func); ok {
+-			recv := obj.Type().(*types.Signature).Recv()
+-			if recv != nil && types.IsInterface(recv.Type().Underlying()) {
+-				r.changeMethods = true
+-				break
+-			}
+-		}
+-	}
+-
+-	// Check that the renaming of the identifier is ok.
+-	for _, obj := range targets {
+-		r.check(obj)
+-		if len(r.conflicts) > 0 {
+-			// Stop at first error.
+-			return nil, nil, fmt.Errorf("%s", strings.Join(r.conflicts, "\n"))
+-		}
+-	}
+-
+-	editMap, err := r.update()
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-
+-	// Remove initial targets so that only 'consequences' remain.
+-	for _, obj := range targets {
+-		delete(r.objsToUpdate, obj)
+-	}
+-	return editMap, r.objsToUpdate, nil
+-}
+-
+-// Rename all references to the target objects.
+-func (r *renamer) update() (map[span.URI][]diff.Edit, error) {
+-	result := make(map[span.URI][]diff.Edit)
+-
+-	// shouldUpdate reports whether obj is one of (or an
+-	// instantiation of one of) the target objects.
+-	shouldUpdate := func(obj types.Object) bool {
+-		return containsOrigin(r.objsToUpdate, obj)
+-	}
+-
+-	// Find all identifiers in the package that define or use a
+-	// renamed object. We iterate over info as it is more efficient
+-	// than calling ast.Inspect for each of r.pkg.CompiledGoFiles().
+-	type item struct {
+-		node  ast.Node // Ident, ImportSpec (obj=PkgName), or CaseClause (obj=Var)
+-		obj   types.Object
+-		isDef bool
+-	}
+-	var items []item
+-	info := r.pkg.GetTypesInfo()
+-	for id, obj := range info.Uses {
+-		if shouldUpdate(obj) {
+-			items = append(items, item{id, obj, false})
+-		}
+-	}
+-	for id, obj := range info.Defs {
+-		if shouldUpdate(obj) {
+-			items = append(items, item{id, obj, true})
+-		}
+-	}
+-	for node, obj := range info.Implicits {
+-		if shouldUpdate(obj) {
+-			switch node.(type) {
+-			case *ast.ImportSpec, *ast.CaseClause:
+-				items = append(items, item{node, obj, true})
+-			}
+-		}
+-	}
+-	sort.Slice(items, func(i, j int) bool {
+-		return items[i].node.Pos() < items[j].node.Pos()
+-	})
+-
+-	// Update each identifier.
+-	for _, item := range items {
+-		pgf, ok := enclosingFile(r.pkg, item.node.Pos())
+-		if !ok {
+-			bug.Reportf("edit does not belong to syntax of package %q", r.pkg)
+-			continue
+-		}
+-
+-		// Renaming a types.PkgName may result in the addition or removal of an identifier,
+-		// so we deal with this separately.
+-		if pkgName, ok := item.obj.(*types.PkgName); ok && item.isDef {
+-			edit, err := r.updatePkgName(pgf, pkgName)
+-			if err != nil {
+-				return nil, err
+-			}
+-			result[pgf.URI] = append(result[pgf.URI], edit)
+-			continue
+-		}
+-
+-		// Workaround the unfortunate lack of a Var object
+-		// for x in "switch x := expr.(type) {}" by adjusting
+-		// the case clause to the switch ident.
+-		// This may result in duplicate edits, but we de-dup later.
+-		if _, ok := item.node.(*ast.CaseClause); ok {
+-			path, _ := astutil.PathEnclosingInterval(pgf.File, item.obj.Pos(), item.obj.Pos())
+-			item.node = path[0].(*ast.Ident)
+-		}
+-
+-		// Replace the identifier with r.to.
+-		edit, err := posEdit(pgf.Tok, item.node.Pos(), item.node.End(), r.to)
+-		if err != nil {
+-			return nil, err
+-		}
+-
+-		result[pgf.URI] = append(result[pgf.URI], edit)
+-
+-		if !item.isDef { // uses do not have doc comments to update.
+-			continue
+-		}
+-
+-		doc := docComment(pgf, item.node.(*ast.Ident))
+-		if doc == nil {
+-			continue
+-		}
+-
+-		// Perform the rename in doc comments declared in the original package.
+-		// go/parser strips out \r\n returns from the comment text, so go
+-		// line-by-line through the comment text to get the correct positions.
+-		docRegexp := regexp.MustCompile(`\b` + r.from + `\b`) // valid identifier => valid regexp
+-		for _, comment := range doc.List {
+-			if isDirective(comment.Text) {
+-				continue
+-			}
+-			// TODO(adonovan): why are we looping over lines?
+-			// Just run the loop body once over the entire multiline comment.
+-			lines := strings.Split(comment.Text, "\n")
+-			tokFile := pgf.Tok
+-			commentLine := safetoken.Line(tokFile, comment.Pos())
+-			uri := span.URIFromPath(tokFile.Name())
+-			for i, line := range lines {
+-				lineStart := comment.Pos()
+-				if i > 0 {
+-					lineStart = tokFile.LineStart(commentLine + i)
+-				}
+-				for _, locs := range docRegexp.FindAllIndex([]byte(line), -1) {
+-					edit, err := posEdit(tokFile, lineStart+token.Pos(locs[0]), lineStart+token.Pos(locs[1]), r.to)
+-					if err != nil {
+-						return nil, err // can't happen
+-					}
+-					result[uri] = append(result[uri], edit)
+-				}
+-			}
+-		}
+-	}
+-
+-	return result, nil
+-}
+-
+-// docComment returns the doc for an identifier within the specified file.
+-func docComment(pgf *ParsedGoFile, id *ast.Ident) *ast.CommentGroup {
+-	nodes, _ := astutil.PathEnclosingInterval(pgf.File, id.Pos(), id.End())
+-	for _, node := range nodes {
+-		switch decl := node.(type) {
+-		case *ast.FuncDecl:
+-			return decl.Doc
+-		case *ast.Field:
+-			return decl.Doc
+-		case *ast.GenDecl:
+-			return decl.Doc
+-		// For {Type,Value}Spec, if the doc on the spec is absent,
+-		// search for the enclosing GenDecl
+-		case *ast.TypeSpec:
+-			if decl.Doc != nil {
+-				return decl.Doc
+-			}
+-		case *ast.ValueSpec:
+-			if decl.Doc != nil {
+-				return decl.Doc
+-			}
+-		case *ast.Ident:
+-		case *ast.AssignStmt:
+-			// *ast.AssignStmt doesn't have an associated comment group.
+-			// So, we try to find a comment just before the identifier.
+-
+-			// Try to find a comment group only for short variable declarations (:=).
+-			if decl.Tok != token.DEFINE {
+-				return nil
+-			}
+-
+-			identLine := safetoken.Line(pgf.Tok, id.Pos())
+-			for _, comment := range nodes[len(nodes)-1].(*ast.File).Comments {
+-				if comment.Pos() > id.Pos() {
+-					// Comment is after the identifier.
+-					continue
+-				}
+-
+-				lastCommentLine := safetoken.Line(pgf.Tok, comment.End())
+-				if lastCommentLine+1 == identLine {
+-					return comment
+-				}
+-			}
+-		default:
+-			return nil
+-		}
+-	}
+-	return nil
+-}
+-
+-// updatePkgName returns the updates to rename a pkgName in the import spec by
+-// only modifying the package name portion of the import declaration.
+-func (r *renamer) updatePkgName(pgf *ParsedGoFile, pkgName *types.PkgName) (diff.Edit, error) {
+-	// Modify ImportSpec syntax to add or remove the Name as needed.
+-	path, _ := astutil.PathEnclosingInterval(pgf.File, pkgName.Pos(), pkgName.Pos())
+-	if len(path) < 2 {
+-		return diff.Edit{}, fmt.Errorf("no path enclosing interval for %s", pkgName.Name())
+-	}
+-	spec, ok := path[1].(*ast.ImportSpec)
+-	if !ok {
+-		return diff.Edit{}, fmt.Errorf("failed to update PkgName for %s", pkgName.Name())
+-	}
+-
+-	newText := ""
+-	if pkgName.Imported().Name() != r.to {
+-		newText = r.to + " "
+-	}
+-
+-	// Replace the portion (possibly empty) of the spec before the path:
+-	//     local "path"      or      "path"
+-	//   ->      <-                -><-
+-	return posEdit(pgf.Tok, spec.Pos(), spec.Path.Pos(), newText)
+-}
+-
+-// parsePackageNameDecl is a convenience function that parses and
+-// returns the package name declaration of file fh, and reports
+-// whether the position ppos lies within it.
+-//
+-// Note: also used by references.
+-func parsePackageNameDecl(ctx context.Context, snapshot Snapshot, fh FileHandle, ppos protocol.Position) (*ParsedGoFile, bool, error) {
+-	pgf, err := snapshot.ParseGo(ctx, fh, ParseHeader)
+-	if err != nil {
+-		return nil, false, err
+-	}
+-	// Careful: because we used ParseHeader,
+-	// pgf.Pos(ppos) may be beyond EOF => (0, err).
+-	pos, _ := pgf.PositionPos(ppos)
+-	return pgf, pgf.File.Name.Pos() <= pos && pos <= pgf.File.Name.End(), nil
+-}
+-
+-// enclosingFile returns the CompiledGoFile of pkg that contains the specified position.
+-func enclosingFile(pkg Package, pos token.Pos) (*ParsedGoFile, bool) {
+-	for _, pgf := range pkg.CompiledGoFiles() {
+-		if pgf.File.Pos() <= pos && pos <= pgf.File.End() {
+-			return pgf, true
+-		}
+-	}
+-	return nil, false
+-}
+-
+-// posEdit returns an edit to replace the (start, end) range of tf with 'new'.
+-func posEdit(tf *token.File, start, end token.Pos, new string) (diff.Edit, error) {
+-	startOffset, endOffset, err := safetoken.Offsets(tf, start, end)
+-	if err != nil {
+-		return diff.Edit{}, err
+-	}
+-	return diff.Edit{Start: startOffset, End: endOffset, New: new}, nil
+-}
 diff -urN a/gopls/internal/lsp/source/rename_check.go b/gopls/internal/lsp/source/rename_check.go
 --- a/gopls/internal/lsp/source/rename_check.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/rename_check.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/rename_check.go	1970-01-01 08:00:00
 @@ -1,921 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -83631,63 +93756,63 @@
 -// checkStructField checks that the field renaming will not cause
 -// conflicts at its declaration, or ambiguity or changes to any selection.
 -func (r *renamer) checkStructField(from *types.Var) {
--	// Check that the struct declaration is free of field conflicts,
--	// and field/method conflicts.
 -
+-	// If this is the declaring package, check that the struct
+-	// declaration is free of field conflicts, and field/method
+-	// conflicts.
+-	//
 -	// go/types offers no easy way to get from a field (or interface
 -	// method) to its declaring struct (or interface), so we must
 -	// ascend the AST.
--	pgf, ok := enclosingFile(r.pkg, from.Pos())
--	if !ok {
--		return // not declared by syntax of this package
--	}
--	path, _ := astutil.PathEnclosingInterval(pgf.File, from.Pos(), from.Pos())
--	// path matches this pattern:
--	// [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
+-	if pgf, ok := enclosingFile(r.pkg, from.Pos()); ok {
+-		path, _ := astutil.PathEnclosingInterval(pgf.File, from.Pos(), from.Pos())
+-		// path matches this pattern:
+-		// [Ident SelectorExpr? StarExpr? Field FieldList StructType ParenExpr* ... File]
 -
--	// Ascend to FieldList.
--	var i int
--	for {
--		if _, ok := path[i].(*ast.FieldList); ok {
--			break
+-		// Ascend to FieldList.
+-		var i int
+-		for {
+-			if _, ok := path[i].(*ast.FieldList); ok {
+-				break
+-			}
+-			i++
 -		}
 -		i++
--	}
--	i++
--	tStruct := path[i].(*ast.StructType)
--	i++
--	// Ascend past parens (unlikely).
--	for {
--		_, ok := path[i].(*ast.ParenExpr)
--		if !ok {
--			break
--		}
+-		tStruct := path[i].(*ast.StructType)
 -		i++
--	}
--	if spec, ok := path[i].(*ast.TypeSpec); ok {
--		// This struct is also a named type.
--		// We must check for direct (non-promoted) field/field
--		// and method/field conflicts.
--		named := r.pkg.GetTypesInfo().Defs[spec.Name].Type()
--		prev, indices, _ := types.LookupFieldOrMethod(named, true, r.pkg.GetTypes(), r.to)
--		if len(indices) == 1 {
--			r.errorf(from.Pos(), "renaming this field %q to %q",
--				from.Name(), r.to)
--			r.errorf(prev.Pos(), "\twould conflict with this %s",
--				objectKind(prev))
--			return // skip checkSelections to avoid redundant errors
+-		// Ascend past parens (unlikely).
+-		for {
+-			_, ok := path[i].(*ast.ParenExpr)
+-			if !ok {
+-				break
+-			}
+-			i++
 -		}
--	} else {
--		// This struct is not a named type.
--		// We need only check for direct (non-promoted) field/field conflicts.
--		T := r.pkg.GetTypesInfo().Types[tStruct].Type.Underlying().(*types.Struct)
--		for i := 0; i < T.NumFields(); i++ {
--			if prev := T.Field(i); prev.Name() == r.to {
+-		if spec, ok := path[i].(*ast.TypeSpec); ok {
+-			// This struct is also a named type.
+-			// We must check for direct (non-promoted) field/field
+-			// and method/field conflicts.
+-			named := r.pkg.GetTypesInfo().Defs[spec.Name].Type()
+-			prev, indices, _ := types.LookupFieldOrMethod(named, true, r.pkg.GetTypes(), r.to)
+-			if len(indices) == 1 {
 -				r.errorf(from.Pos(), "renaming this field %q to %q",
 -					from.Name(), r.to)
--				r.errorf(prev.Pos(), "\twould conflict with this field")
+-				r.errorf(prev.Pos(), "\twould conflict with this %s",
+-					objectKind(prev))
 -				return // skip checkSelections to avoid redundant errors
 -			}
+-		} else {
+-			// This struct is not a named type.
+-			// We need only check for direct (non-promoted) field/field conflicts.
+-			T := r.pkg.GetTypesInfo().Types[tStruct].Type.Underlying().(*types.Struct)
+-			for i := 0; i < T.NumFields(); i++ {
+-				if prev := T.Field(i); prev.Name() == r.to {
+-					r.errorf(from.Pos(), "renaming this field %q to %q",
+-						from.Name(), r.to)
+-					r.errorf(prev.Pos(), "\twould conflict with this field")
+-					return // skip checkSelections to avoid redundant errors
+-				}
+-			}
 -		}
 -	}
 -
@@ -84060,7 +94185,7 @@
 -			// type-checker.
 -			//
 -			// Only proceed if all packages have no errors.
--			if pkg.HasParseErrors() || pkg.HasTypeErrors() {
+-			if len(pkg.GetParseErrors()) > 0 || len(pkg.GetTypeErrors()) > 0 {
 -				r.errorf(token.NoPos, // we don't have a position for this error.
 -					"renaming %q to %q not possible because %q has errors",
 -					r.from, r.to, pkg.Metadata().PkgPath)
@@ -84152,1257 +94277,9 @@
 -func isDigit(ch rune) bool {
 -	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
 -}
-diff -urN a/gopls/internal/lsp/source/rename.go b/gopls/internal/lsp/source/rename.go
---- a/gopls/internal/lsp/source/rename.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/rename.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1244 +0,0 @@
--// Copyright 2019 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package source
--
--// TODO(adonovan):
--//
--// - method of generic concrete type -> arbitrary instances of same
--//
--// - make satisfy work across packages.
--//
--// - tests, tests, tests:
--//   - play with renamings in the k8s tree.
--//   - generics
--//   - error cases (e.g. conflicts)
--//   - renaming a symbol declared in the module cache
--//     (currently proceeds with half of the renaming!)
--//   - make sure all tests have both a local and a cross-package analogue.
--//   - look at coverage
--//   - special cases: embedded fields, interfaces, test variants,
--//     function-local things with uppercase names;
--//     packages with type errors (currently 'satisfy' rejects them),
--//     pakage with missing imports;
--//
--// - measure performance in k8s.
--//
--// - The original gorename tool assumed well-typedness, but the gopls feature
--//   does no such check (which actually makes it much more useful).
--//   Audit to ensure it is safe on ill-typed code.
--//
--// - Generics support was no doubt buggy before but incrementalization
--//   may have exacerbated it. If the problem were just about objects,
--//   defs and uses it would be fairly simple, but type assignability
--//   comes into play in the 'satisfy' check for method renamings.
--//   De-instantiating Vector[int] to Vector[T] changes its type.
--//   We need to come up with a theory for the satisfy check that
--//   works with generics, and across packages. We currently have no
--//   simple way to pass types between packages (think: objectpath for
--//   types), though presumably exportdata could be pressed into service.
--//
--// - FileID-based de-duplication of edits to different URIs for the same file.
--
--import (
--	"context"
--	"errors"
--	"fmt"
--	"go/ast"
--	"go/token"
--	"go/types"
--	"path"
--	"path/filepath"
--	"regexp"
--	"sort"
--	"strconv"
--	"strings"
--
--	"golang.org/x/mod/modfile"
--	"golang.org/x/tools/go/ast/astutil"
--	"golang.org/x/tools/go/types/objectpath"
--	"golang.org/x/tools/go/types/typeutil"
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/safetoken"
--	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
--	"golang.org/x/tools/internal/diff"
--	"golang.org/x/tools/internal/event"
--	"golang.org/x/tools/internal/typeparams"
--	"golang.org/x/tools/refactor/satisfy"
--)
--
--// A renamer holds state of a single call to renameObj, which renames
--// an object (or several coupled objects) within a single type-checked
--// syntax package.
--type renamer struct {
--	pkg                Package               // the syntax package in which the renaming is applied
--	objsToUpdate       map[types.Object]bool // records progress of calls to check
--	hadConflicts       bool
--	conflicts          []string
--	from, to           string
--	satisfyConstraints map[satisfy.Constraint]bool
--	msets              typeutil.MethodSetCache
--	changeMethods      bool
--}
--
--// A PrepareItem holds the result of a "prepare rename" operation:
--// the source range and value of a selected identifier.
--type PrepareItem struct {
--	Range protocol.Range
--	Text  string
--}
--
--// PrepareRename searches for a valid renaming at position pp.
--//
--// The returned usererr is intended to be displayed to the user to explain why
--// the prepare fails. Probably we could eliminate the redundancy in returning
--// two errors, but for now this is done defensively.
--func PrepareRename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position) (_ *PrepareItem, usererr, err error) {
--	ctx, done := event.Start(ctx, "source.PrepareRename")
--	defer done()
--
--	// Is the cursor within the package name declaration?
--	if pgf, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp); err != nil {
--		return nil, err, err
--	} else if inPackageName {
--		item, err := prepareRenamePackageName(ctx, snapshot, pgf)
--		return item, err, err
--	}
--
--	// Ordinary (non-package) renaming.
--	//
--	// Type-check the current package, locate the reference at the position,
--	// validate the object, and report its name and range.
--	//
--	// TODO(adonovan): in all cases below, we return usererr=nil,
--	// which means we return (nil, nil) at the protocol
--	// layer. This seems like a bug, or at best an exploitation of
--	// knowledge of VSCode-specific behavior. Can we avoid that?
--	pkg, pgf, err := PackageForFile(ctx, snapshot, f.URI(), NarrowestPackage)
--	if err != nil {
--		return nil, nil, err
--	}
--	pos, err := pgf.PositionPos(pp)
--	if err != nil {
--		return nil, nil, err
--	}
--	targets, node, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
--	if err != nil {
--		return nil, nil, err
--	}
--	var obj types.Object
--	for obj = range targets {
--		break // pick one arbitrarily
--	}
--	if err := checkRenamable(obj); err != nil {
--		return nil, nil, err
--	}
--	rng, err := pgf.NodeRange(node)
--	if err != nil {
--		return nil, nil, err
--	}
--	if _, isImport := node.(*ast.ImportSpec); isImport {
--		// We're not really renaming the import path.
--		rng.End = rng.Start
--	}
--	return &PrepareItem{
--		Range: rng,
--		Text:  obj.Name(),
--	}, nil, nil
--}
--
--func prepareRenamePackageName(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile) (*PrepareItem, error) {
--	// Does the client support file renaming?
--	fileRenameSupported := false
--	for _, op := range snapshot.View().Options().SupportedResourceOperations {
--		if op == protocol.Rename {
--			fileRenameSupported = true
--			break
--		}
--	}
--	if !fileRenameSupported {
--		return nil, errors.New("can't rename package: LSP client does not support file renaming")
--	}
--
--	// Check validity of the metadata for the file's containing package.
--	fileMeta, err := snapshot.MetadataForFile(ctx, pgf.URI)
--	if err != nil {
--		return nil, err
--	}
--	if len(fileMeta) == 0 {
--		return nil, fmt.Errorf("no packages found for file %q", pgf.URI)
--	}
--	meta := fileMeta[0]
--	if meta.Name == "main" {
--		return nil, fmt.Errorf("can't rename package \"main\"")
--	}
--	if strings.HasSuffix(string(meta.Name), "_test") {
--		return nil, fmt.Errorf("can't rename x_test packages")
--	}
--	if meta.Module == nil {
--		return nil, fmt.Errorf("can't rename package: missing module information for package %q", meta.PkgPath)
--	}
--	if meta.Module.Path == string(meta.PkgPath) {
--		return nil, fmt.Errorf("can't rename package: package path %q is the same as module path %q", meta.PkgPath, meta.Module.Path)
--	}
--
--	// Return the location of the package declaration.
--	rng, err := pgf.NodeRange(pgf.File.Name)
--	if err != nil {
--		return nil, err
--	}
--	return &PrepareItem{
--		Range: rng,
--		Text:  string(meta.Name),
--	}, nil
--}
--
--func checkRenamable(obj types.Object) error {
--	switch obj := obj.(type) {
--	case *types.Var:
--		if obj.Embedded() {
--			return fmt.Errorf("can't rename embedded fields: rename the type directly or name the field")
--		}
--	case *types.Builtin, *types.Nil:
--		return fmt.Errorf("%s is built in and cannot be renamed", obj.Name())
--	}
--	if obj.Pkg() == nil || obj.Pkg().Path() == "unsafe" {
--		// e.g. error.Error, unsafe.Pointer
--		return fmt.Errorf("%s is built in and cannot be renamed", obj.Name())
--	}
--	if obj.Name() == "_" {
--		return errors.New("can't rename \"_\"")
--	}
--	return nil
--}
--
--// Rename returns a map of TextEdits for each file modified when renaming a
--// given identifier within a package and a boolean value of true for renaming
--// package and false otherwise.
--func Rename(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]protocol.TextEdit, bool, error) {
--	ctx, done := event.Start(ctx, "source.Rename")
--	defer done()
--
--	if !isValidIdentifier(newName) {
--		return nil, false, fmt.Errorf("invalid identifier to rename: %q", newName)
--	}
--
--	// Cursor within package name declaration?
--	_, inPackageName, err := parsePackageNameDecl(ctx, snapshot, f, pp)
--	if err != nil {
--		return nil, false, err
--	}
--
--	var editMap map[span.URI][]diff.Edit
--	if inPackageName {
--		editMap, err = renamePackageName(ctx, snapshot, f, PackageName(newName))
--	} else {
--		editMap, err = renameOrdinary(ctx, snapshot, f, pp, newName)
--	}
--	if err != nil {
--		return nil, false, err
--	}
--
--	// Convert edits to protocol form.
--	result := make(map[span.URI][]protocol.TextEdit)
--	for uri, edits := range editMap {
--		// Sort and de-duplicate edits.
--		//
--		// Overlapping edits may arise in local renamings (due
--		// to type switch implicits) and globals ones (due to
--		// processing multiple package variants).
--		//
--		// We assume renaming produces diffs that are all
--		// replacements (no adjacent insertions that might
--		// become reordered) and that are either identical or
--		// non-overlapping.
--		diff.SortEdits(edits)
--		filtered := edits[:0]
--		for i, edit := range edits {
--			if i == 0 || edit != filtered[len(filtered)-1] {
--				filtered = append(filtered, edit)
--			}
--		}
--		edits = filtered
--
--		// TODO(adonovan): the logic above handles repeat edits to the
--		// same file URI (e.g. as a member of package p and p_test) but
--		// is not sufficient to handle file-system level aliasing arising
--		// from symbolic or hard links. For that, we should use a
--		// robustio-FileID-keyed map.
--		// See https://go.dev/cl/457615 for example.
--		// This really occurs in practice, e.g. kubernetes has
--		// vendor/k8s.io/kubectl -> ../../staging/src/k8s.io/kubectl.
--		fh, err := snapshot.GetFile(ctx, uri)
--		if err != nil {
--			return nil, false, err
--		}
--		data, err := fh.Read()
--		if err != nil {
--			return nil, false, err
--		}
--		m := protocol.NewMapper(uri, data)
--		protocolEdits, err := ToProtocolEdits(m, edits)
--		if err != nil {
--			return nil, false, err
--		}
--		result[uri] = protocolEdits
--	}
--
--	return result, inPackageName, nil
--}
--
--// renameOrdinary renames an ordinary (non-package) name throughout the workspace.
--func renameOrdinary(ctx context.Context, snapshot Snapshot, f FileHandle, pp protocol.Position, newName string) (map[span.URI][]diff.Edit, error) {
--	// Type-check the referring package and locate the object(s).
--	// We choose the widest variant as, for non-exported
--	// identifiers, it is the only package we need.
--	pkg, pgf, err := PackageForFile(ctx, snapshot, f.URI(), WidestPackage)
--	if err != nil {
--		return nil, err
--	}
--	pos, err := pgf.PositionPos(pp)
--	if err != nil {
--		return nil, err
--	}
--	targets, _, err := objectsAt(pkg.GetTypesInfo(), pgf.File, pos)
--	if err != nil {
--		return nil, err
--	}
--
--	// Pick a representative object arbitrarily.
--	// (All share the same name, pos, and kind.)
--	var obj types.Object
--	for obj = range targets {
--		break
--	}
--	if obj.Name() == newName {
--		return nil, fmt.Errorf("old and new names are the same: %s", newName)
--	}
--	if err := checkRenamable(obj); err != nil {
--		return nil, err
--	}
--
--	// Find objectpath, if object is exported ("" otherwise).
--	var declObjPath objectpath.Path
--	if obj.Exported() {
--		// objectpath.For requires the origin of a generic
--		// function or type, not an instantiation (a bug?).
--		// Unfortunately we can't call {Func,TypeName}.Origin
--		// as these are not available in go/types@go1.18.
--		// So we take a scenic route.
--		switch obj.(type) { // avoid "obj :=" since cases reassign the var
--		case *types.TypeName:
--			if named, ok := obj.Type().(*types.Named); ok {
--				obj = named.Obj()
--			}
--		case *types.Func:
--			obj = funcOrigin(obj.(*types.Func))
--		case *types.Var:
--			// TODO(adonovan): do vars need the origin treatment too? (issue #58462)
--		}
--		if path, err := objectpath.For(obj); err == nil {
--			declObjPath = path
--		}
--	}
--
--	// Nonexported? Search locally.
--	if declObjPath == "" {
--		var objects []types.Object
--		for obj := range targets {
--			objects = append(objects, obj)
--		}
--		editMap, _, err := renameObjects(ctx, snapshot, newName, pkg, objects...)
--		return editMap, err
--	}
--
--	// Exported: search globally.
--	//
--	// For exported package-level var/const/func/type objects, the
--	// search scope is just the direct importers.
--	//
--	// For exported fields and methods, the scope is the
--	// transitive rdeps. (The exportedness of the field's struct
--	// or method's receiver is irrelevant.)
--	transitive := false
--	switch obj.(type) {
--	case *types.TypeName:
--		// Renaming an exported package-level type
--		// requires us to inspect all transitive rdeps
--		// in the event that the type is embedded.
--		//
--		// TODO(adonovan): opt: this is conservative
--		// but inefficient. Instead, expand the scope
--		// of the search only if we actually encounter
--		// an embedding of the type, and only then to
--		// the rdeps of the embedding package.
--		if obj.Parent() == obj.Pkg().Scope() {
--			transitive = true
--		}
--
--	case *types.Var:
--		if obj.(*types.Var).IsField() {
--			transitive = true // field
--		}
--
--		// TODO(adonovan): opt: process only packages that
--		// contain a reference (xrefs) to the target field.
--
--	case *types.Func:
--		if obj.Type().(*types.Signature).Recv() != nil {
--			transitive = true // method
--		}
--
--		// It's tempting to optimize by skipping
--		// packages that don't contain a reference to
--		// the method in the xrefs index, but we still
--		// need to apply the satisfy check to those
--		// packages to find assignment statements that
--		// might expands the scope of the renaming.
--	}
--
--	// Type-check all the packages to inspect.
--	declURI := span.URIFromPath(pkg.FileSet().File(obj.Pos()).Name())
--	pkgs, err := typeCheckReverseDependencies(ctx, snapshot, declURI, transitive)
--	if err != nil {
--		return nil, err
--	}
--
--	// Apply the renaming to the (initial) object.
--	declPkgPath := PackagePath(obj.Pkg().Path())
--	return renameExported(ctx, snapshot, pkgs, declPkgPath, declObjPath, newName)
--}
--
--// funcOrigin is a go1.18-portable implementation of (*types.Func).Origin.
--func funcOrigin(fn *types.Func) *types.Func {
--	// Method?
--	if fn.Type().(*types.Signature).Recv() != nil {
--		return typeparams.OriginMethod(fn)
--	}
--
--	// Package-level function?
--	// (Assume the origin has the same position.)
--	gen := fn.Pkg().Scope().Lookup(fn.Name())
--	if gen != nil && gen.Pos() == fn.Pos() {
--		return gen.(*types.Func)
--	}
--
--	return fn
--}
--
--// typeCheckReverseDependencies returns the type-checked packages for
--// the reverse dependencies of all packages variants containing
--// file declURI. The packages are in some topological order.
--//
--// It includes all variants (even intermediate test variants) for the
--// purposes of computing reverse dependencies, but discards ITVs for
--// the actual renaming work.
--//
--// (This neglects obscure edge cases where a _test.go file changes the
--// selectors used only in an ITV, but life is short. Also sin must be
--// punished.)
--func typeCheckReverseDependencies(ctx context.Context, snapshot Snapshot, declURI span.URI, transitive bool) ([]Package, error) {
--	variants, err := snapshot.MetadataForFile(ctx, declURI)
--	if err != nil {
--		return nil, err
--	}
--	allRdeps := make(map[PackageID]*Metadata)
--	for _, variant := range variants {
--		rdeps, err := snapshot.ReverseDependencies(ctx, variant.ID, transitive)
--		if err != nil {
--			return nil, err
--		}
--		allRdeps[variant.ID] = variant // include self
--		for id, meta := range rdeps {
--			allRdeps[id] = meta
--		}
--	}
--	var ids []PackageID
--	for id, meta := range allRdeps {
--		if meta.IsIntermediateTestVariant() {
--			continue
--		}
--		ids = append(ids, id)
--	}
--
--	// Sort the packages into some topological order of the
--	// (unfiltered) metadata graph.
--	SortPostOrder(snapshot, ids)
--
--	// Dependencies must be visited first since they can expand
--	// the search set. Ideally we would process the (filtered) set
--	// of packages in the parallel postorder of the snapshot's
--	// (unfiltered) metadata graph, but this is quite tricky
--	// without a good graph abstraction.
--	//
--	// For now, we visit packages sequentially in order of
--	// ascending height, like an inverted breadth-first search.
--	//
--	// Type checking is by far the dominant cost, so
--	// overlapping it with renaming may not be worthwhile.
--	return snapshot.TypeCheck(ctx, ids...)
--}
--
--// SortPostOrder sorts the IDs so that if x depends on y, then y appears before x.
--func SortPostOrder(meta MetadataSource, ids []PackageID) {
--	postorder := make(map[PackageID]int)
--	order := 0
--	var visit func(PackageID)
--	visit = func(id PackageID) {
--		if _, ok := postorder[id]; !ok {
--			postorder[id] = -1 // break recursion
--			if m := meta.Metadata(id); m != nil {
--				for _, depID := range m.DepsByPkgPath {
--					visit(depID)
--				}
--			}
--			order++
--			postorder[id] = order
--		}
--	}
--	for _, id := range ids {
--		visit(id)
--	}
--	sort.Slice(ids, func(i, j int) bool {
--		return postorder[ids[i]] < postorder[ids[j]]
--	})
--}
--
--// renameExported renames the object denoted by (pkgPath, objPath)
--// within the specified packages, along with any other objects that
--// must be renamed as a consequence. The slice of packages must be
--// topologically ordered.
--func renameExported(ctx context.Context, snapshot Snapshot, pkgs []Package, declPkgPath PackagePath, declObjPath objectpath.Path, newName string) (map[span.URI][]diff.Edit, error) {
--
--	// A target is a name for an object that is stable across types.Packages.
--	type target struct {
--		pkg PackagePath
--		obj objectpath.Path
--	}
--
--	// Populate the initial set of target objects.
--	// This set may grow as we discover the consequences of each renaming.
--	//
--	// TODO(adonovan): strictly, each cone of reverse dependencies
--	// of a single variant should have its own target map that
--	// monotonically expands as we go up the import graph, because
--	// declarations in test files can alter the set of
--	// package-level names and change the meaning of field and
--	// method selectors. So if we parallelize the graph
--	// visitation (see above), we should also compute the targets
--	// as a union of dependencies.
--	//
--	// Or we could decide that the logic below is fast enough not
--	// to need parallelism. In small measurements so far the
--	// type-checking step is about 95% and the renaming only 5%.
--	targets := map[target]bool{{declPkgPath, declObjPath}: true}
--
--	// Apply the renaming operation to each package.
--	allEdits := make(map[span.URI][]diff.Edit)
--	for _, pkg := range pkgs {
--
--		// Resolved target objects within package pkg.
--		var objects []types.Object
--		for t := range targets {
--			p := pkg.DependencyTypes(t.pkg)
--			if p == nil {
--				continue // indirect dependency of no consequence
--			}
--			obj, err := objectpath.Object(p, t.obj)
--			if err != nil {
--				// Though this can happen with regular export data
--				// due to trimming of inconsequential objects,
--				// it can't happen if we load dependencies from full
--				// syntax (as today) or shallow export data (soon),
--				// as both are complete.
--				bug.Reportf("objectpath.Object(%v, %v) failed: %v", p, t.obj, err)
--				continue
--			}
--			objects = append(objects, obj)
--		}
--		if len(objects) == 0 {
--			continue // no targets of consequence to this package
--		}
--
--		// Apply the renaming.
--		editMap, moreObjects, err := renameObjects(ctx, snapshot, newName, pkg, objects...)
--		if err != nil {
--			return nil, err
--		}
--
--		// It is safe to concatenate the edits as they are non-overlapping
--		// (or identical, in which case they will be de-duped by Rename).
--		for uri, edits := range editMap {
--			allEdits[uri] = append(allEdits[uri], edits...)
--		}
--
--		// Expand the search set?
--		for obj := range moreObjects {
--			objpath, err := objectpath.For(obj)
--			if err != nil {
--				continue // not exported
--			}
--			target := target{PackagePath(obj.Pkg().Path()), objpath}
--			targets[target] = true
--
--			// TODO(adonovan): methods requires dynamic
--			// programming of the product targets x
--			// packages as any package might add a new
--			// target (from a foward dep) as a
--			// consequence, and any target might imply a
--			// new set of rdeps. See golang/go#58461.
--		}
--	}
--
--	return allEdits, nil
--}
--
--// renamePackageName renames package declarations, imports, and go.mod files.
--func renamePackageName(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) {
--	// Rename the package decl and all imports.
--	renamingEdits, err := renamePackage(ctx, s, f, newName)
--	if err != nil {
--		return nil, err
--	}
--
--	// Update the last component of the file's enclosing directory.
--	oldBase := filepath.Dir(f.URI().Filename())
--	newPkgDir := filepath.Join(filepath.Dir(oldBase), string(newName))
--
--	// Update any affected replace directives in go.mod files.
--	// TODO(adonovan): extract into its own function.
--	//
--	// TODO: should this operate on all go.mod files, irrespective of whether they are included in the workspace?
--	// Get all active mod files in the workspace
--	modFiles := s.ModFiles()
--	for _, m := range modFiles {
--		fh, err := s.GetFile(ctx, m)
--		if err != nil {
--			return nil, err
--		}
--		pm, err := s.ParseMod(ctx, fh)
--		if err != nil {
--			return nil, err
--		}
--
--		modFileDir := filepath.Dir(pm.URI.Filename())
--		affectedReplaces := []*modfile.Replace{}
--
--		// Check if any replace directives need to be fixed
--		for _, r := range pm.File.Replace {
--			if !strings.HasPrefix(r.New.Path, "/") && !strings.HasPrefix(r.New.Path, "./") && !strings.HasPrefix(r.New.Path, "../") {
--				continue
--			}
--
--			replacedPath := r.New.Path
--			if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") {
--				replacedPath = filepath.Join(modFileDir, r.New.Path)
--			}
--
--			// TODO: Is there a risk of converting a '\' delimited replacement to a '/' delimited replacement?
--			if !strings.HasPrefix(filepath.ToSlash(replacedPath)+"/", filepath.ToSlash(oldBase)+"/") {
--				continue // not affected by the package renaming
--			}
--
--			affectedReplaces = append(affectedReplaces, r)
--		}
--
--		if len(affectedReplaces) == 0 {
--			continue
--		}
--		copied, err := modfile.Parse("", pm.Mapper.Content, nil)
--		if err != nil {
--			return nil, err
--		}
--
--		for _, r := range affectedReplaces {
--			replacedPath := r.New.Path
--			if strings.HasPrefix(r.New.Path, "./") || strings.HasPrefix(r.New.Path, "../") {
--				replacedPath = filepath.Join(modFileDir, r.New.Path)
--			}
--
--			suffix := strings.TrimPrefix(replacedPath, string(oldBase))
--
--			newReplacedPath, err := filepath.Rel(modFileDir, newPkgDir+suffix)
--			if err != nil {
--				return nil, err
--			}
--
--			newReplacedPath = filepath.ToSlash(newReplacedPath)
--
--			if !strings.HasPrefix(newReplacedPath, "/") && !strings.HasPrefix(newReplacedPath, "../") {
--				newReplacedPath = "./" + newReplacedPath
--			}
--
--			if err := copied.AddReplace(r.Old.Path, "", newReplacedPath, ""); err != nil {
--				return nil, err
--			}
--		}
--
--		copied.Cleanup()
--		newContent, err := copied.Format()
--		if err != nil {
--			return nil, err
--		}
--
--		// Calculate the edits to be made due to the change.
--		edits := s.View().Options().ComputeEdits(string(pm.Mapper.Content), string(newContent))
--		renamingEdits[pm.URI] = append(renamingEdits[pm.URI], edits...)
--	}
--
--	return renamingEdits, nil
--}
--
--// renamePackage computes all workspace edits required to rename the package
--// described by the given metadata, to newName, by renaming its package
--// directory.
--//
--// It updates package clauses and import paths for the renamed package as well
--// as any other packages affected by the directory renaming among packages
--// described by allMetadata.
--func renamePackage(ctx context.Context, s Snapshot, f FileHandle, newName PackageName) (map[span.URI][]diff.Edit, error) {
--	if strings.HasSuffix(string(newName), "_test") {
--		return nil, fmt.Errorf("cannot rename to _test package")
--	}
--
--	// We need metadata for the relevant package and module paths.
--	// These should be the same for all packages containing the file.
--	metas, err := s.MetadataForFile(ctx, f.URI())
--	if err != nil {
--		return nil, err
--	}
--	if len(metas) == 0 {
--		return nil, fmt.Errorf("no packages found for file %q", f.URI())
--	}
--	meta := metas[0] // narrowest
--
--	oldPkgPath := meta.PkgPath
--	if meta.Module == nil {
--		return nil, fmt.Errorf("cannot rename package: missing module information for package %q", meta.PkgPath)
--	}
--	modulePath := PackagePath(meta.Module.Path)
--	if modulePath == oldPkgPath {
--		return nil, fmt.Errorf("cannot rename package: module path %q is the same as the package path, so renaming the package directory would have no effect", modulePath)
--	}
--
--	newPathPrefix := path.Join(path.Dir(string(oldPkgPath)), string(newName))
--
--	// We must inspect all packages, not just direct importers,
--	// because we also rename subpackages, which may be unrelated.
--	// (If the renamed package imports a subpackage it may require
--	// edits to both its package and import decls.)
--	allMetadata, err := s.AllMetadata(ctx)
--	if err != nil {
--		return nil, err
--	}
--
--	// Rename package and import declarations in all relevant packages.
--	edits := make(map[span.URI][]diff.Edit)
--	for _, m := range allMetadata {
--		// Special case: x_test packages for the renamed package will not have the
--		// package path as as a dir prefix, but still need their package clauses
--		// renamed.
--		if m.PkgPath == oldPkgPath+"_test" {
--			if err := renamePackageClause(ctx, m, s, newName+"_test", edits); err != nil {
--				return nil, err
--			}
--			continue
--		}
--
--		// Subtle: check this condition before checking for valid module info
--		// below, because we should not fail this operation if unrelated packages
--		// lack module info.
--		if !strings.HasPrefix(string(m.PkgPath)+"/", string(oldPkgPath)+"/") {
--			continue // not affected by the package renaming
--		}
--
--		if m.Module == nil {
--			// This check will always fail under Bazel.
--			return nil, fmt.Errorf("cannot rename package: missing module information for package %q", m.PkgPath)
--		}
--
--		if modulePath != PackagePath(m.Module.Path) {
--			continue // don't edit imports if nested package and renaming package have different module paths
--		}
--
--		// Renaming a package consists of changing its import path and package name.
--		suffix := strings.TrimPrefix(string(m.PkgPath), string(oldPkgPath))
--		newPath := newPathPrefix + suffix
--
--		pkgName := m.Name
--		if m.PkgPath == oldPkgPath {
--			pkgName = PackageName(newName)
--
--			if err := renamePackageClause(ctx, m, s, newName, edits); err != nil {
--				return nil, err
--			}
--		}
--
--		imp := ImportPath(newPath) // TODO(adonovan): what if newPath has vendor/ prefix?
--		if err := renameImports(ctx, s, m, imp, pkgName, edits); err != nil {
--			return nil, err
--		}
--	}
--
--	return edits, nil
--}
--
--// renamePackageClause computes edits renaming the package clause of files in
--// the package described by the given metadata, to newName.
--//
--// Edits are written into the edits map.
--func renamePackageClause(ctx context.Context, m *Metadata, snapshot Snapshot, newName PackageName, edits map[span.URI][]diff.Edit) error {
--	// Rename internal references to the package in the renaming package.
--	for _, uri := range m.CompiledGoFiles {
--		fh, err := snapshot.GetFile(ctx, uri)
--		if err != nil {
--			return err
--		}
--		f, err := snapshot.ParseGo(ctx, fh, ParseHeader)
--		if err != nil {
--			return err
--		}
--		if f.File.Name == nil {
--			continue // no package declaration
--		}
--
--		edit, err := posEdit(f.Tok, f.File.Name.Pos(), f.File.Name.End(), string(newName))
--		if err != nil {
--			return err
--		}
--		edits[f.URI] = append(edits[f.URI], edit)
--	}
--
--	return nil
--}
--
--// renameImports computes the set of edits to imports resulting from renaming
--// the package described by the given metadata, to a package with import path
--// newPath and name newName.
--//
--// Edits are written into the edits map.
--func renameImports(ctx context.Context, snapshot Snapshot, m *Metadata, newPath ImportPath, newName PackageName, allEdits map[span.URI][]diff.Edit) error {
--	rdeps, err := snapshot.ReverseDependencies(ctx, m.ID, false) // find direct importers
--	if err != nil {
--		return err
--	}
--
--	// Pass 1: rename import paths in import declarations.
--	needsTypeCheck := make(map[PackageID][]span.URI)
--	for _, rdep := range rdeps {
--		if rdep.IsIntermediateTestVariant() {
--			continue // for renaming, these variants are redundant
--		}
--
--		for _, uri := range rdep.CompiledGoFiles {
--			fh, err := snapshot.GetFile(ctx, uri)
--			if err != nil {
--				return err
--			}
--			f, err := snapshot.ParseGo(ctx, fh, ParseHeader)
--			if err != nil {
--				return err
--			}
--			if f.File.Name == nil {
--				continue // no package declaration
--			}
--			for _, imp := range f.File.Imports {
--				if rdep.DepsByImpPath[UnquoteImportPath(imp)] != m.ID {
--					continue // not the import we're looking for
--				}
--
--				// If the import does not explicitly specify
--				// a local name, then we need to invoke the
--				// type checker to locate references to update.
--				//
--				// TODO(adonovan): is this actually true?
--				// Renaming an import with a local name can still
--				// cause conflicts: shadowing of built-ins, or of
--				// package-level decls in the same or another file.
--				if imp.Name == nil {
--					needsTypeCheck[rdep.ID] = append(needsTypeCheck[rdep.ID], uri)
--				}
--
--				// Create text edit for the import path (string literal).
--				edit, err := posEdit(f.Tok, imp.Path.Pos(), imp.Path.End(), strconv.Quote(string(newPath)))
--				if err != nil {
--					return err
--				}
--				allEdits[uri] = append(allEdits[uri], edit)
--			}
--		}
--	}
--
--	// If the imported package's name hasn't changed,
--	// we don't need to rename references within each file.
--	if newName == m.Name {
--		return nil
--	}
--
--	// Pass 2: rename local name (types.PkgName) of imported
--	// package throughout one or more files of the package.
--	ids := make([]PackageID, 0, len(needsTypeCheck))
--	for id := range needsTypeCheck {
--		ids = append(ids, id)
--	}
--	pkgs, err := snapshot.TypeCheck(ctx, ids...)
--	if err != nil {
--		return err
--	}
--	for i, id := range ids {
--		pkg := pkgs[i]
--		for _, uri := range needsTypeCheck[id] {
--			f, err := pkg.File(uri)
--			if err != nil {
--				return err
--			}
--			for _, imp := range f.File.Imports {
--				if imp.Name != nil {
--					continue // has explicit local name
--				}
--				if rdeps[id].DepsByImpPath[UnquoteImportPath(imp)] != m.ID {
--					continue // not the import we're looking for
--				}
--
--				pkgname := pkg.GetTypesInfo().Implicits[imp].(*types.PkgName)
--
--				pkgScope := pkg.GetTypes().Scope()
--				fileScope := pkg.GetTypesInfo().Scopes[f.File]
--
--				localName := string(newName)
--				try := 0
--
--				// Keep trying with fresh names until one succeeds.
--				//
--				// TODO(adonovan): fix: this loop is not sufficient to choose a name
--				// that is guaranteed to be conflict-free; renameObj may still fail.
--				// So the retry loop should be around renameObj, and we shouldn't
--				// bother with scopes here.
--				for fileScope.Lookup(localName) != nil || pkgScope.Lookup(localName) != nil {
--					try++
--					localName = fmt.Sprintf("%s%d", newName, try)
--				}
--
--				// renameObj detects various conflicts, including:
--				// - new name conflicts with a package-level decl in this file;
--				// - new name hides a package-level decl in another file that
--				//   is actually referenced in this file;
--				// - new name hides a built-in that is actually referenced
--				//   in this file;
--				// - a reference in this file to the old package name would
--				//   become shadowed by an intervening declaration that
--				//   uses the new name.
--				// It returns the edits if no conflict was detected.
--				editMap, _, err := renameObjects(ctx, snapshot, localName, pkg, pkgname)
--				if err != nil {
--					return err
--				}
--
--				// If the chosen local package name matches the package's
--				// new name, delete the change that would have inserted
--				// an explicit local name, which is always the lexically
--				// first change.
--				if localName == string(newName) {
--					edits, ok := editMap[uri]
--					if !ok {
--						return fmt.Errorf("internal error: no changes for %s", uri)
--					}
--					diff.SortEdits(edits)
--					editMap[uri] = edits[1:]
--				}
--				for uri, edits := range editMap {
--					allEdits[uri] = append(allEdits[uri], edits...)
--				}
--			}
--		}
--	}
--	return nil
--}
--
--// renameObjects computes the edits to the type-checked syntax package pkg
--// required to rename a set of target objects to newName.
--//
--// It also returns the set of objects that were found (due to
--// corresponding methods and embedded fields) to require renaming as a
--// consequence of the requested renamings.
--//
--// It returns an error if the renaming would cause a conflict.
--func renameObjects(ctx context.Context, snapshot Snapshot, newName string, pkg Package, targets ...types.Object) (map[span.URI][]diff.Edit, map[types.Object]bool, error) {
--	r := renamer{
--		pkg:          pkg,
--		objsToUpdate: make(map[types.Object]bool),
--		from:         targets[0].Name(),
--		to:           newName,
--	}
--
--	// A renaming initiated at an interface method indicates the
--	// intention to rename abstract and concrete methods as needed
--	// to preserve assignability.
--	// TODO(adonovan): pull this into the caller.
--	for _, obj := range targets {
--		if obj, ok := obj.(*types.Func); ok {
--			recv := obj.Type().(*types.Signature).Recv()
--			if recv != nil && types.IsInterface(recv.Type().Underlying()) {
--				r.changeMethods = true
--				break
--			}
--		}
--	}
--
--	// Check that the renaming of the identifier is ok.
--	for _, obj := range targets {
--		r.check(obj)
--		if len(r.conflicts) > 0 {
--			// Stop at first error.
--			return nil, nil, fmt.Errorf("%s", strings.Join(r.conflicts, "\n"))
--		}
--	}
--
--	editMap, err := r.update()
--	if err != nil {
--		return nil, nil, err
--	}
--
--	// Remove initial targets so that only 'consequences' remain.
--	for _, obj := range targets {
--		delete(r.objsToUpdate, obj)
--	}
--	return editMap, r.objsToUpdate, nil
--}
--
--// Rename all references to the target objects.
--func (r *renamer) update() (map[span.URI][]diff.Edit, error) {
--	result := make(map[span.URI][]diff.Edit)
--
--	// shouldUpdate reports whether obj is one of (or an
--	// instantiation of one of) the target objects.
--	shouldUpdate := func(obj types.Object) bool {
--		if r.objsToUpdate[obj] {
--			return true
--		}
--		if fn, ok := obj.(*types.Func); ok && r.objsToUpdate[funcOrigin(fn)] {
--			return true
--		}
--		return false
--	}
--
--	// Find all identifiers in the package that define or use a
--	// renamed object. We iterate over info as it is more efficent
--	// than calling ast.Inspect for each of r.pkg.CompiledGoFiles().
--	type item struct {
--		node  ast.Node // Ident, ImportSpec (obj=PkgName), or CaseClause (obj=Var)
--		obj   types.Object
--		isDef bool
--	}
--	var items []item
--	info := r.pkg.GetTypesInfo()
--	for id, obj := range info.Uses {
--		if shouldUpdate(obj) {
--			items = append(items, item{id, obj, false})
--		}
--	}
--	for id, obj := range info.Defs {
--		if shouldUpdate(obj) {
--			items = append(items, item{id, obj, true})
--		}
--	}
--	for node, obj := range info.Implicits {
--		if shouldUpdate(obj) {
--			switch node.(type) {
--			case *ast.ImportSpec, *ast.CaseClause:
--				items = append(items, item{node, obj, true})
--			}
--		}
--	}
--	sort.Slice(items, func(i, j int) bool {
--		return items[i].node.Pos() < items[j].node.Pos()
--	})
--
--	// Update each identifier.
--	for _, item := range items {
--		pgf, ok := enclosingFile(r.pkg, item.node.Pos())
--		if !ok {
--			bug.Reportf("edit does not belong to syntax of package %q", r.pkg)
--			continue
--		}
--
--		// Renaming a types.PkgName may result in the addition or removal of an identifier,
--		// so we deal with this separately.
--		if pkgName, ok := item.obj.(*types.PkgName); ok && item.isDef {
--			edit, err := r.updatePkgName(pgf, pkgName)
--			if err != nil {
--				return nil, err
--			}
--			result[pgf.URI] = append(result[pgf.URI], edit)
--			continue
--		}
--
--		// Workaround the unfortunate lack of a Var object
--		// for x in "switch x := expr.(type) {}" by adjusting
--		// the case clause to the switch ident.
--		// This may result in duplicate edits, but we de-dup later.
--		if _, ok := item.node.(*ast.CaseClause); ok {
--			path, _ := astutil.PathEnclosingInterval(pgf.File, item.obj.Pos(), item.obj.Pos())
--			item.node = path[0].(*ast.Ident)
--		}
--
--		// Replace the identifier with r.to.
--		edit, err := posEdit(pgf.Tok, item.node.Pos(), item.node.End(), r.to)
--		if err != nil {
--			return nil, err
--		}
--
--		result[pgf.URI] = append(result[pgf.URI], edit)
--
--		if !item.isDef { // uses do not have doc comments to update.
--			continue
--		}
--
--		doc := docComment(pgf, item.node.(*ast.Ident))
--		if doc == nil {
--			continue
--		}
--
--		// Perform the rename in doc comments declared in the original package.
--		// go/parser strips out \r\n returns from the comment text, so go
--		// line-by-line through the comment text to get the correct positions.
--		docRegexp := regexp.MustCompile(`\b` + r.from + `\b`) // valid identifier => valid regexp
--		for _, comment := range doc.List {
--			if isDirective(comment.Text) {
--				continue
--			}
--			// TODO(adonovan): why are we looping over lines?
--			// Just run the loop body once over the entire multiline comment.
--			lines := strings.Split(comment.Text, "\n")
--			tokFile := pgf.Tok
--			commentLine := tokFile.Line(comment.Pos())
--			uri := span.URIFromPath(tokFile.Name())
--			for i, line := range lines {
--				lineStart := comment.Pos()
--				if i > 0 {
--					lineStart = tokFile.LineStart(commentLine + i)
--				}
--				for _, locs := range docRegexp.FindAllIndex([]byte(line), -1) {
--					edit, err := posEdit(tokFile, lineStart+token.Pos(locs[0]), lineStart+token.Pos(locs[1]), r.to)
--					if err != nil {
--						return nil, err // can't happen
--					}
--					result[uri] = append(result[uri], edit)
--				}
--			}
--		}
--	}
--
--	return result, nil
--}
--
--// docComment returns the doc for an identifier within the specified file.
--func docComment(pgf *ParsedGoFile, id *ast.Ident) *ast.CommentGroup {
--	nodes, _ := astutil.PathEnclosingInterval(pgf.File, id.Pos(), id.End())
--	for _, node := range nodes {
--		switch decl := node.(type) {
--		case *ast.FuncDecl:
--			return decl.Doc
--		case *ast.Field:
--			return decl.Doc
--		case *ast.GenDecl:
--			return decl.Doc
--		// For {Type,Value}Spec, if the doc on the spec is absent,
--		// search for the enclosing GenDecl
--		case *ast.TypeSpec:
--			if decl.Doc != nil {
--				return decl.Doc
--			}
--		case *ast.ValueSpec:
--			if decl.Doc != nil {
--				return decl.Doc
--			}
--		case *ast.Ident:
--		case *ast.AssignStmt:
--			// *ast.AssignStmt doesn't have an associated comment group.
--			// So, we try to find a comment just before the identifier.
--
--			// Try to find a comment group only for short variable declarations (:=).
--			if decl.Tok != token.DEFINE {
--				return nil
--			}
--
--			identLine := pgf.Tok.Line(id.Pos())
--			for _, comment := range nodes[len(nodes)-1].(*ast.File).Comments {
--				if comment.Pos() > id.Pos() {
--					// Comment is after the identifier.
--					continue
--				}
--
--				lastCommentLine := pgf.Tok.Line(comment.End())
--				if lastCommentLine+1 == identLine {
--					return comment
--				}
--			}
--		default:
--			return nil
--		}
--	}
--	return nil
--}
--
--// updatePkgName returns the updates to rename a pkgName in the import spec by
--// only modifying the package name portion of the import declaration.
--func (r *renamer) updatePkgName(pgf *ParsedGoFile, pkgName *types.PkgName) (diff.Edit, error) {
--	// Modify ImportSpec syntax to add or remove the Name as needed.
--	path, _ := astutil.PathEnclosingInterval(pgf.File, pkgName.Pos(), pkgName.Pos())
--	if len(path) < 2 {
--		return diff.Edit{}, fmt.Errorf("no path enclosing interval for %s", pkgName.Name())
--	}
--	spec, ok := path[1].(*ast.ImportSpec)
--	if !ok {
--		return diff.Edit{}, fmt.Errorf("failed to update PkgName for %s", pkgName.Name())
--	}
--
--	newText := ""
--	if pkgName.Imported().Name() != r.to {
--		newText = r.to + " "
--	}
--
--	// Replace the portion (possibly empty) of the spec before the path:
--	//     local "path"      or      "path"
--	//   ->      <-                -><-
--	return posEdit(pgf.Tok, spec.Pos(), spec.Path.Pos(), newText)
--}
--
--// parsePackageNameDecl is a convenience function that parses and
--// returns the package name declaration of file fh, and reports
--// whether the position ppos lies within it.
--//
--// Note: also used by references2.
--func parsePackageNameDecl(ctx context.Context, snapshot Snapshot, fh FileHandle, ppos protocol.Position) (*ParsedGoFile, bool, error) {
--	pgf, err := snapshot.ParseGo(ctx, fh, ParseHeader)
--	if err != nil {
--		return nil, false, err
--	}
--	// Careful: because we used ParseHeader,
--	// pgf.Pos(ppos) may be beyond EOF => (0, err).
--	pos, _ := pgf.PositionPos(ppos)
--	return pgf, pgf.File.Name.Pos() <= pos && pos <= pgf.File.Name.End(), nil
--}
--
--// enclosingFile returns the CompiledGoFile of pkg that contains the specified position.
--func enclosingFile(pkg Package, pos token.Pos) (*ParsedGoFile, bool) {
--	for _, pgf := range pkg.CompiledGoFiles() {
--		if pgf.File.Pos() <= pos && pos <= pgf.File.End() {
--			return pgf, true
--		}
--	}
--	return nil, false
--}
--
--// posEdit returns an edit to replace the (start, end) range of tf with 'new'.
--func posEdit(tf *token.File, start, end token.Pos, new string) (diff.Edit, error) {
--	startOffset, endOffset, err := safetoken.Offsets(tf, start, end)
--	if err != nil {
--		return diff.Edit{}, err
--	}
--	return diff.Edit{Start: startOffset, End: endOffset, New: new}, nil
--}
 diff -urN a/gopls/internal/lsp/source/signature_help.go b/gopls/internal/lsp/source/signature_help.go
 --- a/gopls/internal/lsp/source/signature_help.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/signature_help.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/signature_help.go	1970-01-01 08:00:00
 @@ -1,185 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -85429,7 +94306,7 @@
 -
 -	// We need full type-checking here, as we must type-check function bodies in
 -	// order to provide signature help at the requested position.
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, 0, fmt.Errorf("getting file for SignatureHelp: %w", err)
 -	}
@@ -85523,7 +94400,7 @@
 -	}
 -	return &protocol.SignatureInformation{
 -		Label:         name + s.Format(),
--		Documentation: stringToSigInfoDocumentation(s.doc, snapshot.View().Options()),
+-		Documentation: stringToSigInfoDocumentation(s.doc, snapshot.Options()),
 -		Parameters:    paramInfo,
 -	}, activeParam, nil
 -}
@@ -85540,7 +94417,7 @@
 -	activeParam := activeParameter(callExpr, len(sig.params), sig.variadic, pos)
 -	return &protocol.SignatureInformation{
 -		Label:         sig.name + sig.Format(),
--		Documentation: stringToSigInfoDocumentation(sig.doc, snapshot.View().Options()),
+-		Documentation: stringToSigInfoDocumentation(sig.doc, snapshot.Options()),
 -		Parameters:    paramInfo,
 -	}, activeParam, nil
 -
@@ -85591,8 +94468,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/stub.go b/gopls/internal/lsp/source/stub.go
 --- a/gopls/internal/lsp/source/stub.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/stub.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,238 +0,0 @@
++++ b/gopls/internal/lsp/source/stub.go	1970-01-01 08:00:00
+@@ -1,250 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -85613,10 +94490,12 @@
 -
 -	"golang.org/x/tools/go/analysis"
 -	"golang.org/x/tools/go/ast/astutil"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/analysis/stubmethods"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/internal/diff"
+-	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/typeparams"
 -)
 -
@@ -85624,7 +94503,7 @@
 -// methods of the concrete type that is assigned to an interface type
 -// at the cursor position.
 -func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle, rng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, nil, fmt.Errorf("GetTypedFile: %w", err)
 -	}
@@ -85654,7 +94533,7 @@
 -	if err != nil {
 -		return nil, nil, fmt.Errorf("failed to parse file %q declaring implementation type: %w", declPGF.URI, err)
 -	}
--	if declPGF.Fixed {
+-	if declPGF.Fixed() {
 -		return nil, nil, fmt.Errorf("file contains parse errors: %s", declPGF.URI)
 -	}
 -
@@ -85719,6 +94598,12 @@
 -	var newImports []newImport // for AddNamedImport
 -	qual := func(pkg *types.Package) string {
 -		// TODO(adonovan): don't ignore vendor prefix.
+-		//
+-		// Ignore the current package import.
+-		if pkg.Path() == conc.Pkg().Path() {
+-			return ""
+-		}
+-
 -		importPath := ImportPath(pkg.Path())
 -		name, ok := importEnv[importPath]
 -		if !ok {
@@ -85756,7 +94641,7 @@
 -	// Format the new methods.
 -	var newMethods bytes.Buffer
 -	for _, method := range missing {
--		fmt.Fprintf(&newMethods, `// %s implements %s
+-		fmt.Fprintf(&newMethods, `// %s implements %s.
 -func (%s%s%s) %s%s {
 -	panic("unimplemented")
 -}
@@ -85818,22 +94703,26 @@
 -	}
 -
 -	// Report the diff.
--	diffs := snapshot.View().Options().ComputeEdits(string(input), output.String())
--	var edits []analysis.TextEdit
+-	diffs := snapshot.Options().ComputeEdits(string(input), output.String())
+-	return tokeninternal.FileSetFor(declPGF.Tok), // edits use declPGF.Tok
+-		&analysis.SuggestedFix{TextEdits: diffToTextEdits(declPGF.Tok, diffs)},
+-		nil
+-}
+-
+-func diffToTextEdits(tok *token.File, diffs []diff.Edit) []analysis.TextEdit {
+-	edits := make([]analysis.TextEdit, 0, len(diffs))
 -	for _, edit := range diffs {
 -		edits = append(edits, analysis.TextEdit{
--			Pos:     declPGF.Tok.Pos(edit.Start),
--			End:     declPGF.Tok.Pos(edit.End),
+-			Pos:     tok.Pos(edit.Start),
+-			End:     tok.Pos(edit.End),
 -			NewText: []byte(edit.New),
 -		})
 -	}
--	return FileSetFor(declPGF.Tok), // edits use declPGF.Tok
--		&analysis.SuggestedFix{TextEdits: edits},
--		nil
+-	return edits
 -}
 diff -urN a/gopls/internal/lsp/source/symbols.go b/gopls/internal/lsp/source/symbols.go
 --- a/gopls/internal/lsp/source/symbols.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/symbols.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/symbols.go	1970-01-01 08:00:00
 @@ -1,227 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -86064,8 +94953,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/type_definition.go b/gopls/internal/lsp/source/type_definition.go
 --- a/gopls/internal/lsp/source/type_definition.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/type_definition.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,55 +0,0 @@
++++ b/gopls/internal/lsp/source/type_definition.go	1970-01-01 08:00:00
+@@ -1,57 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -86077,6 +94966,7 @@
 -	"fmt"
 -	"go/token"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/internal/event"
 -)
@@ -86086,7 +94976,7 @@
 -	ctx, done := event.Start(ctx, "source.TypeDefinition")
 -	defer done()
 -
--	pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), NarrowestPackage)
+-	pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, fh.URI())
 -	if err != nil {
 -		return nil, err
 -	}
@@ -86103,28 +94993,2392 @@
 -		return nil, nil
 -	}
 -
--	typObj := typeToObject(obj.Type())
--	if typObj == nil {
+-	tname := typeToObject(obj.Type())
+-	if tname == nil {
 -		return nil, fmt.Errorf("no type definition for %s", obj.Name())
 -	}
 -
--	// Identifiers with the type "error" are a special case with no position.
--	if hasErrorType(typObj) {
--		// TODO(rfindley): we can do better here, returning a link to the builtin
--		// file.
+-	if !tname.Pos().IsValid() {
+-		// The only defined types with no position are error and comparable.
+-		if tname.Name() != "error" && tname.Name() != "comparable" {
+-			bug.Reportf("unexpected type name with no position: %s", tname)
+-		}
 -		return nil, nil
 -	}
 -
--	loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, typObj.Pos(), typObj.Pos()+token.Pos(len(typObj.Name())))
+-	loc, err := mapPosition(ctx, pkg.FileSet(), snapshot, tname.Pos(), tname.Pos()+token.Pos(len(tname.Name())))
 -	if err != nil {
 -		return nil, err
 -	}
 -	return []protocol.Location{loc}, nil
 -}
+diff -urN a/gopls/internal/lsp/source/typerefs/doc.go b/gopls/internal/lsp/source/typerefs/doc.go
+--- a/gopls/internal/lsp/source/typerefs/doc.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/doc.go	1970-01-01 08:00:00
+@@ -1,151 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Package typerefs extracts symbol-level reachability information
+-// from the syntax of a Go package.
+-//
+-// # Background
+-//
+-// The goal of this analysis is to determine, for each package P, a nearly
+-// minimal set of packages that could affect the type checking of P. This set
+-// may contain false positives, but the smaller this set the better we can
+-// invalidate and prune packages in gopls.
+-//
+-// More precisely, for each package P we define the set of "reachable" packages
+-// from P as the set of packages that may affect the (deep) export data of the
+-// direct dependencies of P. By this definition, the complement of this set
+-// cannot affect any information derived from type checking P, such as
+-// diagnostics, cross references, or method sets. Therefore we need not
+-// invalidate any results for P when a package in the complement of this set
+-// changes.
+-//
+-// # Computing references
+-//
+-// For a given declaration D, references are computed based on identifiers or
+-// dotted identifiers referenced in the declaration of D, that may affect
+-// the type of D. However, these references reflect only local knowledge of the
+-// package and its dependency metadata, and do not depend on any analysis of
+-// the dependencies themselves. This allows the reference information for
+-// a package to be cached independent of all others.
+-//
+-// Specifically, if a referring identifier I appears in the declaration, we
+-// record an edge from D to each object possibly referenced by I. We search for
+-// references within type syntax, but do not actually type-check, so we can't
+-// reliably determine whether an expression is a type or a term, or whether a
+-// function is a builtin or generic. For example, the type of x in var x =
+-// p.F(W) only depends on W if p.F is a builtin or generic function, which we
+-// cannot know without type-checking package p. So we may over-approximate in
+-// this way.
+-//
+-//   - If I is declared in the current package, record a reference to its
+-//     declaration.
+-//   - Otherwise, if there are any dot imports in the current
+-//     file and I is exported, record a (possibly dangling) edge to
+-//     the corresponding declaration in each dot-imported package.
+-//
+-// If a dotted identifier q.I appears in the declaration, we
+-// perform a similar operation:
+-//
+-//   - If q is declared in the current package, we record a reference to that
+-//     object. It may be a var or const that has a field or method I.
+-//   - Otherwise, if q is a valid import name based on imports in the current file
+-//     and the provided metadata for dependency package names, record a
+-//     reference to the object I in that package.
+-//   - Additionally, handle the case where Q is exported, and Q.I may refer to
+-//     a field or method in a dot-imported package.
+-//
+-// That is essentially the entire algorithm, though there is some subtlety to
+-// visiting the set of identifiers or dotted identifiers that may affect the
+-// declaration type. See the visitDeclOrSpec function for the details of this
+-// analysis. Notably, we also skip identifiers that refer to type parameters in
+-// generic declarations.
+-//
+-// # Graph optimizations
+-//
+-// The references extracted from the syntax are used to construct
+-// edges between nodes representing declarations. Edges are of two
+-// kinds: internal references, from one package-level declaration to
+-// another; and external references, from a symbol in this package to
+-// a symbol imported from a direct dependency.
+-//
+-// Once the symbol reference graph is constructed, we find its
+-// strongly connected components (SCCs) using Tarjan's algorithm.
+-// As we coalesce the nodes of each SCC we compute the union of
+-// external references reached by each package-level declaration.
+-// The final result is the mapping from each exported package-level
+-// declaration to the set of external (imported) declarations that it
+-// reaches.
+-//
+-// Because it is common for many package members to have the same
+-// reachability, the result takes the form of a set of equivalence
+-// classes, each mapping a set of package-level declarations to a set
+-// of external symbols. We use a hash table to canonicalize sets so that
+-// repeated occurrences of the same set (which are common) are only
+-// represented once in memory or in the file system.
+-// For example, all declarations that ultimately reference only
+-// {fmt.Println,strings.Join} would be classed as equivalent.
+-//
+-// This approach was inspired by the Hash-Value Numbering (HVN)
+-// optimization described by Hardekopf and Lin. See
+-// golang.org/x/tools/go/pointer/hvn.go for an implementation. (Like
+-// pointer analysis, this problem is fundamentally one of graph
+-// reachability.) The HVN algorithm takes the compression a step
+-// further by preserving the topology of the SCC DAG, in which edges
+-// represent "is a superset of" constraints. Redundant edges that
+-// don't increase the solution can be deleted. We could apply the same
+-// technique here to further reduce the worst-case size of the result,
+-// but the current implementation seems adequate.
+-//
+-// # API
+-//
+-// The main entry point for this analysis is the [Encode] function,
+-// which implements the analysis described above for one package, and
+-// encodes the result as a binary message.
+-//
+-// The [Decode] function decodes the message into a usable form: a set
+-// of equivalence classes. The decoder uses a shared [PackageIndex] to
+-// enable more compact representations of sets of packages
+-// ([PackageSet]) during the global reacahability computation.
+-//
+-// The [BuildPackageGraph] constructor implements a whole-graph analysis similar
+-// to that which will be implemented by gopls, but for various reasons the
+-// logic for this analysis will eventually live in the
+-// [golang.org/x/tools/gopls/internal/lsp/cache] package. Nevertheless,
+-// BuildPackageGraph and its test serve to verify the syntactic analysis, and
+-// may serve as a proving ground for new optimizations of the whole-graph analysis.
+-//
+-// # Export data is insufficient
+-//
+-// At first it may seem that the simplest way to implement this analysis would
+-// be to consider the types.Packages of the dependencies of P, for example
+-// during export. After all, it makes sense that the type checked packages
+-// themselves could describe their dependencies. However, this does not work as
+-// type information does not describe certain syntactic relationships.
+-//
+-// For example, the following scenarios cause type information to miss
+-// syntactic relationships:
+-//
+-// Named type forwarding:
+-//
+-//	package a; type A b.B
+-//	package b; type B int
+-//
+-// Aliases:
+-//
+-//	package a; func A(f b.B)
+-//	package b; type B = func()
+-//
+-// Initializers:
+-//
+-//	package a; var A = b.B()
+-//	package b; func B() string { return "hi" }
+-//
+-// Use of the unsafe package:
+-//
+-//	package a; type A [unsafe.Sizeof(B{})]int
+-//	package b; type B struct { f1, f2, f3 int }
+-//
+-// In all of these examples, types do not contain information about the edge
+-// between the a.A and b.B declarations.
+-package typerefs
+diff -urN a/gopls/internal/lsp/source/typerefs/packageset.go b/gopls/internal/lsp/source/typerefs/packageset.go
+--- a/gopls/internal/lsp/source/typerefs/packageset.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/packageset.go	1970-01-01 08:00:00
+@@ -1,148 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package typerefs
+-
+-import (
+-	"fmt"
+-	"math/bits"
+-	"sort"
+-	"strings"
+-	"sync"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-)
+-
+-// PackageIndex stores common data to enable efficient representation of
+-// references and package sets.
+-type PackageIndex struct {
+-	// For now, PackageIndex just indexes package ids, to save space and allow for
+-	// faster unions via sparse int vectors.
+-	mu  sync.Mutex
+-	ids []source.PackageID
+-	m   map[source.PackageID]IndexID
+-}
+-
+-// NewPackageIndex creates a new PackageIndex instance for use in building
+-// reference and package sets.
+-func NewPackageIndex() *PackageIndex {
+-	return &PackageIndex{
+-		m: make(map[source.PackageID]IndexID),
+-	}
+-}
+-
+-// IndexID returns the packageIdx referencing id, creating one if id is not yet
+-// tracked by the receiver.
+-func (index *PackageIndex) IndexID(id source.PackageID) IndexID {
+-	index.mu.Lock()
+-	defer index.mu.Unlock()
+-	if i, ok := index.m[id]; ok {
+-		return i
+-	}
+-	i := IndexID(len(index.ids))
+-	index.m[id] = i
+-	index.ids = append(index.ids, id)
+-	return i
+-}
+-
+-// PackageID returns the PackageID for idx.
+-//
+-// idx must have been created by this PackageIndex instance.
+-func (index *PackageIndex) PackageID(idx IndexID) source.PackageID {
+-	index.mu.Lock()
+-	defer index.mu.Unlock()
+-	return index.ids[idx]
+-}
+-
+-// A PackageSet is a set of source.PackageIDs, optimized for inuse memory
+-// footprint and efficient union operations.
+-type PackageSet struct {
+-	// PackageSet is a sparse int vector of package indexes from parent.
+-	parent *PackageIndex
+-	sparse map[int]blockType // high bits in key, set of low bits in value
+-}
+-
+-type blockType = uint // type of each sparse vector element
+-const blockSize = bits.UintSize
+-
+-// NewSet creates a new PackageSet bound to this PackageIndex instance.
+-//
+-// PackageSets may only be combined with other PackageSets from the same
+-// instance.
+-func (index *PackageIndex) NewSet() *PackageSet {
+-	return &PackageSet{
+-		parent: index,
+-		sparse: make(map[int]blockType),
+-	}
+-}
+-
+-// DeclaringPackage returns the ID of the symbol's declaring package.
+-// The package index must be the one used during decoding.
+-func (index *PackageIndex) DeclaringPackage(sym Symbol) source.PackageID {
+-	return index.PackageID(sym.Package)
+-}
+-
+-// Add records a new element in the package set, for the provided package ID.
+-func (s *PackageSet) AddPackage(id source.PackageID) {
+-	s.Add(s.parent.IndexID(id))
+-}
+-
+-// Add records a new element in the package set.
+-// It is the caller's responsibility to ensure that idx was created with the
+-// same PackageIndex as the PackageSet.
+-func (s *PackageSet) Add(idx IndexID) {
+-	i := int(idx)
+-	s.sparse[i/blockSize] |= 1 << (i % blockSize)
+-}
+-
+-// Union records all elements from other into the receiver, mutating the
+-// receiver set but not the argument set. The receiver must not be nil, but the
+-// argument set may be nil.
+-//
+-// Precondition: both package sets were created with the same PackageIndex.
+-func (s *PackageSet) Union(other *PackageSet) {
+-	if other == nil {
+-		return // e.g. unsafe
+-	}
+-	if other.parent != s.parent {
+-		panic("other set is from a different PackageIndex instance")
+-	}
+-	for k, v := range other.sparse {
+-		if v0 := s.sparse[k]; v0 != v {
+-			s.sparse[k] = v0 | v
+-		}
+-	}
+-}
+-
+-// Contains reports whether id is contained in the receiver set.
+-func (s *PackageSet) Contains(id source.PackageID) bool {
+-	i := int(s.parent.IndexID(id))
+-	return s.sparse[i/blockSize]&(1<<(i%blockSize)) != 0
+-}
+-
+-// Elems calls f for each element of the set in ascending order.
+-func (s *PackageSet) Elems(f func(IndexID)) {
+-	blockIndexes := make([]int, 0, len(s.sparse))
+-	for k := range s.sparse {
+-		blockIndexes = append(blockIndexes, k)
+-	}
+-	sort.Ints(blockIndexes)
+-	for _, i := range blockIndexes {
+-		v := s.sparse[i]
+-		for b := 0; b < blockSize; b++ {
+-			if (v & (1 << b)) != 0 {
+-				f(IndexID(i*blockSize + b))
+-			}
+-		}
+-	}
+-}
+-
+-// String returns a human-readable representation of the set: {A, B, ...}.
+-func (s *PackageSet) String() string {
+-	var ids []string
+-	s.Elems(func(id IndexID) {
+-		ids = append(ids, string(s.parent.PackageID(id)))
+-	})
+-	return fmt.Sprintf("{%s}", strings.Join(ids, ", "))
+-}
+diff -urN a/gopls/internal/lsp/source/typerefs/pkggraph_test.go b/gopls/internal/lsp/source/typerefs/pkggraph_test.go
+--- a/gopls/internal/lsp/source/typerefs/pkggraph_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/pkggraph_test.go	1970-01-01 08:00:00
+@@ -1,243 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package typerefs_test
+-
+-// This file is logically part of the test in pkgrefs_test.go: that
+-// file defines the test assertion logic; this file provides a
+-// reference implementation of a client of the typerefs package.
+-
+-import (
+-	"bytes"
+-	"context"
+-	"fmt"
+-	"os"
+-	"runtime"
+-	"sync"
+-
+-	"golang.org/x/sync/errgroup"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
+-	"golang.org/x/tools/gopls/internal/span"
+-)
+-
+-const (
+-	// trace enables additional trace output to stdout, for debugging.
+-	//
+-	// Warning: produces a lot of output! Best to run with small package queries.
+-	trace = false
+-)
+-
+-// A Package holds reference information for a single package.
+-type Package struct {
+-	// metadata holds metadata about this package and its dependencies.
+-	metadata *source.Metadata
+-
+-	// transitiveRefs records, for each exported declaration in the package, the
+-	// transitive set of packages within the containing graph that are
+-	// transitively reachable through references, starting with the given decl.
+-	transitiveRefs map[string]*typerefs.PackageSet
+-
+-	// ReachesViaDeps records the set of packages in the containing graph whose
+-	// syntax may affect the current package's types. See the package
+-	// documentation for more details of what this means.
+-	ReachesByDeps *typerefs.PackageSet
+-}
+-
+-// A PackageGraph represents a fully analyzed graph of packages and their
+-// dependencies.
+-type PackageGraph struct {
+-	pkgIndex *typerefs.PackageIndex
+-	meta     source.MetadataSource
+-	parse    func(context.Context, span.URI) (*source.ParsedGoFile, error)
+-
+-	mu       sync.Mutex
+-	packages map[source.PackageID]*futurePackage
+-}
+-
+-// BuildPackageGraph analyzes the package graph for the requested ids, whose
+-// metadata is described by meta.
+-//
+-// The provided parse function is used to parse the CompiledGoFiles of each package.
+-//
+-// The resulting PackageGraph is fully evaluated, and may be investigated using
+-// the Package method.
+-//
+-// See the package documentation for more information on the package reference
+-// algorithm.
+-func BuildPackageGraph(ctx context.Context, meta source.MetadataSource, ids []source.PackageID, parse func(context.Context, span.URI) (*source.ParsedGoFile, error)) (*PackageGraph, error) {
+-	g := &PackageGraph{
+-		pkgIndex: typerefs.NewPackageIndex(),
+-		meta:     meta,
+-		parse:    parse,
+-		packages: make(map[source.PackageID]*futurePackage),
+-	}
+-	source.SortPostOrder(meta, ids)
+-
+-	workers := runtime.GOMAXPROCS(0)
+-	if trace {
+-		workers = 1
+-	}
+-
+-	var eg errgroup.Group
+-	eg.SetLimit(workers)
+-	for _, id := range ids {
+-		id := id
+-		eg.Go(func() error {
+-			_, err := g.Package(ctx, id)
+-			return err
+-		})
+-	}
+-	return g, eg.Wait()
+-}
+-
+-// futurePackage is a future result of analyzing a package, for use from Package only.
+-type futurePackage struct {
+-	done chan struct{}
+-	pkg  *Package
+-	err  error
+-}
+-
+-// Package gets the result of analyzing references for a single package.
+-func (g *PackageGraph) Package(ctx context.Context, id source.PackageID) (*Package, error) {
+-	g.mu.Lock()
+-	fut, ok := g.packages[id]
+-	if ok {
+-		g.mu.Unlock()
+-		select {
+-		case <-fut.done:
+-		case <-ctx.Done():
+-			return nil, ctx.Err()
+-		}
+-	} else {
+-		fut = &futurePackage{done: make(chan struct{})}
+-		g.packages[id] = fut
+-		g.mu.Unlock()
+-		fut.pkg, fut.err = g.buildPackage(ctx, id)
+-		close(fut.done)
+-	}
+-	return fut.pkg, fut.err
+-}
+-
+-// buildPackage parses a package and extracts its reference graph. It should
+-// only be called from Package.
+-func (g *PackageGraph) buildPackage(ctx context.Context, id source.PackageID) (*Package, error) {
+-	p := &Package{
+-		metadata:       g.meta.Metadata(id),
+-		transitiveRefs: make(map[string]*typerefs.PackageSet),
+-	}
+-	var files []*source.ParsedGoFile
+-	for _, filename := range p.metadata.CompiledGoFiles {
+-		f, err := g.parse(ctx, filename)
+-		if err != nil {
+-			return nil, err
+-		}
+-		files = append(files, f)
+-	}
+-	imports := make(map[source.ImportPath]*source.Metadata)
+-	for impPath, depID := range p.metadata.DepsByImpPath {
+-		if depID != "" {
+-			imports[impPath] = g.meta.Metadata(depID)
+-		}
+-	}
+-
+-	// Compute the symbol-level dependencies through this package.
+-	data := typerefs.Encode(files, id, imports)
+-
+-	// data can be persisted in a filecache, keyed
+-	// by hash(id, CompiledGoFiles, imports).
+-
+-	//      This point separates the local preprocessing
+-	//  --  of a single package (above) from the global   --
+-	//      transitive reachability query (below).
+-
+-	// classes records syntactic edges between declarations in this
+-	// package and declarations in this package or another
+-	// package. See the package documentation for a detailed
+-	// description of what these edges do (and do not) represent.
+-	classes := typerefs.Decode(g.pkgIndex, id, data)
+-
+-	// Debug
+-	if trace && len(classes) > 0 {
+-		var buf bytes.Buffer
+-		fmt.Fprintf(&buf, "%s\n", id)
+-		for _, class := range classes {
+-			for i, name := range class.Decls {
+-				if i == 0 {
+-					fmt.Fprintf(&buf, "\t")
+-				}
+-				fmt.Fprintf(&buf, " .%s", name)
+-			}
+-			// Group symbols by package.
+-			var prevID PackageID
+-			for _, sym := range class.Refs {
+-				id := g.pkgIndex.DeclaringPackage(sym)
+-				if id != prevID {
+-					prevID = id
+-					fmt.Fprintf(&buf, "\n\t\t-> %s:", id)
+-				}
+-				fmt.Fprintf(&buf, " .%s", sym.Name)
+-			}
+-			fmt.Fprintln(&buf)
+-		}
+-		os.Stderr.Write(buf.Bytes())
+-	}
+-
+-	// Now compute the transitive closure of packages reachable
+-	// from any exported symbol of this package.
+-	for _, class := range classes {
+-		set := g.pkgIndex.NewSet()
+-
+-		// The Refs slice is sorted by (PackageID, name),
+-		// so we can economize by calling g.Package only
+-		// when the package id changes.
+-		depP := p
+-		for _, sym := range class.Refs {
+-			symPkgID := g.pkgIndex.DeclaringPackage(sym)
+-			if symPkgID == id {
+-				panic("intra-package edge")
+-			}
+-			if depP.metadata.ID != symPkgID {
+-				// package changed
+-				var err error
+-				depP, err = g.Package(ctx, symPkgID)
+-				if err != nil {
+-					return nil, err
+-				}
+-			}
+-			set.Add(sym.Package)
+-			set.Union(depP.transitiveRefs[sym.Name])
+-		}
+-		for _, name := range class.Decls {
+-			p.transitiveRefs[name] = set
+-		}
+-	}
+-
+-	// Finally compute the union of transitiveRefs
+-	// across the direct deps of this package.
+-	byDeps, err := g.reachesByDeps(ctx, p.metadata)
+-	if err != nil {
+-		return nil, err
+-	}
+-	p.ReachesByDeps = byDeps
+-
+-	return p, nil
+-}
+-
+-// reachesByDeps computes the set of packages that are reachable through
+-// dependencies of the package m.
+-func (g *PackageGraph) reachesByDeps(ctx context.Context, m *source.Metadata) (*typerefs.PackageSet, error) {
+-	transitive := g.pkgIndex.NewSet()
+-	for _, depID := range m.DepsByPkgPath {
+-		dep, err := g.Package(ctx, depID)
+-		if err != nil {
+-			return nil, err
+-		}
+-		transitive.AddPackage(dep.metadata.ID)
+-		for _, set := range dep.transitiveRefs {
+-			transitive.Union(set)
+-		}
+-	}
+-	return transitive, nil
+-}
+diff -urN a/gopls/internal/lsp/source/typerefs/pkgrefs_test.go b/gopls/internal/lsp/source/typerefs/pkgrefs_test.go
+--- a/gopls/internal/lsp/source/typerefs/pkgrefs_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/pkgrefs_test.go	1970-01-01 08:00:00
+@@ -1,407 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package typerefs_test
+-
+-import (
+-	"bytes"
+-	"context"
+-	"flag"
+-	"fmt"
+-	"go/token"
+-	"go/types"
+-	"os"
+-	"sort"
+-	"strings"
+-	"sync"
+-	"testing"
+-	"time"
+-
+-	"golang.org/x/tools/go/gcexportdata"
+-	"golang.org/x/tools/go/packages"
+-	"golang.org/x/tools/gopls/internal/astutil"
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/packagesinternal"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-var (
+-	dir    = flag.String("dir", "", "dir to run go/packages from")
+-	query  = flag.String("query", "std", "go/packages load query to use for walkdecl tests")
+-	verify = flag.Bool("verify", true, "whether to verify reachable packages using export data (may be slow on large graphs)")
+-)
+-
+-type (
+-	packageName    = source.PackageName
+-	PackageID      = source.PackageID
+-	ImportPath     = source.ImportPath
+-	PackagePath    = source.PackagePath
+-	Metadata       = source.Metadata
+-	MetadataSource = source.MetadataSource
+-	ParsedGoFile   = source.ParsedGoFile
+-)
+-
+-// TestBuildPackageGraph tests the BuildPackageGraph constructor, which uses
+-// the reference analysis of the Refs function to build a graph of
+-// relationships between packages.
+-//
+-// It simulates the operation of gopls at startup: packages are loaded via
+-// go/packages, and their syntax+metadata analyzed to determine which packages
+-// are reachable from others.
+-//
+-// The test then verifies that the 'load' graph (the graph of relationships in
+-// export data) is a subgraph of the 'reach' graph constructed by
+-// BuildPackageGraph. While doing so, it constructs some statistics about the
+-// relative sizes of these graphs, along with the 'transitive imports' graph,
+-// to report the effectiveness of the reachability analysis.
+-//
+-// The following flags affect this test:
+-//   - dir sets the dir from which to run go/packages
+-//   - query sets the go/packages query to load
+-//   - verify toggles the verification w.r.t. the load graph (which may be
+-//     prohibitively expensive with large queries).
+-func TestBuildPackageGraph(t *testing.T) {
+-	if testing.Short() {
+-		t.Skip("skipping with -short: loading the packages can take a long time with a cold cache")
+-	}
+-	testenv.NeedsGoBuild(t) // for go/packages
+-
+-	t0 := time.Now()
+-	exports, meta, err := load(*query, *verify)
+-	if err != nil {
+-		t.Fatalf("loading failed: %v", err)
+-	}
+-	t.Logf("loaded %d packages in %v", len(exports), time.Since(t0))
+-
+-	ctx := context.Background()
+-	var ids []PackageID
+-	for id := range exports {
+-		ids = append(ids, id)
+-	}
+-	sort.Slice(ids, func(i, j int) bool {
+-		return ids[i] < ids[j]
+-	})
+-
+-	t0 = time.Now()
+-	g, err := BuildPackageGraph(ctx, meta, ids, newParser().parse)
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	t.Logf("building package graph took %v", time.Since(t0))
+-
+-	// Collect information about the edges between packages for later analysis.
+-	//
+-	// We compare the following package graphs:
+-	//  - the imports graph: edges are transitive imports
+-	//  - the reaches graph: edges are reachability relationships through syntax
+-	//    of imports (as defined in the package doc)
+-	//  - the loads graph: edges are packages loaded through the export data of
+-	//    imports
+-	//
+-	// By definition, loads < reaches < imports.
+-	type edgeSet map[PackageID]map[PackageID]bool
+-	var (
+-		imports    = make(edgeSet) // A imports B transitively
+-		importedBy = make(edgeSet) // A is imported by B transitively
+-		reaches    = make(edgeSet) // A reaches B through top-level declaration syntax
+-		reachedBy  = make(edgeSet) // A is reached by B through top-level declaration syntax
+-		loads      = make(edgeSet) // A loads B through export data of its direct dependencies
+-		loadedBy   = make(edgeSet) // A is loaded by B through export data of B's direct dependencies
+-	)
+-	recordEdge := func(from, to PackageID, fwd, rev edgeSet) {
+-		if fwd[from] == nil {
+-			fwd[from] = make(map[PackageID]bool)
+-		}
+-		fwd[from][to] = true
+-		if rev[to] == nil {
+-			rev[to] = make(map[PackageID]bool)
+-		}
+-		rev[to][from] = true
+-	}
+-
+-	exportedPackages := make(map[PackageID]*types.Package)
+-	importPackage := func(id PackageID) *types.Package {
+-		exportFile := exports[id]
+-		if exportFile == "" {
+-			return nil // no exported symbols
+-		}
+-		m := meta.Metadata(id)
+-		tpkg, ok := exportedPackages[id]
+-		if !ok {
+-			pkgPath := string(m.PkgPath)
+-			tpkg, err = importFromExportData(pkgPath, exportFile)
+-			if err != nil {
+-				t.Fatalf("importFromExportData(%s, %s) failed: %v", pkgPath, exportFile, err)
+-			}
+-			exportedPackages[id] = tpkg
+-		}
+-		return tpkg
+-	}
+-
+-	for _, id := range ids {
+-		pkg, err := g.Package(ctx, id)
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-		pkg.ReachesByDeps.Elems(func(id2 typerefs.IndexID) {
+-			recordEdge(id, g.pkgIndex.PackageID(id2), reaches, reachedBy)
+-		})
+-
+-		importMap := importMap(id, meta)
+-		for _, id2 := range importMap {
+-			recordEdge(id, id2, imports, importedBy)
+-		}
+-
+-		if *verify {
+-			for _, depID := range meta.Metadata(id).DepsByPkgPath {
+-				tpkg := importPackage(depID)
+-				if tpkg == nil {
+-					continue
+-				}
+-				for _, imp := range tpkg.Imports() {
+-					depID, ok := importMap[PackagePath(imp.Path())]
+-					if !ok {
+-						t.Errorf("import map (len: %d) for %s missing imported types.Package %s", len(importMap), id, imp.Path())
+-						continue
+-					}
+-					recordEdge(id, depID, loads, loadedBy)
+-				}
+-			}
+-
+-			for depID := range loads[id] {
+-				if !pkg.ReachesByDeps.Contains(depID) {
+-					t.Errorf("package %s was imported by %s, but not detected as reachable", depID, id)
+-				}
+-			}
+-		}
+-	}
+-
+-	if testing.Verbose() {
+-		fmt.Printf("%-52s%8s%8s%8s%8s%8s%8s\n", "package ID", "imp", "impBy", "reach", "reachBy", "load", "loadBy")
+-		for _, id := range ids {
+-			fmt.Printf("%-52s%8d%8d%8d%8d%8d%8d\n", id, len(imports[id]), len(importedBy[id]), len(reaches[id]), len(reachedBy[id]), len(loads[id]), len(loadedBy[id]))
+-		}
+-		fmt.Println(strings.Repeat("-", 100))
+-		fmt.Printf("%-52s%8s%8s%8s%8s%8s%8s\n", "package ID", "imp", "impBy", "reach", "reachBy", "load", "loadBy")
+-
+-		avg := func(m edgeSet) float64 {
+-			var avg float64
+-			for _, id := range ids {
+-				s := m[id]
+-				avg += float64(len(s)) / float64(len(ids))
+-			}
+-			return avg
+-		}
+-		fmt.Printf("%52s%8.1f%8.1f%8.1f%8.1f%8.1f%8.1f\n", "averages:", avg(imports), avg(importedBy), avg(reaches), avg(reachedBy), avg(loads), avg(loadedBy))
+-	}
+-}
+-
+-func importMap(id PackageID, meta MetadataSource) map[PackagePath]PackageID {
+-	imports := make(map[PackagePath]PackageID)
+-	var recordIDs func(PackageID)
+-	recordIDs = func(id PackageID) {
+-		m := meta.Metadata(id)
+-		if _, ok := imports[m.PkgPath]; ok {
+-			return
+-		}
+-		imports[m.PkgPath] = id
+-		for _, id := range m.DepsByPkgPath {
+-			recordIDs(id)
+-		}
+-	}
+-	for _, id := range meta.Metadata(id).DepsByPkgPath {
+-		recordIDs(id)
+-	}
+-	return imports
+-}
+-
+-func importFromExportData(pkgPath, exportFile string) (*types.Package, error) {
+-	file, err := os.Open(exportFile)
+-	if err != nil {
+-		return nil, err
+-	}
+-	r, err := gcexportdata.NewReader(file)
+-	if err != nil {
+-		file.Close()
+-		return nil, err
+-	}
+-	fset := token.NewFileSet()
+-	tpkg, err := gcexportdata.Read(r, fset, make(map[string]*types.Package), pkgPath)
+-	file.Close()
+-	if err != nil {
+-		return nil, err
+-	}
+-	// The export file reported by go/packages is produced by the compiler, which
+-	// has additional package dependencies due to inlining.
+-	//
+-	// Export and re-import so that we only observe dependencies from the
+-	// exported API.
+-	var out bytes.Buffer
+-	err = gcexportdata.Write(&out, fset, tpkg)
+-	if err != nil {
+-		return nil, err
+-	}
+-	return gcexportdata.Read(&out, token.NewFileSet(), make(map[string]*types.Package), pkgPath)
+-}
+-
+-func BenchmarkBuildPackageGraph(b *testing.B) {
+-	t0 := time.Now()
+-	exports, meta, err := load(*query, *verify)
+-	if err != nil {
+-		b.Fatalf("loading failed: %v", err)
+-	}
+-	b.Logf("loaded %d packages in %v", len(exports), time.Since(t0))
+-	ctx := context.Background()
+-	var ids []PackageID
+-	for id := range exports {
+-		ids = append(ids, id)
+-	}
+-	b.ResetTimer()
+-
+-	for i := 0; i < b.N; i++ {
+-		_, err := BuildPackageGraph(ctx, meta, ids, newParser().parse)
+-		if err != nil {
+-			b.Fatal(err)
+-		}
+-	}
+-}
+-
+-type memoizedParser struct {
+-	mu    sync.Mutex
+-	files map[span.URI]*futureParse
+-}
+-
+-type futureParse struct {
+-	done chan struct{}
+-	pgf  *ParsedGoFile
+-	err  error
+-}
+-
+-func newParser() *memoizedParser {
+-	return &memoizedParser{
+-		files: make(map[span.URI]*futureParse),
+-	}
+-}
+-
+-func (p *memoizedParser) parse(ctx context.Context, uri span.URI) (*ParsedGoFile, error) {
+-	doParse := func(ctx context.Context, uri span.URI) (*ParsedGoFile, error) {
+-		// TODO(adonovan): hoist this operation outside the benchmark critsec.
+-		content, err := os.ReadFile(uri.Filename())
+-		if err != nil {
+-			return nil, err
+-		}
+-		content = astutil.PurgeFuncBodies(content)
+-		pgf, _ := cache.ParseGoSrc(ctx, token.NewFileSet(), uri, content, source.ParseFull, false)
+-		return pgf, nil
+-	}
+-
+-	p.mu.Lock()
+-	fut, ok := p.files[uri]
+-	if ok {
+-		p.mu.Unlock()
+-		select {
+-		case <-fut.done:
+-		case <-ctx.Done():
+-			return nil, ctx.Err()
+-		}
+-	} else {
+-		fut = &futureParse{done: make(chan struct{})}
+-		p.files[uri] = fut
+-		p.mu.Unlock()
+-		fut.pgf, fut.err = doParse(ctx, uri)
+-		close(fut.done)
+-	}
+-	return fut.pgf, fut.err
+-}
+-
+-type mapMetadataSource struct {
+-	m map[PackageID]*Metadata
+-}
+-
+-func (s mapMetadataSource) Metadata(id PackageID) *Metadata {
+-	return s.m[id]
+-}
+-
+-// This function is a compressed version of snapshot.load from the
+-// internal/lsp/cache package, for use in testing.
+-//
+-// TODO(rfindley): it may be valuable to extract this logic from the snapshot,
+-// since it is otherwise standalone.
+-func load(query string, needExport bool) (map[PackageID]string, MetadataSource, error) {
+-	cfg := &packages.Config{
+-		Dir: *dir,
+-		Mode: packages.NeedName |
+-			packages.NeedFiles |
+-			packages.NeedCompiledGoFiles |
+-			packages.NeedImports |
+-			packages.NeedDeps |
+-			packages.NeedTypesSizes |
+-			packages.NeedModule |
+-			packages.NeedEmbedFiles |
+-			packages.LoadMode(packagesinternal.DepsErrors) |
+-			packages.LoadMode(packagesinternal.ForTest),
+-		Tests: true,
+-	}
+-	if needExport {
+-		cfg.Mode |= packages.NeedExportFile // ExportFile is not requested by gopls: this is used to verify reachability
+-	}
+-	pkgs, err := packages.Load(cfg, query)
+-	if err != nil {
+-		return nil, nil, err
+-	}
+-
+-	meta := make(map[PackageID]*Metadata)
+-	var buildMetadata func(pkg *packages.Package)
+-	buildMetadata = func(pkg *packages.Package) {
+-		id := PackageID(pkg.ID)
+-		if meta[id] != nil {
+-			return
+-		}
+-		m := &Metadata{
+-			ID:         id,
+-			PkgPath:    PackagePath(pkg.PkgPath),
+-			Name:       packageName(pkg.Name),
+-			ForTest:    PackagePath(packagesinternal.GetForTest(pkg)),
+-			TypesSizes: pkg.TypesSizes,
+-			LoadDir:    cfg.Dir,
+-			Module:     pkg.Module,
+-			Errors:     pkg.Errors,
+-			DepsErrors: packagesinternal.GetDepsErrors(pkg),
+-		}
+-		meta[id] = m
+-
+-		for _, filename := range pkg.CompiledGoFiles {
+-			m.CompiledGoFiles = append(m.CompiledGoFiles, span.URIFromPath(filename))
+-		}
+-		for _, filename := range pkg.GoFiles {
+-			m.GoFiles = append(m.GoFiles, span.URIFromPath(filename))
+-		}
+-
+-		m.DepsByImpPath = make(map[ImportPath]PackageID)
+-		m.DepsByPkgPath = make(map[PackagePath]PackageID)
+-		for importPath, imported := range pkg.Imports {
+-			importPath := ImportPath(importPath)
+-
+-			// see note in gopls/internal/lsp/cache/load.go for an explanation of this check.
+-			if importPath != "unsafe" && len(imported.CompiledGoFiles) == 0 {
+-				m.DepsByImpPath[importPath] = "" // missing
+-				continue
+-			}
+-
+-			m.DepsByImpPath[importPath] = PackageID(imported.ID)
+-			m.DepsByPkgPath[PackagePath(imported.PkgPath)] = PackageID(imported.ID)
+-			buildMetadata(imported)
+-		}
+-	}
+-
+-	exportFiles := make(map[PackageID]string)
+-	for _, pkg := range pkgs {
+-		exportFiles[PackageID(pkg.ID)] = pkg.ExportFile
+-		buildMetadata(pkg)
+-	}
+-	return exportFiles, &mapMetadataSource{meta}, nil
+-}
+diff -urN a/gopls/internal/lsp/source/typerefs/refs.go b/gopls/internal/lsp/source/typerefs/refs.go
+--- a/gopls/internal/lsp/source/typerefs/refs.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/refs.go	1970-01-01 08:00:00
+@@ -1,832 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package typerefs
+-
+-import (
+-	"fmt"
+-	"go/ast"
+-	"go/token"
+-	"sort"
+-	"strings"
+-
+-	"golang.org/x/tools/gopls/internal/astutil"
+-	"golang.org/x/tools/gopls/internal/lsp/frob"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/typeparams"
+-)
+-
+-// Encode analyzes the Go syntax trees of a package, constructs a
+-// reference graph, and uses it to compute, for each exported
+-// declaration, the set of exported symbols of directly imported
+-// packages that it references, perhaps indirectly.
+-//
+-// It returns a serializable index of this information.
+-// Use Decode to expand the result.
+-func Encode(files []*source.ParsedGoFile, id source.PackageID, imports map[source.ImportPath]*source.Metadata) []byte {
+-	return index(files, id, imports)
+-}
+-
+-// Decode decodes a serializable index of symbol
+-// reachability produced by Encode.
+-//
+-// Because many declarations reference the exact same set of symbols,
+-// the results are grouped into equivalence classes.
+-// Classes are sorted by Decls[0], ascending.
+-// The class with empty reachability is omitted.
+-//
+-// See the package documentation for more details as to what a
+-// reference does (and does not) represent.
+-func Decode(pkgIndex *PackageIndex, id source.PackageID, data []byte) []Class {
+-	return decode(pkgIndex, id, data)
+-}
+-
+-// A Class is a reachability equivalence class.
+-//
+-// It attests that each exported package-level declaration in Decls
+-// references (perhaps indirectly) one of the external (imported)
+-// symbols in Refs.
+-//
+-// Because many Decls reach the same Refs,
+-// it is more efficient to group them into classes.
+-type Class struct {
+-	Decls []string // sorted set of names of exported decls with same reachability
+-	Refs  []Symbol // set of external symbols, in ascending (PackageID, Name) order
+-}
+-
+-// A Symbol represents an external (imported) symbol
+-// referenced by the analyzed package.
+-type Symbol struct {
+-	Package IndexID // w.r.t. PackageIndex passed to decoder
+-	Name    string
+-}
+-
+-// An IndexID is a small integer that uniquely identifies a package within a
+-// given PackageIndex.
+-type IndexID int
+-
+-// -- internals --
+-
+-// A symbolSet is a set of symbols used internally during index construction.
+-//
+-// TODO(adonovan): opt: evaluate unifying Symbol and symbol.
+-// (Encode would have to create a private PackageIndex.)
+-type symbolSet map[symbol]bool
+-
+-// A symbol is the internal representation of an external
+-// (imported) symbol referenced by the analyzed package.
+-type symbol struct {
+-	pkg  source.PackageID
+-	name string
+-}
+-
+-// declNode holds information about a package-level declaration
+-// (or more than one with the same name, in ill-typed code).
+-//
+-// It is a node in the symbol reference graph, whose outgoing edges
+-// are of two kinds: intRefs and extRefs.
+-type declNode struct {
+-	name string
+-	rep  *declNode // canonical representative of this SCC (initially self)
+-
+-	// outgoing graph edges
+-	intRefs      map[*declNode]bool // to symbols in this package
+-	extRefs      symbolSet          // to imported symbols
+-	extRefsClass int                // extRefs equivalence class number (-1 until set at end)
+-
+-	// Tarjan's SCC algorithm
+-	index, lowlink int32 // Tarjan numbering
+-	scc            int32 // -ve => on stack; 0 => unvisited; +ve => node is root of a found SCC
+-}
+-
+-// state holds the working state of the Refs algorithm for a single package.
+-//
+-// The number of distinct symbols referenced by a single package
+-// (measured across all of kubernetes), was found to be:
+-//   - max = 1750.
+-//   - Several packages reference > 100 symbols.
+-//   - p95 = 32, p90 = 22, p50 = 8.
+-type state struct {
+-	// numbering of unique symbol sets
+-	class      []symbolSet    // unique symbol sets
+-	classIndex map[string]int // index of above (using SymbolSet.hash as key)
+-
+-	// Tarjan's SCC algorithm
+-	index int32
+-	stack []*declNode
+-}
+-
+-// getClassIndex returns the small integer (an index into
+-// state.class) that identifies the given set.
+-func (st *state) getClassIndex(set symbolSet) int {
+-	key := classKey(set)
+-	i, ok := st.classIndex[key]
+-	if !ok {
+-		i = len(st.class)
+-		st.classIndex[key] = i
+-		st.class = append(st.class, set)
+-	}
+-	return i
+-}
+-
+-// appendSorted appends the symbols to syms, sorts by ascending
+-// (PackageID, name), and returns the result.
+-// The argument must be an empty slice, ideally with capacity len(set).
+-func (set symbolSet) appendSorted(syms []symbol) []symbol {
+-	for sym := range set {
+-		syms = append(syms, sym)
+-	}
+-	sort.Slice(syms, func(i, j int) bool {
+-		x, y := syms[i], syms[j]
+-		if x.pkg != y.pkg {
+-			return x.pkg < y.pkg
+-		}
+-		return x.name < y.name
+-	})
+-	return syms
+-}
+-
+-// classKey returns a key such that equal keys imply equal sets.
+-// (e.g. a sorted string representation, or a cryptographic hash of same).
+-func classKey(set symbolSet) string {
+-	// Sort symbols into a stable order.
+-	// TODO(adonovan): opt: a cheap crypto hash (e.g. BLAKE2b) might
+-	// make a cheaper map key than a large string.
+-	// Try using a hasher instead of a builder.
+-	var s strings.Builder
+-	for _, sym := range set.appendSorted(make([]symbol, 0, len(set))) {
+-		fmt.Fprintf(&s, "%s:%s;", sym.pkg, sym.name)
+-	}
+-	return s.String()
+-}
+-
+-// index builds the reference graph and encodes the index.
+-func index(pgfs []*source.ParsedGoFile, id source.PackageID, imports map[source.ImportPath]*source.Metadata) []byte {
+-	// First pass: gather package-level names and create a declNode for each.
+-	//
+-	// In ill-typed code, there may be multiple declarations of the
+-	// same name; a single declInfo node will represent them all.
+-	decls := make(map[string]*declNode)
+-	addDecl := func(id *ast.Ident) {
+-		if name := id.Name; name != "_" && decls[name] == nil {
+-			node := &declNode{name: name, extRefsClass: -1}
+-			node.rep = node
+-			decls[name] = node
+-		}
+-	}
+-	for _, pgf := range pgfs {
+-		for _, d := range pgf.File.Decls {
+-			switch d := d.(type) {
+-			case *ast.GenDecl:
+-				switch d.Tok {
+-				case token.TYPE:
+-					for _, spec := range d.Specs {
+-						addDecl(spec.(*ast.TypeSpec).Name)
+-					}
+-
+-				case token.VAR, token.CONST:
+-					for _, spec := range d.Specs {
+-						for _, ident := range spec.(*ast.ValueSpec).Names {
+-							addDecl(ident)
+-						}
+-					}
+-				}
+-
+-			case *ast.FuncDecl:
+-				// non-method functions
+-				if d.Recv.NumFields() == 0 {
+-					addDecl(d.Name)
+-				}
+-			}
+-		}
+-	}
+-
+-	// Second pass: process files to collect referring identifiers.
+-	st := &state{classIndex: make(map[string]int)}
+-	for _, pgf := range pgfs {
+-		visitFile(pgf.File, imports, decls)
+-	}
+-
+-	// Find the strong components of the declNode graph
+-	// using Tarjan's algorithm, and coalesce each component.
+-	st.index = 1
+-	for _, decl := range decls {
+-		if decl.index == 0 { // unvisited
+-			st.visit(decl)
+-		}
+-	}
+-
+-	// TODO(adonovan): opt: consider compressing the serialized
+-	// representation by recording not the classes but the DAG of
+-	// non-trivial union operations (the "pointer equivalence"
+-	// optimization of Hardekopf & Lin). Unlike that algorithm,
+-	// which piggybacks on SCC coalescing, in our case it would
+-	// be better to make a forward traversal from the exported
+-	// decls, since it avoids visiting unreachable nodes, and
+-	// results in a dense (not sparse) numbering of the sets.
+-
+-	// Tabulate the unique reachability sets of
+-	// each exported package member.
+-	classNames := make(map[int][]string) // set of decls (names) for a given reachability set
+-	for name, decl := range decls {
+-		if !ast.IsExported(name) {
+-			continue
+-		}
+-
+-		decl = decl.find()
+-
+-		// Skip decls with empty reachability.
+-		if len(decl.extRefs) == 0 {
+-			continue
+-		}
+-
+-		// Canonicalize the set (and memoize).
+-		class := decl.extRefsClass
+-		if class < 0 {
+-			class = st.getClassIndex(decl.extRefs)
+-			decl.extRefsClass = class
+-		}
+-		classNames[class] = append(classNames[class], name)
+-	}
+-
+-	return encode(classNames, st.class)
+-}
+-
+-// visitFile inspects the file syntax for referring identifiers, and
+-// populates the internal and external references of decls.
+-func visitFile(file *ast.File, imports map[source.ImportPath]*source.Metadata, decls map[string]*declNode) {
+-	// Import information for this file. Multiple packages
+-	// may be referenced by a given name in the presence
+-	// of type errors (or multiple dot imports, which are
+-	// keyed by ".").
+-	fileImports := make(map[string][]source.PackageID)
+-
+-	// importEdge records a reference from decl to an imported symbol
+-	// (pkgname.name). The package name may be ".".
+-	importEdge := func(decl *declNode, pkgname, name string) {
+-		if token.IsExported(name) {
+-			for _, depID := range fileImports[pkgname] {
+-				if decl.extRefs == nil {
+-					decl.extRefs = make(symbolSet)
+-				}
+-				decl.extRefs[symbol{depID, name}] = true
+-			}
+-		}
+-	}
+-
+-	// visit finds refs within node and builds edges from fromId's decl.
+-	// References to the type parameters are ignored.
+-	visit := func(fromId *ast.Ident, node ast.Node, tparams map[string]bool) {
+-		if fromId.Name == "_" {
+-			return
+-		}
+-		from := decls[fromId.Name]
+-		// When visiting a method, there may not be a valid type declaration for
+-		// the receiver. In this case there is no way to refer to the method, so
+-		// we need not record edges.
+-		if from == nil {
+-			return
+-		}
+-
+-		// Visit each reference to name or name.sel.
+-		visitDeclOrSpec(node, func(name, sel string) {
+-			// Ignore references to type parameters.
+-			if tparams[name] {
+-				return
+-			}
+-
+-			// If name is declared in the package scope,
+-			// record an edge whether or not sel is empty.
+-			// A field or method selector may affect the
+-			// type of the current decl via initializers:
+-			//
+-			//  package p
+-			//  var x = y.F
+-			//  var y = struct{ F int }{}
+-			if to, ok := decls[name]; ok {
+-				if from.intRefs == nil {
+-					from.intRefs = make(map[*declNode]bool)
+-				}
+-				from.intRefs[to] = true
+-
+-			} else {
+-				// Only record an edge to dot-imported packages
+-				// if there was no edge to a local name.
+-				// This assumes that there are no duplicate declarations.
+-				// We conservatively, assume that this name comes from
+-				// every dot-imported package.
+-				importEdge(from, ".", name)
+-			}
+-
+-			// Record an edge to an import if it matches the name, even if that
+-			// name collides with a package level name. Unlike the case of dotted
+-			// imports, we know the package is invalid here, and choose to fail
+-			// conservatively.
+-			if sel != "" {
+-				importEdge(from, name, sel)
+-			}
+-		})
+-	}
+-
+-	// Visit the declarations and gather reference edges.
+-	// Import declarations appear before all others.
+-	for _, d := range file.Decls {
+-		switch d := d.(type) {
+-		case *ast.GenDecl:
+-			switch d.Tok {
+-			case token.IMPORT:
+-				// Record local import names for this file.
+-				for _, spec := range d.Specs {
+-					spec := spec.(*ast.ImportSpec)
+-					path := source.UnquoteImportPath(spec)
+-					if path == "" {
+-						continue
+-					}
+-					dep := imports[path]
+-					if dep == nil {
+-						// Note here that we don't try to "guess"
+-						// the name of an import based on e.g.
+-						// its importPath. Doing so would only
+-						// result in edges that don't go anywhere.
+-						continue
+-					}
+-					name := string(dep.Name)
+-					if spec.Name != nil {
+-						if spec.Name.Name == "_" {
+-							continue
+-						}
+-						name = spec.Name.Name // possibly "."
+-					}
+-					fileImports[name] = append(fileImports[name], dep.ID)
+-				}
+-
+-			case token.TYPE:
+-				for _, spec := range d.Specs {
+-					spec := spec.(*ast.TypeSpec)
+-					tparams := tparamsMap(typeparams.ForTypeSpec(spec))
+-					visit(spec.Name, spec, tparams)
+-				}
+-
+-			case token.VAR, token.CONST:
+-				for _, spec := range d.Specs {
+-					spec := spec.(*ast.ValueSpec)
+-					for _, name := range spec.Names {
+-						visit(name, spec, nil)
+-					}
+-				}
+-			}
+-
+-		case *ast.FuncDecl:
+-			// This check for NumFields() > 0 is consistent with go/types,
+-			// which reports an error but treats the declaration like a
+-			// normal function when Recv is non-nil but empty
+-			// (as in func () f()).
+-			if d.Recv.NumFields() > 0 {
+-				// Method. Associate it with the receiver.
+-				_, id, typeParams := astutil.UnpackRecv(d.Recv.List[0].Type)
+-				if id != nil {
+-					var tparams map[string]bool
+-					if len(typeParams) > 0 {
+-						tparams = make(map[string]bool)
+-						for _, tparam := range typeParams {
+-							if tparam.Name != "_" {
+-								tparams[tparam.Name] = true
+-							}
+-						}
+-					}
+-					visit(id, d, tparams)
+-				}
+-			} else {
+-				// Non-method.
+-				tparams := tparamsMap(typeparams.ForFuncType(d.Type))
+-				visit(d.Name, d, tparams)
+-			}
+-		}
+-	}
+-}
+-
+-// tparamsMap returns a set recording each name declared by the provided field
+-// list. It so happens that we only care about names declared by type parameter
+-// lists.
+-func tparamsMap(tparams *ast.FieldList) map[string]bool {
+-	if tparams == nil || len(tparams.List) == 0 {
+-		return nil
+-	}
+-	m := make(map[string]bool)
+-	for _, f := range tparams.List {
+-		for _, name := range f.Names {
+-			if name.Name != "_" {
+-				m[name.Name] = true
+-			}
+-		}
+-	}
+-	return m
+-}
+-
+-// A refVisitor visits referring identifiers and dotted identifiers.
+-//
+-// For a referring identifier I, name="I" and sel="". For a dotted identifier
+-// q.I, name="q" and sel="I".
+-type refVisitor = func(name, sel string)
+-
+-// visitDeclOrSpec visits referring idents or dotted idents that may affect
+-// the type of the declaration at the given node, which must be an ast.Decl or
+-// ast.Spec.
+-func visitDeclOrSpec(node ast.Node, f refVisitor) {
+-	// Declarations
+-	switch n := node.(type) {
+-	// ImportSpecs should not appear here, and will panic in the default case.
+-
+-	case *ast.ValueSpec:
+-		// Skip Doc, Names, Comments, which do not affect the decl type.
+-		// Initializers only affect the type of a value spec if the type is unset.
+-		if n.Type != nil {
+-			visitExpr(n.Type, f)
+-		} else { // only need to walk expr list if type is nil
+-			visitExprList(n.Values, f)
+-		}
+-
+-	case *ast.TypeSpec:
+-		// Skip Doc, Name, and Comment, which do not affect the decl type.
+-		if tparams := typeparams.ForTypeSpec(n); tparams != nil {
+-			visitFieldList(tparams, f)
+-		}
+-		visitExpr(n.Type, f)
+-
+-	case *ast.BadDecl:
+-		// nothing to do
+-
+-	// We should not reach here with a GenDecl, so panic below in the default case.
+-
+-	case *ast.FuncDecl:
+-		// Skip Doc, Name, and Body, which do not affect the type.
+-		// Recv is handled by Refs: methods are associated with their type.
+-		visitExpr(n.Type, f)
+-
+-	default:
+-		panic(fmt.Sprintf("unexpected node type %T", node))
+-	}
+-}
+-
+-// visitExpr visits referring idents and dotted idents that may affect the
+-// type of expr.
+-//
+-// visitExpr can't reliably distinguish a dotted ident pkg.X from a
+-// selection expr.f or T.method.
+-func visitExpr(expr ast.Expr, f refVisitor) {
+-	switch n := expr.(type) {
+-	// These four cases account for about two thirds of all nodes,
+-	// so we place them first to shorten the common control paths.
+-	// (See go.dev/cl/480915.)
+-	case *ast.Ident:
+-		f(n.Name, "")
+-
+-	case *ast.BasicLit:
+-		// nothing to do
+-
+-	case *ast.SelectorExpr:
+-		if ident, ok := n.X.(*ast.Ident); ok {
+-			f(ident.Name, n.Sel.Name)
+-		} else {
+-			visitExpr(n.X, f)
+-			// Skip n.Sel as we don't care about which field or method is selected,
+-			// as we'll have recorded an edge to all declarations relevant to the
+-			// receiver type via visiting n.X above.
+-		}
+-
+-	case *ast.CallExpr:
+-		visitExpr(n.Fun, f)
+-		visitExprList(n.Args, f) // args affect types for unsafe.Sizeof or builtins or generics
+-
+-	// Expressions
+-	case *ast.Ellipsis:
+-		if n.Elt != nil {
+-			visitExpr(n.Elt, f)
+-		}
+-
+-	case *ast.FuncLit:
+-		visitExpr(n.Type, f)
+-		// Skip Body, which does not affect the type.
+-
+-	case *ast.CompositeLit:
+-		if n.Type != nil {
+-			visitExpr(n.Type, f)
+-		}
+-		// Skip Elts, which do not affect the type.
+-
+-	case *ast.ParenExpr:
+-		visitExpr(n.X, f)
+-
+-	case *ast.IndexExpr:
+-		visitExpr(n.X, f)
+-		visitExpr(n.Index, f) // may affect type for instantiations
+-
+-	case *typeparams.IndexListExpr:
+-		visitExpr(n.X, f)
+-		for _, index := range n.Indices {
+-			visitExpr(index, f) // may affect the type for instantiations
+-		}
+-
+-	case *ast.SliceExpr:
+-		visitExpr(n.X, f)
+-		// skip Low, High, and Max, which do not affect type.
+-
+-	case *ast.TypeAssertExpr:
+-		// Skip X, as it doesn't actually affect the resulting type of the type
+-		// assertion.
+-		if n.Type != nil {
+-			visitExpr(n.Type, f)
+-		}
+-
+-	case *ast.StarExpr:
+-		visitExpr(n.X, f)
+-
+-	case *ast.UnaryExpr:
+-		visitExpr(n.X, f)
+-
+-	case *ast.BinaryExpr:
+-		visitExpr(n.X, f)
+-		visitExpr(n.Y, f)
+-
+-	case *ast.KeyValueExpr:
+-		panic("unreachable") // unreachable, as we don't descend into elts of composite lits.
+-
+-	case *ast.ArrayType:
+-		if n.Len != nil {
+-			visitExpr(n.Len, f)
+-		}
+-		visitExpr(n.Elt, f)
+-
+-	case *ast.StructType:
+-		visitFieldList(n.Fields, f)
+-
+-	case *ast.FuncType:
+-		if tparams := typeparams.ForFuncType(n); tparams != nil {
+-			visitFieldList(tparams, f)
+-		}
+-		if n.Params != nil {
+-			visitFieldList(n.Params, f)
+-		}
+-		if n.Results != nil {
+-			visitFieldList(n.Results, f)
+-		}
+-
+-	case *ast.InterfaceType:
+-		visitFieldList(n.Methods, f)
+-
+-	case *ast.MapType:
+-		visitExpr(n.Key, f)
+-		visitExpr(n.Value, f)
+-
+-	case *ast.ChanType:
+-		visitExpr(n.Value, f)
+-
+-	case *ast.BadExpr:
+-		// nothing to do
+-
+-	default:
+-		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
+-	}
+-}
+-
+-func visitExprList(list []ast.Expr, f refVisitor) {
+-	for _, x := range list {
+-		visitExpr(x, f)
+-	}
+-}
+-
+-func visitFieldList(n *ast.FieldList, f refVisitor) {
+-	for _, field := range n.List {
+-		visitExpr(field.Type, f)
+-	}
+-}
+-
+-// -- strong component graph construction (plundered from go/pointer) --
+-
+-// visit implements the depth-first search of Tarjan's SCC algorithm
+-// (see https://doi.org/10.1137/0201010).
+-// Precondition: x is canonical.
+-func (st *state) visit(x *declNode) {
+-	checkCanonical(x)
+-	x.index = st.index
+-	x.lowlink = st.index
+-	st.index++
+-
+-	st.stack = append(st.stack, x) // push
+-	assert(x.scc == 0, "node revisited")
+-	x.scc = -1
+-
+-	for y := range x.intRefs {
+-		// Loop invariant: x is canonical.
+-
+-		y := y.find()
+-
+-		if x == y {
+-			continue // nodes already coalesced
+-		}
+-
+-		switch {
+-		case y.scc > 0:
+-			// y is already a collapsed SCC
+-
+-		case y.scc < 0:
+-			// y is on the stack, and thus in the current SCC.
+-			if y.index < x.lowlink {
+-				x.lowlink = y.index
+-			}
+-
+-		default:
+-			// y is unvisited; visit it now.
+-			st.visit(y)
+-			// Note: x and y are now non-canonical.
+-
+-			x = x.find()
+-
+-			if y.lowlink < x.lowlink {
+-				x.lowlink = y.lowlink
+-			}
+-		}
+-	}
+-	checkCanonical(x)
+-
+-	// Is x the root of an SCC?
+-	if x.lowlink == x.index {
+-		// Coalesce all nodes in the SCC.
+-		for {
+-			// Pop y from stack.
+-			i := len(st.stack) - 1
+-			y := st.stack[i]
+-			st.stack = st.stack[:i]
+-
+-			checkCanonical(x)
+-			checkCanonical(y)
+-
+-			if x == y {
+-				break // SCC is complete.
+-			}
+-			coalesce(x, y)
+-		}
+-
+-		// Accumulate union of extRefs over
+-		// internal edges (to other SCCs).
+-		for y := range x.intRefs {
+-			y := y.find()
+-			if y == x {
+-				continue // already coalesced
+-			}
+-			assert(y.scc == 1, "edge to non-scc node")
+-			for z := range y.extRefs {
+-				if x.extRefs == nil {
+-					x.extRefs = make(symbolSet)
+-				}
+-				x.extRefs[z] = true // extRefs: x U= y
+-			}
+-		}
+-
+-		x.scc = 1
+-	}
+-}
+-
+-// coalesce combines two nodes in the strong component graph.
+-// Precondition: x and y are canonical.
+-func coalesce(x, y *declNode) {
+-	// x becomes y's canonical representative.
+-	y.rep = x
+-
+-	// x accumulates y's internal references.
+-	for z := range y.intRefs {
+-		x.intRefs[z] = true
+-	}
+-	y.intRefs = nil
+-
+-	// x accumulates y's external references.
+-	for z := range y.extRefs {
+-		if x.extRefs == nil {
+-			x.extRefs = make(symbolSet)
+-		}
+-		x.extRefs[z] = true
+-	}
+-	y.extRefs = nil
+-}
+-
+-// find returns the canonical node decl.
+-// (The nodes form a disjoint set forest.)
+-func (decl *declNode) find() *declNode {
+-	rep := decl.rep
+-	if rep != decl {
+-		rep = rep.find()
+-		decl.rep = rep // simple path compression (no union-by-rank)
+-	}
+-	return rep
+-}
+-
+-const debugSCC = false // enable assertions in strong-component algorithm
+-
+-func checkCanonical(x *declNode) {
+-	if debugSCC {
+-		assert(x == x.find(), "not canonical")
+-	}
+-}
+-
+-func assert(cond bool, msg string) {
+-	if debugSCC && !cond {
+-		panic(msg)
+-	}
+-}
+-
+-// -- serialization --
+-
+-// (The name says gob but in fact we use frob.)
+-var classesCodec = frob.CodecFor[gobClasses]()
+-
+-type gobClasses struct {
+-	Strings []string // table of strings (PackageIDs and names)
+-	Classes []gobClass
+-}
+-
+-type gobClass struct {
+-	Decls []int32 // indices into gobClasses.Strings
+-	Refs  []int32 // list of (package, name) pairs, each an index into gobClasses.Strings
+-}
+-
+-// encode encodes the equivalence classes,
+-// (classNames[i], classes[i]), for i in range classes.
+-//
+-// With the current encoding, across kubernetes,
+-// the encoded size distribution has
+-// p50 = 511B, p95 = 4.4KB, max = 108K.
+-func encode(classNames map[int][]string, classes []symbolSet) []byte {
+-	payload := gobClasses{
+-		Classes: make([]gobClass, 0, len(classNames)),
+-	}
+-
+-	// index of unique strings
+-	strings := make(map[string]int32)
+-	stringIndex := func(s string) int32 {
+-		i, ok := strings[s]
+-		if !ok {
+-			i = int32(len(payload.Strings))
+-			strings[s] = i
+-			payload.Strings = append(payload.Strings, s)
+-		}
+-		return i
+-	}
+-
+-	var refs []symbol // recycled temporary
+-	for class, names := range classNames {
+-		set := classes[class]
+-
+-		// names, sorted
+-		sort.Strings(names)
+-		gobDecls := make([]int32, len(names))
+-		for i, name := range names {
+-			gobDecls[i] = stringIndex(name)
+-		}
+-
+-		// refs, sorted by ascending (PackageID, name)
+-		gobRefs := make([]int32, 0, 2*len(set))
+-		for _, sym := range set.appendSorted(refs[:0]) {
+-			gobRefs = append(gobRefs,
+-				stringIndex(string(sym.pkg)),
+-				stringIndex(sym.name))
+-		}
+-		payload.Classes = append(payload.Classes, gobClass{
+-			Decls: gobDecls,
+-			Refs:  gobRefs,
+-		})
+-	}
+-
+-	return classesCodec.Encode(payload)
+-}
+-
+-func decode(pkgIndex *PackageIndex, id source.PackageID, data []byte) []Class {
+-	var payload gobClasses
+-	classesCodec.Decode(data, &payload)
+-
+-	classes := make([]Class, len(payload.Classes))
+-	for i, gobClass := range payload.Classes {
+-		decls := make([]string, len(gobClass.Decls))
+-		for i, decl := range gobClass.Decls {
+-			decls[i] = payload.Strings[decl]
+-		}
+-		refs := make([]Symbol, len(gobClass.Refs)/2)
+-		for i := range refs {
+-			pkgID := pkgIndex.IndexID(source.PackageID(payload.Strings[gobClass.Refs[2*i]]))
+-			name := payload.Strings[gobClass.Refs[2*i+1]]
+-			refs[i] = Symbol{Package: pkgID, Name: name}
+-		}
+-		classes[i] = Class{
+-			Decls: decls,
+-			Refs:  refs,
+-		}
+-	}
+-
+-	// Sort by ascending Decls[0].
+-	// TODO(adonovan): move sort to encoder. Determinism is good.
+-	sort.Slice(classes, func(i, j int) bool {
+-		return classes[i].Decls[0] < classes[j].Decls[0]
+-	})
+-
+-	return classes
+-}
+diff -urN a/gopls/internal/lsp/source/typerefs/refs_test.go b/gopls/internal/lsp/source/typerefs/refs_test.go
+--- a/gopls/internal/lsp/source/typerefs/refs_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/source/typerefs/refs_test.go	1970-01-01 08:00:00
+@@ -1,558 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package typerefs_test
+-
+-import (
+-	"context"
+-	"fmt"
+-	"go/token"
+-	"sort"
+-	"testing"
+-
+-	"github.com/google/go-cmp/cmp"
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
+-	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/lsp/source/typerefs"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-// TestRefs checks that the analysis reports, for each exported member
+-// of the test package ("p"), its correct dependencies on exported
+-// members of its direct imports (e.g. "ext").
+-func TestRefs(t *testing.T) {
+-	ctx := context.Background()
+-
+-	tests := []struct {
+-		label     string
+-		srcs      []string            // source for the local package; package name must be p
+-		imports   map[string]string   // for simplicity: importPath -> pkgID/pkgName (we set pkgName == pkgID); 'ext' is always available.
+-		want      map[string][]string // decl name -> id.<decl name>
+-		go118     bool                // test uses generics
+-		allowErrs bool                // whether we expect parsing errors
+-	}{
+-		{
+-			label: "empty package",
+-			want:  map[string][]string{},
+-		},
+-		{
+-			label: "fields",
+-			srcs: []string{`
+-package p
+-
+-import "ext"
+-
+-type A struct{ b B }
+-type B func(c C) (d D)
+-type C ext.C
+-type D ext.D
+-
+-// Should not be referenced by field names.
+-type b ext.B_
+-type c int.C_
+-type d ext.D_
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.C", "ext.D"},
+-				"B": {"ext.C", "ext.D"},
+-				"C": {"ext.C"},
+-				"D": {"ext.D"},
+-			},
+-		},
+-		{
+-			label: "embedding",
+-			srcs: []string{`
+-package p
+-
+-import "ext"
+-
+-type A struct{
+-	B
+-	_ struct {
+-		C
+-	}
+-	D
+-}
+-type B ext.B
+-type C ext.C
+-type D interface{
+-	B
+-}
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.B", "ext.C"},
+-				"B": {"ext.B"},
+-				"C": {"ext.C"},
+-				"D": {"ext.B"},
+-			},
+-		},
+-		{
+-			label: "constraint embedding",
+-			srcs: []string{`
+-package p
+-
+-import "ext"
+-
+-type A interface{
+-	int | B | ~C
+-	struct{D}
+-}
+-
+-type B ext.B
+-type C ext.C
+-type D ext.D
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.B", "ext.C", "ext.D"},
+-				"B": {"ext.B"},
+-				"C": {"ext.C"},
+-				"D": {"ext.D"},
+-			},
+-			go118: true,
+-		},
+-		{
+-			label: "funcs",
+-			srcs: []string{`
+-package p
+-
+-import "ext"
+-
+-type A ext.A
+-type B ext.B
+-const C B = 2
+-func F(A) B {
+-	return C
+-}
+-var V = F(W)
+-var W A
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.A"},
+-				"B": {"ext.B"},
+-				"C": {"ext.B"},
+-				"F": {"ext.A", "ext.B"},
+-				"V": {
+-					"ext.A", // via F
+-					"ext.B", // via W: can't be eliminated: F could be builtin or generic
+-				},
+-				"W": {"ext.A"},
+-			},
+-		},
+-		{
+-			label: "methods",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A ext.A
+-type B ext.B
+-`, `package p
+-
+-func (A) M(B)
+-func (*B) M(A)
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.A", "ext.B"},
+-				"B": {"ext.A", "ext.B"},
+-			},
+-		},
+-		{
+-			label: "initializers",
+-			srcs: []string{`
+-package p
+-
+-import "ext"
+-
+-var A b = C // type does not depend on C
+-type b ext.B
+-var C = d // type does depend on D
+-var d b
+-
+-var e = d + a
+-
+-var F = func() B { return E }
+-
+-var G = struct{
+-	A b
+-	_ [unsafe.Sizeof(ext.V)]int // array size + Sizeof creates edge to a var
+-	_ [unsafe.Sizeof(G)]int // creates a self edge; doesn't affect output though
+-}{}
+-
+-var H = (D + A + C*C)
+-
+-var I = (A+C).F
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.B"},
+-				"C": {"ext.B"},          // via d
+-				"G": {"ext.B", "ext.V"}, // via b,C
+-				"H": {"ext.B"},          // via d,A,C
+-				"I": {"ext.B"},
+-			},
+-		},
+-		{
+-			label: "builtins",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-var A = new(b)
+-type b struct{ ext.B }
+-
+-type C chan d
+-type d ext.D
+-
+-type S []ext.S
+-type t ext.T
+-var U = append(([]*S)(nil), new(t))
+-
+-type X map[k]v
+-type k ext.K
+-type v ext.V
+-
+-var Z = make(map[k]A)
+-
+-// close, delete, and panic cannot occur outside of statements
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.B"},
+-				"C": {"ext.D"},
+-				"S": {"ext.S"},
+-				"U": {"ext.S", "ext.T"}, // ext.T edge could be eliminated
+-				"X": {"ext.K", "ext.V"},
+-				"Z": {"ext.B", "ext.K"},
+-			},
+-		},
+-		{
+-			label: "builtin shadowing",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-var A = new(ext.B)
+-func new() c
+-type c ext.C
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.B", "ext.C"},
+-			},
+-		},
+-		{
+-			label: "named forwarding",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A B
+-type B c
+-type c ext.C
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.C"},
+-				"B": {"ext.C"},
+-			},
+-		},
+-		{
+-			label: "aliases",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A = B
+-type B = C
+-type C = ext.C
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.C"},
+-				"B": {"ext.C"},
+-				"C": {"ext.C"},
+-			},
+-		},
+-		{
+-			label: "array length",
+-			srcs: []string{`package p
+-
+-import "ext"
+-import "unsafe"
+-
+-type A [unsafe.Sizeof(ext.B{ext.C})]int
+-type A2 [unsafe.Sizeof(ext.B{f:ext.C})]int // use a KeyValueExpr
+-
+-type D [unsafe.Sizeof(struct{ f E })]int
+-type E ext.E
+-
+-type F [3]G
+-type G [ext.C]int
+-`},
+-			want: map[string][]string{
+-				"A":  {"ext.B"}, // no ext.C: doesn't enter CompLit
+-				"A2": {"ext.B"}, // ditto
+-				"D":  {"ext.E"},
+-				"E":  {"ext.E"},
+-				"F":  {"ext.C"},
+-				"G":  {"ext.C"},
+-			},
+-		},
+-		{
+-			label: "imports",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-import (
+-	"q"
+-	r2 "r"
+-	"s" // note: package name is t
+-	"z"
+-)
+-
+-type A struct {
+-	q.Q
+-	r2.R
+-	s.S // invalid ref
+-	z.Z // references both external z.Z as well as package-level type z
+-}
+-
+-type B struct {
+-	r.R // invalid ref
+-	t.T
+-}
+-
+-var X int = q.V // X={}: no descent into RHS of 'var v T = rhs'
+-var Y = q.V.W
+-
+-type z ext.Z
+-`},
+-			imports: map[string]string{"q": "q", "r": "r", "s": "t", "z": "z"},
+-			want: map[string][]string{
+-				"A": {"ext.Z", "q.Q", "r.R", "z.Z"},
+-				"B": {"t.T"},
+-				"Y": {"q.V"},
+-			},
+-		},
+-		{
+-			label: "import blank",
+-			srcs: []string{`package p
+-
+-import _ "q"
+-
+-type A q.Q
+-`},
+-			imports: map[string]string{"q": "q"},
+-			want:    map[string][]string{},
+-		},
+-		{
+-			label: "import dot",
+-			srcs: []string{`package p
+-
+-import . "q"
+-
+-type A q.Q // not actually an edge, since q is imported .
+-type B struct {
+-	C // assumed to be an edge to q
+-	D // resolved to package decl
+-}
+-
+-
+-type E error // unexported, therefore must be universe.error
+-type F Field
+-var G = Field.X
+-`, `package p
+-
+-import "ext"
+-import "q"
+-
+-type D ext.D
+-`},
+-			imports: map[string]string{"q": "q"},
+-			want: map[string][]string{
+-				"B": {"ext.D", "q.C"},
+-				"D": {"ext.D"},
+-				"F": {"q.Field"},
+-				"G": {"q.Field"},
+-			},
+-		},
+-		{
+-			label: "typeparams",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A[T any] struct {
+-	t T
+-	b B
+-}
+-
+-type B ext.B
+-
+-func F1[T any](T, B)
+-func F2[T C]()(T, B)
+-
+-type T ext.T
+-
+-type C ext.C
+-
+-func F3[T1 ~[]T2, T2 ~[]T3](t1 T1, t2 T2)
+-type T3 ext.T3
+-`, `package p
+-
+-func (A[B]) M(C) {}
+-`},
+-			want: map[string][]string{
+-				"A":  {"ext.B", "ext.C"},
+-				"B":  {"ext.B"},
+-				"C":  {"ext.C"},
+-				"F1": {"ext.B"},
+-				"F2": {"ext.B", "ext.C"},
+-				"F3": {"ext.T3"},
+-				"T":  {"ext.T"},
+-				"T3": {"ext.T3"},
+-			},
+-			go118: true,
+-		},
+-		{
+-			label: "instances",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A[T any] ext.A
+-type B[T1, T2 any] ext.B
+-
+-type C A[int]
+-type D B[int, A[E]]
+-type E ext.E
+-`},
+-			want: map[string][]string{
+-				"A": {"ext.A"},
+-				"B": {"ext.B"},
+-				"C": {"ext.A"},
+-				"D": {"ext.A", "ext.B", "ext.E"},
+-				"E": {"ext.E"},
+-			},
+-			go118: true,
+-		},
+-		{
+-			label: "duplicate decls",
+-			srcs: []string{`package p
+-
+-import "a"
+-import "ext"
+-
+-type a a.A
+-type A a
+-type b ext.B
+-type C a.A
+-func (C) Foo(x) {} // invalid parameter, but that does not matter
+-type C b
+-func (C) Bar(y) {} // invalid parameter, but that does not matter
+-
+-var x ext.X
+-var y ext.Y
+-`},
+-			imports: map[string]string{"a": "a", "b": "b"}, // "b" import should not matter, since it isn't in this file
+-			want: map[string][]string{
+-				"A": {"a.A"},
+-				"C": {"a.A", "ext.B", "ext.X", "ext.Y"},
+-			},
+-		},
+-		{
+-			label: "invalid decls",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type A B
+-
+-func () Foo(B){}
+-
+-var B struct{ ext.B
+-`},
+-			want: map[string][]string{
+-				"A":   {"ext.B"},
+-				"B":   {"ext.B"},
+-				"Foo": {"ext.B"},
+-			},
+-			allowErrs: true,
+-		},
+-		{
+-			label: "unmapped receiver",
+-			srcs: []string{`package p
+-
+-type P struct{}
+-
+-func (a) x(P)
+-`},
+-			want:      map[string][]string{},
+-			allowErrs: true,
+-		},
+-		{
+-			label: "SCC special case",
+-			srcs: []string{`package p
+-
+-import "ext"
+-
+-type X Y
+-type Y struct { Z; *X }
+-type Z map[ext.A]ext.B
+-`},
+-			want: map[string][]string{
+-				"X": {"ext.A", "ext.B"},
+-				"Y": {"ext.A", "ext.B"},
+-				"Z": {"ext.A", "ext.B"},
+-			},
+-			allowErrs: true,
+-		},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(test.label, func(t *testing.T) {
+-			if test.go118 {
+-				testenv.NeedsGo1Point(t, 18)
+-			}
+-
+-			var pgfs []*source.ParsedGoFile
+-			for i, src := range test.srcs {
+-				uri := span.URI(fmt.Sprintf("file:///%d.go", i))
+-				pgf, _ := cache.ParseGoSrc(ctx, token.NewFileSet(), uri, []byte(src), source.ParseFull, false)
+-				if !test.allowErrs && pgf.ParseErr != nil {
+-					t.Fatalf("ParseGoSrc(...) returned parse errors: %v", pgf.ParseErr)
+-				}
+-				pgfs = append(pgfs, pgf)
+-			}
+-
+-			imports := map[source.ImportPath]*source.Metadata{
+-				"ext": {ID: "ext", Name: "ext"}, // this one comes for free
+-			}
+-			for path, m := range test.imports {
+-				imports[source.ImportPath(path)] = &source.Metadata{
+-					ID:   source.PackageID(m),
+-					Name: source.PackageName(m),
+-				}
+-			}
+-
+-			data := typerefs.Encode(pgfs, "p", imports)
+-
+-			got := make(map[string][]string)
+-			index := typerefs.NewPackageIndex()
+-			for _, class := range typerefs.Decode(index, "p", data) {
+-				// We redundantly expand out the name x refs cross product
+-				// here since that's what the existing tests expect.
+-				for _, name := range class.Decls {
+-					var syms []string
+-					for _, sym := range class.Refs {
+-						syms = append(syms, fmt.Sprintf("%s.%s", index.DeclaringPackage(sym), sym.Name))
+-					}
+-					sort.Strings(syms)
+-					got[name] = syms
+-				}
+-			}
+-
+-			if diff := cmp.Diff(test.want, got); diff != "" {
+-				t.Errorf("Refs(...) returned unexpected refs (-want +got):\n%s", diff)
+-			}
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/lsp/source/types_format.go b/gopls/internal/lsp/source/types_format.go
 --- a/gopls/internal/lsp/source/types_format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/types_format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,517 +0,0 @@
++++ b/gopls/internal/lsp/source/types_format.go	1970-01-01 08:00:00
+@@ -1,520 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -86142,10 +97396,11 @@
 -	"go/types"
 -	"strings"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/event/tag"
+-	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/typeparams"
 -)
 -
@@ -86237,11 +97492,11 @@
 -			variadic = true
 -		}
 -	}
--	fset := FileSetFor(builtin.Tok)
+-	fset := tokeninternal.FileSetFor(builtin.Tok)
 -	params, _ := formatFieldList(ctx, fset, decl.Type.Params, variadic)
 -	results, needResultParens := formatFieldList(ctx, fset, decl.Type.Results, false)
 -	d := decl.Doc.Text()
--	switch s.View().Options().HoverKind {
+-	switch s.Options().HoverKind {
 -	case SynopsisDocumentation:
 -		d = doc.Synopsis(d)
 -	case NoDocumentation:
@@ -86371,7 +97626,7 @@
 -	if comment != nil {
 -		d = comment.Text()
 -	}
--	switch s.View().Options().HoverKind {
+-	switch s.Options().HoverKind {
 -	case SynopsisDocumentation:
 -		d = doc.Synopsis(d)
 -	case NoDocumentation:
@@ -86415,6 +97670,8 @@
 -		return types.TypeString(obj.Type(), qf), nil
 -	}
 -
+-	// TODO(rfindley): parsing to produce candidates can be costly; consider
+-	// using faster methods.
 -	targetpgf, pos, err := parseFull(ctx, snapshot, srcpkg.FileSet(), obj.Pos())
 -	if err != nil {
 -		return "", err // e.g. ctx cancelled
@@ -86644,8 +97901,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/util.go b/gopls/internal/lsp/source/util.go
 --- a/gopls/internal/lsp/source/util.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/util.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,555 +0,0 @@
++++ b/gopls/internal/lsp/source/util.go	1970-01-01 08:00:00
+@@ -1,533 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -86664,10 +97921,10 @@
 -	"strconv"
 -	"strings"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/span"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/tokeninternal"
 -	"golang.org/x/tools/internal/typeparams"
 -)
@@ -86677,9 +97934,9 @@
 -// https://golang.org/s/generatedcode.
 -//
 -// TODO(adonovan): opt: this function does too much.
--// Move snapshot.GetFile into the caller (most of which have already done it).
+-// Move snapshot.ReadFile into the caller (most of which have already done it).
 -func IsGenerated(ctx context.Context, snapshot Snapshot, uri span.URI) bool {
--	fh, err := snapshot.GetFile(ctx, uri)
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		return false
 -	}
@@ -86775,26 +98032,10 @@
 -// FormatNodeFile is like FormatNode, but requires only the token.File for the
 -// syntax containing the given ast node.
 -func FormatNodeFile(file *token.File, n ast.Node) string {
--	fset := FileSetFor(file)
+-	fset := tokeninternal.FileSetFor(file)
 -	return FormatNode(fset, n)
 -}
 -
--// FileSetFor returns a new FileSet containing a sequence of new Files with
--// the same base, size, and line as the input files, for use in APIs that
--// require a FileSet.
--//
--// Precondition: the input files must be non-overlapping, and sorted in order
--// of their Base.
--func FileSetFor(files ...*token.File) *token.FileSet {
--	fset := token.NewFileSet()
--	for _, f := range files {
--		f2 := fset.AddFile(f.Name(), f.Base(), f.Size())
--		lines := tokeninternal.GetLines(f)
--		f2.SetLines(lines)
--	}
--	return fset
--}
--
 -// Deref returns a pointer's element type, traversing as many levels as needed.
 -// Otherwise it returns typ.
 -//
@@ -86919,13 +98160,7 @@
 -	// Construct mapping of import paths to their defined or implicit names.
 -	imports := make(map[*types.Package]string)
 -	for _, imp := range f.Imports {
--		var obj types.Object
--		if imp.Name != nil {
--			obj = info.Defs[imp.Name]
--		} else {
--			obj = info.Implicits[imp]
--		}
--		if pkgname, ok := obj.(*types.PkgName); ok {
+-		if pkgname, ok := ImportedPkgName(info, imp); ok {
 -			imports[pkgname.Imported()] = pkgname.Name()
 -		}
 -	}
@@ -87203,8 +98438,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go
 --- a/gopls/internal/lsp/source/view.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/view.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,857 +0,0 @@
++++ b/gopls/internal/lsp/source/view.go	1970-01-01 08:00:00
+@@ -1,1036 +0,0 @@
 -// Copyright 2018 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -87215,9 +98450,11 @@
 -	"bytes"
 -	"context"
 -	"crypto/sha256"
+-	"encoding/json"
 -	"errors"
 -	"fmt"
 -	"go/ast"
+-	"go/parser"
 -	"go/scanner"
 -	"go/token"
 -	"go/types"
@@ -87227,11 +98464,12 @@
 -	"golang.org/x/tools/go/analysis"
 -	"golang.org/x/tools/go/packages"
 -	"golang.org/x/tools/go/types/objectpath"
--	"golang.org/x/tools/gopls/internal/govulncheck"
+-	"golang.org/x/tools/gopls/internal/lsp/progress"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source/methodsets"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
 -	"golang.org/x/tools/internal/event/label"
 -	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/gocommand"
@@ -87262,6 +98500,18 @@
 -	// subsequent snapshots in a view may not have adjacent global IDs.
 -	GlobalID() GlobalSnapshotID
 -
+-	// FileKind returns the type of a file.
+-	//
+-	// We can't reliably deduce the kind from the file name alone,
+-	// as some editors can be told to interpret a buffer as
+-	// language different from the file name heuristic, e.g. that
+-	// an .html file actually contains Go "html/template" syntax,
+-	// or even that a .go file contains Python.
+-	FileKind(FileHandle) FileKind
+-
+-	// Options returns the options associated with this snapshot.
+-	Options() *Options
+-
 -	// View returns the View associated with this snapshot.
 -	View() View
 -
@@ -87269,19 +98519,16 @@
 -	// on behalf of this snapshot.
 -	BackgroundContext() context.Context
 -
--	// ValidBuildConfiguration returns true if there is some error in the
--	// user's workspace. In particular, if they are both outside of a module
--	// and their GOPATH.
--	ValidBuildConfiguration() bool
+-	// A Snapshot is a caching implementation of FileSource whose
+-	// ReadFile method returns consistent information about the existence
+-	// and content of each file throughout its lifetime.
+-	FileSource
 -
 -	// FindFile returns the FileHandle for the given URI, if it is already
 -	// in the given snapshot.
+-	// TODO(adonovan): delete this operation; use ReadFile instead.
 -	FindFile(uri span.URI) FileHandle
 -
--	// GetFile returns the FileHandle for a given URI, initializing it if it is
--	// not already part of the snapshot.
--	GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
--
 -	// AwaitInitialized waits until the snapshot's view is initialized.
 -	AwaitInitialized(ctx context.Context)
 -
@@ -87298,10 +98545,13 @@
 -	// ParseGo returns the parsed AST for the file.
 -	// If the file is not available, returns nil and an error.
 -	// Position information is added to FileSet().
--	ParseGo(ctx context.Context, fh FileHandle, mode ParseMode) (*ParsedGoFile, error)
+-	ParseGo(ctx context.Context, fh FileHandle, mode parser.Mode) (*ParsedGoFile, error)
 -
--	// Analyze runs the specified analyzers on the given package at this snapshot.
--	Analyze(ctx context.Context, id PackageID, analyzers []*Analyzer) ([]*Diagnostic, error)
+-	// Analyze runs the specified analyzers on the given packages at this snapshot.
+-	//
+-	// If the provided tracker is non-nil, it may be used to report progress of
+-	// the analysis pass.
+-	Analyze(ctx context.Context, pkgIDs map[PackageID]unit, analyzers []*Analyzer, tracker *progress.Tracker) ([]*Diagnostic, error)
 -
 -	// RunGoCommandPiped runs the given `go` command, writing its output
 -	// to stdout and stderr. Verb, Args, and WorkingDir must be specified.
@@ -87321,7 +98571,7 @@
 -
 -	// RunProcessEnvFunc runs fn with the process env for this snapshot's view.
 -	// Note: the process env contains cached module and filesystem state.
--	RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error
+-	RunProcessEnvFunc(ctx context.Context, fn func(context.Context, *imports.Options) error) error
 -
 -	// ModFiles are the go.mod files enclosed in the snapshot's view and known
 -	// to the snapshot.
@@ -87340,7 +98590,7 @@
 -
 -	// ModVuln returns import vulnerability analysis for the given go.mod URI.
 -	// Concurrent requests are combined into a single command.
--	ModVuln(ctx context.Context, modURI span.URI) (*govulncheck.Result, error)
+-	ModVuln(ctx context.Context, modURI span.URI) (*vulncheck.Result, error)
 -
 -	// GoModForFile returns the URI of the go.mod file for the given URI.
 -	GoModForFile(uri span.URI) span.URI
@@ -87355,7 +98605,20 @@
 -	BuiltinFile(ctx context.Context) (*ParsedGoFile, error)
 -
 -	// IsBuiltin reports whether uri is part of the builtin package.
--	IsBuiltin(ctx context.Context, uri span.URI) bool
+-	IsBuiltin(uri span.URI) bool
+-
+-	// CriticalError returns any critical errors in the workspace.
+-	//
+-	// A nil result may mean success, or context cancellation.
+-	CriticalError(ctx context.Context) *CriticalError
+-
+-	// Symbols returns all symbols in the snapshot.
+-	//
+-	// If workspaceOnly is set, this only includes symbols from files in a
+-	// workspace package. Otherwise, it returns symbols from all loaded packages.
+-	Symbols(ctx context.Context, workspaceOnly bool) (map[span.URI][]Symbol, error)
+-
+-	// -- package metadata --
 -
 -	// ReverseDependencies returns a new mapping whose entries are
 -	// the ID and Metadata of each package in the workspace that
@@ -87363,35 +98626,59 @@
 -	// excluding id itself.
 -	ReverseDependencies(ctx context.Context, id PackageID, transitive bool) (map[PackageID]*Metadata, error)
 -
--	// ActiveMetadata returns a new, unordered slice containing
--	// metadata for all packages considered 'active' in the workspace.
+-	// WorkspaceMetadata returns a new, unordered slice containing
+-	// metadata for all ordinary and test packages (but not
+-	// intermediate test variants) in the workspace.
 -	//
--	// In normal memory mode, this is all workspace packages. In degraded memory
--	// mode, this is just the reverse transitive closure of open packages.
--	ActiveMetadata(ctx context.Context) ([]*Metadata, error)
+-	// The workspace is the set of modules typically defined by a
+-	// go.work file. It is not transitively closed: for example,
+-	// the standard library is not usually part of the workspace
+-	// even though every module in the workspace depends on it.
+-	//
+-	// Operations that must inspect all the dependencies of the
+-	// workspace packages should instead use AllMetadata.
+-	WorkspaceMetadata(ctx context.Context) ([]*Metadata, error)
 -
--	// AllMetadata returns a new unordered array of metadata for all packages in the workspace.
+-	// AllMetadata returns a new unordered array of metadata for
+-	// all packages known to this snapshot, which includes the
+-	// packages of all workspace modules plus their transitive
+-	// import dependencies.
+-	//
+-	// It may also contain ad-hoc packages for standalone files.
+-	// It includes all test variants.
 -	AllMetadata(ctx context.Context) ([]*Metadata, error)
 -
--	// Symbols returns all symbols in the snapshot.
--	Symbols(ctx context.Context) (map[span.URI][]Symbol, error)
--
 -	// Metadata returns the metadata for the specified package,
 -	// or nil if it was not found.
 -	Metadata(id PackageID) *Metadata
 -
 -	// MetadataForFile returns a new slice containing metadata for each
 -	// package containing the Go file identified by uri, ordered by the
--	// number of CompiledGoFiles (i.e. "narrowest" to "widest" package).
+-	// number of CompiledGoFiles (i.e. "narrowest" to "widest" package),
+-	// and secondarily by IsIntermediateTestVariant (false < true).
 -	// The result may include tests and intermediate test variants of
 -	// importable packages.
 -	// It returns an error if the context was cancelled.
 -	MetadataForFile(ctx context.Context, uri span.URI) ([]*Metadata, error)
 -
+-	// OrphanedFileDiagnostics reports diagnostics for files that have no package
+-	// associations or which only have only command-line-arguments packages.
+-	//
+-	// The caller must not mutate the result.
+-	OrphanedFileDiagnostics(ctx context.Context) (map[span.URI]*Diagnostic, error)
+-
+-	// -- package type-checking --
+-
 -	// TypeCheck parses and type-checks the specified packages,
 -	// and returns them in the same order as the ids.
 -	// The resulting packages' types may belong to different importers,
 -	// so types from different packages are incommensurable.
+-	//
+-	// In general, clients should never need to type-checked
+-	// syntax for an intermediate test variant (ITV) package.
+-	// Callers should apply RemoveIntermediateTestVariants (or
+-	// equivalent) before this method, or any of the potentially
+-	// type-checking methods below.
 -	TypeCheck(ctx context.Context, ids ...PackageID) ([]Package, error)
 -
 -	// PackageDiagnostics returns diagnostics for files contained in specified
@@ -87412,11 +98699,21 @@
 -	// If these indexes cannot be loaded from cache, the requested packages may
 -	// be type-checked.
 -	MethodSets(ctx context.Context, ids ...PackageID) ([]*methodsets.Index, error)
+-}
 -
--	// GetCriticalError returns any critical errors in the workspace.
--	//
--	// A nil result may mean success, or context cancellation.
--	GetCriticalError(ctx context.Context) *CriticalError
+-// NarrowestMetadataForFile returns metadata for the narrowest package
+-// (the one with the fewest files) that encloses the specified file.
+-// The result may be a test variant, but never an intermediate test variant.
+-func NarrowestMetadataForFile(ctx context.Context, snapshot Snapshot, uri span.URI) (*Metadata, error) {
+-	metas, err := snapshot.MetadataForFile(ctx, uri)
+-	if err != nil {
+-		return nil, err
+-	}
+-	RemoveIntermediateTestVariants(&metas)
+-	if len(metas) == 0 {
+-		return nil, fmt.Errorf("no package metadata for file %s", uri)
+-	}
+-	return metas[0], nil
 -}
 -
 -type XrefIndex interface {
@@ -87429,28 +98726,34 @@
 -	return []label.Label{tag.Snapshot.Of(snapshot.SequenceID()), tag.Directory.Of(snapshot.View().Folder())}
 -}
 -
--// PackageForFile is a convenience function that selects a package to
--// which this file belongs (narrowest or widest), type-checks it in
--// the requested mode (full or workspace), and returns it, along with
--// the parse tree of that file.
+-// NarrowestPackageForFile is a convenience function that selects the
+-// narrowest non-ITV package to which this file belongs, type-checks
+-// it in the requested mode (full or workspace), and returns it, along
+-// with the parse tree of that file.
+-//
+-// The "narrowest" package is the one with the fewest number of files
+-// that includes the given file. This solves the problem of test
+-// variants, as the test will have more files than the non-test package.
+-// (Historically the preference was a parameter but widest was almost
+-// never needed.)
+-//
+-// An intermediate test variant (ITV) package has identical source
+-// to a regular package but resolves imports differently.
+-// gopls should never need to type-check them.
 -//
 -// Type-checking is expensive. Call snapshot.ParseGo if all you need
 -// is a parse tree, or snapshot.MetadataForFile if you only need metadata.
--func PackageForFile(ctx context.Context, snapshot Snapshot, uri span.URI, pkgSel PackageSelector) (Package, *ParsedGoFile, error) {
+-func NarrowestPackageForFile(ctx context.Context, snapshot Snapshot, uri span.URI) (Package, *ParsedGoFile, error) {
 -	metas, err := snapshot.MetadataForFile(ctx, uri)
 -	if err != nil {
 -		return nil, nil, err
 -	}
+-	RemoveIntermediateTestVariants(&metas)
 -	if len(metas) == 0 {
 -		return nil, nil, fmt.Errorf("no package metadata for file %s", uri)
 -	}
--	switch pkgSel {
--	case NarrowestPackage:
--		metas = metas[:1]
--	case WidestPackage:
--		metas = metas[len(metas)-1:]
--	}
--	pkgs, err := snapshot.TypeCheck(ctx, metas[0].ID)
+-	narrowest := metas[0]
+-	pkgs, err := snapshot.TypeCheck(ctx, narrowest.ID)
 -	if err != nil {
 -		return nil, nil, err
 -	}
@@ -87462,23 +98765,6 @@
 -	return pkg, pgf, err
 -}
 -
--// PackageSelector sets how a package is selected out from a set of packages
--// containing a given file.
--type PackageSelector int
--
--const (
--	// NarrowestPackage picks the "narrowest" package for a given file.
--	// By "narrowest" package, we mean the package with the fewest number of
--	// files that includes the given file. This solves the problem of test
--	// variants, as the test will have more files than the non-test package.
--	NarrowestPackage PackageSelector = iota
--
--	// WidestPackage returns the Package containing the most files.
--	// This is useful for something like diagnostics, where we'd prefer to
--	// offer diagnostics for as many files as possible.
--	WidestPackage
--)
--
 -// InvocationFlags represents the settings of a particular go command invocation.
 -// It is a mode, plus a set of flag bits.
 -type InvocationFlags int
@@ -87512,15 +98798,15 @@
 -// This is the level at which we maintain configuration like working directory
 -// and build tags.
 -type View interface {
+-	// ID returns a globally unique identifier for this view.
+-	ID() string
+-
 -	// Name returns the name this view was constructed with.
 -	Name() string
 -
 -	// Folder returns the folder with which this view was created.
 -	Folder() span.URI
 -
--	// Options returns a copy of the Options for this view.
--	Options() *Options
--
 -	// Snapshot returns the current snapshot for the view, and a
 -	// release function that must be called when the Snapshot is
 -	// no longer needed.
@@ -87547,20 +98833,11 @@
 -	// Vulnerabilities returns known vulnerabilities for the given modfile.
 -	// TODO(suzmue): replace command.Vuln with a different type, maybe
 -	// https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck/govulnchecklib#Summary?
--	Vulnerabilities(modfile ...span.URI) map[span.URI]*govulncheck.Result
+-	Vulnerabilities(modfile ...span.URI) map[span.URI]*vulncheck.Result
 -
 -	// SetVulnerabilities resets the list of vulnerabilities that exists for the given modules
 -	// required by modfile.
--	SetVulnerabilities(modfile span.URI, vulncheckResult *govulncheck.Result)
--
--	// FileKind returns the type of a file.
--	//
--	// We can't reliably deduce the kind from the file name alone,
--	// as some editors can be told to interpret a buffer as
--	// language different from the file name heuristic, e.g. that
--	// an .html file actually contains Go "html/template" syntax,
--	// or even that a .go file contains Python.
--	FileKind(FileHandle) FileKind
+-	SetVulnerabilities(modfile span.URI, vulncheckResult *vulncheck.Result)
 -
 -	// GoVersion returns the configured Go version for this view.
 -	GoVersion() int
@@ -87570,10 +98847,14 @@
 -	GoVersionString() string
 -}
 -
--// A FileSource maps uris to FileHandles.
+-// A FileSource maps URIs to FileHandles.
 -type FileSource interface {
--	// GetFile returns the FileHandle for a given URI.
--	GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
+-	// ReadFile returns the FileHandle for a given URI, either by
+-	// reading the content of the file or by obtaining it from a cache.
+-	//
+-	// Invariant: ReadFile must only return an error in the case of context
+-	// cancellation. If ctx.Err() is nil, the resulting error must also be nil.
+-	ReadFile(ctx context.Context, uri span.URI) (FileHandle, error)
 -}
 -
 -// A MetadataSource maps package IDs to metadata.
@@ -87589,17 +98870,39 @@
 -// A ParsedGoFile contains the results of parsing a Go file.
 -type ParsedGoFile struct {
 -	URI  span.URI
--	Mode ParseMode
+-	Mode parser.Mode
 -	File *ast.File
 -	Tok  *token.File
 -	// Source code used to build the AST. It may be different from the
 -	// actual content of the file if we have fixed the AST.
--	Src      []byte
--	Fixed    bool
+-	Src []byte
+-
+-	// FixedSrc and Fixed AST report on "fixing" that occurred during parsing of
+-	// this file.
+-	//
+-	// If FixedSrc == true, the source contained in the Src field was modified
+-	// from the original source to improve parsing.
+-	//
+-	// If FixedAST == true, the ast was modified after parsing, and therefore
+-	// positions encoded in the AST may not accurately represent the content of
+-	// the Src field.
+-	//
+-	// TODO(rfindley): there are many places where we haphazardly use the Src or
+-	// positions without checking these fields. Audit these places and guard
+-	// accordingly. After doing so, we may find that we don't need to
+-	// differentiate FixedSrc and FixedAST.
+-	FixedSrc bool
+-	FixedAST bool
 -	Mapper   *protocol.Mapper // may map fixed Src, not file content
 -	ParseErr scanner.ErrorList
 -}
 -
+-// Fixed reports whether p was "Fixed", meaning that its source or positions
+-// may not correlate with the original file.
+-func (p ParsedGoFile) Fixed() bool {
+-	return p.FixedSrc || p.FixedAST
+-}
+-
 -// -- go/token domain convenience helpers --
 -
 -// PositionPos returns the token.Pos of protocol position p within the file.
@@ -87677,35 +98980,47 @@
 -}
 -
 -// Metadata represents package metadata retrieved from go/packages.
+-// The Deps* maps do not contain self-import edges.
+-//
+-// An ad-hoc package (without go.mod or GOPATH) has its ID, PkgPath,
+-// and LoadDir equal to the absolute path of its directory.
 -type Metadata struct {
--	ID              PackageID
--	PkgPath         PackagePath
--	Name            PackageName
+-	ID      PackageID
+-	PkgPath PackagePath
+-	Name    PackageName
+-
+-	// these three fields are as defined by go/packages.Package
 -	GoFiles         []span.URI
 -	CompiledGoFiles []span.URI
--	ForTest         PackagePath // package path under test, or ""
--	TypesSizes      types.Sizes
--	Errors          []packages.Error
--	DepsByImpPath   map[ImportPath]PackageID  // may contain dups; empty ID => missing
--	DepsByPkgPath   map[PackagePath]PackageID // values are unique and non-empty
--	Module          *packages.Module
--	DepsErrors      []*packagesinternal.PackageError
--	Diagnostics     []*Diagnostic // processed diagnostics from 'go list'
--	LoadDir         string        // directory from which go/packages was run
+-	IgnoredFiles    []span.URI
+-
+-	ForTest       PackagePath // q in a "p [q.test]" package, else ""
+-	TypesSizes    types.Sizes
+-	Errors        []packages.Error          // must be set for packages in import cycles
+-	DepsByImpPath map[ImportPath]PackageID  // may contain dups; empty ID => missing
+-	DepsByPkgPath map[PackagePath]PackageID // values are unique and non-empty
+-	Module        *packages.Module
+-	DepsErrors    []*packagesinternal.PackageError
+-	Diagnostics   []*Diagnostic // processed diagnostics from 'go list'
+-	LoadDir       string        // directory from which go/packages was run
+-	Standalone    bool          // package synthesized for a standalone file (e.g. ignore-tagged)
 -}
 -
 -func (m *Metadata) String() string { return string(m.ID) }
 -
 -// IsIntermediateTestVariant reports whether the given package is an
--// intermediate test variant, e.g. "net/http [net/url.test]".
+-// intermediate test variant (ITV), e.g. "net/http [net/url.test]".
+-//
+-// An ITV has identical syntax to the regular variant, but different
+-// import metadata (DepsBy{Imp,Pkg}Path).
 -//
 -// Such test variants arise when an x_test package (in this case net/url_test)
--// imports a package (in this case net/http) that itself imports the the
+-// imports a package (in this case net/http) that itself imports the
 -// non-x_test package (in this case net/url).
 -//
 -// This is done so that the forward transitive closure of net/url_test has
 -// only one package for the "net/url" import.
--// The intermediate test variant exists to hold the test variant import:
+-// The ITV exists to hold the test variant import:
 -//
 -// net/url_test [net/url.test]
 -//
@@ -87726,19 +99041,86 @@
 -// variants can result in many additional packages that are essentially (but
 -// not quite) identical. For this reason, we filter these variants wherever
 -// possible.
+-//
+-// # Why we mostly ignore intermediate test variants
+-//
+-// In projects with complicated tests, there may be a very large
+-// number of ITVs--asymptotically more than the number of ordinary
+-// variants. Since they have identical syntax, it is fine in most
+-// cases to ignore them since the results of analyzing the ordinary
+-// variant suffice. However, this is not entirely sound.
+-//
+-// Consider this package:
+-//
+-//	// p/p.go -- in all variants of p
+-//	package p
+-//	type T struct { io.Closer }
+-//
+-//	// p/p_test.go -- in test variant of p
+-//	package p
+-//	func (T) Close() error { ... }
+-//
+-// The ordinary variant "p" defines T with a Close method promoted
+-// from io.Closer. But its test variant "p [p.test]" defines a type T
+-// with a Close method from p_test.go.
+-//
+-// Now consider a package q that imports p, perhaps indirectly. Within
+-// it, T.Close will resolve to the first Close method:
+-//
+-//	// q/q.go -- in all variants of q
+-//	package q
+-//	import "p"
+-//	var _ = new(p.T).Close
+-//
+-// Let's assume p also contains this file defining an external test (xtest):
+-//
+-//	// p/p_x_test.go -- external test of p
+-//	package p_test
+-//	import ( "q"; "testing" )
+-//	func Test(t *testing.T) { ... }
+-//
+-// Note that q imports p, but p's xtest imports q. Now, in "q
+-// [p.test]", the intermediate test variant of q built for p's
+-// external test, T.Close resolves not to the io.Closer.Close
+-// interface method, but to the concrete method of T.Close
+-// declared in p_test.go.
+-//
+-// If we now request all references to the T.Close declaration in
+-// p_test.go, the result should include the reference from q's ITV.
+-// (It's not just methods that can be affected; fields can too, though
+-// it requires bizarre code to achieve.)
+-//
+-// As a matter of policy, gopls mostly ignores this subtlety,
+-// because to account for it would require that we type-check every
+-// intermediate test variant of p, of which there could be many.
+-// Good code doesn't rely on such trickery.
+-//
+-// Most callers of MetadataForFile call RemoveIntermediateTestVariants
+-// to discard them before requesting type checking, or the products of
+-// type-checking such as the cross-reference index or method set index.
+-//
+-// MetadataForFile doesn't do this filtering itself becaused in some
+-// cases we need to make a reverse dependency query on the metadata
+-// graph, and it's important to include the rdeps of ITVs in that
+-// query. But the filtering of ITVs should be applied after that step,
+-// before type checking.
+-//
+-// In general, we should never type check an ITV.
 -func (m *Metadata) IsIntermediateTestVariant() bool {
 -	return m.ForTest != "" && m.ForTest != m.PkgPath && m.ForTest+"_test" != m.PkgPath
 -}
 -
 -// RemoveIntermediateTestVariants removes intermediate test variants, modifying the array.
--func RemoveIntermediateTestVariants(metas []*Metadata) []*Metadata {
+-// We use a pointer to a slice make it impossible to forget to use the result.
+-func RemoveIntermediateTestVariants(pmetas *[]*Metadata) {
+-	metas := *pmetas
 -	res := metas[:0]
 -	for _, m := range metas {
 -		if !m.IsIntermediateTestVariant() {
 -			res = append(res, m)
 -		}
 -	}
--	return res
+-	*pmetas = res
 -}
 -
 -var ErrViewExists = errors.New("view already exists for session")
@@ -87802,22 +99184,26 @@
 -	return err == ErrTmpModfileUnsupported || err == ErrNoModOnDisk
 -}
 -
--// ParseMode controls the content of the AST produced when parsing a source file.
--type ParseMode int
--
+-// Common parse modes; these should be reused wherever possible to increase
+-// cache hits.
 -const (
 -	// ParseHeader specifies that the main package declaration and imports are needed.
 -	// This is the mode used when attempting to examine the package graph structure.
--	ParseHeader ParseMode = iota
+-	ParseHeader = parser.AllErrors | parser.ParseComments | parser.ImportsOnly | SkipObjectResolution
 -
 -	// ParseFull specifies the full AST is needed.
 -	// This is used for files of direct interest where the entire contents must
 -	// be considered.
--	ParseFull
+-	ParseFull = parser.AllErrors | parser.ParseComments | SkipObjectResolution
 -)
 -
--// A FileHandle is an interface to files tracked by the LSP session, which may
--// be either files read from disk, or open in the editor session (overlays).
+-// A FileHandle represents the URI, content, hash, and optional
+-// version of a file tracked by the LSP session.
+-//
+-// File content may be provided by the file system (for Saved files)
+-// or from an overlay, for open files with unsaved edits.
+-// A FileHandle may record an attempt to read a non-existent file,
+-// in which case Content returns an error.
 -type FileHandle interface {
 -	// URI is the URI for this file handle.
 -	// TODO(rfindley): this is not actually well-defined. In some cases, there
@@ -87827,15 +99213,15 @@
 -	// FileIdentity returns a FileIdentity for the file, even if there was an
 -	// error reading it.
 -	FileIdentity() FileIdentity
--	// Saved reports whether the file has the same content on disk.
--	// For on-disk files, this is trivially true.
--	Saved() bool
+-	// SameContentsOnDisk reports whether the file has the same content on disk:
+-	// it is false for files open on an editor with unsaved edits.
+-	SameContentsOnDisk() bool
 -	// Version returns the file version, as defined by the LSP client.
 -	// For on-disk file handles, Version returns 0.
 -	Version() int32
--	// Read reads the contents of a file.
+-	// Content returns the contents of a file.
 -	// If the file is not available, returns a nil slice and an error.
--	Read() ([]byte, error)
+-	Content() ([]byte, error)
 -}
 -
 -// A Hash is a cryptographic digest of the contents of a file.
@@ -87938,6 +99324,10 @@
 -	// the analyzer's suggested fixes through a Command, not a TextEdit.
 -	Fix string
 -
+-	// fixesDiagnostic reports if a diagnostic from the analyzer can be fixed by Fix.
+-	// If nil then all diagnostics from the analyzer are assumed to be fixable.
+-	fixesDiagnostic func(*Diagnostic) bool
+-
 -	// ActionKind is the kind of code action this analyzer produces. If
 -	// unspecified the type defaults to quickfix.
 -	ActionKind []protocol.CodeActionKind
@@ -87945,6 +99335,10 @@
 -	// Severity is the severity set for diagnostics reported by this
 -	// analyzer. If left unset it defaults to Warning.
 -	Severity protocol.DiagnosticSeverity
+-
+-	// Tag is extra tags (unnecessary, deprecated, etc) for diagnostics
+-	// reported by this analyzer.
+-	Tag []protocol.DiagnosticTag
 -}
 -
 -func (a *Analyzer) String() string { return a.Analyzer.String() }
@@ -87963,6 +99357,14 @@
 -	return a.Enabled
 -}
 -
+-// FixesDiagnostic returns true if Analyzer.Fix can fix the Diagnostic.
+-func (a Analyzer) FixesDiagnostic(d *Diagnostic) bool {
+-	if a.fixesDiagnostic == nil {
+-		return true
+-	}
+-	return a.fixesDiagnostic(d)
+-}
+-
 -// Declare explicit types for package paths, names, and IDs to ensure that we
 -// never use an ID where a path belongs, and vice versa. If we confused these,
 -// it would result in confusing errors because package IDs often look like
@@ -87989,17 +99391,16 @@
 -
 -	// Results of parsing:
 -	FileSet() *token.FileSet
--	ParseMode() ParseMode
 -	CompiledGoFiles() []*ParsedGoFile // (borrowed)
 -	File(uri span.URI) (*ParsedGoFile, error)
 -	GetSyntax() []*ast.File // (borrowed)
--	HasParseErrors() bool
+-	GetParseErrors() []scanner.ErrorList
 -
 -	// Results of type checking:
 -	GetTypes() *types.Package
+-	GetTypeErrors() []types.Error
 -	GetTypesInfo() *types.Info
 -	DependencyTypes(PackagePath) *types.Package // nil for indirect dependency of no consequence
--	HasTypeErrors() bool
 -	DiagnosticsForFile(ctx context.Context, s Snapshot, uri span.URI) ([]*Diagnostic, error)
 -}
 -
@@ -88019,7 +99420,8 @@
 -// An Diagnostic corresponds to an LSP Diagnostic.
 -// https://microsoft.github.io/language-server-protocol/specification#diagnostic
 -type Diagnostic struct {
--	URI      span.URI
+-	// TODO(adonovan): should be a protocol.URI, for symmetry.
+-	URI      span.URI // of diagnosed file (not diagnostic documentation)
 -	Range    protocol.Range
 -	Severity protocol.DiagnosticSeverity
 -	Code     string
@@ -88035,7 +99437,18 @@
 -	Related []protocol.DiagnosticRelatedInformation
 -
 -	// Fields below are used internally to generate quick fixes. They aren't
--	// part of the LSP spec and don't leave the server.
+-	// part of the LSP spec and historically didn't leave the server.
+-	//
+-	// Update(2023-05): version 3.16 of the LSP spec included support for the
+-	// Diagnostic.data field, which holds arbitrary data preserved in the
+-	// diagnostic for codeAction requests. This field allows bundling additional
+-	// information for quick-fixes, and gopls can (and should) use this
+-	// information to avoid re-evaluating diagnostics in code-action handlers.
+-	//
+-	// In order to stage this transition incrementally, the 'BundledFixes' field
+-	// may store a 'bundled' (=json-serialized) form of the associated
+-	// SuggestedFixes. Not all diagnostics have their fixes bundled.
+-	BundledFixes   *json.RawMessage
 -	SuggestedFixes []SuggestedFix
 -}
 -
@@ -88057,6 +99470,7 @@
 -	Govulncheck              DiagnosticSource = "govulncheck"
 -	TemplateError            DiagnosticSource = "template"
 -	WorkFileError            DiagnosticSource = "go.work file"
+-	ConsistencyInfo          DiagnosticSource = "consistency"
 -)
 -
 -func AnalyzerErrorKind(name string) DiagnosticSource {
@@ -88064,8 +99478,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/workspace_symbol.go b/gopls/internal/lsp/source/workspace_symbol.go
 --- a/gopls/internal/lsp/source/workspace_symbol.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/workspace_symbol.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,632 +0,0 @@
++++ b/gopls/internal/lsp/source/workspace_symbol.go	1970-01-01 08:00:00
+@@ -1,611 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -88075,7 +99489,6 @@
 -import (
 -	"context"
 -	"fmt"
--	"go/types"
 -	"path"
 -	"path/filepath"
 -	"regexp"
@@ -88382,13 +99795,19 @@
 -		// whether a URI is in any open workspace.
 -		roots = append(roots, strings.TrimRight(string(v.Folder()), "/"))
 -
--		filters := v.Options().DirectoryFilters
+-		filters := snapshot.Options().DirectoryFilters
 -		filterer := NewFilterer(filters)
 -		folder := filepath.ToSlash(v.Folder().Filename())
--		symbols, err := snapshot.Symbols(ctx)
+-
+-		workspaceOnly := true
+-		if snapshot.Options().SymbolScope == AllSymbolScope {
+-			workspaceOnly = false
+-		}
+-		symbols, err := snapshot.Symbols(ctx, workspaceOnly)
 -		if err != nil {
 -			return nil, err
 -		}
+-
 -		for uri, syms := range symbols {
 -			norm := filepath.ToSlash(uri.Filename())
 -			nm := strings.TrimPrefix(norm, folder)
@@ -88399,17 +99818,13 @@
 -			if seen[uri] {
 -				continue
 -			}
--			mds, err := snapshot.MetadataForFile(ctx, uri)
+-			meta, err := NarrowestMetadataForFile(ctx, snapshot, uri)
 -			if err != nil {
 -				event.Error(ctx, fmt.Sprintf("missing metadata for %q", uri), err)
 -				continue
 -			}
--			if len(mds) == 0 {
--				// TODO: should use the bug reporting API
--				continue
--			}
 -			seen[uri] = true
--			work = append(work, symbolFile{uri, mds[0], syms})
+-			work = append(work, symbolFile{uri, meta, syms})
 -		}
 -	}
 -
@@ -88539,18 +99954,21 @@
 -		// All factors are multiplicative, meaning if more than one applies they are
 -		// multiplied together.
 -		const (
--			// nonWorkspaceFactor is applied to symbols outside of any active
--			// workspace. Developers are less likely to want to jump to code that they
+-			// nonWorkspaceFactor is applied to symbols outside the workspace.
+-			// Developers are less likely to want to jump to code that they
 -			// are not actively working on.
 -			nonWorkspaceFactor = 0.5
--			// nonWorkspaceUnexportedFactor is applied to unexported symbols outside of
--			// any active workspace. Since one wouldn't usually jump to unexported
+-			// nonWorkspaceUnexportedFactor is applied to unexported symbols outside
+-			// the workspace. Since one wouldn't usually jump to unexported
 -			// symbols to understand a package API, they are particularly irrelevant.
 -			nonWorkspaceUnexportedFactor = 0.5
 -			// every field or method nesting level to access the field decreases
 -			// the score by a factor of 1.0 - depth*depthFactor, up to a depth of
 -			// 3.
--			depthFactor = 0.2
+-			//
+-			// Use a small constant here, as this exists mostly to break ties
+-			// (e.g. given a type Foo and a field x.Foo, prefer Foo).
+-			depthFactor = 0.01
 -		)
 -
 -		startWord := true
@@ -88568,6 +99986,8 @@
 -			}
 -		}
 -
+-		// TODO(rfindley): use metadata to determine if the file is in a workspace
+-		// package, rather than this heuristic.
 -		inWorkspace := false
 -		for _, root := range roots {
 -			if strings.HasPrefix(string(i.uri), root) {
@@ -88646,33 +100066,6 @@
 -	return res
 -}
 -
--func typeToKind(typ types.Type) protocol.SymbolKind {
--	switch typ := typ.Underlying().(type) {
--	case *types.Interface:
--		return protocol.Interface
--	case *types.Struct:
--		return protocol.Struct
--	case *types.Signature:
--		if typ.Recv() != nil {
--			return protocol.Method
--		}
--		return protocol.Function
--	case *types.Named:
--		return typeToKind(typ.Underlying())
--	case *types.Basic:
--		i := typ.Info()
--		switch {
--		case i&types.IsNumeric != 0:
--			return protocol.Number
--		case i&types.IsBoolean != 0:
--			return protocol.Boolean
--		case i&types.IsString != 0:
--			return protocol.String
--		}
--	}
--	return protocol.Variable
--}
--
 -// symbolInformation is a cut-down version of protocol.SymbolInformation that
 -// allows struct values of this type to be used as map keys.
 -type symbolInformation struct {
@@ -88700,7 +100093,7 @@
 -}
 diff -urN a/gopls/internal/lsp/source/workspace_symbol_test.go b/gopls/internal/lsp/source/workspace_symbol_test.go
 --- a/gopls/internal/lsp/source/workspace_symbol_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/workspace_symbol_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/source/workspace_symbol_test.go	1970-01-01 08:00:00
 @@ -1,136 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -88840,8 +100233,8 @@
 -}
 diff -urN a/gopls/internal/lsp/source/xrefs/xrefs.go b/gopls/internal/lsp/source/xrefs/xrefs.go
 --- a/gopls/internal/lsp/source/xrefs/xrefs.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/source/xrefs/xrefs.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,216 +0,0 @@
++++ b/gopls/internal/lsp/source/xrefs/xrefs.go	1970-01-01 08:00:00
+@@ -1,193 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -88849,21 +100242,19 @@
 -// Package xrefs defines the serializable index of cross-package
 -// references that is computed during type checking.
 -//
--// See ../references2.go for the 'references' query.
+-// See ../references.go for the 'references' query.
 -package xrefs
 -
 -import (
--	"bytes"
--	"encoding/gob"
 -	"go/ast"
 -	"go/types"
--	"log"
 -	"sort"
 -
 -	"golang.org/x/tools/go/types/objectpath"
+-	"golang.org/x/tools/gopls/internal/lsp/frob"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/internal/typesinternal"
+-	"golang.org/x/tools/internal/typeparams"
 -)
 -
 -// Index constructs a serializable index of outbound cross-references
@@ -88886,7 +100277,7 @@
 -		return objects
 -	}
 -
--	objectpathFor := typesinternal.NewObjectpathFunc()
+-	objectpathFor := new(objectpath.Encoder).For
 -
 -	for fileIndex, pgf := range files {
 -
@@ -88909,6 +100300,12 @@
 -						obj.Pkg() != nil &&
 -						obj.Pkg() != pkg {
 -
+-						// For instantiations of generic methods,
+-						// use the generic object (see issue #60622).
+-						if fn, ok := obj.(*types.Func); ok {
+-							obj = typeparams.OriginMethod(fn)
+-						}
+-
 -						objects := getObjects(obj.Pkg())
 -						gobObj, ok := objects[obj]
 -						if !ok {
@@ -88932,16 +100329,11 @@
 -			case *ast.ImportSpec:
 -				// Report a reference from each import path
 -				// string to the imported package.
--				var obj types.Object
--				if n.Name != nil {
--					obj = info.Defs[n.Name]
--				} else {
--					obj = info.Implicits[n]
--				}
--				if obj == nil {
+-				pkgname, ok := source.ImportedPkgName(info, n)
+-				if !ok {
 -					return true // missing import
 -				}
--				objects := getObjects(obj.(*types.PkgName).Imported())
+-				objects := getObjects(pkgname.Imported())
 -				gobObj, ok := objects[nil]
 -				if !ok {
 -					gobObj = &gobObject{Path: ""}
@@ -88976,7 +100368,7 @@
 -		return packages[i].PkgPath < packages[j].PkgPath
 -	})
 -
--	return mustEncode(packages)
+-	return packageCodec.Encode(packages)
 -}
 -
 -// Lookup searches a serialized index produced by an indexPackage
@@ -88984,15 +100376,8 @@
 -// to any object in the target set. Each object is denoted by a pair
 -// of (package path, object path).
 -func Lookup(m *source.Metadata, data []byte, targets map[source.PackagePath]map[objectpath.Path]struct{}) (locs []protocol.Location) {
--
--	// TODO(adonovan): opt: evaluate whether it would be faster to decode
--	// in two passes, first with struct { PkgPath string; Objects BLOB }
--	// to find the relevant record without decoding the Objects slice,
--	// then decode just the desired BLOB into a slice. BLOB would be a
--	// type whose Unmarshal method just retains (a copy of) the bytes.
--	var packages []gobPackage
--	mustDecode(data, &packages)
--
+-	var packages []*gobPackage
+-	packageCodec.Decode(data, &packages)
 -	for _, gp := range packages {
 -		if objectSet, ok := targets[gp.PkgPath]; ok {
 -			for _, gobObj := range gp.Objects {
@@ -89020,10 +100405,11 @@
 -// The index for package P consists of a list of gopPackage records,
 -// each enumerating references to symbols defined a single dependency, Q.
 -
--// TODO(adonovan): opt: choose a more compact encoding. Gzip reduces
--// the gob output to about one third its size, so clearly there's room
--// to improve. The gobRef.Range field is the obvious place to begin.
--// Even a zero-length slice gob-encodes to ~285 bytes.
+-// TODO(adonovan): opt: choose a more compact encoding.
+-// The gobRef.Range field is the obvious place to begin.
+-
+-// (The name says gob but in fact we use frob.)
+-var packageCodec = frob.CodecFor[[]*gobPackage]()
 -
 -// A gobPackage records the set of outgoing references from the index
 -// package to symbols defined in a dependency package.
@@ -89042,25 +100428,9 @@
 -	FileIndex int            // index of enclosing file within P's CompiledGoFiles
 -	Range     protocol.Range // source range of reference
 -}
--
--// -- duplicated from ../../cache/analysis.go --
--
--func mustEncode(x interface{}) []byte {
--	var buf bytes.Buffer
--	if err := gob.NewEncoder(&buf).Encode(x); err != nil {
--		log.Fatalf("internal error encoding %T: %v", x, err)
--	}
--	return buf.Bytes()
--}
--
--func mustDecode(data []byte, ptr interface{}) {
--	if err := gob.NewDecoder(bytes.NewReader(data)).Decode(ptr); err != nil {
--		log.Fatalf("internal error decoding %T: %v", ptr, err)
--	}
--}
 diff -urN a/gopls/internal/lsp/symbols.go b/gopls/internal/lsp/symbols.go
 --- a/gopls/internal/lsp/symbols.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/symbols.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/symbols.go	1970-01-01 08:00:00
 @@ -1,60 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89079,7 +100449,7 @@
 -)
 -
 -func (s *Server) documentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]interface{}, error) {
--	ctx, done := event.Start(ctx, "lsp.Server.documentSymbol")
+-	ctx, done := event.Start(ctx, "lsp.Server.documentSymbol", tag.URI.Of(params.TextDocument.URI))
 -	defer done()
 -
 -	snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.UnknownKind)
@@ -89088,7 +100458,7 @@
 -		return []interface{}{}, err
 -	}
 -	var docSymbols []protocol.DocumentSymbol
--	switch snapshot.View().FileKind(fh) {
+-	switch snapshot.FileKind(fh) {
 -	case source.Tmpl:
 -		docSymbols, err = template.DocumentSymbols(snapshot, fh)
 -	case source.Go:
@@ -89097,14 +100467,14 @@
 -		return []interface{}{}, nil
 -	}
 -	if err != nil {
--		event.Error(ctx, "DocumentSymbols failed", err, tag.URI.Of(fh.URI()))
+-		event.Error(ctx, "DocumentSymbols failed", err)
 -		return []interface{}{}, nil
 -	}
 -	// Convert the symbols to an interface array.
 -	// TODO: Remove this once the lsp deprecates SymbolInformation.
 -	symbols := make([]interface{}, len(docSymbols))
 -	for i, s := range docSymbols {
--		if snapshot.View().Options().HierarchicalDocumentSymbolSupport {
+-		if snapshot.Options().HierarchicalDocumentSymbolSupport {
 -			symbols[i] = s
 -			continue
 -		}
@@ -89124,7 +100494,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/completion.go b/gopls/internal/lsp/template/completion.go
 --- a/gopls/internal/lsp/template/completion.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/completion.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/completion.go	1970-01-01 08:00:00
 @@ -1,287 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89415,7 +100785,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/completion_test.go b/gopls/internal/lsp/template/completion_test.go
 --- a/gopls/internal/lsp/template/completion_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/completion_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/completion_test.go	1970-01-01 08:00:00
 @@ -1,102 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89521,7 +100891,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/highlight.go b/gopls/internal/lsp/template/highlight.go
 --- a/gopls/internal/lsp/template/highlight.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/highlight.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/highlight.go	1970-01-01 08:00:00
 @@ -1,96 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89539,7 +100909,7 @@
 -)
 -
 -func Highlight(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, loc protocol.Position) ([]protocol.DocumentHighlight, error) {
--	buf, err := fh.Read()
+-	buf, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -89621,7 +100991,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/implementations.go b/gopls/internal/lsp/template/implementations.go
 --- a/gopls/internal/lsp/template/implementations.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/implementations.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/implementations.go	1970-01-01 08:00:00
 @@ -1,189 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89650,7 +101020,7 @@
 -func Diagnose(f source.FileHandle) []*source.Diagnostic {
 -	// no need for skipTemplate check, as Diagnose is called on the
 -	// snapshot's template files
--	buf, err := f.Read()
+-	buf, err := f.Content()
 -	if err != nil {
 -		// Is a Diagnostic with no Range useful? event.Error also?
 -		msg := fmt.Sprintf("failed to read %s (%v)", f.URI().Filename(), err)
@@ -89773,11 +101143,11 @@
 -}
 -
 -func SemanticTokens(ctx context.Context, snapshot source.Snapshot, spn span.URI, add func(line, start, len uint32), d func() []uint32) (*protocol.SemanticTokens, error) {
--	fh, err := snapshot.GetFile(ctx, spn)
+-	fh, err := snapshot.ReadFile(ctx, spn)
 -	if err != nil {
 -		return nil, err
 -	}
--	buf, err := fh.Read()
+-	buf, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -89814,7 +101184,7 @@
 -// still need to do rename, etc
 diff -urN a/gopls/internal/lsp/template/parse.go b/gopls/internal/lsp/template/parse.go
 --- a/gopls/internal/lsp/template/parse.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/parse.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/parse.go	1970-01-01 08:00:00
 @@ -1,508 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -89891,7 +101261,7 @@
 -func New(tmpls map[span.URI]source.FileHandle) *All {
 -	all := make(map[span.URI]*Parsed)
 -	for k, v := range tmpls {
--		buf, err := v.Read()
+-		buf, err := v.Content()
 -		if err != nil { // PJW: decide what to do with these errors
 -			log.Printf("failed to read %s (%v)", v.URI().Filename(), err)
 -			continue
@@ -90196,7 +101566,7 @@
 -}
 -
 -func symAtPosition(fh source.FileHandle, loc protocol.Position) (*symbol, *Parsed, error) {
--	buf, err := fh.Read()
+-	buf, err := fh.Content()
 -	if err != nil {
 -		return nil, nil, err
 -	}
@@ -90326,7 +101696,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/parse_test.go b/gopls/internal/lsp/template/parse_test.go
 --- a/gopls/internal/lsp/template/parse_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/parse_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/parse_test.go	1970-01-01 08:00:00
 @@ -1,238 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -90568,7 +101938,7 @@
 -}
 diff -urN a/gopls/internal/lsp/template/symbols.go b/gopls/internal/lsp/template/symbols.go
 --- a/gopls/internal/lsp/template/symbols.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/template/symbols.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/template/symbols.go	1970-01-01 08:00:00
 @@ -1,230 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -90583,9 +101953,9 @@
 -	"text/template/parse"
 -	"unicode/utf8"
 -
--	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/internal/event"
 -)
 -
 -// in local coordinates, to be translated to protocol.DocumentSymbol
@@ -90766,7 +102136,7 @@
 -// DocumentSymbols returns a hierarchy of the symbols defined in a template file.
 -// (The hierarchy is flat. SymbolInformation might be better.)
 -func DocumentSymbols(snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentSymbol, error) {
--	buf, err := fh.Read()
+-	buf, err := fh.Content()
 -	if err != nil {
 -		return nil, err
 -	}
@@ -90800,9 +102170,14 @@
 -	}
 -	return ans, nil
 -}
+diff -urN a/gopls/internal/lsp/testdata/%percent/perc%ent.go b/gopls/internal/lsp/testdata/%percent/perc%ent.go
+--- a/gopls/internal/lsp/testdata/%percent/perc%ent.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/%percent/perc%ent.go	1970-01-01 08:00:00
+@@ -1 +0,0 @@
+-package percent
 diff -urN a/gopls/internal/lsp/testdata/addimport/addimport.go.golden b/gopls/internal/lsp/testdata/addimport/addimport.go.golden
 --- a/gopls/internal/lsp/testdata/addimport/addimport.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/addimport/addimport.go.golden	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 --- addimport --
 -package addimport //@addimport("", "bytes")
@@ -90813,14 +102188,14 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/addimport/addimport.go.in b/gopls/internal/lsp/testdata/addimport/addimport.go.in
 --- a/gopls/internal/lsp/testdata/addimport/addimport.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/addimport/addimport.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/addimport/addimport.go.in	1970-01-01 08:00:00
 @@ -1,3 +0,0 @@
 -package addimport //@addimport("", "bytes")
 -
 -func main() {}
 diff -urN a/gopls/internal/lsp/testdata/address/address.go b/gopls/internal/lsp/testdata/address/address.go
 --- a/gopls/internal/lsp/testdata/address/address.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/address/address.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/address/address.go	1970-01-01 08:00:00
 @@ -1,78 +0,0 @@
 -package address
 -
@@ -90900,37 +102275,9 @@
 -	// addrNestedC is not addressable, so rank lower
 -	wantsPtr(getNestedfc) //@fuzzy(")", addrNestedPtrC, addrNestedC)
 -}
-diff -urN a/gopls/internal/lsp/testdata/analyzer/bad_test.go b/gopls/internal/lsp/testdata/analyzer/bad_test.go
---- a/gopls/internal/lsp/testdata/analyzer/bad_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/analyzer/bad_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
--package analyzer
--
--import (
--	"fmt"
--	"sync"
--	"testing"
--	"time"
--)
--
--func Testbad(t *testing.T) { //@diag("", "tests", "Testbad has malformed name: first letter after 'Test' must not be lowercase", "warning")
--	var x sync.Mutex
--	_ = x //@diag("x", "copylocks", "assignment copies lock value to _: sync.Mutex", "warning")
--
--	printfWrapper("%s") //@diag(re`printfWrapper\(.*\)`, "printf", "golang.org/lsptests/analyzer.printfWrapper format %s reads arg #1, but call has 0 args", "warning")
--}
--
--func printfWrapper(format string, args ...interface{}) {
--	fmt.Printf(format, args...)
--}
--
--func _() {
--	now := time.Now()
--	fmt.Println(now.Format("2006-02-01")) //@diag("2006-02-01", "timeformat", "2006-02-01 should be 2006-01-02", "warning")
--}
 diff -urN a/gopls/internal/lsp/testdata/anon/anon.go.in b/gopls/internal/lsp/testdata/anon/anon.go.in
 --- a/gopls/internal/lsp/testdata/anon/anon.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/anon/anon.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/anon/anon.go.in	1970-01-01 08:00:00
 @@ -1,23 +0,0 @@
 -package anon
 -
@@ -90955,19 +102302,9 @@
 -		struct{ x int }{  }: 1, //@complete("  }", anonX, structS)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/testdata/append/append2.go.in b/gopls/internal/lsp/testdata/append/append2.go.in
---- a/gopls/internal/lsp/testdata/append/append2.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/append/append2.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package append
--
--func _() {
--	_ = append(a, struct) //@complete(")")
--}
-\ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/append/append.go b/gopls/internal/lsp/testdata/append/append.go
 --- a/gopls/internal/lsp/testdata/append/append.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/append/append.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/append/append.go	1970-01-01 08:00:00
 @@ -1,38 +0,0 @@
 -package append
 -
@@ -91007,63 +102344,19 @@
 -
 -	foo(append([]string{}, *a)) //@snippet("))", appendStringsPtr, "aStringsPtr...", "aStringsPtr...")
 -}
-diff -urN a/gopls/internal/lsp/testdata/arraytype/array_type.go.in b/gopls/internal/lsp/testdata/arraytype/array_type.go.in
---- a/gopls/internal/lsp/testdata/arraytype/array_type.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/arraytype/array_type.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,50 +0,0 @@
--package arraytype
--
--import (
--	"golang.org/lsptests/foo"
--)
+diff -urN a/gopls/internal/lsp/testdata/append/append2.go.in b/gopls/internal/lsp/testdata/append/append2.go.in
+--- a/gopls/internal/lsp/testdata/append/append2.go.in	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/append/append2.go.in	1970-01-01 08:00:00
+@@ -1,5 +0,0 @@
+-package append
 -
 -func _() {
--	var (
--		val string //@item(atVal, "val", "string", "var")
--	)
--
--	// disabled - see issue #54822
--	[] // complete(" //", PackageFoo)
--
--	[]val //@complete(" //")
--
--	[]foo.StructFoo //@complete(" //", StructFoo)
--
--	[]foo.StructFoo(nil) //@complete("(", StructFoo)
--
--	[]*foo.StructFoo //@complete(" //", StructFoo)
--
--	[...]foo.StructFoo //@complete(" //", StructFoo)
--
--	[2][][4]foo.StructFoo //@complete(" //", StructFoo)
--
--	[]struct { f []foo.StructFoo } //@complete(" }", StructFoo)
+-	_ = append(a, struct) //@complete(")")
 -}
--
--func _() {
--	type myInt int //@item(atMyInt, "myInt", "int", "type")
--
--	var mark []myInt //@item(atMark, "mark", "[]myInt", "var")
--
--	var s []myInt //@item(atS, "s", "[]myInt", "var")
--	s = []m //@complete(" //", atMyInt)
--	// disabled - see issue #54822
--	s = [] // complete(" //", atMyInt, PackageFoo)
--
--	var a [1]myInt
--	a = [1]m //@complete(" //", atMyInt)
--
--	var ds [][]myInt
--	ds = [][]m //@complete(" //", atMyInt)
--}
--
--func _() {
--	var b [0]byte //@item(atByte, "b", "[0]byte", "var")
--	var _ []byte = b //@snippet(" //", atByte, "b[:]", "b[:]")
--}
+\ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/assign/assign.go.in b/gopls/internal/lsp/testdata/assign/assign.go.in
 --- a/gopls/internal/lsp/testdata/assign/assign.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/assign/assign.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/assign/assign.go.in	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -package assign
 -
@@ -91093,206 +102386,15 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go
 --- a/gopls/internal/lsp/testdata/assign/internal/secret/secret.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/assign/internal/secret/secret.go	1970-01-01 08:00:00
 @@ -1,3 +0,0 @@
 -package secret
 -
 -func Hello() {}
 \ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/bad/bad0.go b/gopls/internal/lsp/testdata/bad/bad0.go
---- a/gopls/internal/lsp/testdata/bad/bad0.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/bad/bad0.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
--//go:build go1.11
--// +build go1.11
--
--package bad
--
--import _ "golang.org/lsptests/assign/internal/secret" //@diag("\"golang.org/lsptests/assign/internal/secret\"", "compiler", "could not import golang.org/lsptests/assign/internal/secret \\(invalid use of internal package \"golang.org/lsptests/assign/internal/secret\"\\)", "error")
--
--func stuff() { //@item(stuff, "stuff", "func()", "func")
--	x := "heeeeyyyy"
--	random2(x) //@diag("x", "compiler", "cannot use x \\(variable of type string\\) as int value in argument to random2", "error")
--	random2(1) //@complete("dom", random, random2, random3)
--	y := 3     //@diag("y", "compiler", "y declared (and|but) not used", "error")
--}
--
--type bob struct { //@item(bob, "bob", "struct{...}", "struct")
--	x int
--}
--
--func _() {
--	var q int
--	_ = &bob{
--		f: q, //@diag("f: q", "compiler", "unknown field f in struct literal", "error")
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/bad/bad1.go b/gopls/internal/lsp/testdata/bad/bad1.go
---- a/gopls/internal/lsp/testdata/bad/bad1.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/bad/bad1.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,34 +0,0 @@
--//go:build go1.11
--// +build go1.11
--
--package bad
--
--// See #36637
--type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type")
--
--var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "(undeclared name|undefined): unknown", "error")
--
--func random() int { //@item(random, "random", "func() int", "func")
--	//@complete("", global_a, bob, random, random2, random3, stateFunc, stuff)
--	return 0
--}
--
--func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var")
--	x := 6       //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared (and|but) not used", "error")
--	var q blah   //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared (and|but) not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error")
--	var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared (and|but) not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error")
--	//@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff)
--
--	return y
--}
--
--func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var")
--	//@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
--
--	var ch chan (favType1)   //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared (and|but) not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error")
--	var m map[keyType]int    //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared (and|but) not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error")
--	var arr []favType2       //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared (and|but) not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error")
--	var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared (and|but) not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error")
--	var fn2 func(badParam)   //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared (and|but) not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error")
--	//@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
--}
-diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in
---- a/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_2.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package badstmt
--
--import (
--	"golang.org/lsptests/foo"
--)
--
--func _() {
--	defer func() { foo. } //@rank(" }", Foo)
--}
-diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in
---- a/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_3.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package badstmt
--
--import (
--	"golang.org/lsptests/foo"
--)
--
--func _() {
--	go foo. //@rank(" //", Foo, IntFoo),snippet(" //", Foo, "Foo()", "Foo()")
--}
-diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in
---- a/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/badstmt/badstmt_4.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
--package badstmt
--
--import (
--	"golang.org/lsptests/foo"
--)
--
--func _() {
--	go func() {
--		defer foo. //@rank(" //", Foo, IntFoo)
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in
---- a/gopls/internal/lsp/testdata/badstmt/badstmt.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/badstmt/badstmt.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,29 +0,0 @@
--package badstmt
--
--import (
--	"golang.org/lsptests/foo"
--)
--
--// The nonewvars expectation asserts that the go/analysis framework ran.
--// See comments in noparse.
--
--func _(x int) {
--	defer foo.F //@complete(" //", Foo),diag(" //", "syntax", "function must be invoked in defer statement|expression in defer must be function call", "error")
--	defer foo.F //@complete(" //", Foo)
--	x := 123 //@diag(":=", "nonewvars", "no new variables", "warning")
--}
--
--func _() {
--	switch true {
--	case true:
--		go foo.F //@complete(" //", Foo)
--	}
--}
--
--func _() {
--	defer func() {
--		foo.F //@complete(" //", Foo),snippet(" //", Foo, "Foo()", "Foo()")
--
--		foo. //@rank(" //", Foo)
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/bar/bar.go.in b/gopls/internal/lsp/testdata/bar/bar.go.in
---- a/gopls/internal/lsp/testdata/bar/bar.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/bar/bar.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,47 +0,0 @@
--// +build go1.11
--
--package bar
--
--import (
--	"golang.org/lsptests/foo" //@item(foo, "foo", "\"golang.org/lsptests/foo\"", "package")
--)
--
--func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func")
--
--func _() {
--	help //@complete("l", helper)
--	_ = foo.StructFoo{} //@complete("S", IntFoo, StructFoo)
--}
--
--// Bar is a function.
--func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.")
--	foo.Foo()        //@complete("F", Foo, IntFoo, StructFoo)
--	var _ foo.IntFoo //@complete("I", IntFoo, StructFoo)
--	foo.()           //@complete("(", Foo, IntFoo, StructFoo)
--}
--
--func _() {
--	var Valentine int //@item(Valentine, "Valentine", "int", "var")
--
--	_ = foo.StructFoo{
--		Valu //@complete(" //", Value)
--	}
--  	_ = foo.StructFoo{
--		Va        //@complete("a", Value, Valentine)
--	}
--	_ = foo.StructFoo{
--		Value: 5, //@complete("a", Value)
--	}
--	_ = foo.StructFoo{
--		//@complete("", Value, Valentine, foo, helper, Bar)
--	}
--	_ = foo.StructFoo{
--		Value: Valen //@complete("le", Valentine)
--	}
--	_ = foo.StructFoo{
--		Value:       //@complete(" //", Valentine, foo, helper, Bar)
--	}
--	_ = foo.StructFoo{
--		Value:       //@complete(" ", Valentine, foo, helper, Bar)
--	}
--}
 diff -urN a/gopls/internal/lsp/testdata/basiclit/basiclit.go b/gopls/internal/lsp/testdata/basiclit/basiclit.go
 --- a/gopls/internal/lsp/testdata/basiclit/basiclit.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/basiclit/basiclit.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/basiclit/basiclit.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package basiclit
 -
@@ -91307,46 +102409,9 @@
 -
 -	_ = 'a' //@complete("' ")
 -}
-diff -urN a/gopls/internal/lsp/testdata/baz/baz.go.in b/gopls/internal/lsp/testdata/baz/baz.go.in
---- a/gopls/internal/lsp/testdata/baz/baz.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/baz/baz.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,33 +0,0 @@
--// +build go1.11
--
--package baz
--
--import (
--	"golang.org/lsptests/bar"
--
--	f "golang.org/lsptests/foo"
--)
--
--var FooStruct f.StructFoo
--
--func Baz() {
--	defer bar.Bar() //@complete("B", Bar)
--	// TODO(rstambler): Test completion here.
--	defer bar.B
--	var x f.IntFoo  //@complete("n", IntFoo),typdef("x", IntFoo)
--	bar.Bar()       //@complete("B", Bar)
--}
--
--func _() {
--	bob := f.StructFoo{Value: 5}
--	if x := bob. //@complete(" //", Value)
--	switch true == false {
--		case true:
--			if x := bob. //@complete(" //", Value)
--		case false:
--	}
--	if x := bob.Va //@complete("a", Value)
--	switch true == true {
--		default:
--	}
--}
 diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_args.go b/gopls/internal/lsp/testdata/builtins/builtin_args.go
 --- a/gopls/internal/lsp/testdata/builtins/builtin_args.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtin_args.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/builtins/builtin_args.go	1970-01-01 08:00:00
 @@ -1,62 +0,0 @@
 -package builtins
 -
@@ -91410,96 +102475,9 @@
 -
 -	<-a //@rank(" //", builtinChan, builtinInt)
 -}
-diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go117.go b/gopls/internal/lsp/testdata/builtins/builtin_go117.go
---- a/gopls/internal/lsp/testdata/builtins/builtin_go117.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtin_go117.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
--//go:build !go1.18
--// +build !go1.18
--
--package builtins
--
--func _() {
--	//@complete("", append, bool, byte, cap, close, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
--}
-diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go118.go b/gopls/internal/lsp/testdata/builtins/builtin_go118.go
---- a/gopls/internal/lsp/testdata/builtins/builtin_go118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtin_go118.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
--//go:build go1.18 && !go1.21
--// +build go1.18,!go1.21
--
--package builtins
--
--func _() {
--	//@complete("", any, append, bool, byte, cap, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
--}
-diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_go121.go b/gopls/internal/lsp/testdata/builtins/builtin_go121.go
---- a/gopls/internal/lsp/testdata/builtins/builtin_go121.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtin_go121.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
--//go:build go1.21
--// +build go1.21
--
--package builtins
--
--func _() {
--	//@complete("", any, append, bool, byte, cap, clear, close, comparable, complex, complex128, complex64, copy, delete, error, _false, float32, float64, imag, int, int16, int32, int64, int8, len, make, new, panic, print, println, real, recover, rune, string, _true, uint, uint16, uint32, uint64, uint8, uintptr, _nil)
--}
-diff -urN a/gopls/internal/lsp/testdata/builtins/builtins.go b/gopls/internal/lsp/testdata/builtins/builtins.go
---- a/gopls/internal/lsp/testdata/builtins/builtins.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtins.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,47 +0,0 @@
--package builtins
--
--// Definitions of builtin completion items.
--
--/* any */ //@item(any, "any", "", "interface")
--/* Create markers for builtin types. Only for use by this test.
--/* append(slice []Type, elems ...Type) []Type */ //@item(append, "append", "func(slice []Type, elems ...Type) []Type", "func")
--/* bool */ //@item(bool, "bool", "", "type")
--/* byte */ //@item(byte, "byte", "", "type")
--/* cap(v Type) int */ //@item(cap, "cap", "func(v Type) int", "func")
--/* clear[T interface{ ~[]Type | ~map[Type]Type1 }](t T) */ //@item(clear, "clear", "func(t T)", "func")
--/* close(c chan<- Type) */ //@item(close, "close", "func(c chan<- Type)", "func")
--/* comparable */ //@item(comparable, "comparable", "", "interface")
--/* complex(r float64, i float64) */ //@item(complex, "complex", "func(r float64, i float64) complex128", "func")
--/* complex128 */ //@item(complex128, "complex128", "", "type")
--/* complex64 */ //@item(complex64, "complex64", "", "type")
--/* copy(dst []Type, src []Type) int */ //@item(copy, "copy", "func(dst []Type, src []Type) int", "func")
--/* delete(m map[Type]Type1, key Type) */ //@item(delete, "delete", "func(m map[Type]Type1, key Type)", "func")
--/* error */ //@item(error, "error", "", "interface")
--/* false */ //@item(_false, "false", "", "const")
--/* float32 */ //@item(float32, "float32", "", "type")
--/* float64 */ //@item(float64, "float64", "", "type")
--/* imag(c complex128) float64 */ //@item(imag, "imag", "func(c complex128) float64", "func")
--/* int */ //@item(int, "int", "", "type")
--/* int16 */ //@item(int16, "int16", "", "type")
--/* int32 */ //@item(int32, "int32", "", "type")
--/* int64 */ //@item(int64, "int64", "", "type")
--/* int8 */ //@item(int8, "int8", "", "type")
--/* iota */ //@item(iota, "iota", "", "const")
--/* len(v Type) int */ //@item(len, "len", "func(v Type) int", "func")
--/* make(t Type, size ...int) Type */ //@item(make, "make", "func(t Type, size ...int) Type", "func")
--/* new(Type) *Type */ //@item(new, "new", "func(Type) *Type", "func")
--/* nil */ //@item(_nil, "nil", "", "var")
--/* panic(v interface{}) */ //@item(panic, "panic", "func(v interface{})", "func")
--/* print(args ...Type) */ //@item(print, "print", "func(args ...Type)", "func")
--/* println(args ...Type) */ //@item(println, "println", "func(args ...Type)", "func")
--/* real(c complex128) float64 */ //@item(real, "real", "func(c complex128) float64", "func")
--/* recover() interface{} */ //@item(recover, "recover", "func() interface{}", "func")
--/* rune */ //@item(rune, "rune", "", "type")
--/* string */ //@item(string, "string", "", "type")
--/* true */ //@item(_true, "true", "", "const")
--/* uint */ //@item(uint, "uint", "", "type")
--/* uint16 */ //@item(uint16, "uint16", "", "type")
--/* uint32 */ //@item(uint32, "uint32", "", "type")
--/* uint64 */ //@item(uint64, "uint64", "", "type")
--/* uint8 */ //@item(uint8, "uint8", "", "type")
--/* uintptr */ //@item(uintptr, "uintptr", "", "type")
 diff -urN a/gopls/internal/lsp/testdata/builtins/builtin_types.go b/gopls/internal/lsp/testdata/builtins/builtin_types.go
 --- a/gopls/internal/lsp/testdata/builtins/builtin_types.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/builtin_types.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/builtins/builtin_types.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package builtins
 -
@@ -91512,9 +102490,26 @@
 -
 -	var _ [][]bool = make([][], 0) //@rank(",", bool, int)
 -}
+diff -urN a/gopls/internal/lsp/testdata/builtins/builtins.go b/gopls/internal/lsp/testdata/builtins/builtins.go
+--- a/gopls/internal/lsp/testdata/builtins/builtins.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/builtins/builtins.go	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-package builtins
+-
+-// Definitions of builtin completion items that are still used in tests.
+-
+-/* bool */ //@item(bool, "bool", "", "type")
+-/* complex(r float64, i float64) */ //@item(complex, "complex", "func(r float64, i float64) complex128", "func")
+-/* float32 */ //@item(float32, "float32", "", "type")
+-/* float64 */ //@item(float64, "float64", "", "type")
+-/* imag(c complex128) float64 */ //@item(imag, "imag", "func(c complex128) float64", "func")
+-/* int */ //@item(int, "int", "", "type")
+-/* iota */ //@item(iota, "iota", "", "const")
+-/* string */ //@item(string, "string", "", "type")
+-/* true */ //@item(_true, "true", "", "const")
 diff -urN a/gopls/internal/lsp/testdata/builtins/constants.go b/gopls/internal/lsp/testdata/builtins/constants.go
 --- a/gopls/internal/lsp/testdata/builtins/constants.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/builtins/constants.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/builtins/constants.go	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 -package builtins
 -
@@ -91537,7 +102532,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go
 --- a/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/callhierarchy/callhierarchy.go	1970-01-01 08:00:00
 @@ -1,70 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -91611,7 +102606,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go
 --- a/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/callhierarchy/incoming/incoming.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -91627,7 +102622,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go
 --- a/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/callhierarchy/outgoing/outgoing.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -91640,7 +102635,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go
 --- a/gopls/internal/lsp/testdata/casesensitive/casesensitive.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/casesensitive/casesensitive.go	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -91660,7 +102655,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/cast/cast.go.in b/gopls/internal/lsp/testdata/cast/cast.go.in
 --- a/gopls/internal/lsp/testdata/cast/cast.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cast/cast.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/cast/cast.go.in	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package cast
 -
@@ -91674,131 +102669,9 @@
 -	_ = float64(foo. //@complete(" /", x_field)
 -}
 \ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo.go
---- a/gopls/internal/lsp/testdata/cgo/declarecgo.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,27 +0,0 @@
--package cgo
--
--/*
--#include <stdio.h>
--#include <stdlib.h>
--
--void myprint(char* s) {
--	printf("%s\n", s);
--}
--*/
--import "C"
--
--import (
--	"fmt"
--	"unsafe"
--)
--
--func Example() { //@mark(funccgoexample, "Example"),item(funccgoexample, "Example", "func()", "func")
--	fmt.Println()
--	cs := C.CString("Hello from stdio\n")
--	C.myprint(cs)
--	C.free(unsafe.Pointer(cs))
--}
--
--func _() {
--	Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample)
--}
-diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden
---- a/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cgo/declarecgo.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,30 +0,0 @@
---- funccgoexample-definition --
--cgo/declarecgo.go:18:6-13: defined here as ```go
--func Example()
--```
--
--[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
---- funccgoexample-definition-json --
--{
--	"span": {
--		"uri": "file://cgo/declarecgo.go",
--		"start": {
--			"line": 18,
--			"column": 6,
--			"offset": 151
--		},
--		"end": {
--			"line": 18,
--			"column": 13,
--			"offset": 158
--		}
--	},
--	"description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)"
--}
--
---- funccgoexample-hoverdef --
--```go
--func Example()
--```
--
--[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
-diff -urN a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go
---- a/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cgo/declarecgo_nocgo.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
--//+build !cgo
--
--package cgo
--
--// Set a dummy marker to keep the test framework happy. The tests should be skipped.
--var _ = "Example" //@mark(funccgoexample, "Example"),godef("ample", funccgoexample),complete("ample", funccgoexample)
-diff -urN a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden
---- a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,30 +0,0 @@
---- funccgoexample-definition --
--cgo/declarecgo.go:18:6-13: defined here as ```go
--func cgo.Example()
--```
--
--[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
---- funccgoexample-definition-json --
--{
--	"span": {
--		"uri": "file://cgo/declarecgo.go",
--		"start": {
--			"line": 18,
--			"column": 6,
--			"offset": 151
--		},
--		"end": {
--			"line": 18,
--			"column": 13,
--			"offset": 158
--		}
--	},
--	"description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)"
--}
--
---- funccgoexample-hoverdef --
--```go
--func cgo.Example()
--```
--
--[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/cgo#Example)
-diff -urN a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in
---- a/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/cgoimport/usecgo.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package cgoimport
--
--import (
--	"golang.org/lsptests/cgo"
--)
--
--func _() {
--	cgo.Example() //@godef("ample", funccgoexample),complete("ample", funccgoexample)
--}
 diff -urN a/gopls/internal/lsp/testdata/channel/channel.go b/gopls/internal/lsp/testdata/channel/channel.go
 --- a/gopls/internal/lsp/testdata/channel/channel.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/channel/channel.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/channel/channel.go	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -package channel
 -
@@ -91825,29 +102698,9 @@
 -		wantsInt(<-) //@rank(")", channelFoo, channelAB)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/testdata/codelens/codelens_test.go b/gopls/internal/lsp/testdata/codelens/codelens_test.go
---- a/gopls/internal/lsp/testdata/codelens/codelens_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/codelens/codelens_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--package codelens //@codelens("package codelens", "run file benchmarks", "test")
--
--import "testing"
--
--func TestMain(m *testing.M) {} // no code lens for TestMain
--
--func TestFuncWithCodeLens(t *testing.T) { //@codelens("func", "run test", "test")
--}
--
--func thisShouldNotHaveACodeLens(t *testing.T) {
--}
--
--func BenchmarkFuncWithCodeLens(b *testing.B) { //@codelens("func", "run benchmark", "test")
--}
--
--func helper() {} // expect no code lens
 diff -urN a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in
 --- a/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/comment_completion/comment_completion.go.in	1970-01-01 08:00:00
 @@ -1,70 +0,0 @@
 -package comment_completion
 -
@@ -91921,7 +102774,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/complit/complit.go.in b/gopls/internal/lsp/testdata/complit/complit.go.in
 --- a/gopls/internal/lsp/testdata/complit/complit.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/complit/complit.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/complit/complit.go.in	1970-01-01 08:00:00
 @@ -1,90 +0,0 @@
 -package complit
 -
@@ -92015,7 +102868,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/constant/constant.go b/gopls/internal/lsp/testdata/constant/constant.go
 --- a/gopls/internal/lsp/testdata/constant/constant.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/constant/constant.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/constant/constant.go	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 -package constant
 -
@@ -92033,7 +102886,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92044,9 +102897,22 @@
 -func bar() bool { //@item(danglingBar, "bar", "func() bool", "func")
 -	return true
 -}
+diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go
+--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go	1970-01-01 08:00:00
+@@ -1,9 +0,0 @@
+-package danglingstmt
+-
+-func _() {
+-	for i := bar //@rank(" //", danglingBar2)
+-}
+-
+-func bar2() int { //@item(danglingBar2, "bar2", "func() int", "func")
+-	return 0
+-}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92059,7 +102925,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init_cond_post.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92070,34 +102936,9 @@
 -func bar4() int { //@item(danglingBar4, "bar4", "func() int", "func")
 -	return 0
 -}
-diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go
---- a/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_for_init.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package danglingstmt
--
--func _() {
--	for i := bar //@rank(" //", danglingBar2)
--}
--
--func bar2() int { //@item(danglingBar2, "bar2", "func() int", "func")
--	return 0
--}
-diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go
---- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
--package danglingstmt
--
--func bar5() bool { //@item(danglingBar5, "bar5", "func() bool", "func")
--	return true
--}
--
--func _() {
--	if b //@rank(" //", danglingBar5)
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92108,22 +102949,21 @@
 -func foo() bool { //@item(danglingFoo, "foo", "func() bool", "func")
 -	return true
 -}
-diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go
---- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
+diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go
+--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_eof.go	1970-01-01 08:00:00
+@@ -1,8 +0,0 @@
 -package danglingstmt
 -
--func _() {
--	if i := 123; foo //@rank(" //", danglingFoo3)
--}
--
--func foo3() bool { //@item(danglingFoo3, "foo3", "func() bool", "func")
+-func bar5() bool { //@item(danglingBar5, "bar5", "func() bool", "func")
 -	return true
 -}
+-
+-func _() {
+-	if b //@rank(" //", danglingBar5)
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92134,9 +102974,22 @@
 -func foo2() bool { //@item(danglingFoo2, "foo2", "func() bool", "func")
 -	return true
 -}
+diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go
+--- a/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_if_init_cond.go	1970-01-01 08:00:00
+@@ -1,9 +0,0 @@
+-package danglingstmt
+-
+-func _() {
+-	if i := 123; foo //@rank(" //", danglingFoo3)
+-}
+-
+-func foo3() bool { //@item(danglingFoo3, "foo3", "func() bool", "func")
+-	return true
+-}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_multiline_if.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -package danglingstmt
 -
@@ -92150,7 +103003,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_1.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package danglingstmt
 -
@@ -92161,19 +103014,21 @@
 -var x struct { i int } //@item(danglingI, "i", "int", "field")
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_selector_2.go	1970-01-01 08:00:00
+@@ -1,10 +0,0 @@
 -package danglingstmt
 -
--import "golang.org/lsptests/foo"
+-// TODO: re-enable this test, which was broken when the foo package was removed.
+-// (we can replicate the relevant definitions in the new marker test)
+-// import "golang.org/lsptests/foo"
 -
 -func _() {
--	foo. //@rank(" //", Foo)
--	var _ = []string{foo.} //@rank("}", Foo)
+-	foo. // rank(" //", Foo)
+-	var _ = []string{foo.} // rank("}", Foo)
 -}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92186,7 +103041,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go
 --- a/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/danglingstmt/dangling_switch_init_tag.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package danglingstmt
 -
@@ -92199,7 +103054,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/deep/deep.go b/gopls/internal/lsp/testdata/deep/deep.go
 --- a/gopls/internal/lsp/testdata/deep/deep.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/deep/deep.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/deep/deep.go	1970-01-01 08:00:00
 @@ -1,142 +0,0 @@
 -package deep
 -
@@ -92343,9 +103198,61 @@
 -	b.thing.val      //@item(deepBazFieldVal, "b.thing.val", "int", "field")
 -	var _ int = bval //@rank(" //", deepBazFieldVal, deepBazMethVal)
 -}
+diff -urN a/gopls/internal/lsp/testdata/embeddirective/embed.txt b/gopls/internal/lsp/testdata/embeddirective/embed.txt
+--- a/gopls/internal/lsp/testdata/embeddirective/embed.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/embeddirective/embed.txt	1970-01-01 08:00:00
+@@ -1 +0,0 @@
+-text
+diff -urN a/gopls/internal/lsp/testdata/embeddirective/fix_import.go b/gopls/internal/lsp/testdata/embeddirective/fix_import.go
+--- a/gopls/internal/lsp/testdata/embeddirective/fix_import.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/embeddirective/fix_import.go	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package embeddirective
+-
+-import (
+-	"io"
+-	"os"
+-)
+-
+-//go:embed embed.txt //@suggestedfix("//go:embed", "quickfix", "")
+-var t string
+-
+-func unused() {
+-	_ = os.Stdin
+-	_ = io.EOF
+-}
+diff -urN a/gopls/internal/lsp/testdata/embeddirective/fix_import.go.golden b/gopls/internal/lsp/testdata/embeddirective/fix_import.go.golden
+--- a/gopls/internal/lsp/testdata/embeddirective/fix_import.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/embeddirective/fix_import.go.golden	1970-01-01 08:00:00
+@@ -1,21 +0,0 @@
+--- suggestedfix_fix_import_12_1 --
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package embeddirective
+-
+-import (
+-	_ "embed"
+-	"io"
+-	"os"
+-)
+-
+-//go:embed embed.txt //@suggestedfix("//go:embed", "quickfix", "")
+-var t string
+-
+-func unused() {
+-	_ = os.Stdin
+-	_ = io.EOF
+-}
+-
 diff -urN a/gopls/internal/lsp/testdata/errors/errors.go b/gopls/internal/lsp/testdata/errors/errors.go
 --- a/gopls/internal/lsp/testdata/errors/errors.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/errors/errors.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/errors/errors.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -package errors
 -
@@ -92357,761 +103264,9 @@
 -	bob.Bob() //@complete(".")
 -	types.b //@complete(" //", Bob_interface)
 -}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
--package extract
--
--func _() {
--	a := 1
--	a = 5     //@mark(exSt0, "a")
--	a = a + 2 //@mark(exEn0, "2")
--	//@extractfunc(exSt0, exEn0)
--	b := a * 2 //@mark(exB, "	b")
--	_ = 3 + 4  //@mark(exEnd, "4")
--	//@extractfunc(exB, exEnd)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
---- functionextraction_extract_args_returns_5_2 --
--package extract
--
--func _() {
--	a := 1
--	//@mark(exSt0, "a")
--	a = newFunction(a) //@mark(exEn0, "2")
--	//@extractfunc(exSt0, exEn0)
--	b := a * 2 //@mark(exB, "	b")
--	_ = 3 + 4  //@mark(exEnd, "4")
--	//@extractfunc(exB, exEnd)
--}
--
--func newFunction(a int) int {
--	a = 5
--	a = a + 2
--	return a
--}
--
---- functionextraction_extract_args_returns_8_1 --
--package extract
--
--func _() {
--	a := 1
--	a = 5     //@mark(exSt0, "a")
--	a = a + 2 //@mark(exEn0, "2")
--	//@extractfunc(exSt0, exEn0)
--	//@mark(exB, "	b")
--	newFunction(a)  //@mark(exEnd, "4")
--	//@extractfunc(exB, exEnd)
--}
--
--func newFunction(a int) {
--	b := a * 2
--	_ = 3 + 4
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
--package extract
--
--func _() {
--	a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
--	// Comment on its own line  //@mark(exSt19, "Comment")
--	_ = 3 + 4 //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
--	// Comment right after 3 + 4
--
--	// Comment after with space //@mark(exEn20, "Comment")
--
--	//@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,57 +0,0 @@
---- functionextraction_extract_basic_comment_4_2 --
--package extract
--
--func _() {
--	/* comment in the middle of a line */
--	//@mark(exSt18, "a")
--	// Comment on its own line  //@mark(exSt19, "Comment")
--	newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
--	// Comment right after 3 + 4
--
--	// Comment after with space //@mark(exEn20, "Comment")
--
--	//@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
--}
--
--func newFunction() {
--	a := 1
--
--	_ = 3 + 4
--}
--
---- functionextraction_extract_basic_comment_5_5 --
--package extract
--
--func _() {
--	a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
--	// Comment on its own line  //@mark(exSt19, "Comment")
--	newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
--	// Comment right after 3 + 4
--
--	// Comment after with space //@mark(exEn20, "Comment")
--
--	//@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
--}
--
--func newFunction() {
--	_ = 3 + 4
--}
--
---- functionextraction_extract_basic_comment_6_2 --
--package extract
--
--func _() {
--	a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
--	// Comment on its own line  //@mark(exSt19, "Comment")
--	newFunction() //@mark(exEn18, "4"),mark(exEn19, "4"),mark(exSt20, "_")
--	// Comment right after 3 + 4
--
--	// Comment after with space //@mark(exEn20, "Comment")
--
--	//@extractfunc(exSt18, exEn18),extractfunc(exSt19, exEn19),extractfunc(exSt20, exEn20)
--}
--
--func newFunction() {
--	_ = 3 + 4
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,8 +0,0 @@
--package extract
--
--func _() { //@mark(exSt25, "{")
--	a := 1    //@mark(exSt1, "a")
--	_ = 3 + 4 //@mark(exEn1, "4")
--	//@extractfunc(exSt1, exEn1)
--	//@extractfunc(exSt25, exEn25)
--} //@mark(exEn25, "}")
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,30 +0,0 @@
---- functionextraction_extract_basic_3_10 --
--package extract
--
--func _() { //@mark(exSt25, "{")
--	//@mark(exSt1, "a")
--	newFunction() //@mark(exEn1, "4")
--	//@extractfunc(exSt1, exEn1)
--	//@extractfunc(exSt25, exEn25)
--}
--
--func newFunction() {
--	a := 1
--	_ = 3 + 4
--} //@mark(exEn25, "}")
--
---- functionextraction_extract_basic_4_2 --
--package extract
--
--func _() { //@mark(exSt25, "{")
--	//@mark(exSt1, "a")
--	newFunction() //@mark(exEn1, "4")
--	//@extractfunc(exSt1, exEn1)
--	//@extractfunc(exSt25, exEn25)
--}
--
--func newFunction() {
--	a := 1
--	_ = 3 + 4
--} //@mark(exEn25, "}")
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
--package extract
--
--import "fmt"
--
--func main() {
--	x := []rune{} //@mark(exSt9, "x")
--	s := "HELLO"
--	for _, c := range s {
--		x = append(x, c)
--	} //@mark(exEn9, "}")
--	//@extractfunc(exSt9, exEn9)
--	fmt.Printf("%x\n", x)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
---- functionextraction_extract_issue_44813_6_2 --
--package extract
--
--import "fmt"
--
--func main() {
--	//@mark(exSt9, "x")
--	x := newFunction() //@mark(exEn9, "}")
--	//@extractfunc(exSt9, exEn9)
--	fmt.Printf("%x\n", x)
--}
--
--func newFunction() []rune {
--	x := []rune{}
--	s := "HELLO"
--	for _, c := range s {
--		x = append(x, c)
--	}
--	return x
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
--package extract
--
--import "strconv"
--
--func _() {
--	i, err := strconv.Atoi("1")
--	u, err := strconv.Atoi("2") //@extractfunc("u", ")")
--	if i == u || err == nil {
--		return
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_redefine.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
---- functionextraction_extract_redefine_7_2 --
--package extract
--
--import "strconv"
--
--func _() {
--	i, err := strconv.Atoi("1")
--	u, err := newFunction() //@extractfunc("u", ")")
--	if i == u || err == nil {
--		return
--	}
--}
--
--func newFunction() (int, error) {
--	u, err := strconv.Atoi("2")
--	return u, err
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package extract
--
--func _() bool {
--	x := 1
--	if x == 0 { //@mark(exSt2, "if")
--		return true
--	} //@mark(exEn2, "}")
--	return false
--	//@extractfunc(exSt2, exEn2)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
---- functionextraction_extract_return_basic_5_2 --
--package extract
--
--func _() bool {
--	x := 1
--	//@mark(exSt2, "if")
--	shouldReturn, returnValue := newFunction(x)
--	if shouldReturn {
--		return returnValue
--	} //@mark(exEn2, "}")
--	return false
--	//@extractfunc(exSt2, exEn2)
--}
--
--func newFunction(x int) (bool, bool) {
--	if x == 0 {
--		return true, true
--	}
--	return false, false
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package extract
--
--func _() bool {
--	x := 1 //@mark(exSt13, "x")
--	if x == 0 {
--		return true
--	}
--	return false //@mark(exEn13, "false")
--	//@extractfunc(exSt13, exEn13)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,17 +0,0 @@
---- functionextraction_extract_return_basic_nonnested_4_2 --
--package extract
--
--func _() bool {
--	//@mark(exSt13, "x")
--	return newFunction() //@mark(exEn13, "false")
--	//@extractfunc(exSt13, exEn13)
--}
--
--func newFunction() bool {
--	x := 1
--	if x == 0 {
--		return true
--	}
--	return false
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,17 +0,0 @@
--package extract
--
--import "fmt"
--
--func _() (int, string, error) {
--	x := 1
--	y := "hello"
--	z := "bye" //@mark(exSt3, "z")
--	if y == z {
--		return x, y, fmt.Errorf("same")
--	} else {
--		z = "hi"
--		return x, z, nil
--	} //@mark(exEn3, "}")
--	return x, z, nil
--	//@extractfunc(exSt3, exEn3)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,28 +0,0 @@
---- functionextraction_extract_return_complex_8_2 --
--package extract
--
--import "fmt"
--
--func _() (int, string, error) {
--	x := 1
--	y := "hello"
--	//@mark(exSt3, "z")
--	z, shouldReturn, returnValue, returnValue1, returnValue2 := newFunction(y, x)
--	if shouldReturn {
--		return returnValue, returnValue1, returnValue2
--	} //@mark(exEn3, "}")
--	return x, z, nil
--	//@extractfunc(exSt3, exEn3)
--}
--
--func newFunction(y string, x int) (string, bool, int, string, error) {
--	z := "bye"
--	if y == z {
--		return "", true, x, y, fmt.Errorf("same")
--	} else {
--		z = "hi"
--		return "", true, x, z, nil
--	}
--	return z, false, 0, "", nil
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,17 +0,0 @@
--package extract
--
--import "fmt"
--
--func _() (int, string, error) {
--	x := 1
--	y := "hello"
--	z := "bye" //@mark(exSt10, "z")
--	if y == z {
--		return x, y, fmt.Errorf("same")
--	} else {
--		z = "hi"
--		return x, z, nil
--	}
--	return x, z, nil //@mark(exEn10, "nil")
--	//@extractfunc(exSt10, exEn10)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
---- functionextraction_extract_return_complex_nonnested_8_2 --
--package extract
--
--import "fmt"
--
--func _() (int, string, error) {
--	x := 1
--	y := "hello"
--	//@mark(exSt10, "z")
--	return newFunction(y, x) //@mark(exEn10, "nil")
--	//@extractfunc(exSt10, exEn10)
--}
--
--func newFunction(y string, x int) (int, string, error) {
--	z := "bye"
--	if y == z {
--		return x, y, fmt.Errorf("same")
--	} else {
--		z = "hi"
--		return x, z, nil
--	}
--	return x, z, nil
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
--package extract
--
--import "go/ast"
--
--func _() {
--	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
--		if n == nil { //@mark(exSt4, "if")
--			return true
--		} //@mark(exEn4, "}")
--		return false
--	})
--	//@extractfunc(exSt4, exEn4)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
---- functionextraction_extract_return_func_lit_7_3 --
--package extract
--
--import "go/ast"
--
--func _() {
--	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
--		//@mark(exSt4, "if")
--		shouldReturn, returnValue := newFunction(n)
--		if shouldReturn {
--			return returnValue
--		} //@mark(exEn4, "}")
--		return false
--	})
--	//@extractfunc(exSt4, exEn4)
--}
--
--func newFunction(n ast.Node) (bool, bool) {
--	if n == nil {
--		return true, true
--	}
--	return false, false
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
--package extract
--
--import "go/ast"
--
--func _() {
--	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
--		if n == nil { //@mark(exSt11, "if")
--			return true
--		}
--		return false //@mark(exEn11, "false")
--	})
--	//@extractfunc(exSt11, exEn11)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,20 +0,0 @@
---- functionextraction_extract_return_func_lit_nonnested_7_3 --
--package extract
--
--import "go/ast"
--
--func _() {
--	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
--		//@mark(exSt11, "if")
--		return newFunction(n) //@mark(exEn11, "false")
--	})
--	//@extractfunc(exSt11, exEn11)
--}
--
--func newFunction(n ast.Node) bool {
--	if n == nil {
--		return true
--	}
--	return false
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
--package extract
--
--func _() string {
--	x := 1
--	if x == 0 { //@mark(exSt5, "if")
--		x = 3
--		return "a"
--	} //@mark(exEn5, "}")
--	x = 2
--	return "b"
--	//@extractfunc(exSt5, exEn5)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,23 +0,0 @@
---- functionextraction_extract_return_init_5_2 --
--package extract
--
--func _() string {
--	x := 1
--	//@mark(exSt5, "if")
--	shouldReturn, returnValue := newFunction(x)
--	if shouldReturn {
--		return returnValue
--	} //@mark(exEn5, "}")
--	x = 2
--	return "b"
--	//@extractfunc(exSt5, exEn5)
--}
--
--func newFunction(x int) (bool, string) {
--	if x == 0 {
--		x = 3
--		return true, "a"
--	}
--	return false, ""
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
--package extract
--
--func _() string {
--	x := 1
--	if x == 0 { //@mark(exSt12, "if")
--		x = 3
--		return "a"
--	}
--	x = 2
--	return "b" //@mark(exEn12, "\"b\"")
--	//@extractfunc(exSt12, exEn12)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,19 +0,0 @@
---- functionextraction_extract_return_init_nonnested_5_2 --
--package extract
--
--func _() string {
--	x := 1
--	//@mark(exSt12, "if")
--	return newFunction(x) //@mark(exEn12, "\"b\"")
--	//@extractfunc(exSt12, exEn12)
--}
--
--func newFunction(x int) string {
--	if x == 0 {
--		x = 3
--		return "a"
--	}
--	x = 2
--	return "b"
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package extract
--
--func _() {
--	newFunction := 1
--	a := newFunction //@extractfunc("a", "newFunction")
--}
--
--func newFunction1() int {
--	return 1
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_scope.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
---- functionextraction_extract_scope_5_2 --
--package extract
--
--func _() {
--	newFunction := 1
--	newFunction2(newFunction) //@extractfunc("a", "newFunction")
--}
--
--func newFunction2(newFunction int) {
--	a := newFunction
--}
--
--func newFunction1() int {
--	return 1
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package extract
--
--func _() {
--	var a []int
--	a = append(a, 2) //@mark(exSt6, "a")
--	b := 4           //@mark(exEn6, "4")
--	//@extractfunc(exSt6, exEn6)
--	a = append(a, b)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,17 +0,0 @@
---- functionextraction_extract_smart_initialization_5_2 --
--package extract
--
--func _() {
--	var a []int
--	//@mark(exSt6, "a")
--	a, b := newFunction(a)           //@mark(exEn6, "4")
--	//@extractfunc(exSt6, exEn6)
--	a = append(a, b)
--}
--
--func newFunction(a []int) ([]int, int) {
--	a = append(a, 2)
--	b := 4
--	return a, b
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
--package extract
--
--func _() {
--	var b []int
--	var a int
--	a = 2 //@mark(exSt7, "a")
--	b = []int{}
--	b = append(b, a) //@mark(exEn7, ")")
--	b[0] = 1
--	//@extractfunc(exSt7, exEn7)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,19 +0,0 @@
---- functionextraction_extract_smart_return_6_2 --
--package extract
--
--func _() {
--	var b []int
--	var a int
--	//@mark(exSt7, "a")
--	b = newFunction(a, b) //@mark(exEn7, ")")
--	b[0] = 1
--	//@extractfunc(exSt7, exEn7)
--}
--
--func newFunction(a int, b []int) []int {
--	a = 2
--	b = []int{}
--	b = append(b, a)
--	return b
--}
--
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--package extract
--
--func _() {
--	var b []int
--	var a int
--	a := 2 //@mark(exSt8, "a")
--	b = []int{}
--	b = append(b, a) //@mark(exEn8, ")")
--	b[0] = 1
--	if a == 2 {
--		return
--	}
--	//@extractfunc(exSt8, exEn8)
--}
-diff -urN a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
---- a/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,22 +0,0 @@
---- functionextraction_extract_unnecessary_param_6_2 --
--package extract
--
--func _() {
--	var b []int
--	var a int
--	//@mark(exSt8, "a")
--	a, b = newFunction(b) //@mark(exEn8, ")")
--	b[0] = 1
--	if a == 2 {
--		return
--	}
--	//@extractfunc(exSt8, exEn8)
--}
--
--func newFunction(b []int) (int, []int) {
--	a := 2
--	b = []int{}
--	b = append(b, a)
--	return a, b
--}
--
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go
 --- a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -package extract
 -
@@ -93139,7 +103294,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden
 --- a/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_basic.go.golden	1970-01-01 08:00:00
 @@ -1,364 +0,0 @@
 --- functionextraction_extract_basic_13_2 --
 -package extract
@@ -93505,9 +103660,89 @@
 -	return sum       //@extractmethod("return", "sum"),extractfunc("return", "sum")
 -}
 -
+diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go b/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go
+--- a/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
+-package extract
+-
+-import "context"
+-
+-type B struct {
+-	x int
+-	y int
+-}
+-
+-func (b *B) AddP(ctx context.Context) (int, error) {
+-	sum := b.x + b.y
+-	return sum, ctx.Err() //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+-
+-func (b *B) LongList(ctx context.Context) (int, error) {
+-	p1 := 1
+-	p2 := 1
+-	p3 := 1
+-	return p1 + p2 + p3, ctx.Err() //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+diff -urN a/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go.golden b/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go.golden
+--- a/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/extract/extract_method/extract_context.go.golden	1970-01-01 08:00:00
+@@ -1,52 +0,0 @@
+--- methodextraction_extract_context_12_2 --
+-package extract
+-
+-import "context"
+-
+-type B struct {
+-	x int
+-	y int
+-}
+-
+-func (b *B) AddP(ctx context.Context) (int, error) {
+-	sum := b.x + b.y
+-	return b.newMethod(ctx, sum) //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+-
+-func (*B) newMethod(ctx context.Context, sum int) (int, error) {
+-	return sum, ctx.Err()
+-}
+-
+-func (b *B) LongList(ctx context.Context) (int, error) {
+-	p1 := 1
+-	p2 := 1
+-	p3 := 1
+-	return p1 + p2 + p3, ctx.Err() //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+-
+--- methodextraction_extract_context_19_2 --
+-package extract
+-
+-import "context"
+-
+-type B struct {
+-	x int
+-	y int
+-}
+-
+-func (b *B) AddP(ctx context.Context) (int, error) {
+-	sum := b.x + b.y
+-	return sum, ctx.Err() //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+-
+-func (b *B) LongList(ctx context.Context) (int, error) {
+-	p1 := 1
+-	p2 := 1
+-	p3 := 1
+-	return b.newMethod(ctx, p1, p2, p3) //@extractmethod("return", "ctx.Err()"),extractfunc("return", "ctx.Err()")
+-}
+-
+-func (*B) newMethod(ctx context.Context, p1 int, p2 int, p3 int) (int, error) {
+-	return p1 + p2 + p3, ctx.Err()
+-}
+-
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package extract
 -
@@ -93517,7 +103752,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_basic_lit.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- suggestedfix_extract_basic_lit_4_10 --
 -package extract
@@ -93539,7 +103774,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package extract
 -
@@ -93552,7 +103787,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_func_call.go.golden	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 --- suggestedfix_extract_func_call_6_8 --
 -package extract
@@ -93580,7 +103815,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package extract
 -
@@ -93597,7 +103832,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden
 --- a/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/extract/extract_variable/extract_scope.go.golden	1970-01-01 08:00:00
 @@ -1,32 +0,0 @@
 --- suggestedfix_extract_scope_11_9 --
 -package extract
@@ -93633,7 +103868,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fieldlist/field_list.go b/gopls/internal/lsp/testdata/fieldlist/field_list.go
 --- a/gopls/internal/lsp/testdata/fieldlist/field_list.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fieldlist/field_list.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fieldlist/field_list.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -package fieldlist
 -
@@ -93662,9 +103897,170 @@
 -		m() my //@complete("("),complete(" //", flType)
 -	}
 -}
+diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go b/gopls/internal/lsp/testdata/fillstruct/a.go
+--- a/gopls/internal/lsp/testdata/fillstruct/a.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a.go	1970-01-01 08:00:00
+@@ -1,27 +0,0 @@
+-package fillstruct
+-
+-import (
+-	"golang.org/lsptests/fillstruct/data"
+-)
+-
+-type basicStruct struct {
+-	foo int
+-}
+-
+-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type twoArgStruct struct {
+-	foo int
+-	bar string
+-}
+-
+-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type nestedStruct struct {
+-	bar   string
+-	basic basicStruct
+-}
+-
+-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go.golden b/gopls/internal/lsp/testdata/fillstruct/a.go.golden
+--- a/gopls/internal/lsp/testdata/fillstruct/a.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a.go.golden	1970-01-01 08:00:00
+@@ -1,126 +0,0 @@
+--- suggestedfix_a_11_21 --
+-package fillstruct
+-
+-import (
+-	"golang.org/lsptests/fillstruct/data"
+-)
+-
+-type basicStruct struct {
+-	foo int
+-}
+-
+-var _ = basicStruct{
+-	foo: 0,
+-} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type twoArgStruct struct {
+-	foo int
+-	bar string
+-}
+-
+-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type nestedStruct struct {
+-	bar   string
+-	basic basicStruct
+-}
+-
+-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+--- suggestedfix_a_18_22 --
+-package fillstruct
+-
+-import (
+-	"golang.org/lsptests/fillstruct/data"
+-)
+-
+-type basicStruct struct {
+-	foo int
+-}
+-
+-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type twoArgStruct struct {
+-	foo int
+-	bar string
+-}
+-
+-var _ = twoArgStruct{
+-	foo: 0,
+-	bar: "",
+-} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type nestedStruct struct {
+-	bar   string
+-	basic basicStruct
+-}
+-
+-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+--- suggestedfix_a_25_22 --
+-package fillstruct
+-
+-import (
+-	"golang.org/lsptests/fillstruct/data"
+-)
+-
+-type basicStruct struct {
+-	foo int
+-}
+-
+-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type twoArgStruct struct {
+-	foo int
+-	bar string
+-}
+-
+-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type nestedStruct struct {
+-	bar   string
+-	basic basicStruct
+-}
+-
+-var _ = nestedStruct{
+-	bar:   "",
+-	basic: basicStruct{},
+-} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+--- suggestedfix_a_27_16 --
+-package fillstruct
+-
+-import (
+-	"golang.org/lsptests/fillstruct/data"
+-)
+-
+-type basicStruct struct {
+-	foo int
+-}
+-
+-var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type twoArgStruct struct {
+-	foo int
+-	bar string
+-}
+-
+-var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-type nestedStruct struct {
+-	bar   string
+-	basic basicStruct
+-}
+-
+-var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
+-var _ = data.B{
+-	ExportedInt: 0,
+-} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a2.go b/gopls/internal/lsp/testdata/fillstruct/a2.go
 --- a/gopls/internal/lsp/testdata/fillstruct/a2.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a2.go	1970-01-01 08:00:00
 @@ -1,29 +0,0 @@
 -package fillstruct
 -
@@ -93697,7 +104093,7 @@
 -var _ = funStructEmpty{} //@suggestedfix("}", "refactor.rewrite", "Fill")
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/a2.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a2.go.golden	1970-01-01 08:00:00
 @@ -1,139 +0,0 @@
 --- suggestedfix_a2_11_21 --
 -package fillstruct
@@ -93840,7 +104236,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a3.go b/gopls/internal/lsp/testdata/fillstruct/a3.go
 --- a/gopls/internal/lsp/testdata/fillstruct/a3.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a3.go	1970-01-01 08:00:00
 @@ -1,42 +0,0 @@
 -package fillstruct
 -
@@ -93886,7 +104282,7 @@
 -var _ = []ast.BasicLit{{}} //@suggestedfix("}", "refactor.rewrite", "Fill")
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/a3.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a3.go.golden	1970-01-01 08:00:00
 @@ -1,243 +0,0 @@
 --- suggestedfix_a3_17_13 --
 -package fillstruct
@@ -94133,7 +104529,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a4.go b/gopls/internal/lsp/testdata/fillstruct/a4.go
 --- a/gopls/internal/lsp/testdata/fillstruct/a4.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a4.go	1970-01-01 08:00:00
 @@ -1,39 +0,0 @@
 -package fillstruct
 -
@@ -94176,7 +104572,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/a4.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/a4.go.golden	1970-01-01 08:00:00
 @@ -1,174 +0,0 @@
 --- suggestedfix_a4_25_18 --
 -package fillstruct
@@ -94352,170 +104748,9 @@
 -	} //@suggestedfix("}", "refactor.rewrite", "Fill")
 -}
 -
-diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go b/gopls/internal/lsp/testdata/fillstruct/a.go
---- a/gopls/internal/lsp/testdata/fillstruct/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,27 +0,0 @@
--package fillstruct
--
--import (
--	"golang.org/lsptests/fillstruct/data"
--)
--
--type basicStruct struct {
--	foo int
--}
--
--var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type twoArgStruct struct {
--	foo int
--	bar string
--}
--
--var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type nestedStruct struct {
--	bar   string
--	basic basicStruct
--}
--
--var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
-diff -urN a/gopls/internal/lsp/testdata/fillstruct/a.go.golden b/gopls/internal/lsp/testdata/fillstruct/a.go.golden
---- a/gopls/internal/lsp/testdata/fillstruct/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/a.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,126 +0,0 @@
---- suggestedfix_a_11_21 --
--package fillstruct
--
--import (
--	"golang.org/lsptests/fillstruct/data"
--)
--
--type basicStruct struct {
--	foo int
--}
--
--var _ = basicStruct{
--	foo: 0,
--} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type twoArgStruct struct {
--	foo int
--	bar string
--}
--
--var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type nestedStruct struct {
--	bar   string
--	basic basicStruct
--}
--
--var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
---- suggestedfix_a_18_22 --
--package fillstruct
--
--import (
--	"golang.org/lsptests/fillstruct/data"
--)
--
--type basicStruct struct {
--	foo int
--}
--
--var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type twoArgStruct struct {
--	foo int
--	bar string
--}
--
--var _ = twoArgStruct{
--	foo: 0,
--	bar: "",
--} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type nestedStruct struct {
--	bar   string
--	basic basicStruct
--}
--
--var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
---- suggestedfix_a_25_22 --
--package fillstruct
--
--import (
--	"golang.org/lsptests/fillstruct/data"
--)
--
--type basicStruct struct {
--	foo int
--}
--
--var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type twoArgStruct struct {
--	foo int
--	bar string
--}
--
--var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type nestedStruct struct {
--	bar   string
--	basic basicStruct
--}
--
--var _ = nestedStruct{
--	bar:   "",
--	basic: basicStruct{},
--} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--var _ = data.B{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
---- suggestedfix_a_27_16 --
--package fillstruct
--
--import (
--	"golang.org/lsptests/fillstruct/data"
--)
--
--type basicStruct struct {
--	foo int
--}
--
--var _ = basicStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type twoArgStruct struct {
--	foo int
--	bar string
--}
--
--var _ = twoArgStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--type nestedStruct struct {
--	bar   string
--	basic basicStruct
--}
--
--var _ = nestedStruct{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
--var _ = data.B{
--	ExportedInt: 0,
--} //@suggestedfix("}", "refactor.rewrite", "Fill")
--
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/data/a.go b/gopls/internal/lsp/testdata/fillstruct/data/a.go
 --- a/gopls/internal/lsp/testdata/fillstruct/data/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/data/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/data/a.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package data

 -

@@ -94523,51 +104758,9 @@
 -	ExportedInt   int

 -	unexportedInt int

 -}

-diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go
---- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--package fillstruct
--
--type StructAnon struct {
--	a struct{}
--	b map[string]interface{}
--	c map[string]struct {
--		d int
--		e bool
--	}
--}
--
--func fill() {
--	_ := StructAnon{} //@suggestedfix("}", "refactor.rewrite", "Fill")
--}
-diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden
---- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,20 +0,0 @@
---- suggestedfix_fill_struct_anon_13_18 --
--package fillstruct
--
--type StructAnon struct {
--	a struct{}
--	b map[string]interface{}
--	c map[string]struct {
--		d int
--		e bool
--	}
--}
--
--func fill() {
--	_ := StructAnon{
--		a: struct{}{},
--		b: map[string]interface{}{},
--		c: map[string]struct{d int; e bool}{},
--	} //@suggestedfix("}", "refactor.rewrite", "Fill")
--}
--
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -package fillstruct
 -
@@ -94597,7 +104790,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct.go.golden	1970-01-01 08:00:00
 @@ -1,124 +0,0 @@
 --- suggestedfix_fill_struct_20_15 --
 -package fillstruct
@@ -94723,9 +104916,51 @@
 -	}
 -}
 -
+diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go
+--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package fillstruct
+-
+-type StructAnon struct {
+-	a struct{}
+-	b map[string]interface{}
+-	c map[string]struct {
+-		d int
+-		e bool
+-	}
+-}
+-
+-func fill() {
+-	_ := StructAnon{} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-}
+diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden
+--- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_anon.go.golden	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
+--- suggestedfix_fill_struct_anon_13_18 --
+-package fillstruct
+-
+-type StructAnon struct {
+-	a struct{}
+-	b map[string]interface{}
+-	c map[string]struct {
+-		d int
+-		e bool
+-	}
+-}
+-
+-func fill() {
+-	_ := StructAnon{
+-		a: struct{}{},
+-		b: map[string]interface{}{},
+-		c: map[string]struct{d int; e bool}{},
+-	} //@suggestedfix("}", "refactor.rewrite", "Fill")
+-}
+-
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -package fillstruct
 -
@@ -94744,7 +104979,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_nested.go.golden	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 --- suggestedfix_fill_struct_nested_13_20 --
 -package fillstruct
@@ -94767,7 +105002,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -package fillstruct
 -
@@ -94783,7 +105018,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_package.go.golden	1970-01-01 08:00:00
 @@ -1,36 +0,0 @@
 --- suggestedfix_fill_struct_package_10_14 --
 -package fillstruct
@@ -94823,7 +105058,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -package fillstruct
 -
@@ -94851,7 +105086,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_partial.go.golden	1970-01-01 08:00:00
 @@ -1,52 +0,0 @@
 --- suggestedfix_fill_struct_partial_17_2 --
 -package fillstruct
@@ -94907,7 +105142,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package fillstruct
 -
@@ -94920,7 +105155,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_spaces.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- suggestedfix_fill_struct_spaces_8_15 --
 -package fillstruct
@@ -94937,7 +105172,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -package fillstruct
 -
@@ -94953,7 +105188,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/fill_struct_unsafe.go.golden	1970-01-01 08:00:00
 @@ -1,17 +0,0 @@
 --- suggestedfix_fill_struct_unsafe_11_20 --
 -package fillstruct
@@ -94974,7 +105209,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/typeparams.go b/gopls/internal/lsp/testdata/fillstruct/typeparams.go
 --- a/gopls/internal/lsp/testdata/fillstruct/typeparams.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go	1970-01-01 08:00:00
 @@ -1,37 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -95015,7 +105250,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden
 --- a/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fillstruct/typeparams.go.golden	1970-01-01 08:00:00
 @@ -1,206 +0,0 @@
 --- suggestedfix_typeparams_14_40 --
 -//go:build go1.18
@@ -95223,1062 +105458,9 @@
 -	} //@suggestedfix("}", "refactor.rewrite", "Fill")
 -}
 -
-diff -urN a/gopls/internal/lsp/testdata/folding/a.go b/gopls/internal/lsp/testdata/folding/a.go
---- a/gopls/internal/lsp/testdata/folding/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/folding/a.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,75 +0,0 @@
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println("true")
--		} else {
--			fmt.Println("false")
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println("true from x")
--		} else {
--			fmt.Println("false from x")
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
-diff -urN a/gopls/internal/lsp/testdata/folding/a.go.golden b/gopls/internal/lsp/testdata/folding/a.go.golden
---- a/gopls/internal/lsp/testdata/folding/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/folding/a.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,722 +0,0 @@
---- foldingRange-0 --
--package folding //@fold("package")
--
--import (<>)
--
--import _ "os"
--
--// bar is a function.<>
--func bar(<>) string {<>}
--
---- foldingRange-1 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {<>}
--	/* This is a multiline<>
--
--	/* This is a multiline<>
--	_ = []int{<>}
--	_ = [2]string{<>}
--	_ = map[string]int{<>}
--	type T struct {<>}
--	_ = T{<>}
--	x, y := make(<>), make(<>)
--	select {<>}
--	// This is a multiline comment<>
--	return <>
--}
--
---- foldingRange-2 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:<>
--	case false:<>
--	default:<>
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:<>
--	case <-y:<>
--	default:<>
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-3 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {<>} else {<>}
--	case false:
--		fmt.Println(<>)
--	default:
--		fmt.Println(<>)
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {<>} else {<>}
--	case <-y:
--		fmt.Println(<>)
--	default:
--		fmt.Println(<>)
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-4 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println(<>)
--		} else {
--			fmt.Println(<>)
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println(<>)
--		} else {
--			fmt.Println(<>)
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-comment-0 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.<>
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println("true")
--		} else {
--			fmt.Println("false")
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline<>
--
--	/* This is a multiline<>
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println("true from x")
--		} else {
--			fmt.Println("false from x")
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment<>
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-imports-0 --
--package folding //@fold("package")
--
--import (<>)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println("true")
--		} else {
--			fmt.Println("false")
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println("true from x")
--		} else {
--			fmt.Println("false from x")
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-lineFolding-0 --
--package folding //@fold("package")
--
--import (<>
--)
--
--import _ "os"
--
--// bar is a function.<>
--func bar() string {<>
--}
--
---- foldingRange-lineFolding-1 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {<>
--	}
--	/* This is a multiline<>
--
--	/* This is a multiline<>
--	_ = []int{<>,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{<>,
--	}
--	type T struct {<>
--	}
--	_ = T{<>,
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {<>
--	}
--	// This is a multiline comment<>
--	return <>
--}
--
---- foldingRange-lineFolding-2 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:<>
--	case false:<>
--	default:<>
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:<>
--	case <-y:<>
--	default:<>
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-lineFolding-3 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {<>
--		} else {<>
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {<>
--		} else {<>
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-lineFolding-comment-0 --
--package folding //@fold("package")
--
--import (
--	"fmt"
--	_ "log"
--)
--
--import _ "os"
--
--// bar is a function.<>
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println("true")
--		} else {
--			fmt.Println("false")
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline<>
--
--	/* This is a multiline<>
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println("true from x")
--		} else {
--			fmt.Println("false from x")
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment<>
--	return `
--this string
--is not indented`
--}
--
---- foldingRange-lineFolding-imports-0 --
--package folding //@fold("package")
--
--import (<>
--)
--
--import _ "os"
--
--// bar is a function.
--// With a multiline doc comment.
--func bar() string {
--	/* This is a single line comment */
--	switch {
--	case true:
--		if true {
--			fmt.Println("true")
--		} else {
--			fmt.Println("false")
--		}
--	case false:
--		fmt.Println("false")
--	default:
--		fmt.Println("default")
--	}
--	/* This is a multiline
--	block
--	comment */
--
--	/* This is a multiline
--	block
--	comment */
--	// Followed by another comment.
--	_ = []int{
--		1,
--		2,
--		3,
--	}
--	_ = [2]string{"d",
--		"e",
--	}
--	_ = map[string]int{
--		"a": 1,
--		"b": 2,
--		"c": 3,
--	}
--	type T struct {
--		f string
--		g int
--		h string
--	}
--	_ = T{
--		f: "j",
--		g: 4,
--		h: "i",
--	}
--	x, y := make(chan bool), make(chan bool)
--	select {
--	case val := <-x:
--		if val {
--			fmt.Println("true from x")
--		} else {
--			fmt.Println("false from x")
--		}
--	case <-y:
--		fmt.Println("y")
--	default:
--		fmt.Println("default")
--	}
--	// This is a multiline comment
--	// that is not a doc comment.
--	return `
--this string
--is not indented`
--}
--
-diff -urN a/gopls/internal/lsp/testdata/folding/bad.go.golden b/gopls/internal/lsp/testdata/folding/bad.go.golden
---- a/gopls/internal/lsp/testdata/folding/bad.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/folding/bad.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,81 +0,0 @@
---- foldingRange-0 --
--package folding //@fold("package")
--
--import (<>)
--
--import (<>)
--	
--// badBar is a function.
--func badBar(<>) string {<>}
--
---- foldingRange-1 --
--package folding //@fold("package")
--
--import ( "fmt"
--	_ "log"
--)
--
--import ( 
--	_ "os" )
--	
--// badBar is a function.
--func badBar() string { x := true
--	if x {<>} else {<>}
--	return
--}
--
---- foldingRange-2 --
--package folding //@fold("package")
--
--import ( "fmt"
--	_ "log"
--)
--
--import ( 
--	_ "os" )
--	
--// badBar is a function.
--func badBar() string { x := true
--	if x { 
--		// This is the only foldable thing in this file when lineFoldingOnly
--		fmt.Println(<>)
--	} else {
--		fmt.Println(<>) }
--	return
--}
--
---- foldingRange-imports-0 --
--package folding //@fold("package")
--
--import (<>)
--
--import (<>)
--	
--// badBar is a function.
--func badBar() string { x := true
--	if x { 
--		// This is the only foldable thing in this file when lineFoldingOnly
--		fmt.Println("true")
--	} else {
--		fmt.Println("false") }
--	return
--}
--
---- foldingRange-lineFolding-0 --
--package folding //@fold("package")
--
--import ( "fmt"
--	_ "log"
--)
--
--import ( 
--	_ "os" )
--	
--// badBar is a function.
--func badBar() string { x := true
--	if x {<>
--	} else {
--		fmt.Println("false") }
--	return
--}
--
-diff -urN a/gopls/internal/lsp/testdata/folding/bad.go.in b/gopls/internal/lsp/testdata/folding/bad.go.in
---- a/gopls/internal/lsp/testdata/folding/bad.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/folding/bad.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
--package folding //@fold("package")
--
--import ( "fmt"
--	_ "log"
--)
--
--import ( 
--	_ "os" )
--	
--// badBar is a function.
--func badBar() string { x := true
--	if x { 
--		// This is the only foldable thing in this file when lineFoldingOnly
--		fmt.Println("true")
--	} else {
--		fmt.Println("false") }
--	return
--}
-diff -urN a/gopls/internal/lsp/testdata/foo/foo.go b/gopls/internal/lsp/testdata/foo/foo.go
---- a/gopls/internal/lsp/testdata/foo/foo.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/foo/foo.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,30 +0,0 @@
--package foo //@mark(PackageFoo, "foo"),item(PackageFoo, "foo", "\"golang.org/lsptests/foo\"", "package")
--
--type StructFoo struct { //@item(StructFoo, "StructFoo", "struct{...}", "struct")
--	Value int //@item(Value, "Value", "int", "field")
--}
--
--// Pre-set this marker, as we don't have a "source" for it in this package.
--/* Error() */ //@item(Error, "Error", "func() string", "method")
--
--func Foo() { //@item(Foo, "Foo", "func()", "func")
--	var err error
--	err.Error() //@complete("E", Error)
--}
--
--func _() {
--	var sFoo StructFoo           //@mark(sFoo1, "sFoo"),complete("t", StructFoo)
--	if x := sFoo; x.Value == 1 { //@mark(sFoo2, "sFoo"),complete("V", Value),typdef("sFoo", StructFoo),refs("sFo", sFoo1, sFoo2)
--		return
--	}
--}
--
--func _() {
--	shadowed := 123
--	{
--		shadowed := "hi" //@item(shadowed, "shadowed", "string", "var"),refs("shadowed", shadowed)
--		sha              //@complete("a", shadowed)
--	}
--}
--
--type IntFoo int //@item(IntFoo, "IntFoo", "int", "type")
-diff -urN a/gopls/internal/lsp/testdata/format/bad_format.go.golden b/gopls/internal/lsp/testdata/format/bad_format.go.golden
---- a/gopls/internal/lsp/testdata/format/bad_format.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/bad_format.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
---- gofmt --
--package format //@format("package")
--
--import (
--	"fmt"
--	"log"
--	"runtime"
--)
--
--func hello() {
--
--	var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
--}
--
--func hi() {
--	runtime.GOROOT()
--	fmt.Printf("")
--
--	log.Printf("")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/format/bad_format.go.in b/gopls/internal/lsp/testdata/format/bad_format.go.in
---- a/gopls/internal/lsp/testdata/format/bad_format.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/bad_format.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,22 +0,0 @@
--package format //@format("package")
--
--import (
--	"runtime"
--	"fmt"
--	"log"
--)
--
--func hello() {
--
--
--
--
--	var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
--}
--
--func hi() {
--	runtime.GOROOT()
--	fmt.Printf("")
--
--	log.Printf("")
--}
-diff -urN a/gopls/internal/lsp/testdata/format/good_format.go b/gopls/internal/lsp/testdata/format/good_format.go
---- a/gopls/internal/lsp/testdata/format/good_format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/good_format.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package format //@format("package")
--
--import (
--	"log"
--)
--
--func goodbye() {
--	log.Printf("byeeeee")
--}
-diff -urN a/gopls/internal/lsp/testdata/format/good_format.go.golden b/gopls/internal/lsp/testdata/format/good_format.go.golden
---- a/gopls/internal/lsp/testdata/format/good_format.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/good_format.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
---- gofmt --
--package format //@format("package")
--
--import (
--	"log"
--)
--
--func goodbye() {
--	log.Printf("byeeeee")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/format/newline_format.go.golden b/gopls/internal/lsp/testdata/format/newline_format.go.golden
---- a/gopls/internal/lsp/testdata/format/newline_format.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/newline_format.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,4 +0,0 @@
---- gofmt --
--package format //@format("package")
--func _()       {}
--
-diff -urN a/gopls/internal/lsp/testdata/format/newline_format.go.in b/gopls/internal/lsp/testdata/format/newline_format.go.in
---- a/gopls/internal/lsp/testdata/format/newline_format.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/newline_format.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2 +0,0 @@
--package format //@format("package")
--func _() {}
-\ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/format/one_line.go.golden b/gopls/internal/lsp/testdata/format/one_line.go.golden
---- a/gopls/internal/lsp/testdata/format/one_line.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/one_line.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
---- gofmt --
--package format //@format("package")
--
-diff -urN a/gopls/internal/lsp/testdata/format/one_line.go.in b/gopls/internal/lsp/testdata/format/one_line.go.in
---- a/gopls/internal/lsp/testdata/format/one_line.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/format/one_line.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--package format //@format("package")
-\ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in
 --- a/gopls/internal/lsp/testdata/func_rank/func_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/func_rank/func_rank.go.in	1970-01-01 08:00:00
 @@ -1,70 +0,0 @@
 -package func_rank
 -
@@ -96352,7 +105534,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/funcsig/func_sig.go b/gopls/internal/lsp/testdata/funcsig/func_sig.go
 --- a/gopls/internal/lsp/testdata/funcsig/func_sig.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/funcsig/func_sig.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/funcsig/func_sig.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package funcsig
 -
@@ -96365,7 +105547,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/funcvalue/func_value.go b/gopls/internal/lsp/testdata/funcvalue/func_value.go
 --- a/gopls/internal/lsp/testdata/funcvalue/func_value.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/funcvalue/func_value.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/funcvalue/func_value.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -package funcvalue
 -
@@ -96396,7 +105578,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go
 --- a/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/fuzzymatch/fuzzymatch.go	1970-01-01 08:00:00
 @@ -1,48 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -96446,988 +105628,11 @@
 -	var s string
 -	s = abc //@fuzzy(" //", fuzzABCstring, fuzzABCInt, fuzzABCbool)
 -}
-diff -urN a/gopls/internal/lsp/testdata/generate/generate.go b/gopls/internal/lsp/testdata/generate/generate.go
---- a/gopls/internal/lsp/testdata/generate/generate.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/generate/generate.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,4 +0,0 @@
--package generate
--
--//go:generate echo Hi //@ codelens("//go:generate", "run go generate", "generate"), codelens("//go:generate", "run go generate ./...", "generate")
--//go:generate echo I shall have no CodeLens
-diff -urN a/gopls/internal/lsp/testdata/generated/generated.go b/gopls/internal/lsp/testdata/generated/generated.go
---- a/gopls/internal/lsp/testdata/generated/generated.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/generated/generated.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
--package generated
--
--// Code generated by generator.go. DO NOT EDIT.
--
--func _() {
--	var y int //@diag("y", "compiler", "y declared (and|but) not used", "error")
--}
-diff -urN a/gopls/internal/lsp/testdata/generated/generator.go b/gopls/internal/lsp/testdata/generated/generator.go
---- a/gopls/internal/lsp/testdata/generated/generator.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/generated/generator.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package generated
--
--func _() {
--	var x int //@diag("x", "compiler", "x declared (and|but) not used", "error")
--}
-diff -urN a/gopls/internal/lsp/testdata/godef/a/a_x_test.go b/gopls/internal/lsp/testdata/godef/a/a_x_test.go
---- a/gopls/internal/lsp/testdata/godef/a/a_x_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package a_test
--
--import (
--	"testing"
--)
--
--func TestA2(t *testing.T) { //@TestA2,godef(TestA2, TestA2)
--	Nonexistant() //@diag("Nonexistant", "compiler", "(undeclared name|undefined): Nonexistant", "error")
--}
-diff -urN a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden
---- a/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/a_x_test.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,26 +0,0 @@
---- TestA2-definition --
--godef/a/a_x_test.go:7:6-12: defined here as ```go
--func TestA2(t *testing.T)
--```
---- TestA2-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/a_x_test.go",
--		"start": {
--			"line": 7,
--			"column": 6,
--			"offset": 44
--		},
--		"end": {
--			"line": 7,
--			"column": 12,
--			"offset": 50
--		}
--	},
--	"description": "```go\nfunc TestA2(t *testing.T)\n```"
--}
--
---- TestA2-hoverdef --
--```go
--func TestA2(t *testing.T)
--```
-diff -urN a/gopls/internal/lsp/testdata/godef/a/d.go b/gopls/internal/lsp/testdata/godef/a/d.go
---- a/gopls/internal/lsp/testdata/godef/a/d.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/d.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,69 +0,0 @@
--package a //@mark(a, "a "),hoverdef("a ", a)
--
--import "fmt"
--
--type Thing struct { //@Thing
--	Member string //@Member
--}
--
--var Other Thing //@Other
--
--func Things(val []string) []Thing { //@Things
--	return nil
--}
--
--func (t Thing) Method(i int) string { //@Method
--	return t.Member
--}
--
--func (t Thing) Method3() {
--}
--
--func (t *Thing) Method2(i int, j int) (error, string) {
--	return nil, t.Member
--}
--
--func (t *Thing) private() {
--}
--
--func useThings() {
--	t := Thing{ //@mark(aStructType, "ing")
--		Member: "string", //@mark(fMember, "ember")
--	}
--	fmt.Print(t.Member) //@mark(aMember, "ember")
--	fmt.Print(Other)    //@mark(aVar, "ther")
--	Things()            //@mark(aFunc, "ings")
--	t.Method()          //@mark(aMethod, "eth")
--}
--
--type NextThing struct { //@NextThing
--	Thing
--	Value int
--}
--
--func (n NextThing) another() string {
--	return n.Member
--}
--
--// Shadows Thing.Method3
--func (n *NextThing) Method3() int {
--	return n.Value
--}
--
--var nextThing NextThing //@hoverdef("NextThing", NextThing)
--
--/*@
--godef(aStructType, Thing)
--godef(aMember, Member)
--godef(aVar, Other)
--godef(aFunc, Things)
--godef(aMethod, Method)
--godef(fMember, Member)
--godef(Member, Member)
--
--//param
--//package name
--//const
--//anon field
--
--*/
-diff -urN a/gopls/internal/lsp/testdata/godef/a/d.go.golden b/gopls/internal/lsp/testdata/godef/a/d.go.golden
---- a/gopls/internal/lsp/testdata/godef/a/d.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/d.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,191 +0,0 @@
---- Member-definition --
--godef/a/d.go:6:2-8: defined here as ```go
--field Member string
--```
--
--@Member
--
--
--[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
---- Member-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 6,
--			"column": 2,
--			"offset": 90
--		},
--		"end": {
--			"line": 6,
--			"column": 8,
--			"offset": 96
--		}
--	},
--	"description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)"
--}
--
---- Member-hoverdef --
--```go
--field Member string
--```
--
--@Member
--
--
--[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
---- Method-definition --
--godef/a/d.go:15:16-22: defined here as ```go
--func (Thing).Method(i int) string
--```
--
--[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)
---- Method-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 15,
--			"column": 16,
--			"offset": 219
--		},
--		"end": {
--			"line": 15,
--			"column": 22,
--			"offset": 225
--		}
--	},
--	"description": "```go\nfunc (Thing).Method(i int) string\n```\n\n[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)"
--}
--
---- Method-hoverdef --
--```go
--func (Thing).Method(i int) string
--```
--
--[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Method)
---- NextThing-hoverdef --
--```go
--type NextThing struct {
--	Thing
--	Value int
--}
--
--func (*NextThing).Method3() int
--func (NextThing).another() string
--```
--
--[`a.NextThing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#NextThing)
---- Other-definition --
--godef/a/d.go:9:5-10: defined here as ```go
--var Other Thing
--```
--
--@Other
--
--
--[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
---- Other-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 9,
--			"column": 5,
--			"offset": 121
--		},
--		"end": {
--			"line": 9,
--			"column": 10,
--			"offset": 126
--		}
--	},
--	"description": "```go\nvar Other Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)"
--}
--
---- Other-hoverdef --
--```go
--var Other Thing
--```
--
--@Other
--
--
--[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
---- Thing-definition --
--godef/a/d.go:5:6-11: defined here as ```go
--type Thing struct {
--	Member string //@Member
--}
--
--func (Thing).Method(i int) string
--func (*Thing).Method2(i int, j int) (error, string)
--func (Thing).Method3()
--func (*Thing).private()
--```
--
--[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
---- Thing-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 5,
--			"column": 6,
--			"offset": 65
--		},
--		"end": {
--			"line": 5,
--			"column": 11,
--			"offset": 70
--		}
--	},
--	"description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (Thing).Method(i int) string\nfunc (*Thing).Method2(i int, j int) (error, string)\nfunc (Thing).Method3()\nfunc (*Thing).private()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)"
--}
--
---- Thing-hoverdef --
--```go
--type Thing struct {
--	Member string //@Member
--}
--
--func (Thing).Method(i int) string
--func (*Thing).Method2(i int, j int) (error, string)
--func (Thing).Method3()
--func (*Thing).private()
--```
--
--[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
---- Things-definition --
--godef/a/d.go:11:6-12: defined here as ```go
--func Things(val []string) []Thing
--```
--
--[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
---- Things-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 11,
--			"column": 6,
--			"offset": 148
--		},
--		"end": {
--			"line": 11,
--			"column": 12,
--			"offset": 154
--		}
--	},
--	"description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)"
--}
--
---- Things-hoverdef --
--```go
--func Things(val []string) []Thing
--```
--
--[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
---- a-hoverdef --
--Package a is a package for testing go to definition.
--
-diff -urN a/gopls/internal/lsp/testdata/godef/a/f.go b/gopls/internal/lsp/testdata/godef/a/f.go
---- a/gopls/internal/lsp/testdata/godef/a/f.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/f.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--// Package a is a package for testing go to definition.
--package a
--
--import "fmt"
--
--func TypeStuff() { //@Stuff
--	var x string
--
--	switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY)
--	case int: //@mark(intY, "int")
--		fmt.Printf("%v", y) //@hoverdef("y", intY)
--	case string: //@mark(stringY, "string")
--		fmt.Printf("%v", y) //@hoverdef("y", stringY)
--	}
--
--}
-diff -urN a/gopls/internal/lsp/testdata/godef/a/f.go.golden b/gopls/internal/lsp/testdata/godef/a/f.go.golden
---- a/gopls/internal/lsp/testdata/godef/a/f.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/f.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,34 +0,0 @@
---- intY-hoverdef --
--```go
--var y int
--```
---- stringY-hoverdef --
--```go
--var y string
--```
---- switchY-definition --
--godef/a/f.go:8:9-10: defined here as ```go
--var y interface{}
--```
---- switchY-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/f.go",
--		"start": {
--			"line": 8,
--			"column": 9,
--			"offset": 76
--		},
--		"end": {
--			"line": 8,
--			"column": 10,
--			"offset": 77
--		}
--	},
--	"description": "```go\nvar y interface{}\n```"
--}
--
---- switchY-hoverdef --
--```go
--var y interface{}
--```
-diff -urN a/gopls/internal/lsp/testdata/godef/a/g.go b/gopls/internal/lsp/testdata/godef/a/g.go
---- a/gopls/internal/lsp/testdata/godef/a/g.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/g.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
--package a
--
--import "time"
--
--// dur is a constant of type time.Duration.
--const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur)
-diff -urN a/gopls/internal/lsp/testdata/godef/a/g.go.golden b/gopls/internal/lsp/testdata/godef/a/g.go.golden
---- a/gopls/internal/lsp/testdata/godef/a/g.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/g.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
---- dur-hoverdef --
--```go
--const dur time.Duration = 910350000000 // 15m10.35s
--```
--
--dur is a constant of type time.Duration.
--
-diff -urN a/gopls/internal/lsp/testdata/godef/a/h.go b/gopls/internal/lsp/testdata/godef/a/h.go
---- a/gopls/internal/lsp/testdata/godef/a/h.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/h.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,147 +0,0 @@
--package a
--
--func _() {
--	type s struct {
--		nested struct {
--			// nested number
--			number int64 //@mark(nestedNumber, "number")
--		}
--		nested2 []struct {
--			// nested string
--			str string //@mark(nestedString, "str")
--		}
--		x struct {
--			x struct {
--				x struct {
--					x struct {
--						x struct {
--							// nested map
--							m map[string]float64 //@mark(nestedMap, "m")
--						}
--					}
--				}
--			}
--		}
--	}
--
--	var t s
--	_ = t.nested.number  //@hoverdef("number", nestedNumber)
--	_ = t.nested2[0].str //@hoverdef("str", nestedString)
--	_ = t.x.x.x.x.x.m    //@hoverdef("m", nestedMap)
--}
--
--func _() {
--	var s struct {
--		// a field
--		a int //@mark(structA, "a")
--		// b nested struct
--		b struct { //@mark(structB, "b")
--			// c field of nested struct
--			c int //@mark(structC, "c")
--		}
--	}
--	_ = s.a   //@hoverdef("a", structA)
--	_ = s.b   //@hoverdef("b", structB)
--	_ = s.b.c //@hoverdef("c", structC)
--
--	var arr []struct {
--		// d field
--		d int //@mark(arrD, "d")
--		// e nested struct
--		e struct { //@mark(arrE, "e")
--			// f field of nested struct
--			f int //@mark(arrF, "f")
--		}
--	}
--	_ = arr[0].d   //@hoverdef("d", arrD)
--	_ = arr[0].e   //@hoverdef("e", arrE)
--	_ = arr[0].e.f //@hoverdef("f", arrF)
--
--	var complex []struct {
--		c <-chan map[string][]struct {
--			// h field
--			h int //@mark(complexH, "h")
--			// i nested struct
--			i struct { //@mark(complexI, "i")
--				// j field of nested struct
--				j int //@mark(complexJ, "j")
--			}
--		}
--	}
--	_ = (<-complex[0].c)["0"][0].h   //@hoverdef("h", complexH)
--	_ = (<-complex[0].c)["0"][0].i   //@hoverdef("i", complexI)
--	_ = (<-complex[0].c)["0"][0].i.j //@hoverdef("j", complexJ)
--
--	var mapWithStructKey map[struct {
--		// X key field
--		x []string //@mark(mapStructKeyX, "x")
--	}]int
--	for k := range mapWithStructKey {
--		_ = k.x //@hoverdef("x", mapStructKeyX)
--	}
--
--	var mapWithStructKeyAndValue map[struct {
--		// Y key field
--		y string //@mark(mapStructKeyY, "y")
--	}]struct {
--		// X value field
--		x string //@mark(mapStructValueX, "x")
--	}
--	for k, v := range mapWithStructKeyAndValue {
--		// TODO: we don't show docs for y field because both map key and value
--		// are structs. And in this case, we parse only map value
--		_ = k.y //@hoverdef("y", mapStructKeyY)
--		_ = v.x //@hoverdef("x", mapStructValueX)
--	}
--
--	var i []map[string]interface {
--		// open method comment
--		open() error //@mark(openMethod, "open")
--	}
--	i[0]["1"].open() //@hoverdef("open", openMethod)
--}
--
--func _() {
--	test := struct {
--		// test description
--		desc string //@mark(testDescription, "desc")
--	}{}
--	_ = test.desc //@hoverdef("desc", testDescription)
--
--	for _, tt := range []struct {
--		// test input
--		in map[string][]struct { //@mark(testInput, "in")
--			// test key
--			key string //@mark(testInputKey, "key")
--			// test value
--			value interface{} //@mark(testInputValue, "value")
--		}
--		result struct {
--			v <-chan struct {
--				// expected test value
--				value int //@mark(testResultValue, "value")
--			}
--		}
--	}{} {
--		_ = tt.in               //@hoverdef("in", testInput)
--		_ = tt.in["0"][0].key   //@hoverdef("key", testInputKey)
--		_ = tt.in["0"][0].value //@hoverdef("value", testInputValue)
--
--		_ = (<-tt.result.v).value //@hoverdef("value", testResultValue)
--	}
--}
--
--func _() {
--	getPoints := func() []struct {
--		// X coord
--		x int //@mark(returnX, "x")
--		// Y coord
--		y int //@mark(returnY, "y")
--	} {
--		return nil
--	}
--
--	r := getPoints()
--	r[0].x //@hoverdef("x", returnX)
--	r[0].y //@hoverdef("y", returnY)
--}
-diff -urN a/gopls/internal/lsp/testdata/godef/a/h.go.golden b/gopls/internal/lsp/testdata/godef/a/h.go.golden
---- a/gopls/internal/lsp/testdata/godef/a/h.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/a/h.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,161 +0,0 @@
---- arrD-hoverdef --
--```go
--field d int
--```
--
--d field
--
---- arrE-hoverdef --
--```go
--field e struct{f int}
--```
--
--e nested struct
--
---- arrF-hoverdef --
--```go
--field f int
--```
--
--f field of nested struct
--
---- complexH-hoverdef --
--```go
--field h int
--```
--
--h field
--
---- complexI-hoverdef --
--```go
--field i struct{j int}
--```
--
--i nested struct
--
---- complexJ-hoverdef --
--```go
--field j int
--```
--
--j field of nested struct
--
---- mapStructKeyX-hoverdef --
--```go
--field x []string
--```
--
--X key field
--
---- mapStructKeyY-hoverdef --
--```go
--field y string
--```
--
--Y key field
--
---- mapStructValueX-hoverdef --
--```go
--field x string
--```
--
--X value field
--
---- nestedMap-hoverdef --
--```go
--field m map[string]float64
--```
--
--nested map
--
---- nestedNumber-hoverdef --
--```go
--field number int64
--```
--
--nested number
--
---- nestedString-hoverdef --
--```go
--field str string
--```
--
--nested string
--
---- openMethod-hoverdef --
--```go
--func (interface).open() error
--```
--
--open method comment
--
---- returnX-hoverdef --
--```go
--field x int
--```
--
--X coord
--
---- returnY-hoverdef --
--```go
--field y int
--```
--
--Y coord
--
---- structA-hoverdef --
--```go
--field a int
--```
--
--a field
--
---- structB-hoverdef --
--```go
--field b struct{c int}
--```
--
--b nested struct
--
---- structC-hoverdef --
--```go
--field c int
--```
--
--c field of nested struct
--
---- testDescription-hoverdef --
--```go
--field desc string
--```
--
--test description
--
---- testInput-hoverdef --
--```go
--field in map[string][]struct{key string; value interface{}}
--```
--
--test input
--
---- testInputKey-hoverdef --
--```go
--field key string
--```
--
--test key
--
---- testInputValue-hoverdef --
--```go
--field value interface{}
--```
--
--test value
--
---- testResultValue-hoverdef --
--```go
--field value int
--```
--
--expected test value
--
-diff -urN a/gopls/internal/lsp/testdata/godef/b/e.go b/gopls/internal/lsp/testdata/godef/b/e.go
---- a/gopls/internal/lsp/testdata/godef/b/e.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/b/e.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
--package b
--
--import (
--	"fmt"
--
--	"golang.org/lsptests/godef/a"
--)
--
--func useThings() {
--	t := a.Thing{}      //@mark(bStructType, "ing")
--	fmt.Print(t.Member) //@mark(bMember, "ember")
--	fmt.Print(a.Other)  //@mark(bVar, "ther")
--	a.Things()          //@mark(bFunc, "ings")
--}
--
--/*@
--godef(bStructType, Thing)
--godef(bMember, Member)
--godef(bVar, Other)
--godef(bFunc, Things)
--*/
--
--func _() {
--	var x interface{}      //@mark(eInterface, "interface{}")
--	switch x := x.(type) { //@hoverdef("x", eInterface)
--	case string: //@mark(eString, "string")
--		fmt.Println(x) //@hoverdef("x", eString)
--	case int: //@mark(eInt, "int")
--		fmt.Println(x) //@hoverdef("x", eInt)
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/godef/b/e.go.golden b/gopls/internal/lsp/testdata/godef/b/e.go.golden
---- a/gopls/internal/lsp/testdata/godef/b/e.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/b/e.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,156 +0,0 @@
---- Member-definition --
--godef/a/d.go:6:2-8: defined here as ```go
--field Member string
--```
--
--@Member
--
--
--[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
---- Member-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 6,
--			"column": 2,
--			"offset": 90
--		},
--		"end": {
--			"line": 6,
--			"column": 8,
--			"offset": 96
--		}
--	},
--	"description": "```go\nfield Member string\n```\n\n@Member\n\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)"
--}
--
---- Member-hoverdef --
--```go
--field Member string
--```
--
--@Member
--
--
--[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing.Member)
---- Other-definition --
--godef/a/d.go:9:5-10: defined here as ```go
--var a.Other a.Thing
--```
--
--@Other
--
--
--[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
---- Other-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 9,
--			"column": 5,
--			"offset": 121
--		},
--		"end": {
--			"line": 9,
--			"column": 10,
--			"offset": 126
--		}
--	},
--	"description": "```go\nvar a.Other a.Thing\n```\n\n@Other\n\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)"
--}
--
---- Other-hoverdef --
--```go
--var a.Other a.Thing
--```
--
--@Other
--
--
--[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Other)
---- Thing-definition --
--godef/a/d.go:5:6-11: defined here as ```go
--type Thing struct {
--	Member string //@Member
--}
--
--func (a.Thing).Method(i int) string
--func (*a.Thing).Method2(i int, j int) (error, string)
--func (a.Thing).Method3()
--```
--
--[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
---- Thing-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 5,
--			"column": 6,
--			"offset": 65
--		},
--		"end": {
--			"line": 5,
--			"column": 11,
--			"offset": 70
--		}
--	},
--	"description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n\nfunc (a.Thing).Method(i int) string\nfunc (*a.Thing).Method2(i int, j int) (error, string)\nfunc (a.Thing).Method3()\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)"
--}
--
---- Thing-hoverdef --
--```go
--type Thing struct {
--	Member string //@Member
--}
--
--func (a.Thing).Method(i int) string
--func (*a.Thing).Method2(i int, j int) (error, string)
--func (a.Thing).Method3()
--```
--
--[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Thing)
---- Things-definition --
--godef/a/d.go:11:6-12: defined here as ```go
--func a.Things(val []string) []a.Thing
--```
--
--[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
---- Things-definition-json --
--{
--	"span": {
--		"uri": "file://godef/a/d.go",
--		"start": {
--			"line": 11,
--			"column": 6,
--			"offset": 148
--		},
--		"end": {
--			"line": 11,
--			"column": 12,
--			"offset": 154
--		}
--	},
--	"description": "```go\nfunc a.Things(val []string) []a.Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)"
--}
--
---- Things-hoverdef --
--```go
--func a.Things(val []string) []a.Thing
--```
--
--[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/lsptests/godef/a#Things)
---- eInt-hoverdef --
--```go
--var x int
--```
---- eInterface-hoverdef --
--```go
--var x interface{}
--```
---- eString-hoverdef --
--```go
--var x string
--```
-diff -urN a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden
---- a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,31 +0,0 @@
---- myUnclosedIf-definition --
--godef/broken/unclosedIf.go:7:7-19: defined here as ```go
--var myUnclosedIf string
--```
--
--@myUnclosedIf
---- myUnclosedIf-definition-json --
--{
--	"span": {
--		"uri": "file://godef/broken/unclosedIf.go",
--		"start": {
--			"line": 7,
--			"column": 7,
--			"offset": 68
--		},
--		"end": {
--			"line": 7,
--			"column": 19,
--			"offset": 80
--		}
--	},
--	"description": "```go\nvar myUnclosedIf string\n```\n\n@myUnclosedIf"
--}
--
---- myUnclosedIf-hoverdef --
--```go
--var myUnclosedIf string
--```
--
--@myUnclosedIf
--
-diff -urN a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in
---- a/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/godef/broken/unclosedIf.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package broken
--
--import "fmt"
--
--func unclosedIf() {
--	if false {
--		var myUnclosedIf string              //@myUnclosedIf
--		fmt.Printf("s = %v\n", myUnclosedIf) //@godef("my", myUnclosedIf)
--}
 diff -urN a/gopls/internal/lsp/testdata/good/good0.go b/gopls/internal/lsp/testdata/good/good0.go
 --- a/gopls/internal/lsp/testdata/good/good0.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/good/good0.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/good/good0.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
--package good //@diag("package", "no_diagnostics", "", "error")
+-package good
 -
 -func stuff() { //@item(good_stuff, "stuff", "func()", "func"),prepare("stu", "stuff", "stuff")
 -	x := 5
@@ -97435,9 +105640,9 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/good/good1.go b/gopls/internal/lsp/testdata/good/good1.go
 --- a/gopls/internal/lsp/testdata/good/good1.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/good/good1.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/good/good1.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
--package good //@diag("package", "no_diagnostics", "", "error")
+-package good
 -
 -import (
 -	"golang.org/lsptests/types" //@item(types_import, "types", "\"golang.org/lsptests/types\"", "package")
@@ -97458,310 +105663,39 @@
 -
 -	return y
 -}
-diff -urN a/gopls/internal/lsp/testdata/highlights/highlights.go b/gopls/internal/lsp/testdata/highlights/highlights.go
---- a/gopls/internal/lsp/testdata/highlights/highlights.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/highlights/highlights.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,151 +0,0 @@
--package highlights
--
--import (
--	"fmt"         //@mark(fmtImp, "\"fmt\""),highlight(fmtImp, fmtImp, fmt1, fmt2, fmt3, fmt4)
--	h2 "net/http" //@mark(hImp, "h2"),highlight(hImp, hImp, hUse)
--	"sort"
--)
--
--type F struct{ bar int } //@mark(barDeclaration, "bar"),highlight(barDeclaration, barDeclaration, bar1, bar2, bar3)
--
--func _() F {
--	return F{
--		bar: 123, //@mark(bar1, "bar"),highlight(bar1, barDeclaration, bar1, bar2, bar3)
--	}
--}
--
--var foo = F{bar: 52} //@mark(fooDeclaration, "foo"),mark(bar2, "bar"),highlight(fooDeclaration, fooDeclaration, fooUse),highlight(bar2, barDeclaration, bar1, bar2, bar3)
--
--func Print() { //@mark(printFunc, "Print"),highlight(printFunc, printFunc, printTest)
--	_ = h2.Client{} //@mark(hUse, "h2"),highlight(hUse, hImp, hUse)
--
--	fmt.Println(foo) //@mark(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse),mark(fmt1, "fmt"),highlight(fmt1, fmtImp, fmt1, fmt2, fmt3, fmt4)
--	fmt.Print("yo")  //@mark(printSep, "Print"),highlight(printSep, printSep, print1, print2),mark(fmt2, "fmt"),highlight(fmt2, fmtImp, fmt1, fmt2, fmt3, fmt4)
--}
--
--func (x *F) Inc() { //@mark(xRightDecl, "x"),mark(xLeftDecl, " *"),highlight(xRightDecl, xRightDecl, xUse),highlight(xLeftDecl, xRightDecl, xUse)
--	x.bar++ //@mark(xUse, "x"),mark(bar3, "bar"),highlight(xUse, xRightDecl, xUse),highlight(bar3, barDeclaration, bar1, bar2, bar3)
--}
--
--func testFunctions() {
--	fmt.Print("main start") //@mark(print1, "Print"),highlight(print1, printSep, print1, print2),mark(fmt3, "fmt"),highlight(fmt3, fmtImp, fmt1, fmt2, fmt3, fmt4)
--	fmt.Print("ok")         //@mark(print2, "Print"),highlight(print2, printSep, print1, print2),mark(fmt4, "fmt"),highlight(fmt4, fmtImp, fmt1, fmt2, fmt3, fmt4)
--	Print()                 //@mark(printTest, "Print"),highlight(printTest, printFunc, printTest)
--}
--
--func toProtocolHighlight(rngs []int) []DocumentHighlight { //@mark(doc1, "DocumentHighlight"),mark(docRet1, "[]DocumentHighlight"),highlight(doc1, docRet1, doc1, doc2, doc3, result)
--	result := make([]DocumentHighlight, 0, len(rngs)) //@mark(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3)
--	for _, rng := range rngs {
--		result = append(result, DocumentHighlight{ //@mark(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3)
--			Range: rng,
--		})
--	}
--	return result //@mark(result, "result")
--}
--
--func testForLoops() {
--	for i := 0; i < 10; i++ { //@mark(forDecl1, "for"),highlight(forDecl1, forDecl1, brk1, cont1)
--		if i > 8 {
--			break //@mark(brk1, "break"),highlight(brk1, forDecl1, brk1, cont1)
--		}
--		if i < 2 {
--			for j := 1; j < 10; j++ { //@mark(forDecl2, "for"),highlight(forDecl2, forDecl2, cont2)
--				if j < 3 {
--					for k := 1; k < 10; k++ { //@mark(forDecl3, "for"),highlight(forDecl3, forDecl3, cont3)
--						if k < 3 {
--							continue //@mark(cont3, "continue"),highlight(cont3, forDecl3, cont3)
--						}
--					}
--					continue //@mark(cont2, "continue"),highlight(cont2, forDecl2, cont2)
--				}
--			}
--			continue //@mark(cont1, "continue"),highlight(cont1, forDecl1, brk1, cont1)
--		}
--	}
--
--	arr := []int{}
--	for i := range arr { //@mark(forDecl4, "for"),highlight(forDecl4, forDecl4, brk4, cont4)
--		if i > 8 {
--			break //@mark(brk4, "break"),highlight(brk4, forDecl4, brk4, cont4)
--		}
--		if i < 4 {
--			continue //@mark(cont4, "continue"),highlight(cont4, forDecl4, brk4, cont4)
--		}
--	}
--
--Outer:
--	for i := 0; i < 10; i++ { //@mark(forDecl5, "for"),highlight(forDecl5, forDecl5, brk5, brk6, brk8)
--		break //@mark(brk5, "break"),highlight(brk5, forDecl5, brk5, brk6, brk8)
--		for { //@mark(forDecl6, "for"),highlight(forDecl6, forDecl6, cont5)
--			if i == 1 {
--				break Outer //@mark(brk6, "break Outer"),highlight(brk6, forDecl5, brk5, brk6, brk8)
--			}
--			switch i { //@mark(switch1, "switch"),highlight(switch1, switch1, brk7)
--			case 5:
--				break //@mark(brk7, "break"),highlight(brk7, switch1, brk7)
--			case 6:
--				continue //@mark(cont5, "continue"),highlight(cont5, forDecl6, cont5)
--			case 7:
--				break Outer //@mark(brk8, "break Outer"),highlight(brk8, forDecl5, brk5, brk6, brk8)
--			}
--		}
--	}
--}
--
--func testSwitch() {
--	var i, j int
--
--L1:
--	for { //@mark(forDecl7, "for"),highlight(forDecl7, forDecl7, brk10, cont6)
--	L2:
--		switch i { //@mark(switch2, "switch"),highlight(switch2, switch2, brk11, brk12, brk13)
--		case 1:
--			switch j { //@mark(switch3, "switch"),highlight(switch3, switch3, brk9)
--			case 1:
--				break //@mark(brk9, "break"),highlight(brk9, switch3, brk9)
--			case 2:
--				break L1 //@mark(brk10, "break L1"),highlight(brk10, forDecl7, brk10, cont6)
--			case 3:
--				break L2 //@mark(brk11, "break L2"),highlight(brk11, switch2, brk11, brk12, brk13)
--			default:
--				continue //@mark(cont6, "continue"),highlight(cont6, forDecl7, brk10, cont6)
--			}
--		case 2:
--			break //@mark(brk12, "break"),highlight(brk12, switch2, brk11, brk12, brk13)
--		default:
--			break L2 //@mark(brk13, "break L2"),highlight(brk13, switch2, brk11, brk12, brk13)
--		}
--	}
--}
--
--func testReturn() bool { //@mark(func1, "func"),mark(bool1, "bool"),highlight(func1, func1, fullRet11, fullRet12),highlight(bool1, bool1, false1, bool2, true1)
--	if 1 < 2 {
--		return false //@mark(ret11, "return"),mark(fullRet11, "return false"),mark(false1, "false"),highlight(ret11, func1, fullRet11, fullRet12)
--	}
--	candidates := []int{}
--	sort.SliceStable(candidates, func(i, j int) bool { //@mark(func2, "func"),mark(bool2, "bool"),highlight(func2, func2, fullRet2)
--		return candidates[i] > candidates[j] //@mark(ret2, "return"),mark(fullRet2, "return candidates[i] > candidates[j]"),highlight(ret2, func2, fullRet2)
--	})
--	return true //@mark(ret12, "return"),mark(fullRet12, "return true"),mark(true1, "true"),highlight(ret12, func1, fullRet11, fullRet12)
--}
--
--func testReturnFields() float64 { //@mark(retVal1, "float64"),highlight(retVal1, retVal1, retVal11, retVal21)
--	if 1 < 2 {
--		return 20.1 //@mark(retVal11, "20.1"),highlight(retVal11, retVal1, retVal11, retVal21)
--	}
--	z := 4.3 //@mark(zDecl, "z")
--	return z //@mark(retVal21, "z"),highlight(retVal21, retVal1, retVal11, zDecl, retVal21)
--}
--
--func testReturnMultipleFields() (float32, string) { //@mark(retVal31, "float32"),mark(retVal32, "string"),highlight(retVal31, retVal31, retVal41, retVal51),highlight(retVal32, retVal32, retVal42, retVal52)
--	y := "im a var" //@mark(yDecl, "y"),
--	if 1 < 2 {
--		return 20.1, y //@mark(retVal41, "20.1"),mark(retVal42, "y"),highlight(retVal41, retVal31, retVal41, retVal51),highlight(retVal42, retVal32, yDecl, retVal42, retVal52)
--	}
--	return 4.9, "test" //@mark(retVal51, "4.9"),mark(retVal52, "\"test\""),highlight(retVal51, retVal31, retVal41, retVal51),highlight(retVal52, retVal32, retVal42, retVal52)
--}
--
--func testReturnFunc() int32 { //@mark(retCall, "int32")
--	mulch := 1          //@mark(mulchDec, "mulch"),highlight(mulchDec, mulchDec, mulchRet)
--	return int32(mulch) //@mark(mulchRet, "mulch"),mark(retFunc, "int32"),mark(retTotal, "int32(mulch)"),highlight(mulchRet, mulchDec, mulchRet),highlight(retFunc, retCall, retFunc, retTotal)
--}
-diff -urN a/gopls/internal/lsp/testdata/implementation/implementation_generics.go b/gopls/internal/lsp/testdata/implementation/implementation_generics.go
---- a/gopls/internal/lsp/testdata/implementation/implementation_generics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/implementation/implementation_generics.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--//go:build go1.18
--// +build go1.18
--
--package implementation
--
--// -- generics --
--
--type GenIface[T any] interface { //@mark(GenIface, "GenIface"),implementations("GenIface", GC)
--	F(int, string, T) //@mark(GenIfaceF, "F"),implementations("F", GCF)
--}
--
--type GenConc[U any] int //@mark(GenConc, "GenConc"),implementations("GenConc", GI)
--
--func (GenConc[V]) F(int, string, V) {} //@mark(GenConcF, "F"),implementations("F", GIF)
--
--type GenConcString struct{ GenConc[string] } //@mark(GenConcString, "GenConcString"),implementations(GenConcString, GIString)
-diff -urN a/gopls/internal/lsp/testdata/implementation/implementation.go b/gopls/internal/lsp/testdata/implementation/implementation.go
---- a/gopls/internal/lsp/testdata/implementation/implementation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/implementation/implementation.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
--package implementation
--
--import "golang.org/lsptests/implementation/other"
--
--type ImpP struct{} //@ImpP,implementations("ImpP", Laugher, OtherLaugher)
--
--func (*ImpP) Laugh() { //@mark(LaughP, "Laugh"),implementations("Laugh", Laugh, OtherLaugh)
--}
--
--type ImpS struct{} //@ImpS,implementations("ImpS", Laugher, OtherLaugher)
--
--func (ImpS) Laugh() { //@mark(LaughS, "Laugh"),implementations("Laugh", Laugh, OtherLaugh)
--}
--
--type Laugher interface { //@Laugher,implementations("Laugher", ImpP, OtherImpP, ImpS, OtherImpS, embedsImpP)
--	Laugh() //@Laugh,implementations("Laugh", LaughP, OtherLaughP, LaughS, OtherLaughS)
--}
--
--type Foo struct { //@implementations("Foo", Joker)
--	other.Foo
--}
--
--type Joker interface { //@Joker
--	Joke() //@Joke,implementations("Joke", ImpJoker)
--}
--
--type cryer int //@implementations("cryer", Cryer)
--
--func (cryer) Cry(other.CryType) {} //@mark(CryImpl, "Cry"),implementations("Cry", Cry)
--
--type Empty interface{} //@implementations("Empty")
--
--var _ interface{ Joke() } //@implementations("Joke", ImpJoker)
--
--type embedsImpP struct { //@embedsImpP
--	ImpP //@implementations("ImpP", Laugher, OtherLaugher)
--}
-diff -urN a/gopls/internal/lsp/testdata/implementation/other/other_generics.go b/gopls/internal/lsp/testdata/implementation/other/other_generics.go
---- a/gopls/internal/lsp/testdata/implementation/other/other_generics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/implementation/other/other_generics.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--//go:build go1.18
--// +build go1.18
--
--package other
--
--// -- generics (limited support) --
--
--type GI[T any] interface { //@mark(GI, "GI"),implementations("GI", GenConc)
--	F(int, string, T) //@mark(GIF, "F"),implementations("F", GenConcF)
--}
--
--type GIString GI[string] //@mark(GIString, "GIString"),implementations("GIString", GenConcString)
--
--type GC[U any] int //@mark(GC, "GC"),implementations("GC", GenIface)
--
--func (GC[V]) F(int, string, V) {} //@mark(GCF, "F"),implementations("F", GenIfaceF)
-diff -urN a/gopls/internal/lsp/testdata/implementation/other/other.go b/gopls/internal/lsp/testdata/implementation/other/other.go
---- a/gopls/internal/lsp/testdata/implementation/other/other.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/implementation/other/other.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,27 +0,0 @@
--package other
--
--type ImpP struct{} //@mark(OtherImpP, "ImpP")
--
--func (*ImpP) Laugh() { //@mark(OtherLaughP, "Laugh")
--}
--
--type ImpS struct{} //@mark(OtherImpS, "ImpS")
--
--func (ImpS) Laugh() { //@mark(OtherLaughS, "Laugh")
--}
--
--type ImpI interface { //@mark(OtherLaugher, "ImpI")
--	Laugh() //@mark(OtherLaugh, "Laugh")
--}
--
--type Foo struct { //@implementations("Foo", Joker)
--}
--
--func (Foo) Joke() { //@mark(ImpJoker, "Joke"),implementations("Joke", Joke)
--}
--
--type CryType int
--
--type Cryer interface { //@Cryer
--	Cry(CryType) //@Cry,implementations("Cry", CryImpl)
--}
-diff -urN a/gopls/internal/lsp/testdata/implementation/other/other_test.go b/gopls/internal/lsp/testdata/implementation/other/other_test.go
---- a/gopls/internal/lsp/testdata/implementation/other/other_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/implementation/other/other_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package other
--
--import (
--	"testing"
--)
--
--// This exists so the other.test package comes into existence.
--
--func TestOther(t *testing.T) {
--}
 diff -urN a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in
 --- a/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,42 +0,0 @@
++++ b/gopls/internal/lsp/testdata/importedcomplit/imported_complit.go.in	1970-01-01 08:00:00
+@@ -1,54 +0,0 @@
 -package importedcomplit
 -
 -import (
--	"golang.org/lsptests/foo"
+-	// TODO(rfindley): re-enable after moving to new framework
+-	// "golang.org/lsptests/foo"
 -
--	// import completions
--	"fm" //@complete("\" //", fmtImport)
--	"go/pars" //@complete("\" //", parserImport)
--	"golang.org/lsptests/signa" //@complete("na\" //", signatureImport)
--	"golang.org/lspte" //@complete("\" //", lsptestsImport)
+-	// import completions (separate blocks to avoid comment alignment)
 -	"crypto/elli" //@complete("\" //", cryptoImport)
--	"golang.org/lsptests/sign" //@complete("\" //", signatureImport)
--	"golang.org/lsptests/sign" //@complete("ests", lsptestsImport)
+-
+-	"fm" //@complete("\" //", fmtImport)
+-
+-	"go/pars" //@complete("\" //", parserImport)
+-
 -	namedParser "go/pars" //@complete("\" //", parserImport)
+-
+-	"golang.org/lspte" //@complete("\" //", lsptestsImport)
+-
+-	"golang.org/lsptests/sign" //@complete("\" //", signatureImport)
+-
+-	"golang.org/lsptests/sign" //@complete("ests", lsptestsImport)
+-
+-	"golang.org/lsptests/signa" //@complete("na\" //", signatureImport)
 -)
 -
 -func _() {
 -	var V int //@item(icVVar, "V", "int", "var")
--	_ = foo.StructFoo{V} //@complete("}", Value, icVVar)
+-
+-	// TODO(rfindley): re-enable after moving to new framework
+-	// _ = foo.StructFoo{V} // complete("}", Value, icVVar)
 -}
 -
 -func _() {
@@ -97770,14 +105704,16 @@
 -		ab int    //@item(icABVar, "ab", "int", "var")
 -	)
 -
--	_ = foo.StructFoo{a} //@complete("}", abVar, aaVar)
+-	// TODO(rfindley): re-enable after moving to new framework
+-	// _ = foo.StructFoo{a} // complete("}", abVar, aaVar)
 -
 -	var s struct {
 -		AA string //@item(icFieldAA, "AA", "string", "field")
 -		AB int    //@item(icFieldAB, "AB", "int", "field")
 -	}
 -
--	_ = foo.StructFoo{s.} //@complete("}", icFieldAB, icFieldAA)
+-	// TODO(rfindley): re-enable after moving to new framework
+-	//_ = foo.StructFoo{s.} // complete("}", icFieldAB, icFieldAA)
 -}
 -
 -/* "fmt" */ //@item(fmtImport, "fmt", "\"fmt\"", "package")
@@ -97785,234 +105721,9 @@
 -/* "golang.org/lsptests/signature" */ //@item(signatureImport, "signature", "\"golang.org/lsptests/signature\"", "package")
 -/* "golang.org/lsptests/" */ //@item(lsptestsImport, "lsptests/", "\"golang.org/lsptests/\"", "package")
 -/* "crypto/elliptic" */ //@item(cryptoImport, "elliptic", "\"crypto/elliptic\"", "package")
-diff -urN a/gopls/internal/lsp/testdata/imports/add_import.go.golden b/gopls/internal/lsp/testdata/imports/add_import.go.golden
---- a/gopls/internal/lsp/testdata/imports/add_import.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/add_import.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--import (
--	"bytes"
--	"fmt"
--)
--
--func _() {
--	fmt.Println("")
--	bytes.NewBuffer(nil)
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/add_import.go.in b/gopls/internal/lsp/testdata/imports/add_import.go.in
---- a/gopls/internal/lsp/testdata/imports/add_import.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/add_import.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package imports //@import("package")
--
--import (
--	"fmt"
--)
--
--func _() {
--	fmt.Println("")
--	bytes.NewBuffer(nil)
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/good_imports.go.golden b/gopls/internal/lsp/testdata/imports/good_imports.go.golden
---- a/gopls/internal/lsp/testdata/imports/good_imports.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--import "fmt"
--
--func _() {
--fmt.Println("")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/good_imports.go.in b/gopls/internal/lsp/testdata/imports/good_imports.go.in
---- a/gopls/internal/lsp/testdata/imports/good_imports.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/good_imports.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
--package imports //@import("package")
--
--import "fmt"
--
--func _() {
--fmt.Println("")
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/issue35458.go.golden b/gopls/internal/lsp/testdata/imports/issue35458.go.golden
---- a/gopls/internal/lsp/testdata/imports/issue35458.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,20 +0,0 @@
---- goimports --
--// package doc
--package imports //@import("package")
--
--
--
--
--
--
--func _() {
--	println("Hello, world!")
--}
--
--
--
--
--
--
--
--
-diff -urN a/gopls/internal/lsp/testdata/imports/issue35458.go.in b/gopls/internal/lsp/testdata/imports/issue35458.go.in
---- a/gopls/internal/lsp/testdata/imports/issue35458.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/issue35458.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,23 +0,0 @@
--
--
--
--
--
--// package doc
--package imports //@import("package")
--
--
--
--
--
--
--func _() {
--	println("Hello, world!")
--}
--
--
--
--
--
--
--
-diff -urN a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden
---- a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--import "fmt"
--
--func _() {
--	fmt.Println("")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in
---- a/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/multiple_blocks.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package imports //@import("package")
--
--import "fmt"
--
--import "bytes"
--
--func _() {
--	fmt.Println("")
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden
---- a/gopls/internal/lsp/testdata/imports/needs_imports.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--import (
--	"fmt"
--	"log"
--)
--
--func goodbye() {
--	fmt.Printf("HI")
--	log.Printf("byeeeee")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/needs_imports.go.in b/gopls/internal/lsp/testdata/imports/needs_imports.go.in
---- a/gopls/internal/lsp/testdata/imports/needs_imports.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/needs_imports.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
--package imports //@import("package")
--
--func goodbye() {
--	fmt.Printf("HI")
--	log.Printf("byeeeee")
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/remove_import.go.golden b/gopls/internal/lsp/testdata/imports/remove_import.go.golden
---- a/gopls/internal/lsp/testdata/imports/remove_import.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,11 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--import (
--	"fmt"
--)
--
--func _() {
--	fmt.Println("")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/remove_import.go.in b/gopls/internal/lsp/testdata/imports/remove_import.go.in
---- a/gopls/internal/lsp/testdata/imports/remove_import.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/remove_import.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package imports //@import("package")
--
--import (
--	"bytes"
--	"fmt"
--)
--
--func _() {
--	fmt.Println("")
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden
---- a/gopls/internal/lsp/testdata/imports/remove_imports.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,6 +0,0 @@
---- goimports --
--package imports //@import("package")
--
--func _() {
--}
--
-diff -urN a/gopls/internal/lsp/testdata/imports/remove_imports.go.in b/gopls/internal/lsp/testdata/imports/remove_imports.go.in
---- a/gopls/internal/lsp/testdata/imports/remove_imports.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/remove_imports.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package imports //@import("package")
--
--import (
--	"bytes"
--	"fmt"
--)
--
--func _() {
--}
-diff -urN a/gopls/internal/lsp/testdata/imports/two_lines.go.golden b/gopls/internal/lsp/testdata/imports/two_lines.go.golden
---- a/gopls/internal/lsp/testdata/imports/two_lines.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,4 +0,0 @@
---- goimports --
--package main
--func main()  {} //@import("main")
--
-diff -urN a/gopls/internal/lsp/testdata/imports/two_lines.go.in b/gopls/internal/lsp/testdata/imports/two_lines.go.in
---- a/gopls/internal/lsp/testdata/imports/two_lines.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/imports/two_lines.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2 +0,0 @@
--package main
--func main()  {} //@import("main")
 diff -urN a/gopls/internal/lsp/testdata/index/index.go b/gopls/internal/lsp/testdata/index/index.go
 --- a/gopls/internal/lsp/testdata/index/index.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/index/index.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/index/index.go	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -package index
 -
@@ -98041,7 +105752,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go
 --- a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -package inlayHint //@inlayHint("package")
 -
@@ -98072,7 +105783,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
 --- a/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/composite_literals.go.golden	1970-01-01 08:00:00
 @@ -1,29 +0,0 @@
 --- inlayHint --
 -package inlayHint //@inlayHint("package")
@@ -98105,7 +105816,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go
 --- a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go	1970-01-01 08:00:00
 @@ -1,45 +0,0 @@
 -package inlayHint //@inlayHint("package")
 -
@@ -98154,7 +105865,7 @@
 -)
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden
 --- a/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/constant_values.go.golden	1970-01-01 08:00:00
 @@ -1,47 +0,0 @@
 --- inlayHint --
 -package inlayHint //@inlayHint("package")
@@ -98205,7 +105916,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go
 --- a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go	1970-01-01 08:00:00
 @@ -1,50 +0,0 @@
 -package inlayHint //@inlayHint("package")
 -
@@ -98259,7 +105970,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden
 --- a/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/parameter_names.go.golden	1970-01-01 08:00:00
 @@ -1,52 +0,0 @@
 --- inlayHint --
 -package inlayHint //@inlayHint("package")
@@ -98315,7 +106026,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/type_params.go b/gopls/internal/lsp/testdata/inlay_hint/type_params.go
 --- a/gopls/internal/lsp/testdata/inlay_hint/type_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go	1970-01-01 08:00:00
 @@ -1,45 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -98364,7 +106075,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden
 --- a/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/type_params.go.golden	1970-01-01 08:00:00
 @@ -1,47 +0,0 @@
 --- inlayHint --
 -//go:build go1.18
@@ -98415,7 +106126,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go
 --- a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -package inlayHint //@inlayHint("package")
 -
@@ -98439,7 +106150,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden
 --- a/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/inlay_hint/variable_types.go.golden	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 --- inlayHint --
 -package inlayHint //@inlayHint("package")
@@ -98465,7 +106176,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go
 --- a/gopls/internal/lsp/testdata/interfacerank/interface_rank.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/interfacerank/interface_rank.go	1970-01-01 08:00:00
 @@ -1,23 +0,0 @@
 -package interfacerank
 -
@@ -98490,9 +106201,446 @@
 -	var ac fooImpl //@item(irAC, "ac", "fooImpl", "var")
 -	wantsFoo(&a)   //@complete(")", irAC, irAA, irAB)
 -}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/boolean.go b/gopls/internal/lsp/testdata/invertifcondition/boolean.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/boolean.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/boolean.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func Boolean() {
+-	b := true
+-	if b { //@suggestedfix("if b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/boolean.go.golden b/gopls/internal/lsp/testdata/invertifcondition/boolean.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/boolean.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/boolean.go.golden	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+--- suggestedfix_boolean_9_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func Boolean() {
+-	b := true
+-	if !b {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("if b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go b/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func BooleanFn() {
+-	if os.IsPathSeparator('X') { //@suggestedfix("if os.IsPathSeparator('X')", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go.golden b/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/boolean_fn.go.golden	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+--- suggestedfix_boolean_fn_9_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func BooleanFn() {
+-	if !os.IsPathSeparator('X') {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("if os.IsPathSeparator('X')", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go b/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func DontRemoveParens() {
+-	a := false
+-	b := true
+-	if !(a ||
+-		b) { //@suggestedfix("b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go.golden b/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/dont_remove_parens.go.golden	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
+--- suggestedfix_dont_remove_parens_11_3 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func DontRemoveParens() {
+-	a := false
+-	b := true
+-	if (a ||
+-		b) {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/else_if.go b/gopls/internal/lsp/testdata/invertifcondition/else_if.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/else_if.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/else_if.go	1970-01-01 08:00:00
+@@ -1,22 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func ElseIf() {
+-	// No inversion expected when there's not else clause
+-	if len(os.Args) > 2 {
+-		fmt.Println("A")
+-	}
+-
+-	// No inversion expected for else-if, that would become unreadable
+-	if len(os.Args) > 2 {
+-		fmt.Println("A")
+-	} else if os.Args[0] == "X" { //@suggestedfix(re"if os.Args.0. == .X.", "refactor.rewrite", "")
+-		fmt.Println("B")
+-	} else {
+-		fmt.Println("C")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/else_if.go.golden b/gopls/internal/lsp/testdata/invertifcondition/else_if.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/else_if.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/else_if.go.golden	1970-01-01 08:00:00
+@@ -1,24 +0,0 @@
+--- suggestedfix_else_if_17_9 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func ElseIf() {
+-	// No inversion expected when there's not else clause
+-	if len(os.Args) > 2 {
+-		fmt.Println("A")
+-	}
+-
+-	// No inversion expected for else-if, that would become unreadable
+-	if len(os.Args) > 2 {
+-		fmt.Println("A")
+-	} else if os.Args[0] != "X" {
+-		fmt.Println("C")
+-	} else { //@suggestedfix(re"if os.Args.0. == .X.", "refactor.rewrite", "")
+-		fmt.Println("B")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/greater_than.go b/gopls/internal/lsp/testdata/invertifcondition/greater_than.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/greater_than.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/greater_than.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func GreaterThan() {
+-	if len(os.Args) > 2 { //@suggestedfix("i", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/greater_than.go.golden b/gopls/internal/lsp/testdata/invertifcondition/greater_than.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/greater_than.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/greater_than.go.golden	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+--- suggestedfix_greater_than_9_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-	"os"
+-)
+-
+-func GreaterThan() {
+-	if len(os.Args) <= 2 {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("i", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go b/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func NotBoolean() {
+-	b := true
+-	if !b { //@suggestedfix("if !b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go.golden b/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/not_boolean.go.golden	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+--- suggestedfix_not_boolean_9_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func NotBoolean() {
+-	b := true
+-	if b {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("if !b", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/remove_else.go b/gopls/internal/lsp/testdata/invertifcondition/remove_else.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/remove_else.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/remove_else.go	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func RemoveElse() {
+-	if true { //@suggestedfix("if true", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-		return
+-	}
+-
+-	fmt.Println("C")
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/remove_else.go.golden b/gopls/internal/lsp/testdata/invertifcondition/remove_else.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/remove_else.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/remove_else.go.golden	1970-01-01 08:00:00
+@@ -1,19 +0,0 @@
+--- suggestedfix_remove_else_8_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func RemoveElse() {
+-	if false {
+-		fmt.Println("B")
+-		return
+-	}
+-
+-	//@suggestedfix("if true", "refactor.rewrite", "")
+-	fmt.Println("A")
+-
+-	fmt.Println("C")
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go b/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func RemoveParens() {
+-	b := true
+-	if !(b) { //@suggestedfix("if", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go.golden b/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/remove_parens.go.golden	1970-01-01 08:00:00
+@@ -1,16 +0,0 @@
+--- suggestedfix_remove_parens_9_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func RemoveParens() {
+-	b := true
+-	if b {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("if", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon.go b/gopls/internal/lsp/testdata/invertifcondition/semicolon.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon.go	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func Semicolon() {
+-	if _, err := fmt.Println("x"); err != nil { //@suggestedfix("if", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon.go.golden b/gopls/internal/lsp/testdata/invertifcondition/semicolon.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon.go.golden	1970-01-01 08:00:00
+@@ -1,15 +0,0 @@
+--- suggestedfix_semicolon_8_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func Semicolon() {
+-	if _, err := fmt.Println("x"); err == nil {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("if", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go b/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func SemicolonAnd() {
+-	if n, err := fmt.Println("x"); err != nil && n > 0 { //@suggestedfix("f", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go.golden b/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon_and.go.golden	1970-01-01 08:00:00
+@@ -1,15 +0,0 @@
+--- suggestedfix_semicolon_and_8_3 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func SemicolonAnd() {
+-	if n, err := fmt.Println("x"); err == nil || n <= 0 {
+-		fmt.Println("B")
+-	} else { //@suggestedfix("f", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go b/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func SemicolonOr() {
+-	if n, err := fmt.Println("x"); err != nil || n < 5 { //@suggestedfix(re"if n, err := fmt.Println..x..; err != nil .. n < 5", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	} else {
+-		fmt.Println("B")
+-	}
+-}
+diff -urN a/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go.golden b/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go.golden
+--- a/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/invertifcondition/semicolon_or.go.golden	1970-01-01 08:00:00
+@@ -1,15 +0,0 @@
+--- suggestedfix_semicolon_or_8_2 --
+-package invertifcondition
+-
+-import (
+-	"fmt"
+-)
+-
+-func SemicolonOr() {
+-	if n, err := fmt.Println("x"); err == nil && n >= 5 {
+-		fmt.Println("B")
+-	} else { //@suggestedfix(re"if n, err := fmt.Println..x..; err != nil .. n < 5", "refactor.rewrite", "")
+-		fmt.Println("A")
+-	}
+-}
+-
 diff -urN a/gopls/internal/lsp/testdata/issues/issue56505.go b/gopls/internal/lsp/testdata/issues/issue56505.go
 --- a/gopls/internal/lsp/testdata/issues/issue56505.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/issues/issue56505.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/issues/issue56505.go	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package issues
 -
@@ -98504,7 +106652,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in
 --- a/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/keywords/accidental_keywords.go.in	1970-01-01 08:00:00
 @@ -1,31 +0,0 @@
 -package keywords
 -
@@ -98539,7 +106687,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/keywords/empty_select.go b/gopls/internal/lsp/testdata/keywords/empty_select.go
 --- a/gopls/internal/lsp/testdata/keywords/empty_select.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/keywords/empty_select.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/keywords/empty_select.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package keywords
 -
@@ -98550,7 +106698,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/keywords/empty_switch.go b/gopls/internal/lsp/testdata/keywords/empty_switch.go
 --- a/gopls/internal/lsp/testdata/keywords/empty_switch.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/keywords/empty_switch.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/keywords/empty_switch.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package keywords
 -
@@ -98565,7 +106713,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/keywords/keywords.go b/gopls/internal/lsp/testdata/keywords/keywords.go
 --- a/gopls/internal/lsp/testdata/keywords/keywords.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/keywords/keywords.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/keywords/keywords.go	1970-01-01 08:00:00
 @@ -1,100 +0,0 @@
 -package keywords
 -
@@ -98669,7 +106817,7 @@
 -/* range */ //@item(range, "range", "", "keyword")
 diff -urN a/gopls/internal/lsp/testdata/labels/labels.go b/gopls/internal/lsp/testdata/labels/labels.go
 --- a/gopls/internal/lsp/testdata/labels/labels.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/labels/labels.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/labels/labels.go	1970-01-01 08:00:00
 @@ -1,49 +0,0 @@
 -package labels
 -
@@ -98722,7 +106870,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/links/links.go b/gopls/internal/lsp/testdata/links/links.go
 --- a/gopls/internal/lsp/testdata/links/links.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/links/links.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/links/links.go	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -package links
 -
@@ -98752,7 +106900,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/maps/maps.go.in b/gopls/internal/lsp/testdata/maps/maps.go.in
 --- a/gopls/internal/lsp/testdata/maps/maps.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/maps/maps.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/maps/maps.go.in	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 -package maps
 -
@@ -98774,7 +106922,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/channels.go b/gopls/internal/lsp/testdata/missingfunction/channels.go
 --- a/gopls/internal/lsp/testdata/missingfunction/channels.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/channels.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package missingfunction
 -
@@ -98787,7 +106935,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/channels.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/channels.go.golden	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 --- suggestedfix_channels_4_2 --
 -package missingfunction
@@ -98806,7 +106954,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go
 --- a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package missingfunction
 -
@@ -98816,7 +106964,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/consecutive_params.go.golden	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 --- suggestedfix_consecutive_params_5_2 --
 -package missingfunction
@@ -98832,7 +106980,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/error_param.go b/gopls/internal/lsp/testdata/missingfunction/error_param.go
 --- a/gopls/internal/lsp/testdata/missingfunction/error_param.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package missingfunction
 -
@@ -98842,7 +106990,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/error_param.go.golden	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 --- suggestedfix_error_param_5_2 --
 -package missingfunction
@@ -98858,7 +107006,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/literals.go b/gopls/internal/lsp/testdata/missingfunction/literals.go
 --- a/gopls/internal/lsp/testdata/missingfunction/literals.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/literals.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package missingfunction
 -
@@ -98869,7 +107017,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/literals.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/literals.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- suggestedfix_literals_6_2 --
 -package missingfunction
@@ -98886,7 +107034,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/operation.go b/gopls/internal/lsp/testdata/missingfunction/operation.go
 --- a/gopls/internal/lsp/testdata/missingfunction/operation.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/operation.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package missingfunction
 -
@@ -98897,7 +107045,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/operation.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/operation.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- suggestedfix_operation_6_2 --
 -package missingfunction
@@ -98914,7 +107062,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/selector.go b/gopls/internal/lsp/testdata/missingfunction/selector.go
 --- a/gopls/internal/lsp/testdata/missingfunction/selector.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/selector.go	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package missingfunction
 -
@@ -98924,7 +107072,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/selector.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/selector.go.golden	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 --- suggestedfix_selector_5_2 --
 -package missingfunction
@@ -98940,7 +107088,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/slice.go b/gopls/internal/lsp/testdata/missingfunction/slice.go
 --- a/gopls/internal/lsp/testdata/missingfunction/slice.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/slice.go	1970-01-01 08:00:00
 @@ -1,5 +0,0 @@
 -package missingfunction
 -
@@ -98949,7 +107097,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/slice.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/slice.go.golden	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 --- suggestedfix_slice_4_2 --
 -package missingfunction
@@ -98964,7 +107112,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/tuple.go b/gopls/internal/lsp/testdata/missingfunction/tuple.go
 --- a/gopls/internal/lsp/testdata/missingfunction/tuple.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package missingfunction
 -
@@ -98977,7 +107125,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/tuple.go.golden	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 --- suggestedfix_tuple_4_2 --
 -package missingfunction
@@ -98996,7 +107144,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/unique_params.go b/gopls/internal/lsp/testdata/missingfunction/unique_params.go
 --- a/gopls/internal/lsp/testdata/missingfunction/unique_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package missingfunction
 -
@@ -99007,7 +107155,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden
 --- a/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/missingfunction/unique_params.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- suggestedfix_unique_params_6_2 --
 -package missingfunction
@@ -99024,7 +107172,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in
 --- a/gopls/internal/lsp/testdata/multireturn/multi_return.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/multireturn/multi_return.go.in	1970-01-01 08:00:00
 @@ -1,48 +0,0 @@
 -package multireturn
 -
@@ -99076,7 +107224,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in
 --- a/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/nested_complit/nested_complit.go.in	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -package nested_complit
 -
@@ -99093,106 +107241,9 @@
 -		baz: [] // complete(" //", structNCFoo, structNCBar)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/testdata/nodisk/empty b/gopls/internal/lsp/testdata/nodisk/empty
---- a/gopls/internal/lsp/testdata/nodisk/empty	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/nodisk/empty	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--an empty file so that this directory exists
-\ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go
---- a/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/nodisk/nodisk.overlay.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package nodisk
--
--import (
--	"golang.org/lsptests/foo"
--)
--
--func _() {
--	foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
--}
-diff -urN a/gopls/internal/lsp/testdata/noparse/noparse.go.in b/gopls/internal/lsp/testdata/noparse/noparse.go.in
---- a/gopls/internal/lsp/testdata/noparse/noparse.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/noparse/noparse.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,24 +0,0 @@
--package noparse
--
--// The type error was chosen carefully to exercise a type-error analyzer.
--// We use the 'nonewvars' analyzer because the other candidates are tricky:
--//
--// - The 'unusedvariable' analyzer is disabled by default, so it is not
--//   consistently enabled across Test{LSP,CommandLine} tests, which
--//   both process this file.
--// - The 'undeclaredname' analyzer depends on the text of the go/types
--//   "undeclared name" error, which changed in go1.20.
--// - The 'noresultvalues' analyzer produces a diagnostic containing newlines,
--//   which breaks the parser used by TestCommandLine.
--//
--// This comment is all that remains of my afternoon.
--
--func bye(x int) {
--	x := 123 //@diag(":=", "nonewvars", "no new variables", "warning")
--}
--
--func stuff() {
--	
--}
--
--func .() {} //@diag(".", "syntax", "expected 'IDENT', found '.'", "error")
-diff -urN a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden
---- a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2 +0,0 @@
---- gofmt --
--
-diff -urN a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in
---- a/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/noparse_format/noparse_format.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--// +build go1.11
--
--package noparse_format //@format("package")
--
--// The nonewvars expectation asserts that the go/analysis framework ran.
--// See comments in badstmt.
--
--func what() {
--	var hi func()
--	if {		hi() //@diag("{", "syntax", "missing condition in if statement", "error")
--	}
--	hi := nil //@diag(":=", "nonewvars", "no new variables", "warning")
--}
--
-diff -urN a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden
---- a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
---- gofmt --
--package noparse_format //@format("package")
--
--func _() {
--	f()
--}
--
-diff -urN a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in
---- a/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/noparse_format/parse_format.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package noparse_format //@format("package")
--
--func _() {
--f()
--}
-\ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/%percent/perc%ent.go b/gopls/internal/lsp/testdata/%percent/perc%ent.go
---- a/gopls/internal/lsp/testdata/%percent/perc%ent.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/%percent/perc%ent.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1 +0,0 @@
--package percent
 diff -urN a/gopls/internal/lsp/testdata/printf/printf.go b/gopls/internal/lsp/testdata/printf/printf.go
 --- a/gopls/internal/lsp/testdata/printf/printf.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/printf/printf.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/printf/printf.go	1970-01-01 08:00:00
 @@ -1,33 +0,0 @@
 -package printf
 -
@@ -99229,7 +107280,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/assign_rank.go.in b/gopls/internal/lsp/testdata/rank/assign_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/assign_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/assign_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/assign_rank.go.in	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 -package rank
 -
@@ -99252,7 +107303,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/binexpr_rank.go.in	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package rank
 -
@@ -99264,7 +107315,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go
 --- a/gopls/internal/lsp/testdata/rank/boolexpr_rank.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/boolexpr_rank.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package rank
 -
@@ -99279,7 +107330,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/convert_rank.go.in b/gopls/internal/lsp/testdata/rank/convert_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/convert_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/convert_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/convert_rank.go.in	1970-01-01 08:00:00
 @@ -1,54 +0,0 @@
 -package rank
 -
@@ -99337,7 +107388,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go
 --- a/gopls/internal/lsp/testdata/rank/struct/struct_rank.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/struct/struct_rank.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package struct_rank
 -
@@ -99352,7 +107403,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/switch_rank.go.in b/gopls/internal/lsp/testdata/rank/switch_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/switch_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/switch_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/switch_rank.go.in	1970-01-01 08:00:00
 @@ -1,29 +0,0 @@
 -package rank
 -
@@ -99385,7 +107436,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/type_assert_rank.go.in	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package rank
 -
@@ -99397,7 +107448,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in
 --- a/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rank/type_switch_rank.go.in	1970-01-01 08:00:00
 @@ -1,31 +0,0 @@
 -package rank
 -
@@ -99430,158 +107481,9 @@
 -	case fmt.Stringer: //@rank(":", fmtStringer, fmtGoStringer)
 -	}
 -}
-diff -urN a/gopls/internal/lsp/testdata/references/another/another.go b/gopls/internal/lsp/testdata/references/another/another.go
---- a/gopls/internal/lsp/testdata/references/another/another.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/references/another/another.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,13 +0,0 @@
--// Package another has another type.
--package another
--
--import (
--	other "golang.org/lsptests/references/other"
--)
--
--func _() {
--	xes := other.GetXes()
--	for _, x := range xes { //@mark(defX, "x")
--		_ = x.Y //@mark(useX, "x"),mark(anotherXY, "Y"),refs("Y", typeXY, anotherXY, GetXesY),refs(".", defX, useX),refs("x", defX, useX)
--	}
--}
-diff -urN a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go
---- a/gopls/internal/lsp/testdata/references/interfaces/interfaces.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/references/interfaces/interfaces.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,34 +0,0 @@
--package interfaces
--
--type first interface {
--	common() //@mark(firCommon, "common"),refs("common", firCommon, xCommon, zCommon)
--	firstMethod() //@mark(firMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod)
--}
--
--type second interface {
--	common() //@mark(secCommon, "common"),refs("common", secCommon, yCommon, zCommon)
--	secondMethod() //@mark(secMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod)
--}
--
--type s struct {}
--
--func (*s) common() {} //@mark(sCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon)
--
--func (*s) firstMethod() {} //@mark(sfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod)
--
--func (*s) secondMethod() {} //@mark(ssMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod)
--
--func main() {
--	var x first = &s{}
--	var y second = &s{}
--
--	x.common() //@mark(xCommon, "common"),refs("common", firCommon, xCommon, zCommon)
--	x.firstMethod() //@mark(xfMethod, "firstMethod"),refs("firstMethod", firMethod, xfMethod, zfMethod)
--	y.common() //@mark(yCommon, "common"),refs("common", secCommon, yCommon, zCommon)
--	y.secondMethod() //@mark(ysMethod, "secondMethod"),refs("secondMethod", secMethod, ysMethod, zsMethod)
--
--	var z *s = &s{}
--	z.firstMethod() //@mark(zfMethod, "firstMethod"),refs("firstMethod", sfMethod, xfMethod, zfMethod)
--	z.secondMethod() //@mark(zsMethod, "secondMethod"),refs("secondMethod", ssMethod, ysMethod, zsMethod)
--	z.common() //@mark(zCommon, "common"),refs("common", sCommon, xCommon, yCommon, zCommon)
--}
-diff -urN a/gopls/internal/lsp/testdata/references/other/other.go b/gopls/internal/lsp/testdata/references/other/other.go
---- a/gopls/internal/lsp/testdata/references/other/other.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/references/other/other.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,19 +0,0 @@
--package other
--
--import (
--	references "golang.org/lsptests/references"
--)
--
--func GetXes() []references.X {
--	return []references.X{
--		{
--			Y: 1, //@mark(GetXesY, "Y"),refs("Y", typeXY, GetXesY, anotherXY)
--		},
--	}
--}
--
--func _() {
--	references.Q = "hello" //@mark(assignExpQ, "Q")
--	bob := func(_ string) {}
--	bob(references.Q) //@mark(bobExpQ, "Q")
--}
-diff -urN a/gopls/internal/lsp/testdata/references/refs.go b/gopls/internal/lsp/testdata/references/refs.go
---- a/gopls/internal/lsp/testdata/references/refs.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/references/refs.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,53 +0,0 @@
--// Package refs is a package used to test find references.
--package refs
--
--import "os" //@mark(osDecl, `"os"`),refs("os", osDecl, osUse)
--
--type i int //@mark(typeI, "i"),refs("i", typeI, argI, returnI, embeddedI)
--
--type X struct {
--	Y int //@mark(typeXY, "Y")
--}
--
--func _(_ i) []bool { //@mark(argI, "i")
--	return nil
--}
--
--func _(_ []byte) i { //@mark(returnI, "i")
--	return 0
--}
--
--var q string //@mark(declQ, "q"),refs("q", declQ, assignQ, bobQ)
--
--var Q string //@mark(declExpQ, "Q"),refs("Q", declExpQ, assignExpQ, bobExpQ)
--
--func _() {
--	q = "hello" //@mark(assignQ, "q")
--	bob := func(_ string) {}
--	bob(q) //@mark(bobQ, "q")
--}
--
--type e struct {
--	i //@mark(embeddedI, "i"),refs("i", embeddedI, embeddedIUse)
--}
--
--func _() {
--	_ = e{}.i //@mark(embeddedIUse, "i")
--}
--
--const (
--	foo = iota //@refs("iota")
--)
--
--func _(x interface{}) {
--	// We use the _ prefix because the markers inhabit a single
--	// namespace and yDecl is already used in ../highlights/highlights.go.
--	switch _y := x.(type) { //@mark(_yDecl, "_y"),refs("_y", _yDecl, _yInt, _yDefault)
--	case int:
--		println(_y) //@mark(_yInt, "_y"),refs("_y", _yDecl, _yInt, _yDefault)
--	default:
--		println(_y) //@mark(_yDefault, "_y")
--	}
--
--	os.Getwd() //@mark(osUse, "os")
--}
-diff -urN a/gopls/internal/lsp/testdata/references/refs_test.go b/gopls/internal/lsp/testdata/references/refs_test.go
---- a/gopls/internal/lsp/testdata/references/refs_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/references/refs_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package references
--
--import (
--	"testing"
--)
--
--// This test exists to bring the test package into existence.
--
--func TestReferences(t *testing.T) {
--}
 diff -urN a/gopls/internal/lsp/testdata/rename/a/random.go.golden b/gopls/internal/lsp/testdata/rename/a/random.go.golden
 --- a/gopls/internal/lsp/testdata/rename/a/random.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/a/random.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/a/random.go.golden	1970-01-01 08:00:00
 @@ -1,616 +0,0 @@
 --- GetSum-rename --
 -package a
@@ -100201,7 +108103,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/a/random.go.in b/gopls/internal/lsp/testdata/rename/a/random.go.in
 --- a/gopls/internal/lsp/testdata/rename/a/random.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/a/random.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/a/random.go.in	1970-01-01 08:00:00
 @@ -1,42 +0,0 @@
 -package a
 -
@@ -100247,7 +108149,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/b/b.go b/gopls/internal/lsp/testdata/rename/b/b.go
 --- a/gopls/internal/lsp/testdata/rename/b/b.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/b/b.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/b/b.go	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -package b
 -
@@ -100271,7 +108173,7 @@
 -func Hello() {} //@rename("Hello", "Goodbye")
 diff -urN a/gopls/internal/lsp/testdata/rename/b/b.go.golden b/gopls/internal/lsp/testdata/rename/b/b.go.golden
 --- a/gopls/internal/lsp/testdata/rename/b/b.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/b/b.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/b/b.go.golden	1970-01-01 08:00:00
 @@ -1,78 +0,0 @@
 --- Bob-rename --
 -package b
@@ -100353,13 +108255,13 @@
 -int is built in and cannot be renamed
 diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden
 --- a/gopls/internal/lsp/testdata/rename/bad/bad.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.golden	1970-01-01 08:00:00
 @@ -1,2 +0,0 @@
 --- rFunc-rename --
 -renaming "sFunc" to "rFunc" not possible because "golang.org/lsptests/rename/bad" has errors
 diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad.go.in b/gopls/internal/lsp/testdata/rename/bad/bad.go.in
 --- a/gopls/internal/lsp/testdata/rename/bad/bad.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/bad/bad.go.in	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package bad
 -
@@ -100371,31 +108273,13 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in
 --- a/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/bad/bad_test.go.in	1970-01-01 08:00:00
 @@ -1 +0,0 @@
 -package bad
 \ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go b/gopls/internal/lsp/testdata/rename/c/c2.go
---- a/gopls/internal/lsp/testdata/rename/c/c2.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/c/c2.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,4 +0,0 @@
--package c
--
--//go:embed Static/*
--var Static embed.FS //@rename("Static", "static")
-\ No newline at end of file
-diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go.golden b/gopls/internal/lsp/testdata/rename/c/c2.go.golden
---- a/gopls/internal/lsp/testdata/rename/c/c2.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/c/c2.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
---- static-rename --
--package c
--
--//go:embed Static/*
--var static embed.FS //@rename("Static", "static")
 diff -urN a/gopls/internal/lsp/testdata/rename/c/c.go b/gopls/internal/lsp/testdata/rename/c/c.go
 --- a/gopls/internal/lsp/testdata/rename/c/c.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/c/c.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/c/c.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package c
 -
@@ -100406,7 +108290,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/c/c.go.golden b/gopls/internal/lsp/testdata/rename/c/c.go.golden
 --- a/gopls/internal/lsp/testdata/rename/c/c.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/c/c.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/c/c.go.golden	1970-01-01 08:00:00
 @@ -1,32 +0,0 @@
 --- Goodbye-rename --
 -b.go:
@@ -100440,9 +108324,27 @@
 -	b.Goodbye() //@rename("Hello", "Goodbye")
 -}
 -
+diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go b/gopls/internal/lsp/testdata/rename/c/c2.go
+--- a/gopls/internal/lsp/testdata/rename/c/c2.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/rename/c/c2.go	1970-01-01 08:00:00
+@@ -1,4 +0,0 @@
+-package c
+-
+-//go:embed Static/*
+-var Static embed.FS //@rename("Static", "static")
+\ No newline at end of file
+diff -urN a/gopls/internal/lsp/testdata/rename/c/c2.go.golden b/gopls/internal/lsp/testdata/rename/c/c2.go.golden
+--- a/gopls/internal/lsp/testdata/rename/c/c2.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/rename/c/c2.go.golden	1970-01-01 08:00:00
+@@ -1,5 +0,0 @@
+--- static-rename --
+-package c
+-
+-//go:embed Static/*
+-var static embed.FS //@rename("Static", "static")
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package another
 -
@@ -100459,7 +108361,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/another/another.go.golden	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 --- G-rename --
 -package another
@@ -100478,7 +108380,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package crosspkg
 -
@@ -100489,7 +108391,7 @@
 -var Bar int //@rename("Bar", "Tomato")
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/crosspkg.go.golden	1970-01-01 08:00:00
 @@ -1,40 +0,0 @@
 --- Dolphin-rename --
 -crosspkg.go:
@@ -100533,7 +108435,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package other
 -
@@ -100545,7 +108447,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden
 --- a/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/crosspkg/other/other.go.golden	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 --- Flamingo-rename --
 -crosspkg.go:
@@ -100569,7 +108471,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/embedded.go b/gopls/internal/lsp/testdata/rename/generics/embedded.go
 --- a/gopls/internal/lsp/testdata/rename/generics/embedded.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -100583,7 +108485,7 @@
 -var _ = x.foo
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden
 --- a/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/embedded.go.golden	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 --- bar-rename --
 -//go:build go1.18
@@ -100599,7 +108501,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/generics.go b/gopls/internal/lsp/testdata/rename/generics/generics.go
 --- a/gopls/internal/lsp/testdata/rename/generics/generics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/generics.go	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -100628,7 +108530,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden
 --- a/gopls/internal/lsp/testdata/rename/generics/generics.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/generics.go.golden	1970-01-01 08:00:00
 @@ -1,108 +0,0 @@
 --- H-rename --
 -//go:build go1.18
@@ -100740,7 +108642,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/unions.go b/gopls/internal/lsp/testdata/rename/generics/unions.go
 --- a/gopls/internal/lsp/testdata/rename/generics/unions.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/unions.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -100754,7 +108656,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden
 --- a/gopls/internal/lsp/testdata/rename/generics/unions.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/generics/unions.go.golden	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 --- R-rename --
 -//go:build go1.18
@@ -100782,7 +108684,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.golden	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 --- bar-rename --
 -package issue39614
@@ -100796,7 +108698,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in
 --- a/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue39614/issue39614.go.in	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package issue39614
 -
@@ -100808,7 +108710,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/1.go b/gopls/internal/lsp/testdata/rename/issue42134/1.go
 --- a/gopls/internal/lsp/testdata/rename/issue42134/1.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package issue42134
 -
@@ -100820,7 +108722,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/1.go.golden	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 --- bar-rename --
 -package issue42134
@@ -100834,7 +108736,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/2.go b/gopls/internal/lsp/testdata/rename/issue42134/2.go
 --- a/gopls/internal/lsp/testdata/rename/issue42134/2.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -package issue42134
 -
@@ -100850,7 +108752,7 @@
 -func min(a, b int) int { return a }
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/2.go.golden	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 --- res-rename --
 -package issue42134
@@ -100868,7 +108770,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/3.go b/gopls/internal/lsp/testdata/rename/issue42134/3.go
 --- a/gopls/internal/lsp/testdata/rename/issue42134/3.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package issue42134
 -
@@ -100883,7 +108785,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/3.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- testCases-rename --
 -package issue42134
@@ -100900,7 +108802,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/4.go b/gopls/internal/lsp/testdata/rename/issue42134/4.go
 --- a/gopls/internal/lsp/testdata/rename/issue42134/4.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package issue42134
 -
@@ -100912,7 +108814,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue42134/4.go.golden	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 --- b-rename --
 -package issue42134
@@ -100926,7 +108828,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden
 --- a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- bar-rename --
 -package issue43616
@@ -100943,7 +108845,7 @@
 -can't rename embedded fields: rename the type directly or name the field
 diff -urN a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in
 --- a/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/issue43616/issue43616.go.in	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package issue43616
 -
@@ -100954,7 +108856,7 @@
 -var _ = x.foo //@rename("foo","quux")
 diff -urN a/gopls/internal/lsp/testdata/rename/shadow/shadow.go b/gopls/internal/lsp/testdata/rename/shadow/shadow.go
 --- a/gopls/internal/lsp/testdata/rename/shadow/shadow.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -package shadow
 -
@@ -100978,7 +108880,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden
 --- a/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/shadow/shadow.go.golden	1970-01-01 08:00:00
 @@ -1,51 +0,0 @@
 --- a-rename --
 -shadow/shadow.go:10:6: renaming this func "A" to "a"
@@ -101033,7 +108935,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy.go b/gopls/internal/lsp/testdata/rename/testy/testy.go
 --- a/gopls/internal/lsp/testdata/rename/testy/testy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/testy/testy.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package testy
 -
@@ -101044,7 +108946,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden
 --- a/gopls/internal/lsp/testdata/rename/testy/testy.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/testy/testy.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- bar-rename --
 -package testy
@@ -101066,7 +108968,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy_test.go b/gopls/internal/lsp/testdata/rename/testy/testy_test.go
 --- a/gopls/internal/lsp/testdata/rename/testy/testy_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go	1970-01-01 08:00:00
 @@ -1,8 +0,0 @@
 -package testy
 -
@@ -101078,7 +108980,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden
 --- a/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/rename/testy/testy_test.go.golden	1970-01-01 08:00:00
 @@ -1,30 +0,0 @@
 --- b-rename --
 -testy.go:
@@ -101110,27 +109012,9 @@
 -	a()       //@rename("a", "b")
 -}
 -
-diff -urN a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go
---- a/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/rundespiteerrors/rundespiteerrors.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--package rundespiteerrors
--
--// This test verifies that analyzers without RunDespiteErrors are not
--// executed on a package containing type errors (see issue #54762).
--func _() {
--	// A type error.
--	_ = 1 + "" //@diag("1", "compiler", "mismatched types|cannot convert", "error")
--
--	// A violation of an analyzer for which RunDespiteErrors=false:
--	// no diagnostic is produced; the diag comment is merely illustrative.
--	for _ = range "" { //diag("for _", "simplifyrange", "simplify range expression", "warning")
--
--	}
--}
 diff -urN a/gopls/internal/lsp/testdata/selectionrange/foo.go b/gopls/internal/lsp/testdata/selectionrange/foo.go
 --- a/gopls/internal/lsp/testdata/selectionrange/foo.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/selectionrange/foo.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package foo
 -
@@ -101147,7 +109031,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden
 --- a/gopls/internal/lsp/testdata/selectionrange/foo.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/selectionrange/foo.go.golden	1970-01-01 08:00:00
 @@ -1,29 +0,0 @@
 --- selectionrange_foo_12_11 --
 -Ranges 0: 
@@ -101178,79 +109062,15 @@
 -	4:0-12:1 "func Bar(x, y i...ionrange(\"+\")\\n}"
 -	0:0-12:1 "package foo\\n\\nim...ionrange(\"+\")\\n}"
 -
-diff -urN a/gopls/internal/lsp/testdata/selector/selector.go.in b/gopls/internal/lsp/testdata/selector/selector.go.in
---- a/gopls/internal/lsp/testdata/selector/selector.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/selector/selector.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,66 +0,0 @@
--// +build go1.11
--
--package selector
--
--import (
--	"golang.org/lsptests/bar"
--)
--
--type S struct {
--	B, A, C int //@item(Bf, "B", "int", "field"),item(Af, "A", "int", "field"),item(Cf, "C", "int", "field")
--}
--
--func _() {
--	_ = S{}.; //@complete(";", Af, Bf, Cf)
--}
--
--type bob struct { a int } //@item(a, "a", "int", "field")
--type george struct { b int }
--type jack struct { c int } //@item(c, "c", "int", "field")
--type jill struct { d int }
--
--func (b *bob) george() *george {} //@item(george, "george", "func() *george", "method")
--func (g *george) jack() *jack {}
--func (j *jack) jill() *jill {} //@item(jill, "jill", "func() *jill", "method")
--
--func _() {
--	b := &bob{}
--	y := b.george().
--		jack();
--	y.; //@complete(";", c, jill)
--}
--
--func _() {
--	bar. //@complete(" /", Bar)
--	x := 5
--
--	var b *bob
--	b. //@complete(" /", a, george)
--	y, z := 5, 6
--
--	b. //@complete(" /", a, george)
--	y, z, a, b, c := 5, 6
--}
--
--func _() {
--	bar. //@complete(" /", Bar)
--	bar.Bar()
--
--	bar. //@complete(" /", Bar)
--	go f()
--}
--
--func _() {
--	var b *bob
--	if y != b. //@complete(" /", a, george)
--	z := 5
--
--	if z + y + 1 + b. //@complete(" /", a, george)
--	r, s, t := 4, 5
--
--	if y != b. //@complete(" /", a, george)
--	z = 5
--
--	if z + y + 1 + b. //@complete(" /", a, george)
--	r = 4
--}
+diff -urN a/gopls/internal/lsp/testdata/semantic/README.md b/gopls/internal/lsp/testdata/semantic/README.md
+--- a/gopls/internal/lsp/testdata/semantic/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/semantic/README.md	1970-01-01 08:00:00
+@@ -1,2 +0,0 @@
+-The golden files are the output of `gopls semtok <src-file>`, with `-- semantic --`
+-inserted as the first line (the spaces are mandatory) and an extra newline at the end.
 diff -urN a/gopls/internal/lsp/testdata/semantic/a.go b/gopls/internal/lsp/testdata/semantic/a.go
 --- a/gopls/internal/lsp/testdata/semantic/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/a.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/semantic/a.go	1970-01-01 08:00:00
 @@ -1,81 +0,0 @@
 -package semantictokens //@ semantic("")
 -
@@ -101335,7 +109155,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/semantic/a.go.golden b/gopls/internal/lsp/testdata/semantic/a.go.golden
 --- a/gopls/internal/lsp/testdata/semantic/a.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/a.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/semantic/a.go.golden	1970-01-01 08:00:00
 @@ -1,83 +0,0 @@
 --- semantic --
 -/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("")
@@ -101422,7 +109242,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/semantic/b.go b/gopls/internal/lsp/testdata/semantic/b.go
 --- a/gopls/internal/lsp/testdata/semantic/b.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/b.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/semantic/b.go	1970-01-01 08:00:00
 @@ -1,38 +0,0 @@
 -package semantictokens //@ semantic("")
 -
@@ -101464,7 +109284,7 @@
 -var c <-chan <-chan int
 diff -urN a/gopls/internal/lsp/testdata/semantic/b.go.golden b/gopls/internal/lsp/testdata/semantic/b.go.golden
 --- a/gopls/internal/lsp/testdata/semantic/b.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/b.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/semantic/b.go.golden	1970-01-01 08:00:00
 @@ -1,40 +0,0 @@
 --- semantic --
 -/*⇒7,keyword,[]*/package /*⇒14,namespace,[]*/semantictokens /*⇒16,comment,[]*///@ semantic("")
@@ -101506,15 +109326,9 @@
 -/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/b /*⇒4,keyword,[]*/chan/*⇒2,operator,[]*/<- /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
 -/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/c /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒2,operator,[]*/<-/*⇒4,keyword,[]*/chan /*⇒3,type,[defaultLibrary]*/int
 -
-diff -urN a/gopls/internal/lsp/testdata/semantic/README.md b/gopls/internal/lsp/testdata/semantic/README.md
---- a/gopls/internal/lsp/testdata/semantic/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2 +0,0 @@
--The golden files are the output of `gopls semtok <src-file>`, with `-- semantic --`
--inserted as the first line (the spaces are mandatory) and an extra newline at the end.
 diff -urN a/gopls/internal/lsp/testdata/semantic/semantic_test.go b/gopls/internal/lsp/testdata/semantic/semantic_test.go
 --- a/gopls/internal/lsp/testdata/semantic/semantic_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/semantic/semantic_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/semantic/semantic_test.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package semantictokens
 -
@@ -101529,42 +109343,9 @@
 -	// find all the .go files
 -
 -}
-diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.golden b/gopls/internal/lsp/testdata/signature/signature2.go.golden
---- a/gopls/internal/lsp/testdata/signature/signature2.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature2.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
---- Foo(a string, b int) (c bool)-signature --
--Foo(a string, b int) (c bool)
--
-diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.in b/gopls/internal/lsp/testdata/signature/signature2.go.in
---- a/gopls/internal/lsp/testdata/signature/signature2.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature2.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package signature
--
--func _() {
--	Foo(//@signature("//", "Foo(a string, b int) (c bool)", 0)
--}
-diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.golden b/gopls/internal/lsp/testdata/signature/signature3.go.golden
---- a/gopls/internal/lsp/testdata/signature/signature3.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature3.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
---- Foo(a string, b int) (c bool)-signature --
--Foo(a string, b int) (c bool)
--
-diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.in b/gopls/internal/lsp/testdata/signature/signature3.go.in
---- a/gopls/internal/lsp/testdata/signature/signature3.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature3.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package signature
--
--func _() {
--	Foo("hello",//@signature("//", "Foo(a string, b int) (c bool)", 1)
--}
-\ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/signature/signature.go b/gopls/internal/lsp/testdata/signature/signature.go
 --- a/gopls/internal/lsp/testdata/signature/signature.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/signature/signature.go	1970-01-01 08:00:00
 @@ -1,85 +0,0 @@
 -// Package signature has tests for signature help.
 -package signature
@@ -101653,7 +109434,7 @@
 -func Hello(func()) {}
 diff -urN a/gopls/internal/lsp/testdata/signature/signature.go.golden b/gopls/internal/lsp/testdata/signature/signature.go.golden
 --- a/gopls/internal/lsp/testdata/signature/signature.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/signature/signature.go.golden	1970-01-01 08:00:00
 @@ -1,53 +0,0 @@
 --- AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)-signature --
 -AliasMap(a map[*Alias]StringAlias) (b map[*Alias]StringAlias, c map[*Alias]StringAlias)
@@ -101708,9 +109489,42 @@
 -
 -The println built-in function formats its arguments in an implementation-specific way and writes the result to standard error.
 -
+diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.golden b/gopls/internal/lsp/testdata/signature/signature2.go.golden
+--- a/gopls/internal/lsp/testdata/signature/signature2.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/signature/signature2.go.golden	1970-01-01 08:00:00
+@@ -1,3 +0,0 @@
+--- Foo(a string, b int) (c bool)-signature --
+-Foo(a string, b int) (c bool)
+-
+diff -urN a/gopls/internal/lsp/testdata/signature/signature2.go.in b/gopls/internal/lsp/testdata/signature/signature2.go.in
+--- a/gopls/internal/lsp/testdata/signature/signature2.go.in	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/signature/signature2.go.in	1970-01-01 08:00:00
+@@ -1,5 +0,0 @@
+-package signature
+-
+-func _() {
+-	Foo(//@signature("//", "Foo(a string, b int) (c bool)", 0)
+-}
+diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.golden b/gopls/internal/lsp/testdata/signature/signature3.go.golden
+--- a/gopls/internal/lsp/testdata/signature/signature3.go.golden	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/signature/signature3.go.golden	1970-01-01 08:00:00
+@@ -1,3 +0,0 @@
+--- Foo(a string, b int) (c bool)-signature --
+-Foo(a string, b int) (c bool)
+-
+diff -urN a/gopls/internal/lsp/testdata/signature/signature3.go.in b/gopls/internal/lsp/testdata/signature/signature3.go.in
+--- a/gopls/internal/lsp/testdata/signature/signature3.go.in	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/signature/signature3.go.in	1970-01-01 08:00:00
+@@ -1,5 +0,0 @@
+-package signature
+-
+-func _() {
+-	Foo("hello",//@signature("//", "Foo(a string, b int) (c bool)", 1)
+-}
+\ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/signature/signature_test.go b/gopls/internal/lsp/testdata/signature/signature_test.go
 --- a/gopls/internal/lsp/testdata/signature/signature_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/signature/signature_test.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package signature_test
 -
@@ -101727,7 +109541,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/signature/signature_test.go.golden b/gopls/internal/lsp/testdata/signature/signature_test.go.golden
 --- a/gopls/internal/lsp/testdata/signature/signature_test.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/signature/signature_test.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/signature/signature_test.go.golden	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 --- AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)-signature --
 -AliasMap(a map[*sig.Alias]sig.StringAlias) (b map[*sig.Alias]sig.StringAlias, c map[*sig.Alias]sig.StringAlias)
@@ -101740,7 +109554,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in
 --- a/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/snippets/func_snippets118.go.in	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 -// +build go1.18
 -//go:build go1.18
@@ -101763,7 +109577,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/snippets/literal.go b/gopls/internal/lsp/testdata/snippets/literal.go
 --- a/gopls/internal/lsp/testdata/snippets/literal.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/literal.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/snippets/literal.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -package snippets
 -
@@ -101790,270 +109604,15 @@
 \ No newline at end of file
 diff -urN a/gopls/internal/lsp/testdata/snippets/literal.go.golden b/gopls/internal/lsp/testdata/snippets/literal.go.golden
 --- a/gopls/internal/lsp/testdata/snippets/literal.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/literal.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/snippets/literal.go.golden	1970-01-01 08:00:00
 @@ -1,3 +0,0 @@
 --- X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias-signature --
 -X(_ map[signature.Alias]t.CoolAlias) map[signature.Alias]t.CoolAlias
 -
-diff -urN a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in
---- a/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets118.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--// +build go1.18
--//go:build go1.18
--
--package snippets
--
--type Tree[T any] struct{}
--
--func (tree Tree[T]) Do(f func(s T)) {}
--
--func _() {
--    _ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")
--	var t Tree[string]
--	t.Do(fun) //@complete(")", litFunc),snippet(")", litFunc, "func(s string) {$0\\}", "func(s string) {$0\\}")
--}
-diff -urN a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in
---- a/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/literal_snippets.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,233 +0,0 @@
--package snippets
--
--import (
--	"bytes"
--	"context"
--	"go/ast"
--	"net/http"
--	"sort"
--
--	"golang.org/lsptests/foo"
--)
--
--func _() {
--	[]int{}        //@item(litIntSlice, "[]int{}", "", "var")
--	&[]int{}       //@item(litIntSliceAddr, "&[]int{}", "", "var")
--	make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func")
--
--	var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}", "&[]int{$0\\}")
--	var _ **[]int = in //@complete(" //")
--
--	var slice []int
--	slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}", "[]int{$0\\}")
--	slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})", "make([]int, ${1:0})")
--}
--
--func _() {
--	type namedInt []int
--
--	namedInt{}        //@item(litNamedSlice, "namedInt{}", "", "var")
--	make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func")
--
--	var namedSlice namedInt
--	namedSlice = n //@snippet(" //", litNamedSlice, "namedInt{$0\\}", "namedInt{$0\\}")
--	namedSlice = m //@snippet(" //", makeNamedSlice, "make(namedInt, ${1:})", "make(namedInt, ${1:0})")
--}
--
--func _() {
--	make(chan int) //@item(makeChan, "make(chan int)", "", "func")
--
--	var ch chan int
--	ch = m //@snippet(" //", makeChan, "make(chan int)", "make(chan int)")
--}
--
--func _() {
--	map[string]struct{}{}     //@item(litMap, "map[string]struct{}{}", "", "var")
--	make(map[string]struct{}) //@item(makeMap, "make(map[string]struct{})", "", "func")
--
--	var m map[string]struct{}
--	m = m //@snippet(" //", litMap, "map[string]struct{\\}{$0\\}", "map[string]struct{\\}{$0\\}")
--	m = m //@snippet(" //", makeMap, "make(map[string]struct{\\})", "make(map[string]struct{\\})")
--
--	struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var")
--
--	m["hi"] = s //@snippet(" //", litEmptyStruct, "struct{\\}{\\}", "struct{\\}{\\}")
--}
--
--func _() {
--	type myStruct struct{ i int } //@item(myStructType, "myStruct", "struct{...}", "struct")
--
--	myStruct{}  //@item(litStruct, "myStruct{}", "", "var")
--	&myStruct{} //@item(litStructPtr, "&myStruct{}", "", "var")
--
--	var ms myStruct
--	ms = m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}")
--
--	var msPtr *myStruct
--	msPtr = m //@snippet(" //", litStructPtr, "&myStruct{$0\\}", "&myStruct{$0\\}")
--
--	msPtr = &m //@snippet(" //", litStruct, "myStruct{$0\\}", "myStruct{$0\\}")
--
--	type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct")
--
--	// Don't offer literal completion for convertible structs.
--	ms = myStruct //@complete(" //", litStruct, myStructType, myStructCopyType)
--}
--
--type myImpl struct{}
--
--func (myImpl) foo() {}
--
--func (*myImpl) bar() {}
--
--type myBasicImpl string
--
--func (myBasicImpl) foo() {}
--
--func _() {
--	type myIntf interface {
--		foo()
--	}
--
--	myImpl{} //@item(litImpl, "myImpl{}", "", "var")
--
--	var mi myIntf
--	mi = m //@snippet(" //", litImpl, "myImpl{\\}", "myImpl{\\}")
--
--	myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var")
--
--	mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)", "myBasicImpl($0)")
--
--	// only satisfied by pointer to myImpl
--	type myPtrIntf interface {
--		bar()
--	}
--
--	&myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var")
--
--	var mpi myPtrIntf
--	mpi = m //@snippet(" //", litImplPtr, "&myImpl{\\}", "&myImpl{\\}")
--}
--
--func _() {
--	var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field")
--	var foo []int
--	// no literal completions after selector
--	foo = s.i //@complete(" //", litSliceField)
--}
--
--func _() {
--	type myStruct struct{ i int } //@item(litMyStructType, "myStruct", "struct{...}", "struct")
--	myStruct{} //@item(litMyStruct, "myStruct{}", "", "var")
--
--	foo := func(s string, args ...myStruct) {}
--	// Don't give literal slice candidate for variadic arg.
--	// Do give literal candidates for variadic element.
--	foo("", myStruct) //@complete(")", litMyStruct, litMyStructType)
--}
--
--func _() {
--	Buffer{} //@item(litBuffer, "Buffer{}", "", "var")
--
--	var b *bytes.Buffer
--	b = bytes.Bu //@snippet(" //", litBuffer, "Buffer{\\}", "Buffer{\\}")
--}
--
--func _() {
--	_ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")
--
--	sort.Slice(nil, fun) //@complete(")", litFunc),snippet(")", litFunc, "func(i, j int) bool {$0\\}", "func(i, j int) bool {$0\\}")
--
--	http.HandleFunc("", f) //@snippet(")", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}")
--
--	// no literal "func" completions
--	http.Handle("", fun) //@complete(")")
--
--	http.HandlerFunc() //@item(handlerFunc, "http.HandlerFunc()", "", "var")
--	http.Handle("", h) //@snippet(")", handlerFunc, "http.HandlerFunc($0)", "http.HandlerFunc($0)")
--	http.Handle("", http.HandlerFunc()) //@snippet("))", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}", "func(${1:w} http.ResponseWriter, ${2:r} *http.Request) {$0\\}")
--
--	var namedReturn func(s string) (b bool)
--	namedReturn = f //@snippet(" //", litFunc, "func(s string) (b bool) {$0\\}", "func(s string) (b bool) {$0\\}")
--
--	var multiReturn func() (bool, int)
--	multiReturn = f //@snippet(" //", litFunc, "func() (bool, int) {$0\\}", "func() (bool, int) {$0\\}")
--
--	var multiNamedReturn func() (b bool, i int)
--	multiNamedReturn = f //@snippet(" //", litFunc, "func() (b bool, i int) {$0\\}", "func() (b bool, i int) {$0\\}")
--
--	var duplicateParams func(myImpl, int, myImpl)
--	duplicateParams = f //@snippet(" //", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}", "func(${1:mi1} myImpl, ${2:i} int, ${3:mi2} myImpl) {$0\\}")
--
--	type aliasImpl = myImpl
--	var aliasParams func(aliasImpl) aliasImpl
--	aliasParams = f //@snippet(" //", litFunc, "func(ai aliasImpl) aliasImpl {$0\\}", "func(${1:ai} aliasImpl) aliasImpl {$0\\}")
--
--	const two = 2
--	var builtinTypes func([]int, [two]bool, map[string]string, struct{ i int }, interface{ foo() }, <-chan int)
--	builtinTypes = f //@snippet(" //", litFunc, "func(i1 []int, b [two]bool, m map[string]string, s struct{ i int \\}, i2 interface{ foo() \\}, c <-chan int) {$0\\}", "func(${1:i1} []int, ${2:b} [two]bool, ${3:m} map[string]string, ${4:s} struct{ i int \\}, ${5:i2} interface{ foo() \\}, ${6:c} <-chan int) {$0\\}")
--
--	var _ func(ast.Node) = f //@snippet(" //", litFunc, "func(n ast.Node) {$0\\}", "func(${1:n} ast.Node) {$0\\}")
--	var _ func(error) = f //@snippet(" //", litFunc, "func(err error) {$0\\}", "func(${1:err} error) {$0\\}")
--	var _ func(context.Context) = f //@snippet(" //", litFunc, "func(ctx context.Context) {$0\\}", "func(${1:ctx} context.Context) {$0\\}")
--
--	type context struct {}
--	var _ func(context) = f //@snippet(" //", litFunc, "func(ctx context) {$0\\}", "func(${1:ctx} context) {$0\\}")
--}
--
--func _() {
--	StructFoo{} //@item(litStructFoo, "StructFoo{}", "struct{...}", "struct")
--
--	var sfp *foo.StructFoo
--	// Don't insert the "&" before "StructFoo{}".
--	sfp = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
--
--	var sf foo.StructFoo
--	sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
--	sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}")
--}
--
--func _() {
--	float64() //@item(litFloat64, "float64()", "float64", "var")
--
--	// don't complete to "&float64()"
--	var _ *float64 = float64 //@complete(" //")
--
--	var f float64
--	f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)")
--
--	type myInt int
--	myInt() //@item(litMyInt, "myInt()", "", "var")
--
--	var mi myInt
--	mi = my //@snippet(" //", litMyInt, "myInt($0)", "myInt($0)")
--}
--
--func _() {
--	type ptrStruct struct {
--		p *ptrStruct
--	}
--
--	ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var")
--
--	ptrStruct{
--		p: &ptrSt, //@rank(",", litPtrStruct)
--	}
--
--	&ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var")
--
--	&ptrStruct{
--		p: ptrSt, //@rank(",", litPtrStructPtr)
--	}
--}
--
--func _() {
--	f := func(...[]int) {}
--	f() //@snippet(")", litIntSlice, "[]int{$0\\}", "[]int{$0\\}")
--}
--
--
--func _() {
--	// don't complete to "untyped int()"
--	[]int{}[untyped] //@complete("] //")
--}
 diff -urN a/gopls/internal/lsp/testdata/snippets/postfix.go b/gopls/internal/lsp/testdata/snippets/postfix.go
 --- a/gopls/internal/lsp/testdata/snippets/postfix.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/postfix.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,42 +0,0 @@
++++ b/gopls/internal/lsp/testdata/snippets/postfix.go	1970-01-01 08:00:00
+@@ -1,43 +0,0 @@
 -package snippets
 -
 -// These tests check that postfix completions do and do not show up in
@@ -102090,25 +109649,29 @@
 -	/* reverse! */ //@item(postfixReverse, "reverse!", "reverse slice", "snippet")
 -	/* sort! */ //@item(postfixSort, "sort!", "sort.Slice()", "snippet")
 -	/* var! */ //@item(postfixVar, "var!", "assign to variable", "snippet")
+-	/* ifnotnil! */ //@item(postfixIfNotNil, "ifnotnil!", "if expr != nil", "snippet")
 -
 -	var foo []int
--	foo. //@complete(" //", postfixAppend, postfixCopy, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar)
+-	foo. //@complete(" //", postfixAppend, postfixCopy, postfixIfNotNil, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar)
 -
 -		foo = nil
 -}
 diff -urN a/gopls/internal/lsp/testdata/snippets/snippets.go.golden b/gopls/internal/lsp/testdata/snippets/snippets.go.golden
 --- a/gopls/internal/lsp/testdata/snippets/snippets.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/snippets/snippets.go.golden	1970-01-01 08:00:00
 @@ -1,3 +0,0 @@
 --- baz(at AliasType, b bool)-signature --
 -baz(at AliasType, b bool)
 -
 diff -urN a/gopls/internal/lsp/testdata/snippets/snippets.go.in b/gopls/internal/lsp/testdata/snippets/snippets.go.in
 --- a/gopls/internal/lsp/testdata/snippets/snippets.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/snippets/snippets.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,61 +0,0 @@
++++ b/gopls/internal/lsp/testdata/snippets/snippets.go.in	1970-01-01 08:00:00
+@@ -1,64 +0,0 @@
 -package snippets
 -
+-// Pre-set this marker, as we don't have a "source" for it in this package.
+-/* Error() */ //@item(Error, "Error", "func() string", "method")
+-
 -type AliasType = int //@item(sigAliasType, "AliasType", "AliasType", "type")
 -
 -func foo(i int, b bool) {} //@item(snipFoo, "foo", "func(i int, b bool)", "func")
@@ -102170,7 +109733,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/statements/append.go b/gopls/internal/lsp/testdata/statements/append.go
 --- a/gopls/internal/lsp/testdata/statements/append.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/statements/append.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/statements/append.go	1970-01-01 08:00:00
 @@ -1,42 +0,0 @@
 -package statements
 -
@@ -102214,25 +109777,9 @@
 -
 -	foo[0] = app //@complete(" //"),snippet(" //", stmtFooAppend, "append(foo[0], ${1:})", "append(foo[0], ${1:})")
 -}
-diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go
---- a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
--package statements
--
--import "os"
--
--func two() error {
--	var s struct{ err error }
--
--	/* if s.err != nil { return s.err } */ //@item(stmtTwoIfErrReturn, "if s.err != nil { return s.err }", "", "")
--
--	_, s.err = os.Open("foo")
--	//@snippet("", stmtTwoIfErrReturn, "", "if s.err != nil {\n\treturn ${1:s.err}\n\\}")
--}
 diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_return.go b/gopls/internal/lsp/testdata/statements/if_err_check_return.go
 --- a/gopls/internal/lsp/testdata/statements/if_err_check_return.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/statements/if_err_check_return.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/statements/if_err_check_return.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -package statements
 -
@@ -102261,9 +109808,25 @@
 -	_, err = os.Open("foo")
 -	if //@snippet("//", stmtOneIfErrReturn, "", "if err != nil {\n\treturn 0, 0, nil, nil, nil, bytes.Buffer{\\}, ${1:err}\n\\}")
 -}
+diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go
+--- a/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/testdata/statements/if_err_check_return_2.go	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-package statements
+-
+-import "os"
+-
+-func two() error {
+-	var s struct{ err error }
+-
+-	/* if s.err != nil { return s.err } */ //@item(stmtTwoIfErrReturn, "if s.err != nil { return s.err }", "", "")
+-
+-	_, s.err = os.Open("foo")
+-	//@snippet("", stmtTwoIfErrReturn, "", "if s.err != nil {\n\treturn ${1:s.err}\n\\}")
+-}
 diff -urN a/gopls/internal/lsp/testdata/statements/if_err_check_test.go b/gopls/internal/lsp/testdata/statements/if_err_check_test.go
 --- a/gopls/internal/lsp/testdata/statements/if_err_check_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/statements/if_err_check_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/statements/if_err_check_test.go	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 -package statements
 -
@@ -102287,7 +109850,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/stub/other/other.go b/gopls/internal/lsp/testdata/stub/other/other.go
 --- a/gopls/internal/lsp/testdata/stub/other/other.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/other/other.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/other/other.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -package other
 -
@@ -102301,7 +109864,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_add_selector.go b/gopls/internal/lsp/testdata/stub/stub_add_selector.go
 --- a/gopls/internal/lsp/testdata/stub/stub_add_selector.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go	1970-01-01 08:00:00
 @@ -1,12 +0,0 @@
 -package stub
 -
@@ -102312,12 +109875,12 @@
 -// then our implementation must add the import/package selector
 -// in the concrete method if the concrete type is outside of the interface
 -// package
--var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "")
+-var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "quickfix", "")
 -
 -type readerFrom struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_add_selector.go.golden	1970-01-01 08:00:00
 @@ -1,19 +0,0 @@
 --- suggestedfix_stub_add_selector_10_23 --
 -package stub
@@ -102329,18 +109892,18 @@
 -// then our implementation must add the import/package selector
 -// in the concrete method if the concrete type is outside of the interface
 -// package
--var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "refactor.rewrite", "")
+-var _ io.ReaderFrom = &readerFrom{} //@suggestedfix("&readerFrom", "quickfix", "")
 -
 -type readerFrom struct{}
 -
--// ReadFrom implements io.ReaderFrom
+-// ReadFrom implements io.ReaderFrom.
 -func (*readerFrom) ReadFrom(r io.Reader) (n int64, err error) {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign.go b/gopls/internal/lsp/testdata/stub/stub_assign.go
 --- a/gopls/internal/lsp/testdata/stub/stub_assign.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_assign.go	1970-01-01 08:00:00
 @@ -1,10 +0,0 @@
 -package stub
 -
@@ -102348,13 +109911,13 @@
 -
 -func main() {
 -	var br io.ByteWriter
--	br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+-	br = &byteWriter{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type byteWriter struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_assign.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_assign.go.golden	1970-01-01 08:00:00
 @@ -1,17 +0,0 @@
 --- suggestedfix_stub_assign_7_7 --
 -package stub
@@ -102363,19 +109926,19 @@
 -
 -func main() {
 -	var br io.ByteWriter
--	br = &byteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+-	br = &byteWriter{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type byteWriter struct{}
 -
--// WriteByte implements io.ByteWriter
+-// WriteByte implements io.ByteWriter.
 -func (*byteWriter) WriteByte(c byte) error {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go
 --- a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package stub
 -
@@ -102384,13 +109947,13 @@
 -func main() {
 -	var br io.ByteWriter
 -	var i int
--	i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+-	i, br = 1, &multiByteWriter{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type multiByteWriter struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_assign_multivars.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- suggestedfix_stub_assign_multivars_8_13 --
 -package stub
@@ -102400,24 +109963,24 @@
 -func main() {
 -	var br io.ByteWriter
 -	var i int
--	i, br = 1, &multiByteWriter{} //@suggestedfix("&", "refactor.rewrite", "")
+-	i, br = 1, &multiByteWriter{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type multiByteWriter struct{}
 -
--// WriteByte implements io.ByteWriter
+-// WriteByte implements io.ByteWriter.
 -func (*multiByteWriter) WriteByte(c byte) error {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_call_expr.go b/gopls/internal/lsp/testdata/stub/stub_call_expr.go
 --- a/gopls/internal/lsp/testdata/stub/stub_call_expr.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package stub
 -
 -func main() {
--	check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "")
+-	check(&callExpr{}) //@suggestedfix("&", "quickfix", "")
 -}
 -
 -func check(err error) {
@@ -102429,13 +109992,13 @@
 -type callExpr struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_call_expr.go.golden	1970-01-01 08:00:00
 @@ -1,20 +0,0 @@
 --- suggestedfix_stub_call_expr_4_8 --
 -package stub
 -
 -func main() {
--	check(&callExpr{}) //@suggestedfix("&", "refactor.rewrite", "")
+-	check(&callExpr{}) //@suggestedfix("&", "quickfix", "")
 -}
 -
 -func check(err error) {
@@ -102446,14 +110009,14 @@
 -
 -type callExpr struct{}
 -
--// Error implements error
+-// Error implements error.
 -func (*callExpr) Error() string {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_embedded.go b/gopls/internal/lsp/testdata/stub/stub_embedded.go
 --- a/gopls/internal/lsp/testdata/stub/stub_embedded.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -package stub
 -
@@ -102462,7 +110025,7 @@
 -	"sort"
 -)
 -
--var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+-var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "quickfix", "")
 -
 -type embeddedConcrete struct{}
 -
@@ -102472,7 +110035,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_embedded.go.golden	1970-01-01 08:00:00
 @@ -1,37 +0,0 @@
 --- suggestedfix_stub_embedded_8_27 --
 -package stub
@@ -102482,26 +110045,26 @@
 -	"sort"
 -)
 -
--var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+-var _ embeddedInterface = (*embeddedConcrete)(nil) //@suggestedfix("(", "quickfix", "")
 -
 -type embeddedConcrete struct{}
 -
--// Len implements embeddedInterface
+-// Len implements embeddedInterface.
 -func (*embeddedConcrete) Len() int {
 -	panic("unimplemented")
 -}
 -
--// Less implements embeddedInterface
+-// Less implements embeddedInterface.
 -func (*embeddedConcrete) Less(i int, j int) bool {
 -	panic("unimplemented")
 -}
 -
--// Read implements embeddedInterface
+-// Read implements embeddedInterface.
 -func (*embeddedConcrete) Read(p []byte) (n int, err error) {
 -	panic("unimplemented")
 -}
 -
--// Swap implements embeddedInterface
+-// Swap implements embeddedInterface.
 -func (*embeddedConcrete) Swap(i int, j int) {
 -	panic("unimplemented")
 -}
@@ -102513,36 +110076,36 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_err.go b/gopls/internal/lsp/testdata/stub/stub_err.go
 --- a/gopls/internal/lsp/testdata/stub/stub_err.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_err.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_err.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package stub
 -
 -func main() {
--	var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "")
+-	var br error = &customErr{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type customErr struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_err.go.golden b/gopls/internal/lsp/testdata/stub/stub_err.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_err.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_err.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_err.go.golden	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 --- suggestedfix_stub_err_4_17 --
 -package stub
 -
 -func main() {
--	var br error = &customErr{} //@suggestedfix("&", "refactor.rewrite", "")
+-	var br error = &customErr{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type customErr struct{}
 -
--// Error implements error
+-// Error implements error.
 -func (*customErr) Error() string {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_function_return.go b/gopls/internal/lsp/testdata/stub/stub_function_return.go
 --- a/gopls/internal/lsp/testdata/stub/stub_function_return.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package stub
 -
@@ -102551,13 +110114,13 @@
 -)
 -
 -func newCloser() io.Closer {
--	return closer{} //@suggestedfix("c", "refactor.rewrite", "")
+-	return closer{} //@suggestedfix("c", "quickfix", "")
 -}
 -
 -type closer struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_function_return.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- suggestedfix_stub_function_return_8_9 --
 -package stub
@@ -102567,19 +110130,19 @@
 -)
 -
 -func newCloser() io.Closer {
--	return closer{} //@suggestedfix("c", "refactor.rewrite", "")
+-	return closer{} //@suggestedfix("c", "quickfix", "")
 -}
 -
 -type closer struct{}
 -
--// Close implements io.Closer
+-// Close implements io.Closer.
 -func (closer) Close() error {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go
 --- a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -102590,7 +110153,7 @@
 -
 -// This file tests that that the stub method generator accounts for concrete
 -// types that have type parameters defined.
--var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom")
+-var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "quickfix", "Implement io.ReaderFrom")
 -
 -type genReader[T, Y any] struct {
 -	T T
@@ -102598,7 +110161,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_generic_receiver.go.golden	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 --- suggestedfix_stub_generic_receiver_10_23 --
 -//go:build go1.18
@@ -102610,21 +110173,21 @@
 -
 -// This file tests that that the stub method generator accounts for concrete
 -// types that have type parameters defined.
--var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "refactor.rewrite", "Implement io.ReaderFrom")
+-var _ io.ReaderFrom = &genReader[string, int]{} //@suggestedfix("&genReader", "quickfix", "Implement io.ReaderFrom")
 -
 -type genReader[T, Y any] struct {
 -	T T
 -	Y Y
 -}
 -
--// ReadFrom implements io.ReaderFrom
+-// ReadFrom implements io.ReaderFrom.
 -func (*genReader[T, Y]) ReadFrom(r io.Reader) (n int64, err error) {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go
 --- a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 -package stub
 -
@@ -102640,13 +110203,13 @@
 -
 -var (
 -	_ Reader
--	_ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+-	_ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "quickfix", "")
 -)
 -
 -type ignoredResetter struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_ignored_imports.go.golden	1970-01-01 08:00:00
 @@ -1,25 +0,0 @@
 --- suggestedfix_stub_ignored_imports_15_20 --
 -package stub
@@ -102663,19 +110226,19 @@
 -
 -var (
 -	_ Reader
--	_ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "refactor.rewrite", "")
+-	_ zlib.Resetter = (*ignoredResetter)(nil) //@suggestedfix("(", "quickfix", "")
 -)
 -
 -type ignoredResetter struct{}
 -
--// Reset implements zlib.Resetter
+-// Reset implements zlib.Resetter.
 -func (*ignoredResetter) Reset(r Reader, dict []byte) error {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_issue2606.go b/gopls/internal/lsp/testdata/stub/stub_issue2606.go
 --- a/gopls/internal/lsp/testdata/stub/stub_issue2606.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go	1970-01-01 08:00:00
 @@ -1,7 +0,0 @@
 -package stub
 -
@@ -102683,10 +110246,10 @@
 -
 -type C int
 -
--var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "")
+-var _ I = C(0) //@suggestedfix("C", "quickfix", "")
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_issue2606.go.golden	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 --- suggestedfix_stub_issue2606_7_11 --
 -package stub
@@ -102695,16 +110258,16 @@
 -
 -type C int
 -
--// Error implements I
+-// Error implements I.
 -func (C) Error() string {
 -	panic("unimplemented")
 -}
 -
--var _ I = C(0) //@suggestedfix("C", "refactor.rewrite", "")
+-var _ I = C(0) //@suggestedfix("C", "quickfix", "")
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_multi_var.go b/gopls/internal/lsp/testdata/stub/stub_multi_var.go
 --- a/gopls/internal/lsp/testdata/stub/stub_multi_var.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package stub
 -
@@ -102714,12 +110277,12 @@
 -// has multiple values on the same line can still be
 -// analyzed correctly to target the interface implementation
 -// diagnostic.
--var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "")
+-var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "quickfix", "")
 -
 -type multiVar struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_multi_var.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- suggestedfix_stub_multi_var_9_38 --
 -package stub
@@ -102730,31 +110293,31 @@
 -// has multiple values on the same line can still be
 -// analyzed correctly to target the interface implementation
 -// diagnostic.
--var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "refactor.rewrite", "")
+-var one, two, three io.Reader = nil, &multiVar{}, nil //@suggestedfix("&", "quickfix", "")
 -
 -type multiVar struct{}
 -
--// Read implements io.Reader
+-// Read implements io.Reader.
 -func (*multiVar) Read(p []byte) (n int, err error) {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_pointer.go b/gopls/internal/lsp/testdata/stub/stub_pointer.go
 --- a/gopls/internal/lsp/testdata/stub/stub_pointer.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package stub
 -
 -import "io"
 -
 -func getReaderFrom() io.ReaderFrom {
--	return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "")
+-	return &pointerImpl{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type pointerImpl struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_pointer.go.golden	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 --- suggestedfix_stub_pointer_6_9 --
 -package stub
@@ -102762,19 +110325,19 @@
 -import "io"
 -
 -func getReaderFrom() io.ReaderFrom {
--	return &pointerImpl{} //@suggestedfix("&", "refactor.rewrite", "")
+-	return &pointerImpl{} //@suggestedfix("&", "quickfix", "")
 -}
 -
 -type pointerImpl struct{}
 -
--// ReadFrom implements io.ReaderFrom
+-// ReadFrom implements io.ReaderFrom.
 -func (*pointerImpl) ReadFrom(r io.Reader) (n int64, err error) {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go
 --- a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package stub
 -
@@ -102783,13 +110346,13 @@
 -	myio "io"
 -)
 -
--var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "")
+-var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "quickfix", "")
 -var _ myio.Reader
 -
 -type myIO struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import.go.golden	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 --- suggestedfix_stub_renamed_import_8_23 --
 -package stub
@@ -102799,19 +110362,19 @@
 -	myio "io"
 -)
 -
--var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "refactor.rewrite", "")
+-var _ zlib.Resetter = &myIO{} //@suggestedfix("&", "quickfix", "")
 -var _ myio.Reader
 -
 -type myIO struct{}
 -
--// Reset implements zlib.Resetter
+-// Reset implements zlib.Resetter.
 -func (*myIO) Reset(r myio.Reader, dict []byte) error {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go
 --- a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package stub
 -
@@ -102823,12 +110386,12 @@
 -// method references an import from its own package
 -// that the concrete type does not yet import, and that import happens
 -// to be renamed, then we prefer the renaming of the interface.
--var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "")
+-var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "quickfix", "")
 -
 -type otherInterfaceImpl struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_renamed_import_iface.go.golden	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 --- suggestedfix_stub_renamed_import_iface_11_25 --
 -package stub
@@ -102843,18 +110406,18 @@
 -// method references an import from its own package
 -// that the concrete type does not yet import, and that import happens
 -// to be renamed, then we prefer the renaming of the interface.
--var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "refactor.rewrite", "")
+-var _ other.Interface = &otherInterfaceImpl{} //@suggestedfix("&otherInterfaceImpl", "quickfix", "")
 -
 -type otherInterfaceImpl struct{}
 -
--// Get implements other.Interface
+-// Get implements other.Interface.
 -func (*otherInterfaceImpl) Get(context.Context) *bytes.Buffer {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_stdlib.go b/gopls/internal/lsp/testdata/stub/stub_stdlib.go
 --- a/gopls/internal/lsp/testdata/stub/stub_stdlib.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go	1970-01-01 08:00:00
 @@ -1,9 +0,0 @@
 -package stub
 -
@@ -102862,12 +110425,12 @@
 -	"io"
 -)
 -
--var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "")
+-var _ io.Writer = writer{} //@suggestedfix("w", "quickfix", "")
 -
 -type writer struct{}
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_stdlib.go.golden	1970-01-01 08:00:00
 @@ -1,16 +0,0 @@
 --- suggestedfix_stub_stdlib_7_19 --
 -package stub
@@ -102876,18 +110439,18 @@
 -	"io"
 -)
 -
--var _ io.Writer = writer{} //@suggestedfix("w", "refactor.rewrite", "")
+-var _ io.Writer = writer{} //@suggestedfix("w", "quickfix", "")
 -
 -type writer struct{}
 -
--// Write implements io.Writer
+-// Write implements io.Writer.
 -func (writer) Write(p []byte) (n int, err error) {
 -	panic("unimplemented")
 -}
 -
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go
 --- a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -package stub
 -
@@ -102897,7 +110460,7 @@
 -import "io"
 -
 -func newReadCloser() io.ReadCloser {
--	return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "")
+-	return rdcloser{} //@suggestedfix("rd", "quickfix", "")
 -}
 -
 -type (
@@ -102918,7 +110481,7 @@
 -)
 diff -urN a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden
 --- a/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/stub/stub_typedecl_group.go.golden	1970-01-01 08:00:00
 @@ -1,39 +0,0 @@
 --- suggestedfix_stub_typedecl_group_9_9 --
 -package stub
@@ -102929,7 +110492,7 @@
 -import "io"
 -
 -func newReadCloser() io.ReadCloser {
--	return rdcloser{} //@suggestedfix("rd", "refactor.rewrite", "")
+-	return rdcloser{} //@suggestedfix("rd", "quickfix", "")
 -}
 -
 -type (
@@ -102938,12 +110501,12 @@
 -	B        int
 -)
 -
--// Close implements io.ReadCloser
+-// Close implements io.ReadCloser.
 -func (rdcloser) Close() error {
 -	panic("unimplemented")
 -}
 -
--// Read implements io.ReadCloser
+-// Read implements io.ReadCloser.
 -func (rdcloser) Read(p []byte) (n int, err error) {
 -	panic("unimplemented")
 -}
@@ -102961,7 +110524,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go
 --- a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go	1970-01-01 08:00:00
 @@ -1,11 +0,0 @@
 -package suggestedfix
 -
@@ -102976,7 +110539,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden
 --- a/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/suggestedfix/has_suggested_fix.go.golden	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 --- suggestedfix_has_suggested_fix_9_2 --
 -package suggestedfix
@@ -102991,354 +110554,31 @@
 -	log.Print(s)
 -}
 -
-diff -urN a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden
---- a/gopls/internal/lsp/testdata/summary_go1.18.txt.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/summary_go1.18.txt.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,32 +0,0 @@
---- summary --
--CallHierarchyCount = 2
--CodeLensCount = 5
--CompletionsCount = 264
--CompletionSnippetCount = 115
--UnimportedCompletionsCount = 5
--DeepCompletionsCount = 5
--FuzzyCompletionsCount = 8
--RankedCompletionsCount = 174
--CaseSensitiveCompletionsCount = 4
--DiagnosticsCount = 42
--FoldingRangesCount = 2
--FormatCount = 6
--ImportCount = 8
--SemanticTokenCount = 3
--SuggestedFixCount = 71
--FunctionExtractionCount = 27
--MethodExtractionCount = 6
--DefinitionsCount = 47
--TypeDefinitionsCount = 18
--HighlightsCount = 69
--InlayHintsCount = 5
--ReferencesCount = 30
--RenamesCount = 48
--PrepareRenamesCount = 7
--SymbolsCount = 2
--WorkspaceSymbolsCount = 20
--SignaturesCount = 33
--LinksCount = 7
--ImplementationsCount = 26
--SelectionRangesCount = 3
--
 diff -urN a/gopls/internal/lsp/testdata/summary.txt.golden b/gopls/internal/lsp/testdata/summary.txt.golden
 --- a/gopls/internal/lsp/testdata/summary.txt.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/summary.txt.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,32 +0,0 @@
++++ b/gopls/internal/lsp/testdata/summary.txt.golden	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
 --- summary --
 -CallHierarchyCount = 2
--CodeLensCount = 5
--CompletionsCount = 263
--CompletionSnippetCount = 106
--UnimportedCompletionsCount = 5
+-CompletionsCount = 194
+-CompletionSnippetCount = 74
 -DeepCompletionsCount = 5
 -FuzzyCompletionsCount = 8
--RankedCompletionsCount = 164
+-RankedCompletionsCount = 166
 -CaseSensitiveCompletionsCount = 4
--DiagnosticsCount = 42
--FoldingRangesCount = 2
--FormatCount = 6
--ImportCount = 8
 -SemanticTokenCount = 3
--SuggestedFixCount = 65
--FunctionExtractionCount = 27
--MethodExtractionCount = 6
--DefinitionsCount = 47
--TypeDefinitionsCount = 18
--HighlightsCount = 69
--InlayHintsCount = 4
--ReferencesCount = 30
--RenamesCount = 41
+-SuggestedFixCount = 80
+-MethodExtractionCount = 8
+-InlayHintsCount = 5
+-RenamesCount = 48
 -PrepareRenamesCount = 7
--SymbolsCount = 1
--WorkspaceSymbolsCount = 20
--SignaturesCount = 33
+-SignaturesCount = 32
 -LinksCount = 7
--ImplementationsCount = 16
 -SelectionRangesCount = 3
 -
-diff -urN a/gopls/internal/lsp/testdata/symbols/go1.18.go b/gopls/internal/lsp/testdata/symbols/go1.18.go
---- a/gopls/internal/lsp/testdata/symbols/go1.18.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--//go:build go1.18
--// +build go1.18
--
--package main
--
--type T[P any] struct { //@symbol("T", "T", "Struct", "struct{...}", "T", "")
--	F P //@symbol("F", "F", "Field", "P", "", "T")
--}
--
--type Constraint interface { //@symbol("Constraint", "Constraint", "Interface", "interface{...}", "Constraint", "")
--	~int | struct{ int } //@symbol("~int | struct{int}", "~int | struct{ int }", "Field", "", "", "Constraint")
--
--	// TODO(rfindley): the selection range below is the entire interface field.
--	// Can we reduce it?
--	interface{ M() } //@symbol("interface{...}", "interface{ M() }", "Field", "", "iFaceField", "Constraint"), symbol("M", "M", "Method", "func()", "", "iFaceField")
--}
-diff -urN a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden
---- a/gopls/internal/lsp/testdata/symbols/go1.18.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/symbols/go1.18.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
---- symbols --
--T Struct 6:6-6:7
--	F Field 7:2-7:3
--Constraint Interface 10:6-10:16
--	interface{...} Field 15:2-15:18
--	~int | struct{int} Field 11:2-11:22
--
-diff -urN a/gopls/internal/lsp/testdata/symbols/main.go b/gopls/internal/lsp/testdata/symbols/main.go
---- a/gopls/internal/lsp/testdata/symbols/main.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/symbols/main.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,91 +0,0 @@
--package main
--
--import (
--	"io"
--)
--
--// Each symbol marker in this file defines the following information:
--//  symbol(name, selectionSpan, kind, detail, id, parentID)
--//    - name: DocumentSymbol.Name
--//    - selectionSpan: DocumentSymbol.SelectionRange
--//    - kind: DocumentSymbol.Kind
--//    - detail: DocumentSymbol.Detail
--//    - id: if non-empty, a unique identifier for this symbol
--//    - parentID: if non-empty, the id of the parent of this symbol
--//
--// This data in aggregate defines a set of document symbols and their
--// parent-child relationships, which is compared against the DocummentSymbols
--// response from gopls for the current file.
--//
--// TODO(rfindley): the symbol annotations here are complicated and difficult to
--// maintain. It would be simpler to just write out the full expected response
--// in the golden file, perhaps as raw JSON.
--
--var _ = 1
--
--var x = 42 //@symbol("x", "x", "Variable", "", "", "")
--
--var nested struct { //@symbol("nested", "nested", "Variable", "struct{...}", "nested", "")
--	nestedField struct { //@symbol("nestedField", "nestedField", "Field", "struct{...}", "nestedField", "nested")
--		f int //@symbol("f", "f", "Field", "int", "", "nestedField")
--	}
--}
--
--const y = 43 //@symbol("y", "y", "Constant", "", "", "")
--
--type Number int //@symbol("Number", "Number", "Class", "int", "", "")
--
--type Alias = string //@symbol("Alias", "Alias", "Class", "string", "", "")
--
--type NumberAlias = Number //@symbol("NumberAlias", "NumberAlias", "Class", "Number", "", "")
--
--type (
--	Boolean   bool   //@symbol("Boolean", "Boolean", "Class", "bool", "", "")
--	BoolAlias = bool //@symbol("BoolAlias", "BoolAlias", "Class", "bool", "", "")
--)
--
--type Foo struct { //@symbol("Foo", "Foo", "Struct", "struct{...}", "Foo", "")
--	Quux                    //@symbol("Quux", "Quux", "Field", "Quux", "", "Foo")
--	W         io.Writer     //@symbol("W", "W", "Field", "io.Writer", "", "Foo")
--	Bar       int           //@symbol("Bar", "Bar", "Field", "int", "", "Foo")
--	baz       string        //@symbol("baz", "baz", "Field", "string", "", "Foo")
--	funcField func(int) int //@symbol("funcField", "funcField", "Field", "func(int) int", "", "Foo")
--}
--
--type Quux struct { //@symbol("Quux", "Quux", "Struct", "struct{...}", "Quux", "")
--	X, Y float64 //@symbol("X", "X", "Field", "float64", "", "Quux"), symbol("Y", "Y", "Field", "float64", "", "Quux")
--}
--
--type EmptyStruct struct{} //@symbol("EmptyStruct", "EmptyStruct", "Struct", "struct{}", "", "")
--
--func (f Foo) Baz() string { //@symbol("(Foo).Baz", "Baz", "Method", "func() string", "", "")
--	return f.baz
--}
--
--func _() {}
--
--func (q *Quux) Do() {} //@symbol("(*Quux).Do", "Do", "Method", "func()", "", "")
--
--func main() { //@symbol("main", "main", "Function", "func()", "", "")
--}
--
--type Stringer interface { //@symbol("Stringer", "Stringer", "Interface", "interface{...}", "Stringer", "")
--	String() string //@symbol("String", "String", "Method", "func() string", "", "Stringer")
--}
--
--type ABer interface { //@symbol("ABer", "ABer", "Interface", "interface{...}", "ABer", "")
--	B()        //@symbol("B", "B", "Method", "func()", "", "ABer")
--	A() string //@symbol("A", "A", "Method", "func() string", "", "ABer")
--}
--
--type WithEmbeddeds interface { //@symbol("WithEmbeddeds", "WithEmbeddeds", "Interface", "interface{...}", "WithEmbeddeds", "")
--	Do()      //@symbol("Do", "Do", "Method", "func()", "", "WithEmbeddeds")
--	ABer      //@symbol("ABer", "ABer", "Field", "ABer", "", "WithEmbeddeds")
--	io.Writer //@symbol("Writer", "Writer", "Field", "io.Writer", "", "WithEmbeddeds")
--}
--
--type EmptyInterface interface{} //@symbol("EmptyInterface", "EmptyInterface", "Interface", "interface{}", "", "")
--
--func Dunk() int { return 0 } //@symbol("Dunk", "Dunk", "Function", "func() int", "", "")
--
--func dunk() {} //@symbol("dunk", "dunk", "Function", "func()", "", "")
-diff -urN a/gopls/internal/lsp/testdata/symbols/main.go.golden b/gopls/internal/lsp/testdata/symbols/main.go.golden
---- a/gopls/internal/lsp/testdata/symbols/main.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/symbols/main.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,36 +0,0 @@
---- symbols --
--x Variable 26:5-26:6
--nested Variable 28:5-28:11
--	nestedField Field 29:2-29:13
--y Constant 34:7-34:8
--Number Class 36:6-36:12
--Alias Class 38:6-38:11
--NumberAlias Class 40:6-40:17
--Boolean Class 43:2-43:9
--BoolAlias Class 44:2-44:11
--Foo Struct 47:6-47:9
--	Bar Field 50:2-50:5
--	Quux Field 48:2-48:6
--	W Field 49:2-49:3
--	baz Field 51:2-51:5
--	funcField Field 52:2-52:11
--Quux Struct 55:6-55:10
--	X Field 56:2-56:3
--	Y Field 56:5-56:6
--EmptyStruct Struct 59:6-59:17
--(Foo).Baz Method 61:14-61:17
--(*Quux).Do Method 67:16-67:18
--main Function 69:6-69:10
--Stringer Interface 72:6-72:14
--	String Method 73:2-73:8
--ABer Interface 76:6-76:10
--	A Method 78:2-78:3
--	B Method 77:2-77:3
--WithEmbeddeds Interface 81:6-81:19
--	ABer Field 83:2-83:6
--	Do Method 82:2-82:4
--	Writer Field 84:5-84:11
--EmptyInterface Interface 87:6-87:20
--Dunk Function 89:6-89:10
--dunk Function 91:6-91:10
--
-diff -urN a/gopls/internal/lsp/testdata/testy/testy.go b/gopls/internal/lsp/testdata/testy/testy.go
---- a/gopls/internal/lsp/testdata/testy/testy.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/testy/testy.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,5 +0,0 @@
--package testy
--
--func a() { //@mark(identA, "a"),item(funcA, "a", "func()", "func"),refs("a", identA, testyA)
--	//@complete("", funcA)
--}
-diff -urN a/gopls/internal/lsp/testdata/testy/testy_test.go b/gopls/internal/lsp/testdata/testy/testy_test.go
---- a/gopls/internal/lsp/testdata/testy/testy_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/testy/testy_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
--package testy
--
--import (
--	"testing"
--
--	sig "golang.org/lsptests/signature"
--	"golang.org/lsptests/snippets"
--)
--
--func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func")
--	var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared (and|but) not used", "error"),refs("x", testyX)
--	a()       //@mark(testyA, "a")
--}
--
--func _() {
--	_ = snippets.X(nil) //@signature("nil", "X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias", 0)
--	var _ sig.Alias
--}
-diff -urN a/gopls/internal/lsp/testdata/testy/testy_test.go.golden b/gopls/internal/lsp/testdata/testy/testy_test.go.golden
---- a/gopls/internal/lsp/testdata/testy/testy_test.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/testy/testy_test.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
---- X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias-signature --
--X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias
--
-diff -urN a/gopls/internal/lsp/testdata/typdef/typdef.go b/gopls/internal/lsp/testdata/typdef/typdef.go
---- a/gopls/internal/lsp/testdata/typdef/typdef.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typdef/typdef.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,65 +0,0 @@
--package typdef
--
--type Struct struct { //@item(Struct, "Struct", "struct{...}", "struct")
--	Field string
--}
--
--type Int int //@item(Int, "Int", "int", "type")
--
--func _() {
--	var (
--		value Struct
--		point *Struct
--	)
--	_ = value //@typdef("value", Struct)
--	_ = point //@typdef("point", Struct)
--
--	var (
--		array   [3]Struct
--		slice   []Struct
--		ch      chan Struct
--		complex [3]chan *[5][]Int
--	)
--	_ = array   //@typdef("array", Struct)
--	_ = slice   //@typdef("slice", Struct)
--	_ = ch      //@typdef("ch", Struct)
--	_ = complex //@typdef("complex", Int)
--
--	var s struct {
--		x struct {
--			xx struct {
--				field1 []Struct
--				field2 []Int
--			}
--		}
--	}
--	s.x.xx.field1 //@typdef("field1", Struct)
--	s.x.xx.field2 //@typdef("field2", Int)
--}
--
--func F1() Int                              { return 0 }
--func F2() (Int, float64)                   { return 0, 0 }
--func F3() (Struct, int, bool, error)       { return Struct{}, 0, false, nil }
--func F4() (**int, Int, bool, *error)       { return nil, Struct{}, false, nil }
--func F5() (int, float64, error, Struct)    { return 0, 0, nil, Struct{} }
--func F6() (int, float64, ***Struct, error) { return 0, 0, nil, nil }
--
--func _() {
--	F1() //@typdef("F1", Int)
--	F2() //@typdef("F2", Int)
--	F3() //@typdef("F3", Struct)
--	F4() //@typdef("F4", Int)
--	F5() //@typdef("F5", Struct)
--	F6() //@typdef("F6", Struct)
--
--	f := func() Int { return 0 }
--	f() //@typdef("f", Int)
--}
--
--// https://github.com/golang/go/issues/38589#issuecomment-620350922
--func _() {
--	type myFunc func(int) Int //@item(myFunc, "myFunc", "func", "type")
--
--	var foo myFunc
--	bar := foo() //@typdef("foo", myFunc)
--}
 diff -urN a/gopls/internal/lsp/testdata/typeassert/type_assert.go b/gopls/internal/lsp/testdata/typeassert/type_assert.go
 --- a/gopls/internal/lsp/testdata/typeassert/type_assert.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typeassert/type_assert.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/typeassert/type_assert.go	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -package typeassert
 -
@@ -103366,7 +110606,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go
 --- a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go	1970-01-01 08:00:00
 @@ -1,5 +0,0 @@
 -package typeerrors
 -
@@ -103375,7 +110615,7 @@
 -func y() { return nil, "hello" } //@suggestedfix("nil", "quickfix", "")
 diff -urN a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden
 --- a/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/typeerrors/noresultvalues.go.golden	1970-01-01 08:00:00
 @@ -1,14 +0,0 @@
 --- suggestedfix_noresultvalues_3_19 --
 -package typeerrors
@@ -103393,7 +110633,7 @@
 -
 diff -urN a/gopls/internal/lsp/testdata/typemods/type_mods.go b/gopls/internal/lsp/testdata/typemods/type_mods.go
 --- a/gopls/internal/lsp/testdata/typemods/type_mods.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typemods/type_mods.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/typemods/type_mods.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -package typemods
 -
@@ -103418,7 +110658,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/typeparams/type_params.go b/gopls/internal/lsp/testdata/typeparams/type_params.go
 --- a/gopls/internal/lsp/testdata/typeparams/type_params.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/typeparams/type_params.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/typeparams/type_params.go	1970-01-01 08:00:00
 @@ -1,61 +0,0 @@
 -//go:build go1.18
 -// +build go1.18
@@ -103483,7 +110723,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/types/types.go b/gopls/internal/lsp/testdata/types/types.go
 --- a/gopls/internal/lsp/testdata/types/types.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/types/types.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/types/types.go	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 -package types
 -
@@ -103503,149 +110743,9 @@
 -
 -func (*X) Bobby() {}
 -func (*Y) Bobby() {}
-diff -urN a/gopls/internal/lsp/testdata/undeclared/var.go b/gopls/internal/lsp/testdata/undeclared/var.go
---- a/gopls/internal/lsp/testdata/undeclared/var.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/undeclared/var.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,14 +0,0 @@
--package undeclared
--
--func m() int {
--	z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
--	if 100 < 90 {
--		z = 1
--	} else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
--		z = 4
--	}
--	for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
--	}
--	r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
--	return z
--}
-diff -urN a/gopls/internal/lsp/testdata/undeclared/var.go.golden b/gopls/internal/lsp/testdata/undeclared/var.go.golden
---- a/gopls/internal/lsp/testdata/undeclared/var.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/undeclared/var.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,51 +0,0 @@
---- suggestedfix_var_10_6 --
--package undeclared
--
--func m() int {
--	z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
--	if 100 < 90 {
--		z = 1
--	} else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
--		z = 4
--	}
--	i := 
--	for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
--	}
--	r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
--	return z
--}
--
---- suggestedfix_var_4_12 --
--package undeclared
--
--func m() int {
--	y := 
--	z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
--	if 100 < 90 {
--		z = 1
--	} else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
--		z = 4
--	}
--	for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
--	}
--	r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
--	return z
--}
--
---- suggestedfix_var_7_18 --
--package undeclared
--
--func m() int {
--	z, _ := 1+y, 11 //@diag("y", "compiler", "(undeclared name|undefined): y", "error"),suggestedfix("y", "quickfix", "")
--	n := 
--	if 100 < 90 {
--		z = 1
--	} else if 100 > n+2 { //@diag("n", "compiler", "(undeclared name|undefined): n", "error"),suggestedfix("n", "quickfix", "")
--		z = 4
--	}
--	for i < 200 { //@diag("i", "compiler", "(undeclared name|undefined): i", "error"),suggestedfix("i", "quickfix", "")
--	}
--	r() //@diag("r", "compiler", "(undeclared name|undefined): r", "error")
--	return z
--}
--
-diff -urN a/gopls/internal/lsp/testdata/unimported/export_test.go b/gopls/internal/lsp/testdata/unimported/export_test.go
---- a/gopls/internal/lsp/testdata/unimported/export_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unimported/export_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
--package unimported
--
--var TestExport int //@item(testexport, "TestExport", "var (from \"golang.org/lsptests/unimported\")", "var")
-diff -urN a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go
---- a/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unimported/unimported_cand_type.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,16 +0,0 @@
--package unimported
--
--import (
--	_ "context"
--
--	"golang.org/lsptests/baz"
--	_ "golang.org/lsptests/signature" // provide type information for unimported completions in the other file
--)
--
--func _() {
--	foo.StructFoo{} //@item(litFooStructFoo, "foo.StructFoo{}", "struct{...}", "struct")
--
--	// We get the literal completion for "foo.StructFoo{}" even though we haven't
--	// imported "foo" yet.
--	baz.FooStruct = f //@snippet(" //", litFooStructFoo, "foo.StructFoo{$0\\}", "foo.StructFoo{$0\\}")
--}
-diff -urN a/gopls/internal/lsp/testdata/unimported/unimported.go.in b/gopls/internal/lsp/testdata/unimported/unimported.go.in
---- a/gopls/internal/lsp/testdata/unimported/unimported.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unimported/unimported.go.in	1970-01-01 00:00:00.000000000 +0000
-@@ -1,23 +0,0 @@
--package unimported
--
--func _() {
--	http //@unimported("p", nethttp)
--	// container/ring is extremely unlikely to be imported by anything, so shouldn't have type information.
--	ring.Ring     //@unimported("Ring", ringring)
--	signature.Foo //@unimported("Foo", signaturefoo)
--
--	context.Bac //@unimported(" //", contextBackground)
--}
--
--// Create markers for unimported std lib packages. Only for use by this test.
--/* http */ //@item(nethttp, "http", "\"net/http\"", "package")
--
--/* ring.Ring */ //@item(ringring, "Ring", "(from \"container/ring\")", "var")
--
--/* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"golang.org/lsptests/signature\")", "func")
--
--/* context.Background */ //@item(contextBackground, "Background", "func (from \"context\")", "func")
--
--// Now that we no longer type-check imported completions,
--// we don't expect the context.Background().Err method (see golang/go#58663).
--/* context.Background().Err */ //@item(contextBackgroundErr, "Background().Err", "func (from \"context\")", "method")
-diff -urN a/gopls/internal/lsp/testdata/unimported/x_test.go b/gopls/internal/lsp/testdata/unimported/x_test.go
---- a/gopls/internal/lsp/testdata/unimported/x_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unimported/x_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package unimported_test
--
--import (
--	"testing"
--)
--
--func TestSomething(t *testing.T) {
--	_ = unimported.TestExport //@unimported("TestExport", testexport)
--}
 diff -urN a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in
 --- a/gopls/internal/lsp/testdata/unresolved/unresolved.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/unresolved/unresolved.go.in	1970-01-01 08:00:00
 @@ -1,6 +0,0 @@
 -package unresolved
 -
@@ -103655,7 +110755,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/unsafe/unsafe.go b/gopls/internal/lsp/testdata/unsafe/unsafe.go
 --- a/gopls/internal/lsp/testdata/unsafe/unsafe.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/unsafe/unsafe.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/unsafe/unsafe.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -package unsafe

 -

@@ -103672,7 +110772,7 @@
 -}

 diff -urN a/gopls/internal/lsp/testdata/variadic/variadic.go.in b/gopls/internal/lsp/testdata/variadic/variadic.go.in
 --- a/gopls/internal/lsp/testdata/variadic/variadic.go.in	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/variadic/variadic.go.in	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/variadic/variadic.go.in	1970-01-01 08:00:00
 @@ -1,38 +0,0 @@
 -package variadic
 -
@@ -103714,7 +110814,7 @@
 -}
 diff -urN a/gopls/internal/lsp/testdata/variadic/variadic_intf.go b/gopls/internal/lsp/testdata/variadic/variadic_intf.go
 --- a/gopls/internal/lsp/testdata/variadic/variadic_intf.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/variadic/variadic_intf.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/testdata/variadic/variadic_intf.go	1970-01-01 08:00:00
 @@ -1,21 +0,0 @@
 -package variadic
 -
@@ -103737,239 +110837,79 @@
 -
 -	wantsBaz() //@rank(")", vImpl, vImplSlice),rank(")", vIntfSlice, vImplSlice)
 -}
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/a/a.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,9 +0,0 @@
--package a
+diff -urN a/gopls/internal/lsp/tests/README.md b/gopls/internal/lsp/tests/README.md
+--- a/gopls/internal/lsp/tests/README.md	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/tests/README.md	1970-01-01 08:00:00
+@@ -1,66 +0,0 @@
+-# Testing
 -
--var RandomGopherVariableA = "a"
+-LSP has "marker tests" defined in `internal/lsp/testdata`, as well as
+-traditional tests.
 -
--const RandomGopherConstantA = "a"
+-## Marker tests
 -
--const (
--	randomgopherinvariable = iota
--)
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
--package a
+-Marker tests have a standard input file, like
+-`internal/lsp/testdata/foo/bar.go`, and some may have a corresponding golden
+-file, like `internal/lsp/testdata/foo/bar.go.golden`. The former is the "input"
+-and the latter is the expected output.
 -
--var RandomGopherTestVariableA = "a"
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/a/a_x_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
--package a_test
+-Each input file contains annotations like
+-`//@suggestedfix("}", "refactor.rewrite", "Fill anonymous struct")`. These annotations are interpreted by
+-test runners to perform certain actions. The expected output after those actions
+-is encoded in the golden file.
 -
--var RandomGopherXTestVariableA = "a"
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/b/b.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/b/b.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,7 +0,0 @@
--package b
+-When tests are run, each annotation results in a new subtest, which is encoded
+-in the golden file with a heading like,
 -
--var RandomGopherVariableB = "b"
+-```bash
+--- suggestedfix_bar_11_21 --
+-// expected contents go here
+--- suggestedfix_bar_13_20 --
+-// expected contents go here
+-```
 -
--type RandomGopherStructB struct {
--	Bar int
--}
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/issue44806.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,10 +0,0 @@
--package main
+-The format of these headings vary: they are defined by the
+-[`Golden`](https://pkg.go.dev/golang.org/x/tools/gopls/internal/lsp/tests#Data.Golden)
+-function for each annotation. In the case above, the format is: annotation
+-name, file name, annotation line location, annotation character location.
 -
--type T struct{}
+-So, if `internal/lsp/testdata/foo/bar.go` has three `suggestedfix` annotations,
+-the golden file should have three headers with `suggestedfix_bar_xx_yy`
+-headings.
 -
--// We should accept all valid receiver syntax when scanning symbols.
--func (*(T)) m1() {}
--func (*T) m2()   {}
--func (T) m3()    {}
--func ((T)) m4()    {}
--func ((*T)) m5()   {}
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/main.go b/gopls/internal/lsp/testdata/workspacesymbol/main.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/main.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/main.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,47 +0,0 @@
--package main
+-To see a list of all available annotations, see the exported "expectations" in
+-[tests.go](https://github.com/golang/tools/blob/299f270db45902e93469b1152fafed034bb3f033/internal/lsp/tests/tests.go#L418-L447).
 -
--import (
--	"encoding/json"
--	"fmt"
--)
+-To run marker tests,
 -
--func main() { // function
--	fmt.Println("Hello")
--}
+-```bash
+-cd /path/to/tools
 -
--var myvar int // variable
+-# The marker tests are located in "internal/lsp", "internal/lsp/cmd, and
+-# "internal/lsp/source".
+-go test ./internal/lsp/...
+-```
 -
--type myType string // basic type
+-There are quite a lot of marker tests, so to run one individually, pass the test
+-path and heading into a -run argument:
 -
--type myDecoder json.Decoder // to use the encoding/json import
+-```bash
+-cd /path/to/tools
+-go test ./internal/lsp/... -v -run TestLSP/Modules/SuggestedFix/bar_11_21
+-```
 -
--func (m *myType) Blahblah() {} // method
+-## Resetting marker tests
 -
--type myStruct struct { // struct type
--	myStructField int // struct field
--}
+-Sometimes, a change is made to lsp that requires a change to multiple golden
+-files. When this happens, you can run,
 -
--type myInterface interface { // interface
--	DoSomeCoolStuff() string // interface method
--}
--
--type embed struct {
--	myStruct
--
--	nestedStruct struct {
--		nestedField int
--
--		nestedStruct2 struct {
--			int
--		}
--	}
--
--	nestedInterface interface {
--		myInterface
--		nestedMethod()
--	}
--}
--
--func Dunk() int { return 0 }
--
--func dunk() {}
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/p/p.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/p/p.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,3 +0,0 @@
--package p
--
--const Message = "Hello World." // constant
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/query.go b/gopls/internal/lsp/testdata/workspacesymbol/query.go
---- a/gopls/internal/lsp/testdata/workspacesymbol/query.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,29 +0,0 @@
--package main
--
--// Contains all of the workspace symbol queries.
--
--// -- Fuzzy matching --
--//@workspacesymbolfuzzy("rgop")
--//@workspacesymbolfuzzy("randoma")
--//@workspacesymbolfuzzy("randomb")
--
--// -- Case sensitive --
--//@workspacesymbolcasesensitive("main.main")
--//@workspacesymbolcasesensitive("p.Message")
--//@workspacesymbolcasesensitive("main.myvar")
--//@workspacesymbolcasesensitive("main.myType")
--//@workspacesymbolcasesensitive("main.myType.Blahblah")
--//@workspacesymbolcasesensitive("main.myStruct")
--//@workspacesymbolcasesensitive("main.myStruct.myStructField")
--//@workspacesymbolcasesensitive("main.myInterface")
--//@workspacesymbolcasesensitive("main.myInterface.DoSomeCoolStuff")
--//@workspacesymbolcasesensitive("main.embed.myStruct")
--//@workspacesymbolcasesensitive("main.embed.nestedStruct.nestedStruct2.int")
--//@workspacesymbolcasesensitive("main.embed.nestedInterface.myInterface")
--//@workspacesymbolcasesensitive("main.embed.nestedInterface.nestedMethod")
--//@workspacesymbolcasesensitive("dunk")
--//@workspacesymbolcasesensitive("Dunk")
--
--// -- Standard --
--//@workspacesymbol("")
--//@workspacesymbol("randomgophervar")
-diff -urN a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden
---- a/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/testdata/workspacesymbol/query.go.golden	1970-01-01 00:00:00.000000000 +0000
-@@ -1,83 +0,0 @@
---- workspace_symbol-caseinsensitive- --
--
--
---- workspace_symbol-caseinsensitive-randomgophervar --
--workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
--workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
--
---- workspace_symbol-casesensitive-Dunk --
--workspacesymbol/main.go:45:6-10 Dunk Function
--
---- workspace_symbol-casesensitive-dunk --
--workspacesymbol/main.go:47:6-10 dunk Function
--
---- workspace_symbol-casesensitive-main.embed.myStruct --
--workspacesymbol/main.go:29:2-10 main.embed.myStruct Field
--
---- workspace_symbol-casesensitive-main.embed.nestedInterface.myInterface --
--workspacesymbol/main.go:40:3-14 main.embed.nestedInterface.myInterface Interface
--
---- workspace_symbol-casesensitive-main.embed.nestedInterface.nestedMethod --
--workspacesymbol/main.go:41:3-15 main.embed.nestedInterface.nestedMethod Method
--
---- workspace_symbol-casesensitive-main.embed.nestedStruct.nestedStruct2.int --
--workspacesymbol/main.go:35:4-7 main.embed.nestedStruct.nestedStruct2.int Field
--
---- workspace_symbol-casesensitive-main.main --
--workspacesymbol/main.go:8:6-10 main.main Function
--
---- workspace_symbol-casesensitive-main.myInterface --
--workspacesymbol/main.go:24:6-17 main.myInterface Interface
--workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method
--
---- workspace_symbol-casesensitive-main.myInterface.DoSomeCoolStuff --
--workspacesymbol/main.go:25:2-17 main.myInterface.DoSomeCoolStuff Method
--
---- workspace_symbol-casesensitive-main.myStruct --
--workspacesymbol/main.go:20:6-14 main.myStruct Struct
--workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field
--
---- workspace_symbol-casesensitive-main.myStruct.myStructField --
--workspacesymbol/main.go:21:2-15 main.myStruct.myStructField Field
--
---- workspace_symbol-casesensitive-main.myType --
--workspacesymbol/main.go:14:6-12 main.myType Class
--workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method
--
---- workspace_symbol-casesensitive-main.myType.Blahblah --
--workspacesymbol/main.go:18:18-26 main.myType.Blahblah Method
--
---- workspace_symbol-casesensitive-main.myvar --
--workspacesymbol/main.go:12:5-10 main.myvar Variable
--
---- workspace_symbol-casesensitive-p.Message --
--workspacesymbol/p/p.go:3:7-14 p.Message Constant
--
---- workspace_symbol-fuzzy-randoma --
--workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
--workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant
--workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
--workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
--workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
--workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
--workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
--
---- workspace_symbol-fuzzy-randomb --
--workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
--workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
--workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
--workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
--workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
--workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct
--workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
--
---- workspace_symbol-fuzzy-rgop --
--workspacesymbol/a/a.go:3:5-26 RandomGopherVariableA Variable
--workspacesymbol/a/a.go:5:7-28 RandomGopherConstantA Constant
--workspacesymbol/a/a.go:8:2-24 randomgopherinvariable Constant
--workspacesymbol/a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
--workspacesymbol/a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
--workspacesymbol/b/b.go:3:5-26 RandomGopherVariableB Variable
--workspacesymbol/b/b.go:5:6-25 RandomGopherStructB Struct
--workspacesymbol/b/b.go:6:2-5 RandomGopherStructB.Bar Field
--
+-```bash
+-cd /path/to/tools
+-./internal/lsp/reset_golden.sh
+-```
 diff -urN a/gopls/internal/lsp/tests/compare/text.go b/gopls/internal/lsp/tests/compare/text.go
 --- a/gopls/internal/lsp/tests/compare/text.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/compare/text.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/tests/compare/text.go	1970-01-01 08:00:00
 @@ -1,49 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -104022,7 +110962,7 @@
 -}
 diff -urN a/gopls/internal/lsp/tests/compare/text_test.go b/gopls/internal/lsp/tests/compare/text_test.go
 --- a/gopls/internal/lsp/tests/compare/text_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/compare/text_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/tests/compare/text_test.go	1970-01-01 08:00:00
 @@ -1,28 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -104054,7 +110994,7 @@
 -}
 diff -urN a/gopls/internal/lsp/tests/markdown_go118.go b/gopls/internal/lsp/tests/markdown_go118.go
 --- a/gopls/internal/lsp/tests/markdown_go118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/markdown_go118.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/tests/markdown_go118.go	1970-01-01 08:00:00
 @@ -1,69 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -104127,7 +111067,7 @@
 -}
 diff -urN a/gopls/internal/lsp/tests/markdown_go119.go b/gopls/internal/lsp/tests/markdown_go119.go
 --- a/gopls/internal/lsp/tests/markdown_go119.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/markdown_go119.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/tests/markdown_go119.go	1970-01-01 08:00:00
 @@ -1,22 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -104151,197 +111091,10 @@
 -func DiffMarkdown(want, got string) string {
 -	return compare.Text(want, got)
 -}
-diff -urN a/gopls/internal/lsp/tests/normalizer.go b/gopls/internal/lsp/tests/normalizer.go
---- a/gopls/internal/lsp/tests/normalizer.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/normalizer.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,113 +0,0 @@
--// Copyright 2019 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
--
--package tests
--
--import (
--	"path/filepath"
--	"strconv"
--	"strings"
--
--	"golang.org/x/tools/go/packages/packagestest"
--)
--
--type Normalizer struct {
--	path     string
--	slashed  string
--	escaped  string
--	fragment string
--}
--
--func CollectNormalizers(exported *packagestest.Exported) []Normalizer {
--	// build the path normalizing patterns
--	var normalizers []Normalizer
--	for _, m := range exported.Modules {
--		for fragment := range m.Files {
--			n := Normalizer{
--				path:     exported.File(m.Name, fragment),
--				fragment: fragment,
--			}
--			if n.slashed = filepath.ToSlash(n.path); n.slashed == n.path {
--				n.slashed = ""
--			}
--			quoted := strconv.Quote(n.path)
--			if n.escaped = quoted[1 : len(quoted)-1]; n.escaped == n.path {
--				n.escaped = ""
--			}
--			normalizers = append(normalizers, n)
--		}
--	}
--	return normalizers
--}
--
--// Normalize replaces all paths present in s with just the fragment portion
--// this is used to make golden files not depend on the temporary paths of the files
--func Normalize(s string, normalizers []Normalizer) string {
--	type entry struct {
--		path     string
--		index    int
--		fragment string
--	}
--	var match []entry
--	// collect the initial state of all the matchers
--	for _, n := range normalizers {
--		index := strings.Index(s, n.path)
--		if index >= 0 {
--			match = append(match, entry{n.path, index, n.fragment})
--		}
--		if n.slashed != "" {
--			index := strings.Index(s, n.slashed)
--			if index >= 0 {
--				match = append(match, entry{n.slashed, index, n.fragment})
--			}
--		}
--		if n.escaped != "" {
--			index := strings.Index(s, n.escaped)
--			if index >= 0 {
--				match = append(match, entry{n.escaped, index, n.fragment})
--			}
--		}
--	}
--	// result should be the same or shorter than the input
--	var b strings.Builder
--	last := 0
--	for {
--		// find the nearest path match to the start of the buffer
--		next := -1
--		nearest := len(s)
--		for i, c := range match {
--			if c.index >= 0 && nearest > c.index {
--				nearest = c.index
--				next = i
--			}
--		}
--		// if there are no matches, we copy the rest of the string and are done
--		if next < 0 {
--			b.WriteString(s[last:])
--			return b.String()
--		}
--		// we have a match
--		n := &match[next]
--		// copy up to the start of the match
--		b.WriteString(s[last:n.index])
--		// skip over the filename
--		last = n.index + len(n.path)
--
--		// Hack: In multi-module mode, we add a "testmodule/" prefix, so trim
--		// it from the fragment.
--		fragment := n.fragment
--		if strings.HasPrefix(fragment, "testmodule") {
--			split := strings.Split(filepath.ToSlash(fragment), "/")
--			fragment = filepath.FromSlash(strings.Join(split[1:], "/"))
--		}
--
--		// add in the fragment instead
--		b.WriteString(fragment)
--		// see what the next match for this path is
--		n.index = strings.Index(s[last:], n.path)
--		if n.index >= 0 {
--			n.index += last
--		}
--	}
--}
-diff -urN a/gopls/internal/lsp/tests/README.md b/gopls/internal/lsp/tests/README.md
---- a/gopls/internal/lsp/tests/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,66 +0,0 @@
--# Testing
--
--LSP has "marker tests" defined in `internal/lsp/testdata`, as well as
--traditional tests.
--
--## Marker tests
--
--Marker tests have a standard input file, like
--`internal/lsp/testdata/foo/bar.go`, and some may have a corresponding golden
--file, like `internal/lsp/testdata/foo/bar.go.golden`. The former is the "input"
--and the latter is the expected output.
--
--Each input file contains annotations like
--`//@suggestedfix("}", "refactor.rewrite", "Fill anonymous struct")`. These annotations are interpreted by
--test runners to perform certain actions. The expected output after those actions
--is encoded in the golden file.
--
--When tests are run, each annotation results in a new subtest, which is encoded
--in the golden file with a heading like,
--
--```bash
---- suggestedfix_bar_11_21 --
--// expected contents go here
---- suggestedfix_bar_13_20 --
--// expected contents go here
--```
--
--The format of these headings vary: they are defined by the
--[`Golden`](https://pkg.go.dev/golang.org/x/tools/gopls/internal/lsp/tests#Data.Golden)
--function for each annotation. In the case above, the format is: annotation
--name, file name, annotation line location, annotation character location.
--
--So, if `internal/lsp/testdata/foo/bar.go` has three `suggestedfix` annotations,
--the golden file should have three headers with `suggestedfix_bar_xx_yy`
--headings.
--
--To see a list of all available annotations, see the exported "expectations" in
--[tests.go](https://github.com/golang/tools/blob/299f270db45902e93469b1152fafed034bb3f033/internal/lsp/tests/tests.go#L418-L447).
--
--To run marker tests,
--
--```bash
--cd /path/to/tools
--
--# The marker tests are located in "internal/lsp", "internal/lsp/cmd, and
--# "internal/lsp/source".
--go test ./internal/lsp/...
--```
--
--There are quite a lot of marker tests, so to run one individually, pass the test
--path and heading into a -run argument:
--
--```bash
--cd /path/to/tools
--go test ./internal/lsp/... -v -run TestLSP/Modules/SuggestedFix/bar_11_21
--```
--
--## Resetting marker tests
--
--Sometimes, a change is made to lsp that requires a change to multiple golden
--files. When this happens, you can run,
--
--```bash
--cd /path/to/tools
--./internal/lsp/reset_golden.sh
--```
 diff -urN a/gopls/internal/lsp/tests/tests.go b/gopls/internal/lsp/tests/tests.go
 --- a/gopls/internal/lsp/tests/tests.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/tests.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1446 +0,0 @@
++++ b/gopls/internal/lsp/tests/tests.go	1970-01-01 08:00:00
+@@ -1,956 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -104357,7 +111110,6 @@
 -	"go/ast"
 -	"go/token"
 -	"io"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"regexp"
@@ -104371,7 +111123,6 @@
 -	"golang.org/x/tools/go/expect"
 -	"golang.org/x/tools/go/packages"
 -	"golang.org/x/tools/go/packages/packagestest"
--	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/safetoken"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
@@ -104387,6 +111138,7 @@
 -	overlayFileSuffix = ".overlay"
 -	goldenFileSuffix  = ".golden"
 -	inFileSuffix      = ".in"
+-	summaryFile       = "summary.txt"
 -
 -	// The module path containing the testdata packages.
 -	//
@@ -104395,45 +111147,24 @@
 -	testModule = "golang.org/lsptests"
 -)
 -
--var summaryFile = "summary.txt"
--
--func init() {
--	if typeparams.Enabled {
--		summaryFile = "summary_go1.18.txt"
--	}
--}
--
 -var UpdateGolden = flag.Bool("golden", false, "Update golden files")
 -
 -// These type names apparently avoid the need to repeat the
 -// type in the field name and the make() expression.
 -type CallHierarchy = map[span.Span]*CallHierarchyResult
--type CodeLens = map[span.URI][]protocol.CodeLens
--type Diagnostics = map[span.URI][]*source.Diagnostic
 -type CompletionItems = map[token.Pos]*completion.CompletionItem
 -type Completions = map[span.Span][]Completion
 -type CompletionSnippets = map[span.Span][]CompletionSnippet
--type UnimportedCompletions = map[span.Span][]Completion
 -type DeepCompletions = map[span.Span][]Completion
 -type FuzzyCompletions = map[span.Span][]Completion
 -type CaseSensitiveCompletions = map[span.Span][]Completion
 -type RankCompletions = map[span.Span][]Completion
--type FoldingRanges = []span.Span
--type Formats = []span.Span
--type Imports = []span.Span
 -type SemanticTokens = []span.Span
 -type SuggestedFixes = map[span.Span][]SuggestedFix
--type FunctionExtractions = map[span.Span]span.Span
 -type MethodExtractions = map[span.Span]span.Span
--type Definitions = map[span.Span]Definition
--type Implementations = map[span.Span][]span.Span
--type Highlights = map[span.Span][]span.Span
--type References = map[span.Span][]span.Span
 -type Renames = map[span.Span]string
 -type PrepareRenames = map[span.Span]*source.PrepareItem
--type Symbols = map[span.URI][]*symbol
 -type InlayHints = []span.Span
--type WorkspaceSymbols = map[WorkspaceSymbolsTestType]map[span.URI][]string
 -type Signatures = map[span.Span]*protocol.SignatureHelp
 -type Links = map[span.URI][]Link
 -type AddImport = map[span.URI]string
@@ -104443,32 +111174,19 @@
 -	Config                   packages.Config
 -	Exported                 *packagestest.Exported
 -	CallHierarchy            CallHierarchy
--	CodeLens                 CodeLens
--	Diagnostics              Diagnostics
 -	CompletionItems          CompletionItems
 -	Completions              Completions
 -	CompletionSnippets       CompletionSnippets
--	UnimportedCompletions    UnimportedCompletions
 -	DeepCompletions          DeepCompletions
 -	FuzzyCompletions         FuzzyCompletions
 -	CaseSensitiveCompletions CaseSensitiveCompletions
 -	RankCompletions          RankCompletions
--	FoldingRanges            FoldingRanges
--	Formats                  Formats
--	Imports                  Imports
 -	SemanticTokens           SemanticTokens
 -	SuggestedFixes           SuggestedFixes
--	FunctionExtractions      FunctionExtractions
 -	MethodExtractions        MethodExtractions
--	Definitions              Definitions
--	Implementations          Implementations
--	Highlights               Highlights
--	References               References
 -	Renames                  Renames
 -	InlayHints               InlayHints
 -	PrepareRenames           PrepareRenames
--	Symbols                  Symbols
--	WorkspaceSymbols         WorkspaceSymbols
 -	Signatures               Signatures
 -	Links                    Links
 -	AddImport                AddImport
@@ -104486,60 +111204,37 @@
 -}
 -
 -// The Tests interface abstracts the LSP-based implementation of the marker
--// test operators (such as @codelens) appearing in files beneath ../testdata/.
+-// test operators appearing in files beneath ../testdata/.
 -//
 -// TODO(adonovan): reduce duplication; see https://github.com/golang/go/issues/54845.
 -// There is only one implementation (*runner in ../lsp_test.go), so
 -// we can abolish the interface now.
 -type Tests interface {
 -	CallHierarchy(*testing.T, span.Span, *CallHierarchyResult)
--	CodeLens(*testing.T, span.URI, []protocol.CodeLens)
--	Diagnostics(*testing.T, span.URI, []*source.Diagnostic)
 -	Completion(*testing.T, span.Span, Completion, CompletionItems)
 -	CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems)
--	UnimportedCompletion(*testing.T, span.Span, Completion, CompletionItems)
 -	DeepCompletion(*testing.T, span.Span, Completion, CompletionItems)
 -	FuzzyCompletion(*testing.T, span.Span, Completion, CompletionItems)
 -	CaseSensitiveCompletion(*testing.T, span.Span, Completion, CompletionItems)
 -	RankCompletion(*testing.T, span.Span, Completion, CompletionItems)
--	FoldingRanges(*testing.T, span.Span)
--	Format(*testing.T, span.Span)
--	Import(*testing.T, span.Span)
 -	SemanticTokens(*testing.T, span.Span)
 -	SuggestedFix(*testing.T, span.Span, []SuggestedFix, int)
--	FunctionExtraction(*testing.T, span.Span, span.Span)
 -	MethodExtraction(*testing.T, span.Span, span.Span)
--	Definition(*testing.T, span.Span, Definition)
--	Implementation(*testing.T, span.Span, []span.Span)
--	Highlight(*testing.T, span.Span, []span.Span)
 -	InlayHints(*testing.T, span.Span)
--	References(*testing.T, span.Span, []span.Span)
 -	Rename(*testing.T, span.Span, string)
 -	PrepareRename(*testing.T, span.Span, *source.PrepareItem)
--	Symbols(*testing.T, span.URI, []protocol.DocumentSymbol)
--	WorkspaceSymbols(*testing.T, span.URI, string, WorkspaceSymbolsTestType)
 -	SignatureHelp(*testing.T, span.Span, *protocol.SignatureHelp)
 -	Link(*testing.T, span.URI, []Link)
 -	AddImport(*testing.T, span.URI, string)
 -	SelectionRanges(*testing.T, span.Span)
 -}
 -
--type Definition struct {
--	Name      string
--	IsType    bool
--	OnlyHover bool
--	Src, Def  span.Span
--}
--
 -type CompletionTestType int
 -
 -const (
 -	// Default runs the standard completion tests.
 -	CompletionDefault = CompletionTestType(iota)
 -
--	// Unimported tests the autocompletion of unimported packages.
--	CompletionUnimported
--
 -	// Deep tests deep completion.
 -	CompletionDeep
 -
@@ -104553,19 +111248,6 @@
 -	CompletionRank
 -)
 -
--type WorkspaceSymbolsTestType int
--
--const (
--	// Default runs the standard workspace symbols tests.
--	WorkspaceSymbolsDefault = WorkspaceSymbolsTestType(iota)
--
--	// Fuzzy tests workspace symbols with fuzzy matching.
--	WorkspaceSymbolsFuzzy
--
--	// CaseSensitive tests workspace symbols with case sensitive.
--	WorkspaceSymbolsCaseSensitive
--)
--
 -type Completion struct {
 -	CompletionItems []token.Pos
 -}
@@ -104590,12 +111272,6 @@
 -	ActionKind, Title string
 -}
 -
--// A symbol holds a DocumentSymbol along with its parent-child edge.
--type symbol struct {
--	pSymbol      protocol.DocumentSymbol
--	id, parentID string
--}
--
 -type Golden struct {
 -	Filename string
 -	Archive  *txtar.Archive
@@ -104612,6 +111288,7 @@
 -			protocol.SourceOrganizeImports: true,
 -			protocol.QuickFix:              true,
 -			protocol.RefactorRewrite:       true,
+-			protocol.RefactorInline:        true,
 -			protocol.RefactorExtract:       true,
 -			protocol.SourceFixAll:          true,
 -		},
@@ -104622,13 +111299,19 @@
 -		source.Work: {},
 -		source.Tmpl: {},
 -	}
--	o.UserOptions.Codelenses[string(command.Test)] = true
--	o.HoverKind = source.SynopsisDocumentation
 -	o.InsertTextFormat = protocol.SnippetTextFormat
 -	o.CompletionBudget = time.Minute
 -	o.HierarchicalDocumentSymbolSupport = true
 -	o.SemanticTokens = true
--	o.InternalOptions.NewDiff = "both"
+-	o.InternalOptions.NewDiff = "new"
+-
+-	// Enable all inlay hints.
+-	if o.Hints == nil {
+-		o.Hints = make(map[string]bool)
+-	}
+-	for name := range source.AllInlayHints {
+-		o.Hints[name] = true
+-	}
 -}
 -
 -func RunTests(t *testing.T, dataDir string, includeMultiModule bool, f func(*testing.T, *Data)) {
@@ -104649,27 +111332,17 @@
 -func load(t testing.TB, mode string, dir string) *Data {
 -	datum := &Data{
 -		CallHierarchy:            make(CallHierarchy),
--		CodeLens:                 make(CodeLens),
--		Diagnostics:              make(Diagnostics),
 -		CompletionItems:          make(CompletionItems),
 -		Completions:              make(Completions),
 -		CompletionSnippets:       make(CompletionSnippets),
--		UnimportedCompletions:    make(UnimportedCompletions),
 -		DeepCompletions:          make(DeepCompletions),
 -		FuzzyCompletions:         make(FuzzyCompletions),
 -		RankCompletions:          make(RankCompletions),
 -		CaseSensitiveCompletions: make(CaseSensitiveCompletions),
--		Definitions:              make(Definitions),
--		Implementations:          make(Implementations),
--		Highlights:               make(Highlights),
--		References:               make(References),
 -		Renames:                  make(Renames),
 -		PrepareRenames:           make(PrepareRenames),
 -		SuggestedFixes:           make(SuggestedFixes),
--		FunctionExtractions:      make(FunctionExtractions),
 -		MethodExtractions:        make(MethodExtractions),
--		Symbols:                  make(Symbols),
--		WorkspaceSymbols:         make(WorkspaceSymbols),
 -		Signatures:               make(Signatures),
 -		Links:                    make(Links),
 -		AddImport:                make(AddImport),
@@ -104724,7 +111397,7 @@
 -		} else if index := strings.Index(fragment, overlayFileSuffix); index >= 0 {
 -			delete(files, fragment)
 -			partial := fragment[:index] + fragment[index+len(overlayFileSuffix):]
--			contents, err := ioutil.ReadFile(filepath.Join(dir, fragment))
+-			contents, err := os.ReadFile(filepath.Join(dir, fragment))
 -			if err != nil {
 -				t.Fatal(err)
 -			}
@@ -104805,53 +111478,29 @@
 -
 -	// Collect any data that needs to be used by subsequent tests.
 -	if err := datum.Exported.Expect(map[string]interface{}{
--		"codelens":        datum.collectCodeLens,
--		"diag":            datum.collectDiagnostics,
--		"item":            datum.collectCompletionItems,
--		"complete":        datum.collectCompletions(CompletionDefault),
--		"unimported":      datum.collectCompletions(CompletionUnimported),
--		"deep":            datum.collectCompletions(CompletionDeep),
--		"fuzzy":           datum.collectCompletions(CompletionFuzzy),
--		"casesensitive":   datum.collectCompletions(CompletionCaseSensitive),
--		"rank":            datum.collectCompletions(CompletionRank),
--		"snippet":         datum.collectCompletionSnippets,
--		"fold":            datum.collectFoldingRanges,
--		"format":          datum.collectFormats,
--		"import":          datum.collectImports,
--		"semantic":        datum.collectSemanticTokens,
--		"godef":           datum.collectDefinitions,
--		"implementations": datum.collectImplementations,
--		"typdef":          datum.collectTypeDefinitions,
--		"hoverdef":        datum.collectHoverDefinitions,
--		"highlight":       datum.collectHighlights,
--		"inlayHint":       datum.collectInlayHints,
--		"refs":            datum.collectReferences,
--		"rename":          datum.collectRenames,
--		"prepare":         datum.collectPrepareRenames,
--		"symbol":          datum.collectSymbols,
--		"signature":       datum.collectSignatures,
--		"link":            datum.collectLinks,
--		"suggestedfix":    datum.collectSuggestedFixes,
--		"extractfunc":     datum.collectFunctionExtractions,
--		"extractmethod":   datum.collectMethodExtractions,
--		"incomingcalls":   datum.collectIncomingCalls,
--		"outgoingcalls":   datum.collectOutgoingCalls,
--		"addimport":       datum.collectAddImports,
--		"selectionrange":  datum.collectSelectionRanges,
+-		"item":           datum.collectCompletionItems,
+-		"complete":       datum.collectCompletions(CompletionDefault),
+-		"deep":           datum.collectCompletions(CompletionDeep),
+-		"fuzzy":          datum.collectCompletions(CompletionFuzzy),
+-		"casesensitive":  datum.collectCompletions(CompletionCaseSensitive),
+-		"rank":           datum.collectCompletions(CompletionRank),
+-		"snippet":        datum.collectCompletionSnippets,
+-		"semantic":       datum.collectSemanticTokens,
+-		"inlayHint":      datum.collectInlayHints,
+-		"rename":         datum.collectRenames,
+-		"prepare":        datum.collectPrepareRenames,
+-		"signature":      datum.collectSignatures,
+-		"link":           datum.collectLinks,
+-		"suggestedfix":   datum.collectSuggestedFixes,
+-		"extractmethod":  datum.collectMethodExtractions,
+-		"incomingcalls":  datum.collectIncomingCalls,
+-		"outgoingcalls":  datum.collectOutgoingCalls,
+-		"addimport":      datum.collectAddImports,
+-		"selectionrange": datum.collectSelectionRanges,
 -	}); err != nil {
 -		t.Fatal(err)
 -	}
 -
--	// Collect names for the entries that require golden files.
--	if err := datum.Exported.Expect(map[string]interface{}{
--		"godef":                        datum.collectDefinitionNames,
--		"hoverdef":                     datum.collectDefinitionNames,
--		"workspacesymbol":              datum.collectWorkspaceSymbols(WorkspaceSymbolsDefault),
--		"workspacesymbolfuzzy":         datum.collectWorkspaceSymbols(WorkspaceSymbolsFuzzy),
--		"workspacesymbolcasesensitive": datum.collectWorkspaceSymbols(WorkspaceSymbolsCaseSensitive),
--	}); err != nil {
--		t.Fatal(err)
--	}
 -	if mode == "MultiModule" {
 -		if err := moveFile(filepath.Join(datum.Config.Dir, "go.mod"), filepath.Join(datum.Config.Dir, "testmodule/go.mod")); err != nil {
 -			t.Fatal(err)
@@ -104953,11 +111602,6 @@
 -		}
 -	})
 -
--	t.Run("UnimportedCompletion", func(t *testing.T) {
--		t.Helper()
--		eachCompletion(t, data.UnimportedCompletions, tests.UnimportedCompletion)
--	})
--
 -	t.Run("DeepCompletion", func(t *testing.T) {
 -		t.Helper()
 -		eachCompletion(t, data.DeepCompletions, tests.DeepCompletion)
@@ -104978,64 +111622,6 @@
 -		eachCompletion(t, data.RankCompletions, tests.RankCompletion)
 -	})
 -
--	t.Run("CodeLens", func(t *testing.T) {
--		t.Helper()
--		for uri, want := range data.CodeLens {
--			// Check if we should skip this URI if the -modfile flag is not available.
--			if shouldSkip(data, uri) {
--				continue
--			}
--			t.Run(uriName(uri), func(t *testing.T) {
--				t.Helper()
--				tests.CodeLens(t, uri, want)
--			})
--		}
--	})
--
--	t.Run("Diagnostics", func(t *testing.T) {
--		t.Helper()
--		for uri, want := range data.Diagnostics {
--			// Check if we should skip this URI if the -modfile flag is not available.
--			if shouldSkip(data, uri) {
--				continue
--			}
--			t.Run(uriName(uri), func(t *testing.T) {
--				t.Helper()
--				tests.Diagnostics(t, uri, want)
--			})
--		}
--	})
--
--	t.Run("FoldingRange", func(t *testing.T) {
--		t.Helper()
--		for _, spn := range data.FoldingRanges {
--			t.Run(uriName(spn.URI()), func(t *testing.T) {
--				t.Helper()
--				tests.FoldingRanges(t, spn)
--			})
--		}
--	})
--
--	t.Run("Format", func(t *testing.T) {
--		t.Helper()
--		for _, spn := range data.Formats {
--			t.Run(uriName(spn.URI()), func(t *testing.T) {
--				t.Helper()
--				tests.Format(t, spn)
--			})
--		}
--	})
--
--	t.Run("Import", func(t *testing.T) {
--		t.Helper()
--		for _, spn := range data.Imports {
--			t.Run(uriName(spn.URI()), func(t *testing.T) {
--				t.Helper()
--				tests.Import(t, spn)
--			})
--		}
--	})
--
 -	t.Run("SemanticTokens", func(t *testing.T) {
 -		t.Helper()
 -		for _, spn := range data.SemanticTokens {
@@ -105060,20 +111646,6 @@
 -		}
 -	})
 -
--	t.Run("FunctionExtraction", func(t *testing.T) {
--		t.Helper()
--		for start, end := range data.FunctionExtractions {
--			// Check if we should skip this spn if the -modfile flag is not available.
--			if shouldSkip(data, start.URI()) {
--				continue
--			}
--			t.Run(SpanName(start), func(t *testing.T) {
--				t.Helper()
--				tests.FunctionExtraction(t, start, end)
--			})
--		}
--	})
--
 -	t.Run("MethodExtraction", func(t *testing.T) {
 -		t.Helper()
 -		for start, end := range data.MethodExtractions {
@@ -105088,39 +111660,6 @@
 -		}
 -	})
 -
--	t.Run("Definition", func(t *testing.T) {
--		t.Helper()
--		for spn, d := range data.Definitions {
--			t.Run(SpanName(spn), func(t *testing.T) {
--				t.Helper()
--				if strings.Contains(t.Name(), "cgo") {
--					testenv.NeedsTool(t, "cgo")
--				}
--				tests.Definition(t, spn, d)
--			})
--		}
--	})
--
--	t.Run("Implementation", func(t *testing.T) {
--		t.Helper()
--		for spn, m := range data.Implementations {
--			t.Run(SpanName(spn), func(t *testing.T) {
--				t.Helper()
--				tests.Implementation(t, spn, m)
--			})
--		}
--	})
--
--	t.Run("Highlight", func(t *testing.T) {
--		t.Helper()
--		for pos, locations := range data.Highlights {
--			t.Run(SpanName(pos), func(t *testing.T) {
--				t.Helper()
--				tests.Highlight(t, pos, locations)
--			})
--		}
--	})
--
 -	t.Run("InlayHints", func(t *testing.T) {
 -		t.Helper()
 -		for _, src := range data.InlayHints {
@@ -105131,16 +111670,6 @@
 -		}
 -	})
 -
--	t.Run("References", func(t *testing.T) {
--		t.Helper()
--		for src, itemList := range data.References {
--			t.Run(SpanName(src), func(t *testing.T) {
--				t.Helper()
--				tests.References(t, src, itemList)
--			})
--		}
--	})
--
 -	t.Run("Renames", func(t *testing.T) {
 -		t.Helper()
 -		for spn, newText := range data.Renames {
@@ -105161,74 +111690,6 @@
 -		}
 -	})
 -
--	t.Run("Symbols", func(t *testing.T) {
--		t.Helper()
--		for uri, allSymbols := range data.Symbols {
--			byParent := make(map[string][]*symbol)
--			for _, sym := range allSymbols {
--				if sym.parentID != "" {
--					byParent[sym.parentID] = append(byParent[sym.parentID], sym)
--				}
--			}
--
--			// collectChildren does a depth-first traversal of the symbol tree,
--			// computing children of child nodes before returning to their parent.
--			// This is necessary as the Children field is slice of non-pointer types,
--			// and therefore we need to be careful to mutate children first before
--			// assigning them to their parent.
--			var collectChildren func(id string) []protocol.DocumentSymbol
--			collectChildren = func(id string) []protocol.DocumentSymbol {
--				children := byParent[id]
--				// delete from byParent before recursing, to ensure that
--				// collectChildren terminates even in the presence of cycles.
--				delete(byParent, id)
--				var result []protocol.DocumentSymbol
--				for _, child := range children {
--					child.pSymbol.Children = collectChildren(child.id)
--					result = append(result, child.pSymbol)
--				}
--				return result
--			}
--
--			var topLevel []protocol.DocumentSymbol
--			for _, sym := range allSymbols {
--				if sym.parentID == "" {
--					sym.pSymbol.Children = collectChildren(sym.id)
--					topLevel = append(topLevel, sym.pSymbol)
--				}
--			}
--
--			t.Run(uriName(uri), func(t *testing.T) {
--				t.Helper()
--				tests.Symbols(t, uri, topLevel)
--			})
--		}
--	})
--
--	t.Run("WorkspaceSymbols", func(t *testing.T) {
--		t.Helper()
--
--		for _, typ := range []WorkspaceSymbolsTestType{
--			WorkspaceSymbolsDefault,
--			WorkspaceSymbolsCaseSensitive,
--			WorkspaceSymbolsFuzzy,
--		} {
--			for uri, cases := range data.WorkspaceSymbols[typ] {
--				for _, query := range cases {
--					name := query
--					if name == "" {
--						name = "EmptyQuery"
--					}
--					t.Run(name, func(t *testing.T) {
--						t.Helper()
--						tests.WorkspaceSymbols(t, uri, query, typ)
--					})
--				}
--			}
--		}
--
--	})
--
 -	t.Run("SignatureHelp", func(t *testing.T) {
 -		t.Helper()
 -		for spn, expectedSignature := range data.Signatures {
@@ -105287,7 +111748,7 @@
 -			sort.Slice(golden.Archive.Files, func(i, j int) bool {
 -				return golden.Archive.Files[i].Name < golden.Archive.Files[j].Name
 -			})
--			if err := ioutil.WriteFile(golden.Filename, txtar.Format(golden.Archive), 0666); err != nil {
+-			if err := os.WriteFile(golden.Filename, txtar.Format(golden.Archive), 0666); err != nil {
 -				t.Fatal(err)
 -			}
 -		}
@@ -105296,23 +111757,10 @@
 -
 -func checkData(t *testing.T, data *Data) {
 -	buf := &bytes.Buffer{}
--	diagnosticsCount := 0
--	for _, want := range data.Diagnostics {
--		diagnosticsCount += len(want)
--	}
 -	linksCount := 0
 -	for _, want := range data.Links {
 -		linksCount += len(want)
 -	}
--	definitionCount := 0
--	typeDefinitionCount := 0
--	for _, d := range data.Definitions {
--		if d.IsType {
--			typeDefinitionCount++
--		} else {
--			definitionCount++
--		}
--	}
 -
 -	snippetCount := 0
 -	for _, want := range data.CompletionSnippets {
@@ -105326,51 +111774,21 @@
 -		return count
 -	}
 -
--	countCodeLens := func(c map[span.URI][]protocol.CodeLens) (count int) {
--		for _, want := range c {
--			count += len(want)
--		}
--		return count
--	}
--
--	countWorkspaceSymbols := func(c map[WorkspaceSymbolsTestType]map[span.URI][]string) (count int) {
--		for _, typs := range c {
--			for _, queries := range typs {
--				count += len(queries)
--			}
--		}
--		return count
--	}
--
 -	fmt.Fprintf(buf, "CallHierarchyCount = %v\n", len(data.CallHierarchy))
--	fmt.Fprintf(buf, "CodeLensCount = %v\n", countCodeLens(data.CodeLens))
 -	fmt.Fprintf(buf, "CompletionsCount = %v\n", countCompletions(data.Completions))
 -	fmt.Fprintf(buf, "CompletionSnippetCount = %v\n", snippetCount)
--	fmt.Fprintf(buf, "UnimportedCompletionsCount = %v\n", countCompletions(data.UnimportedCompletions))
 -	fmt.Fprintf(buf, "DeepCompletionsCount = %v\n", countCompletions(data.DeepCompletions))
 -	fmt.Fprintf(buf, "FuzzyCompletionsCount = %v\n", countCompletions(data.FuzzyCompletions))
 -	fmt.Fprintf(buf, "RankedCompletionsCount = %v\n", countCompletions(data.RankCompletions))
 -	fmt.Fprintf(buf, "CaseSensitiveCompletionsCount = %v\n", countCompletions(data.CaseSensitiveCompletions))
--	fmt.Fprintf(buf, "DiagnosticsCount = %v\n", diagnosticsCount)
--	fmt.Fprintf(buf, "FoldingRangesCount = %v\n", len(data.FoldingRanges))
--	fmt.Fprintf(buf, "FormatCount = %v\n", len(data.Formats))
--	fmt.Fprintf(buf, "ImportCount = %v\n", len(data.Imports))
 -	fmt.Fprintf(buf, "SemanticTokenCount = %v\n", len(data.SemanticTokens))
 -	fmt.Fprintf(buf, "SuggestedFixCount = %v\n", len(data.SuggestedFixes))
--	fmt.Fprintf(buf, "FunctionExtractionCount = %v\n", len(data.FunctionExtractions))
 -	fmt.Fprintf(buf, "MethodExtractionCount = %v\n", len(data.MethodExtractions))
--	fmt.Fprintf(buf, "DefinitionsCount = %v\n", definitionCount)
--	fmt.Fprintf(buf, "TypeDefinitionsCount = %v\n", typeDefinitionCount)
--	fmt.Fprintf(buf, "HighlightsCount = %v\n", len(data.Highlights))
 -	fmt.Fprintf(buf, "InlayHintsCount = %v\n", len(data.InlayHints))
--	fmt.Fprintf(buf, "ReferencesCount = %v\n", len(data.References))
 -	fmt.Fprintf(buf, "RenamesCount = %v\n", len(data.Renames))
 -	fmt.Fprintf(buf, "PrepareRenamesCount = %v\n", len(data.PrepareRenames))
--	fmt.Fprintf(buf, "SymbolsCount = %v\n", len(data.Symbols))
--	fmt.Fprintf(buf, "WorkspaceSymbolsCount = %v\n", countWorkspaceSymbols(data.WorkspaceSymbols))
 -	fmt.Fprintf(buf, "SignaturesCount = %v\n", len(data.Signatures))
 -	fmt.Fprintf(buf, "LinksCount = %v\n", linksCount)
--	fmt.Fprintf(buf, "ImplementationsCount = %v\n", len(data.Implementations))
 -	fmt.Fprintf(buf, "SelectionRangesCount = %v\n", len(data.SelectionRanges))
 -
 -	want := string(data.Golden(t, "summary", summaryFile, func() ([]byte, error) {
@@ -105452,37 +111870,6 @@
 -	return file.Data[:len(file.Data)-1] // drop the trailing \n
 -}
 -
--func (data *Data) collectCodeLens(spn span.Span, title, cmd string) {
--	data.CodeLens[spn.URI()] = append(data.CodeLens[spn.URI()], protocol.CodeLens{
--		Range: data.mustRange(spn),
--		Command: &protocol.Command{
--			Title:   title,
--			Command: cmd,
--		},
--	})
--}
--
--func (data *Data) collectDiagnostics(spn span.Span, msgSource, msgPattern, msgSeverity string) {
--	severity := protocol.SeverityError
--	switch msgSeverity {
--	case "error":
--		severity = protocol.SeverityError
--	case "warning":
--		severity = protocol.SeverityWarning
--	case "hint":
--		severity = protocol.SeverityHint
--	case "information":
--		severity = protocol.SeverityInformation
--	}
--
--	data.Diagnostics[spn.URI()] = append(data.Diagnostics[spn.URI()], &source.Diagnostic{
--		Range:    data.mustRange(spn),
--		Severity: severity,
--		Source:   source.DiagnosticSource(msgSource),
--		Message:  msgPattern,
--	})
--}
--
 -func (data *Data) collectCompletions(typ CompletionTestType) func(span.Span, []token.Pos) {
 -	result := func(m map[span.Span][]Completion, src span.Span, expected []token.Pos) {
 -		m[src] = append(m[src], Completion{
@@ -105494,10 +111881,6 @@
 -		return func(src span.Span, expected []token.Pos) {
 -			result(data.DeepCompletions, src, expected)
 -		}
--	case CompletionUnimported:
--		return func(src span.Span, expected []token.Pos) {
--			result(data.UnimportedCompletions, src, expected)
--		}
 -	case CompletionFuzzy:
 -		return func(src span.Span, expected []token.Pos) {
 -			result(data.FuzzyCompletions, src, expected)
@@ -105530,18 +111913,6 @@
 -	}
 -}
 -
--func (data *Data) collectFoldingRanges(spn span.Span) {
--	data.FoldingRanges = append(data.FoldingRanges, spn)
--}
--
--func (data *Data) collectFormats(spn span.Span) {
--	data.Formats = append(data.Formats, spn)
--}
--
--func (data *Data) collectImports(spn span.Span) {
--	data.Imports = append(data.Imports, spn)
--}
--
 -func (data *Data) collectAddImports(spn span.Span, imp string) {
 -	data.AddImport[spn.URI()] = imp
 -}
@@ -105554,33 +111925,16 @@
 -	data.SuggestedFixes[spn] = append(data.SuggestedFixes[spn], SuggestedFix{actionKind, fix})
 -}
 -
--func (data *Data) collectFunctionExtractions(start span.Span, end span.Span) {
--	if _, ok := data.FunctionExtractions[start]; !ok {
--		data.FunctionExtractions[start] = end
--	}
--}
--
 -func (data *Data) collectMethodExtractions(start span.Span, end span.Span) {
 -	if _, ok := data.MethodExtractions[start]; !ok {
 -		data.MethodExtractions[start] = end
 -	}
 -}
 -
--func (data *Data) collectDefinitions(src, target span.Span) {
--	data.Definitions[src] = Definition{
--		Src: src,
--		Def: target,
--	}
--}
--
 -func (data *Data) collectSelectionRanges(spn span.Span) {
 -	data.SelectionRanges = append(data.SelectionRanges, spn)
 -}
 -
--func (data *Data) collectImplementations(src span.Span, targets []span.Span) {
--	data.Implementations[src] = targets
--}
--
 -func (data *Data) collectIncomingCalls(src span.Span, calls []span.Span) {
 -	for _, call := range calls {
 -		rng := data.mustRange(call)
@@ -105615,41 +111969,10 @@
 -	}
 -}
 -
--func (data *Data) collectHoverDefinitions(src, target span.Span) {
--	data.Definitions[src] = Definition{
--		Src:       src,
--		Def:       target,
--		OnlyHover: true,
--	}
--}
--
--func (data *Data) collectTypeDefinitions(src, target span.Span) {
--	data.Definitions[src] = Definition{
--		Src:    src,
--		Def:    target,
--		IsType: true,
--	}
--}
--
--func (data *Data) collectDefinitionNames(src span.Span, name string) {
--	d := data.Definitions[src]
--	d.Name = name
--	data.Definitions[src] = d
--}
--
--func (data *Data) collectHighlights(src span.Span, expected []span.Span) {
--	// Declaring a highlight in a test file: @highlight(src, expected1, expected2)
--	data.Highlights[src] = append(data.Highlights[src], expected...)
--}
--
 -func (data *Data) collectInlayHints(src span.Span) {
 -	data.InlayHints = append(data.InlayHints, src)
 -}
 -
--func (data *Data) collectReferences(src span.Span, expected []span.Span) {
--	data.References[src] = expected
--}
--
 -func (data *Data) collectRenames(src span.Span, newText string) {
 -	data.Renames[src] = newText
 -}
@@ -105661,23 +111984,6 @@
 -	}
 -}
 -
--// collectSymbols is responsible for collecting @symbol annotations.
--func (data *Data) collectSymbols(name string, selectionRng span.Span, kind, detail, id, parentID string) {
--	// We don't set 'Range' here as it is difficult (impossible?) to express
--	// multi-line ranges in the packagestest framework.
--	uri := selectionRng.URI()
--	data.Symbols[uri] = append(data.Symbols[uri], &symbol{
--		pSymbol: protocol.DocumentSymbol{
--			Name:           name,
--			Kind:           protocol.ParseSymbolKind(kind),
--			SelectionRange: data.mustRange(selectionRng),
--			Detail:         detail,
--		},
--		id:       id,
--		parentID: parentID,
--	})
--}
--
 -// mustRange converts spn into a protocol.Range, panicking on any error.
 -func (data *Data) mustRange(spn span.Span) protocol.Range {
 -	m, err := data.Mapper(spn.URI())
@@ -105688,17 +111994,6 @@
 -	return rng
 -}
 -
--func (data *Data) collectWorkspaceSymbols(typ WorkspaceSymbolsTestType) func(*expect.Note, string) {
--	return func(note *expect.Note, query string) {
--		if data.WorkspaceSymbols[typ] == nil {
--			data.WorkspaceSymbols[typ] = make(map[span.URI][]string)
--		}
--		pos := safetoken.StartPosition(data.Exported.ExpectFileSet, note.Pos)
--		uri := span.URIFromPath(pos.Filename)
--		data.WorkspaceSymbols[typ][uri] = append(data.WorkspaceSymbols[typ][uri], query)
--	}
--}
--
 -func (data *Data) collectSignatures(spn span.Span, signature string, activeParam int64) {
 -	data.Signatures[spn] = &protocol.SignatureHelp{
 -		Signatures: []protocol.SignatureInformation{
@@ -105742,38 +112037,6 @@
 -	return fmt.Sprintf("%v_%v_%v", uriName(spn.URI()), spn.Start().Line(), spn.Start().Column())
 -}
 -
--func CopyFolderToTempDir(folder string) (string, error) {
--	if _, err := os.Stat(folder); err != nil {
--		return "", err
--	}
--	dst, err := ioutil.TempDir("", "modfile_test")
--	if err != nil {
--		return "", err
--	}
--	fds, err := ioutil.ReadDir(folder)
--	if err != nil {
--		return "", err
--	}
--	for _, fd := range fds {
--		srcfp := filepath.Join(folder, fd.Name())
--		stat, err := os.Stat(srcfp)
--		if err != nil {
--			return "", err
--		}
--		if !stat.Mode().IsRegular() {
--			return "", fmt.Errorf("cannot copy non regular file %s", srcfp)
--		}
--		contents, err := ioutil.ReadFile(srcfp)
--		if err != nil {
--			return "", err
--		}
--		if err := ioutil.WriteFile(filepath.Join(dst, fd.Name()), contents, stat.Mode()); err != nil {
--			return "", err
--		}
--	}
--	return dst, nil
--}
--
 -func shouldSkip(data *Data, uri span.URI) bool {
 -	if data.ModfileFlagAvailable {
 -		return false
@@ -105790,8 +112053,8 @@
 -}
 diff -urN a/gopls/internal/lsp/tests/util.go b/gopls/internal/lsp/tests/util.go
 --- a/gopls/internal/lsp/tests/util.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/util.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,547 +0,0 @@
++++ b/gopls/internal/lsp/tests/util.go	1970-01-01 08:00:00
+@@ -1,311 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -105800,21 +112063,15 @@
 -
 -import (
 -	"bytes"
--	"context"
 -	"fmt"
 -	"go/token"
--	"path"
--	"path/filepath"
--	"regexp"
 -	"sort"
 -	"strconv"
 -	"strings"
--	"testing"
 -
 -	"github.com/google/go-cmp/cmp"
 -	"github.com/google/go-cmp/cmp/cmpopts"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/source/completion"
 -	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
 -	"golang.org/x/tools/gopls/internal/span"
@@ -105875,11 +112132,11 @@
 -
 -		if target, ok := links[spn]; ok {
 -			delete(links, spn)
--			if target != link.Target {
--				fmt.Fprintf(&msg, "%s: want link with target %q, got %q\n", spn, target, link.Target)
+-			if target != *link.Target {
+-				fmt.Fprintf(&msg, "%s: want link with target %q, got %q\n", spn, target, *link.Target)
 -			}
 -		} else {
--			fmt.Fprintf(&msg, "%s: got unexpected link with target %q\n", spn, link.Target)
+-			fmt.Fprintf(&msg, "%s: got unexpected link with target %q\n", spn, *link.Target)
 -		}
 -	}
 -	for spn, target := range links {
@@ -105888,79 +112145,6 @@
 -	return msg.String()
 -}
 -
--// CompareDiagnostics reports testing errors to t when the diagnostic set got
--// does not match want. If the sole expectation has source "no_diagnostics",
--// the test expects that no diagnostics were received for the given document.
--func CompareDiagnostics(t *testing.T, uri span.URI, want, got []*source.Diagnostic) {
--	t.Helper()
--	fileName := path.Base(string(uri))
--
--	// A special case to test that there are no diagnostics for a file.
--	if len(want) == 1 && want[0].Source == "no_diagnostics" {
--		want = nil
--	}
--
--	// Build a helper function to match an actual diagnostic to an overlapping
--	// expected diagnostic (if any).
--	unmatched := make([]*source.Diagnostic, len(want))
--	copy(unmatched, want)
--	source.SortDiagnostics(unmatched)
--	match := func(g *source.Diagnostic) *source.Diagnostic {
--		// Find the last expected diagnostic d for which start(d) < end(g), and
--		// check to see if it overlaps.
--		i := sort.Search(len(unmatched), func(i int) bool {
--			d := unmatched[i]
--			// See rangeOverlaps: if a range is a single point, we consider End to be
--			// included in the range...
--			if g.Range.Start == g.Range.End {
--				return protocol.ComparePosition(d.Range.Start, g.Range.End) > 0
--			}
--			// ...otherwise the end position of a range is not included.
--			return protocol.ComparePosition(d.Range.Start, g.Range.End) >= 0
--		})
--		if i == 0 {
--			return nil
--		}
--		w := unmatched[i-1]
--		if rangeOverlaps(w.Range, g.Range) {
--			unmatched = append(unmatched[:i-1], unmatched[i:]...)
--			return w
--		}
--		return nil
--	}
--
--	for _, g := range got {
--		w := match(g)
--		if w == nil {
--			t.Errorf("%s:%s: unexpected diagnostic %q", fileName, g.Range, g.Message)
--			continue
--		}
--		if match, err := regexp.MatchString(w.Message, g.Message); err != nil {
--			t.Errorf("%s:%s: invalid regular expression %q: %v", fileName, w.Range.Start, w.Message, err)
--		} else if !match {
--			t.Errorf("%s:%s: got Message %q, want match for pattern %q", fileName, g.Range.Start, g.Message, w.Message)
--		}
--		if w.Severity != g.Severity {
--			t.Errorf("%s:%s: got Severity %v, want %v", fileName, g.Range.Start, g.Severity, w.Severity)
--		}
--		if w.Source != g.Source {
--			t.Errorf("%s:%s: got Source %v, want %v", fileName, g.Range.Start, g.Source, w.Source)
--		}
--	}
--
--	for _, w := range unmatched {
--		t.Errorf("%s:%s: unmatched diagnostic pattern %q", fileName, w.Range, w.Message)
--	}
--}
--
--// rangeOverlaps reports whether r1 and r2 overlap.
--func rangeOverlaps(r1, r2 protocol.Range) bool {
--	if inRange(r2.Start, r1) || inRange(r1.Start, r2) {
--		return true
--	}
--	return false
--}
--
 -// inRange reports whether p is contained within [r.Start, r.End), or if p ==
 -// r.Start == r.End (special handling for the case where the range is a single
 -// point).
@@ -105974,67 +112158,6 @@
 -	return false
 -}
 -
--func DiffCodeLens(uri span.URI, want, got []protocol.CodeLens) string {
--	sortCodeLens(want)
--	sortCodeLens(got)
--
--	if len(got) != len(want) {
--		return summarizeCodeLens(-1, uri, want, got, "different lengths got %v want %v", len(got), len(want))
--	}
--	for i, w := range want {
--		g := got[i]
--		if w.Command.Command != g.Command.Command {
--			return summarizeCodeLens(i, uri, want, got, "incorrect Command Name got %v want %v", g.Command.Command, w.Command.Command)
--		}
--		if w.Command.Title != g.Command.Title {
--			return summarizeCodeLens(i, uri, want, got, "incorrect Command Title got %v want %v", g.Command.Title, w.Command.Title)
--		}
--		if protocol.ComparePosition(w.Range.Start, g.Range.Start) != 0 {
--			return summarizeCodeLens(i, uri, want, got, "incorrect Start got %v want %v", g.Range.Start, w.Range.Start)
--		}
--		if !protocol.IsPoint(g.Range) { // Accept any 'want' range if the codelens returns a zero-length range.
--			if protocol.ComparePosition(w.Range.End, g.Range.End) != 0 {
--				return summarizeCodeLens(i, uri, want, got, "incorrect End got %v want %v", g.Range.End, w.Range.End)
--			}
--		}
--	}
--	return ""
--}
--
--func sortCodeLens(c []protocol.CodeLens) {
--	sort.Slice(c, func(i int, j int) bool {
--		if r := protocol.CompareRange(c[i].Range, c[j].Range); r != 0 {
--			return r < 0
--		}
--		if c[i].Command.Command < c[j].Command.Command {
--			return true
--		} else if c[i].Command.Command == c[j].Command.Command {
--			return c[i].Command.Title < c[j].Command.Title
--		} else {
--			return false
--		}
--	})
--}
--
--func summarizeCodeLens(i int, uri span.URI, want, got []protocol.CodeLens, reason string, args ...interface{}) string {
--	msg := &bytes.Buffer{}
--	fmt.Fprint(msg, "codelens failed")
--	if i >= 0 {
--		fmt.Fprintf(msg, " at %d", i)
--	}
--	fmt.Fprint(msg, " because of ")
--	fmt.Fprintf(msg, reason, args...)
--	fmt.Fprint(msg, ":\nexpected:\n")
--	for _, d := range want {
--		fmt.Fprintf(msg, "  %s:%v: %s | %s\n", uri, d.Range, d.Command.Command, d.Command.Title)
--	}
--	fmt.Fprintf(msg, "got:\n")
--	for _, d := range got {
--		fmt.Fprintf(msg, "  %s:%v: %s | %s\n", uri, d.Range, d.Command.Command, d.Command.Title)
--	}
--	return msg.String()
--}
--
 -func DiffSignatures(spn span.Span, want, got *protocol.SignatureHelp) string {
 -	decorate := func(f string, args ...interface{}) string {
 -		return fmt.Sprintf("invalid signature at %s: %s", spn, fmt.Sprintf(f, args...))
@@ -106243,105 +112366,9 @@
 -	}
 -	return msg.String()
 -}
--
--func EnableAllAnalyzers(opts *source.Options) {
--	if opts.Analyses == nil {
--		opts.Analyses = make(map[string]bool)
--	}
--	for _, a := range opts.DefaultAnalyzers {
--		if !a.IsEnabled(opts) {
--			opts.Analyses[a.Analyzer.Name] = true
--		}
--	}
--	for _, a := range opts.TypeErrorAnalyzers {
--		if !a.IsEnabled(opts) {
--			opts.Analyses[a.Analyzer.Name] = true
--		}
--	}
--	for _, a := range opts.ConvenienceAnalyzers {
--		if !a.IsEnabled(opts) {
--			opts.Analyses[a.Analyzer.Name] = true
--		}
--	}
--	for _, a := range opts.StaticcheckAnalyzers {
--		if !a.IsEnabled(opts) {
--			opts.Analyses[a.Analyzer.Name] = true
--		}
--	}
--}
--
--func EnableAllInlayHints(opts *source.Options) {
--	if opts.Hints == nil {
--		opts.Hints = make(map[string]bool)
--	}
--	for name := range source.AllInlayHints {
--		opts.Hints[name] = true
--	}
--}
--
--func WorkspaceSymbolsString(ctx context.Context, data *Data, queryURI span.URI, symbols []protocol.SymbolInformation) (string, error) {
--	queryDir := filepath.Dir(queryURI.Filename())
--	var filtered []string
--	for _, s := range symbols {
--		uri := s.Location.URI.SpanURI()
--		dir := filepath.Dir(uri.Filename())
--		if !source.InDir(queryDir, dir) { // assume queries always issue from higher directories
--			continue
--		}
--		m, err := data.Mapper(uri)
--		if err != nil {
--			return "", err
--		}
--		spn, err := m.LocationSpan(s.Location)
--		if err != nil {
--			return "", err
--		}
--		filtered = append(filtered, fmt.Sprintf("%s %s %s", spn, s.Name, s.Kind))
--	}
--	sort.Strings(filtered)
--	return strings.Join(filtered, "\n") + "\n", nil
--}
--
--func WorkspaceSymbolsTestTypeToMatcher(typ WorkspaceSymbolsTestType) source.SymbolMatcher {
--	switch typ {
--	case WorkspaceSymbolsFuzzy:
--		return source.SymbolFuzzy
--	case WorkspaceSymbolsCaseSensitive:
--		return source.SymbolCaseSensitive
--	default:
--		return source.SymbolCaseInsensitive
--	}
--}
--
--// LocationsToSpans converts protocol location into span form for testing.
--func LocationsToSpans(data *Data, locs []protocol.Location) ([]span.Span, error) {
--	spans := make([]span.Span, len(locs))
--	for i, loc := range locs {
--		m, err := data.Mapper(loc.URI.SpanURI())
--		if err != nil {
--			return nil, err
--		}
--		spn, err := m.LocationSpan(loc)
--		if err != nil {
--			return nil, fmt.Errorf("failed for %v: %w", loc, err)
--		}
--		spans[i] = spn
--	}
--	return spans, nil
--}
--
--// SortAndFormatSpans sorts and formats a list of spans for use in an assertion.
--func SortAndFormatSpans(spans []span.Span) string {
--	span.SortSpans(spans)
--	var buf strings.Builder
--	for _, spn := range spans {
--		fmt.Fprintf(&buf, "%v\n", spn)
--	}
--	return buf.String()
--}
 diff -urN a/gopls/internal/lsp/tests/util_go118.go b/gopls/internal/lsp/tests/util_go118.go
 --- a/gopls/internal/lsp/tests/util_go118.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/util_go118.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/tests/util_go118.go	1970-01-01 08:00:00
 @@ -1,13 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -106358,8 +112385,8 @@
 -}
 diff -urN a/gopls/internal/lsp/tests/util_go121.go b/gopls/internal/lsp/tests/util_go121.go
 --- a/gopls/internal/lsp/tests/util_go121.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/tests/util_go121.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,12 +0,0 @@
++++ b/gopls/internal/lsp/tests/util_go121.go	1970-01-01 08:00:00
+@@ -1,14 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -106371,11 +112398,29 @@
 -
 -func init() {
 -	builtins["clear"] = true
+-	builtins["max"] = true
+-	builtins["min"] = true
+-}
+diff -urN a/gopls/internal/lsp/tests/util_go122.go b/gopls/internal/lsp/tests/util_go122.go
+--- a/gopls/internal/lsp/tests/util_go122.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/lsp/tests/util_go122.go	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.22
+-// +build go1.22
+-
+-package tests
+-
+-func init() {
+-	builtins["zero"] = true
 -}
 diff -urN a/gopls/internal/lsp/text_synchronization.go b/gopls/internal/lsp/text_synchronization.go
 --- a/gopls/internal/lsp/text_synchronization.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/text_synchronization.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,349 +0,0 @@
++++ b/gopls/internal/lsp/text_synchronization.go	1970-01-01 08:00:00
+@@ -1,367 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -106393,31 +112438,32 @@
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/event"
+-	"golang.org/x/tools/internal/event/tag"
 -	"golang.org/x/tools/internal/jsonrpc2"
 -)
 -
--// ModificationSource identifies the originating cause of a file modification.
+-// ModificationSource identifies the origin of a change.
 -type ModificationSource int
 -
 -const (
--	// FromDidOpen is a file modification caused by opening a file.
+-	// FromDidOpen is from a didOpen notification.
 -	FromDidOpen = ModificationSource(iota)
 -
--	// FromDidChange is a file modification caused by changing a file.
+-	// FromDidChange is from a didChange notification.
 -	FromDidChange
 -
--	// FromDidChangeWatchedFiles is a file modification caused by a change to a
--	// watched file.
+-	// FromDidChangeWatchedFiles is from didChangeWatchedFiles notification.
 -	FromDidChangeWatchedFiles
 -
--	// FromDidSave is a file modification caused by a file save.
+-	// FromDidSave is from a didSave notification.
 -	FromDidSave
 -
--	// FromDidClose is a file modification caused by closing a file.
+-	// FromDidClose is from a didClose notification.
 -	FromDidClose
 -
--	// TODO: add FromDidChangeConfiguration, once configuration changes cause a
--	// new snapshot to be created.
+-	// FromDidChangeConfiguration is from a didChangeConfiguration notification.
+-	FromDidChangeConfiguration
 -
 -	// FromRegenerateCgo refers to file modifications caused by regenerating
 -	// the cgo sources for the workspace.
@@ -106450,6 +112496,9 @@
 -}
 -
 -func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didOpen", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	uri := params.TextDocument.URI.SpanURI()
 -	if !uri.IsFile() {
 -		return nil
@@ -106461,6 +112510,8 @@
 -	// views, but it won't because ViewOf only returns an error when there
 -	// are no views in the session. I don't know if that logic should go
 -	// here, or if we can continue to rely on that implementation detail.
+-	//
+-	// TODO(golang/go#57979): this will be generalized to a different view calculation.
 -	if _, err := s.session.ViewOf(uri); err != nil {
 -		dir := filepath.Dir(uri.Filename())
 -		if err := s.addFolders(ctx, []protocol.WorkspaceFolder{{
@@ -106480,6 +112531,9 @@
 -}
 -
 -func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didChange", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	uri := params.TextDocument.URI.SpanURI()
 -	if !uri.IsFile() {
 -		return nil
@@ -106540,6 +112594,9 @@
 -}
 -
 -func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didChangeWatchedFiles")
+-	defer done()
+-
 -	var modifications []source.FileModification
 -	for _, change := range params.Changes {
 -		uri := change.URI.SpanURI()
@@ -106557,6 +112614,9 @@
 -}
 -
 -func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocumentParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didSave", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	uri := params.TextDocument.URI.SpanURI()
 -	if !uri.IsFile() {
 -		return nil
@@ -106572,6 +112632,9 @@
 -}
 -
 -func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didClose", tag.URI.Of(params.TextDocument.URI))
+-	defer done()
+-
 -	uri := params.TextDocument.URI.SpanURI()
 -	if !uri.IsFile() {
 -		return nil
@@ -106600,7 +112663,7 @@
 -	wg.Add(1)
 -	defer wg.Done()
 -
--	if s.session.Options().VerboseWorkDoneProgress {
+-	if s.Options().VerboseWorkDoneProgress {
 -		work := s.progress.Start(ctx, DiagnosticWorkTitle(cause), "Calculating file diagnostics...", nil, nil)
 -		go func() {
 -			wg.Wait()
@@ -106641,7 +112704,7 @@
 -	for snapshot, uris := range snapshots {
 -		for _, uri := range uris {
 -			mod := modMap[uri]
--			if snapshot.View().Options().ChattyDiagnostics || mod.Action == source.Open || mod.Action == source.Close {
+-			if snapshot.Options().ChattyDiagnostics || mod.Action == source.Open || mod.Action == source.Close {
 -				s.mustPublishDiagnostics(uri)
 -			}
 -		}
@@ -106680,11 +112743,11 @@
 -}
 -
 -func (s *Server) applyIncrementalChanges(ctx context.Context, uri span.URI, changes []protocol.TextDocumentContentChangeEvent) ([]byte, error) {
--	fh, err := s.session.GetFile(ctx, uri)
+-	fh, err := s.session.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
--	content, err := fh.Read()
+-	content, err := fh.Content()
 -	if err != nil {
 -		return nil, fmt.Errorf("%w: file not found (%v)", jsonrpc2.ErrInternal, err)
 -	}
@@ -106727,7 +112790,7 @@
 -}
 diff -urN a/gopls/internal/lsp/work/completion.go b/gopls/internal/lsp/work/completion.go
 --- a/gopls/internal/lsp/work/completion.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/work/completion.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/work/completion.go	1970-01-01 08:00:00
 @@ -1,154 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -106854,7 +112917,7 @@
 -
 -	sort.Strings(completions)
 -
--	var items []protocol.CompletionItem
+-	items := []protocol.CompletionItem{} // must be a slice
 -	for _, c := range completions {
 -		items = append(items, protocol.CompletionItem{
 -			Label:      c,
@@ -106885,7 +112948,7 @@
 -}
 diff -urN a/gopls/internal/lsp/work/diagnostics.go b/gopls/internal/lsp/work/diagnostics.go
 --- a/gopls/internal/lsp/work/diagnostics.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/work/diagnostics.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/work/diagnostics.go	1970-01-01 08:00:00
 @@ -1,92 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -106915,7 +112978,7 @@
 -	if uri == "" {
 -		return nil, nil
 -	}
--	fh, err := snapshot.GetFile(ctx, uri)
+-	fh, err := snapshot.ReadFile(ctx, uri)
 -	if err != nil {
 -		return nil, err
 -	}
@@ -106925,7 +112988,7 @@
 -		return nil, err
 -	}
 -	for _, d := range diagnostics {
--		fh, err := snapshot.GetFile(ctx, d.URI)
+-		fh, err := snapshot.ReadFile(ctx, d.URI)
 -		if err != nil {
 -			return nil, err
 -		}
@@ -106952,11 +113015,11 @@
 -			return nil, err
 -		}
 -
--		modfh, err := snapshot.GetFile(ctx, modFileURI(pw, use))
+-		modfh, err := snapshot.ReadFile(ctx, modFileURI(pw, use))
 -		if err != nil {
 -			return nil, err
 -		}
--		if _, err := modfh.Read(); err != nil && os.IsNotExist(err) {
+-		if _, err := modfh.Content(); err != nil && os.IsNotExist(err) {
 -			diagnostics = append(diagnostics, &source.Diagnostic{
 -				URI:      fh.URI(),
 -				Range:    rng,
@@ -106981,7 +113044,7 @@
 -}
 diff -urN a/gopls/internal/lsp/work/format.go b/gopls/internal/lsp/work/format.go
 --- a/gopls/internal/lsp/work/format.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/work/format.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/lsp/work/format.go	1970-01-01 08:00:00
 @@ -1,28 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -107008,13 +113071,13 @@
 -	}
 -	formatted := modfile.Format(pw.File.Syntax)
 -	// Calculate the edits to be made due to the change.
--	diffs := snapshot.View().Options().ComputeEdits(string(pw.Mapper.Content), string(formatted))
+-	diffs := snapshot.Options().ComputeEdits(string(pw.Mapper.Content), string(formatted))
 -	return source.ToProtocolEdits(pw.Mapper, diffs)
 -}
 diff -urN a/gopls/internal/lsp/work/hover.go b/gopls/internal/lsp/work/hover.go
 --- a/gopls/internal/lsp/work/hover.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/work/hover.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,89 +0,0 @@
++++ b/gopls/internal/lsp/work/hover.go	1970-01-01 08:00:00
+@@ -1,92 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107061,7 +113124,7 @@
 -	}
 -
 -	// Get the mod file denoted by the use.
--	modfh, err := snapshot.GetFile(ctx, modFileURI(pw, use))
+-	modfh, err := snapshot.ReadFile(ctx, modFileURI(pw, use))
 -	if err != nil {
 -		return nil, fmt.Errorf("getting modfile handle: %w", err)
 -	}
@@ -107069,6 +113132,9 @@
 -	if err != nil {
 -		return nil, fmt.Errorf("getting modfile handle: %w", err)
 -	}
+-	if pm.File.Module == nil {
+-		return nil, fmt.Errorf("modfile has no module declaration")
+-	}
 -	mod := pm.File.Module.Mod
 -
 -	// Get the range to highlight for the hover.
@@ -107076,7 +113142,7 @@
 -	if err != nil {
 -		return nil, err
 -	}
--	options := snapshot.View().Options()
+-	options := snapshot.Options()
 -	return &protocol.Hover{
 -		Contents: protocol.MarkupContent{
 -			Kind:  options.PreferredContentFormat,
@@ -107106,8 +113172,8 @@
 -}
 diff -urN a/gopls/internal/lsp/workspace.go b/gopls/internal/lsp/workspace.go
 --- a/gopls/internal/lsp/workspace.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/workspace.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,95 +0,0 @@
++++ b/gopls/internal/lsp/workspace.go	1970-01-01 08:00:00
+@@ -1,100 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107117,16 +113183,18 @@
 -import (
 -	"context"
 -	"fmt"
+-	"sync"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/internal/event"
 -)
 -
 -func (s *Server) didChangeWorkspaceFolders(ctx context.Context, params *protocol.DidChangeWorkspaceFoldersParams) error {
 -	event := params.Event
 -	for _, folder := range event.Removed {
--		view := s.session.View(folder.Name)
+-		view := s.session.ViewByName(folder.Name)
 -		if view != nil {
 -			s.session.RemoveView(view)
 -		} else {
@@ -107145,8 +113213,8 @@
 -	if state < serverInitialized {
 -		return nil, nil, fmt.Errorf("addView called before server initialized")
 -	}
--	options := s.session.Options().Clone()
--	if err := s.fetchConfig(ctx, name, uri, options); err != nil {
+-	options, err := s.fetchFolderOptions(ctx, uri)
+-	if err != nil {
 -		return nil, nil, err
 -	}
 -	_, snapshot, release, err := s.session.NewView(ctx, name, uri, options)
@@ -107154,30 +113222,50 @@
 -}
 -
 -func (s *Server) didChangeConfiguration(ctx context.Context, _ *protocol.DidChangeConfigurationParams) error {
+-	ctx, done := event.Start(ctx, "lsp.Server.didChangeConfiguration")
+-	defer done()
+-
 -	// Apply any changes to the session-level settings.
--	options := s.session.Options().Clone()
--	if err := s.fetchConfig(ctx, "", "", options); err != nil {
+-	options, err := s.fetchFolderOptions(ctx, "")
+-	if err != nil {
 -		return err
 -	}
--	s.session.SetOptions(options)
+-	s.SetOptions(options)
 -
--	// Go through each view, getting and updating its configuration.
+-	// Collect options for all workspace folders.
+-	seen := make(map[span.URI]bool)
 -	for _, view := range s.session.Views() {
--		options := s.session.Options().Clone()
--		if err := s.fetchConfig(ctx, view.Name(), view.Folder(), options); err != nil {
--			return err
+-		if seen[view.Folder()] {
+-			continue
 -		}
--		view, err := s.session.SetViewOptions(ctx, view, options)
+-		seen[view.Folder()] = true
+-		options, err := s.fetchFolderOptions(ctx, view.Folder())
 -		if err != nil {
 -			return err
 -		}
+-		s.session.SetFolderOptions(ctx, view.Folder(), options)
+-	}
+-
+-	var wg sync.WaitGroup
+-	for _, view := range s.session.Views() {
+-		view := view
+-		wg.Add(1)
 -		go func() {
+-			defer wg.Done()
 -			snapshot, release, err := view.Snapshot()
 -			if err != nil {
 -				return // view is shut down; no need to diagnose
 -			}
 -			defer release()
--			s.diagnoseDetached(snapshot)
+-			s.diagnoseSnapshot(snapshot, nil, false, 0)
+-		}()
+-	}
+-
+-	if s.Options().VerboseWorkDoneProgress {
+-		work := s.progress.Start(ctx, DiagnosticWorkTitle(FromDidChangeConfiguration), "Calculating diagnostics...", nil, nil)
+-		go func() {
+-			wg.Wait()
+-			work.End(ctx, "Done.")
 -		}()
 -	}
 -
@@ -107186,27 +113274,10 @@
 -
 -	return nil
 -}
--
--func semanticTokenRegistration(tokenTypes, tokenModifiers []string) protocol.Registration {
--	return protocol.Registration{
--		ID:     "textDocument/semanticTokens",
--		Method: "textDocument/semanticTokens",
--		RegisterOptions: &protocol.SemanticTokensOptions{
--			Legend: protocol.SemanticTokensLegend{
--				// TODO(pjw): trim these to what we use (and an unused one
--				// at position 0 of TokTypes, to catch typos)
--				TokenTypes:     tokenTypes,
--				TokenModifiers: tokenModifiers,
--			},
--			Full:  &protocol.Or_SemanticTokensOptions_full{Value: true},
--			Range: &protocol.Or_SemanticTokensOptions_range{Value: true},
--		},
--	}
--}
 diff -urN a/gopls/internal/lsp/workspace_symbol.go b/gopls/internal/lsp/workspace_symbol.go
 --- a/gopls/internal/lsp/workspace_symbol.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/lsp/workspace_symbol.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,32 +0,0 @@
++++ b/gopls/internal/lsp/workspace_symbol.go	1970-01-01 08:00:00
+@@ -1,38 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107218,16 +113289,22 @@
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
+-	"golang.org/x/tools/gopls/internal/telemetry"
 -	"golang.org/x/tools/internal/event"
 -)
 -
--func (s *Server) symbol(ctx context.Context, params *protocol.WorkspaceSymbolParams) ([]protocol.SymbolInformation, error) {
+-func (s *Server) symbol(ctx context.Context, params *protocol.WorkspaceSymbolParams) (_ []protocol.SymbolInformation, rerr error) {
+-	recordLatency := telemetry.StartLatencyTimer("symbol")
+-	defer func() {
+-		recordLatency(ctx, rerr)
+-	}()
+-
 -	ctx, done := event.Start(ctx, "lsp.Server.symbol")
 -	defer done()
 -
 -	views := s.session.Views()
--	matcher := s.session.Options().SymbolMatcher
--	style := s.session.Options().SymbolStyle
+-	matcher := s.Options().SymbolMatcher
+-	style := s.Options().SymbolStyle
 -	// TODO(rfindley): it looks wrong that we need to pass views here.
 -	//
 -	// Evidence:
@@ -107241,8 +113318,8 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/bench_test.go b/gopls/internal/regtest/bench/bench_test.go
 --- a/gopls/internal/regtest/bench/bench_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/bench_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,249 +0,0 @@
++++ b/gopls/internal/regtest/bench/bench_test.go	1970-01-01 08:00:00
+@@ -1,351 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107250,29 +113327,33 @@
 -package bench
 -
 -import (
+-	"bytes"
+-	"compress/gzip"
 -	"context"
 -	"flag"
 -	"fmt"
--	"io/ioutil"
+-	"io"
 -	"log"
 -	"os"
 -	"os/exec"
 -	"path/filepath"
+-	"strings"
 -	"sync"
 -	"testing"
 -	"time"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/cmd"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
--	"golang.org/x/tools/internal/bug"
+-	"golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/internal/event"
 -	"golang.org/x/tools/internal/fakenet"
 -	"golang.org/x/tools/internal/jsonrpc2"
 -	"golang.org/x/tools/internal/jsonrpc2/servertest"
+-	"golang.org/x/tools/internal/pprof"
 -	"golang.org/x/tools/internal/tool"
--
--	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -)
 -
 -var (
@@ -107281,9 +113362,10 @@
 -	installGoplsOnce sync.Once // guards installing gopls at -gopls_commit
 -	goplsCommit      = flag.String("gopls_commit", "", "if set, install and use gopls at this commit for testing; incompatible with -gopls_path")
 -
--	cpuProfile = flag.String("gopls_cpuprofile", "", "if set, the cpu profile file suffix; see \"Profiling\" in the package doc")
--	memProfile = flag.String("gopls_memprofile", "", "if set, the mem profile file suffix; see \"Profiling\" in the package doc")
--	trace      = flag.String("gopls_trace", "", "if set, the trace file suffix; see \"Profiling\" in the package doc")
+-	cpuProfile   = flag.String("gopls_cpuprofile", "", "if set, the cpu profile file suffix; see \"Profiling\" in the package doc")
+-	memProfile   = flag.String("gopls_memprofile", "", "if set, the mem profile file suffix; see \"Profiling\" in the package doc")
+-	allocProfile = flag.String("gopls_allocprofile", "", "if set, the alloc profile file suffix; see \"Profiling\" in the package doc")
+-	trace        = flag.String("gopls_trace", "", "if set, the trace file suffix; see \"Profiling\" in the package doc")
 -
 -	// If non-empty, tempDir is a temporary working dir that was created by this
 -	// test suite.
@@ -107316,7 +113398,7 @@
 -func getTempDir() string {
 -	makeTempDirOnce.Do(func() {
 -		var err error
--		tempDir, err = ioutil.TempDir("", "gopls-bench")
+-		tempDir, err = os.MkdirTemp("", "gopls-bench")
 -		if err != nil {
 -			log.Fatal(err)
 -		}
@@ -107349,7 +113431,7 @@
 -
 -// connectEditor connects a fake editor session in the given dir, using the
 -// given editor config.
--func connectEditor(dir string, config fake.EditorConfig, ts servertest.Connector) (*fake.Sandbox, *fake.Editor, *Awaiter, error) {
+-func connectEditor(dir string, config fake.EditorConfig, ts servertest.Connector) (*fake.Sandbox, *fake.Editor, *regtest.Awaiter, error) {
 -	s, err := fake.NewSandbox(&fake.SandboxConfig{
 -		Workdir: dir,
 -		GOPROXY: "https://proxy.golang.org",
@@ -107358,7 +113440,7 @@
 -		return nil, nil, nil, err
 -	}
 -
--	a := NewAwaiter(s.Workdir)
+-	a := regtest.NewAwaiter(s.Workdir)
 -	const skipApplyEdits = false
 -	editor, err := fake.NewEditor(s, config).Connect(context.Background(), ts, a.Hooks(), skipApplyEdits)
 -	if err != nil {
@@ -107368,8 +113450,9 @@
 -	return s, editor, a, nil
 -}
 -
--// newGoplsServer returns a connector that connects to a new gopls process.
--func newGoplsServer(name string) (servertest.Connector, error) {
+-// newGoplsConnector returns a connector that connects to a new gopls process,
+-// executed with the provided arguments.
+-func newGoplsConnector(args []string) (servertest.Connector, error) {
 -	if *goplsPath != "" && *goplsCommit != "" {
 -		panic("can't set both -gopls_path and -gopls_commit")
 -	}
@@ -107388,16 +113471,6 @@
 -		}
 -		env = []string{fmt.Sprintf("%s=true", runAsGopls)}
 -	}
--	var args []string
--	if *cpuProfile != "" {
--		args = append(args, fmt.Sprintf("-profile.cpu=%s", name+"."+*cpuProfile))
--	}
--	if *memProfile != "" {
--		args = append(args, fmt.Sprintf("-profile.mem=%s", name+"."+*memProfile))
--	}
--	if *trace != "" {
--		args = append(args, fmt.Sprintf("-profile.trace=%s", name+"."+*trace))
--	}
 -	return &SidecarServer{
 -		goplsPath: goplsPath,
 -		env:       env,
@@ -107405,6 +113478,39 @@
 -	}, nil
 -}
 -
+-// profileArgs returns additional command-line arguments to use when invoking
+-// gopls, to enable the user-requested profiles.
+-//
+-// If wantCPU is set, CPU profiling is enabled as well. Some tests may want to
+-// instrument profiling around specific critical sections of the benchmark,
+-// rather than the entire process.
+-//
+-// TODO(rfindley): like CPU, all of these would be better served by a custom
+-// command. Very rarely do we care about memory usage as the process exits: we
+-// care about specific points in time during the benchmark. mem and alloc
+-// should be snapshotted, and tracing should be bracketed around critical
+-// sections.
+-func profileArgs(name string, wantCPU bool) []string {
+-	var args []string
+-	if wantCPU && *cpuProfile != "" {
+-		args = append(args, fmt.Sprintf("-profile.cpu=%s", qualifiedName(name, *cpuProfile)))
+-	}
+-	if *memProfile != "" {
+-		args = append(args, fmt.Sprintf("-profile.mem=%s", qualifiedName(name, *memProfile)))
+-	}
+-	if *allocProfile != "" {
+-		args = append(args, fmt.Sprintf("-profile.alloc=%s", qualifiedName(name, *allocProfile)))
+-	}
+-	if *trace != "" {
+-		args = append(args, fmt.Sprintf("-profile.trace=%s", qualifiedName(name, *trace)))
+-	}
+-	return args
+-}
+-
+-func qualifiedName(args ...string) string {
+-	return strings.Join(args, ".")
+-}
+-
 -// getInstalledGopls builds gopls at the given -gopls_commit, returning the
 -// path to the gopls binary.
 -func getInstalledGopls() string {
@@ -107492,11 +113598,84 @@
 -
 -	return clientConn
 -}
-diff -urN a/gopls/internal/regtest/bench/completion_test.go b/gopls/internal/regtest/bench/completion_test.go
---- a/gopls/internal/regtest/bench/completion_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/completion_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,173 +0,0 @@
--// Copyright 2020 The Go Authors. All rights reserved.
+-
+-// startProfileIfSupported checks to see if the remote gopls instance supports
+-// the start/stop profiling commands. If so, it starts profiling and returns a
+-// function that stops profiling and records the total CPU seconds sampled in the
+-// cpu_seconds benchmark metric.
+-//
+-// If the remote gopls instance does not support profiling commands, this
+-// function returns nil.
+-//
+-// If the supplied userSuffix is non-empty, the profile is written to
+-// <repo>.<userSuffix>, and not deleted when the benchmark exits. Otherwise,
+-// the profile is written to a temp file that is deleted after the cpu_seconds
+-// metric has been computed.
+-func startProfileIfSupported(b *testing.B, env *regtest.Env, name string) func() {
+-	if !env.Editor.HasCommand(command.StartProfile.ID()) {
+-		return nil
+-	}
+-	b.StopTimer()
+-	stopProfile := env.StartProfile()
+-	b.StartTimer()
+-	return func() {
+-		b.StopTimer()
+-		profFile := stopProfile()
+-		totalCPU, err := totalCPUForProfile(profFile)
+-		if err != nil {
+-			b.Fatalf("reading profile: %v", err)
+-		}
+-		b.ReportMetric(totalCPU.Seconds()/float64(b.N), "cpu_seconds/op")
+-		if *cpuProfile == "" {
+-			// The user didn't request profiles, so delete it to clean up.
+-			if err := os.Remove(profFile); err != nil {
+-				b.Errorf("removing profile file: %v", err)
+-			}
+-		} else {
+-			// NOTE: if this proves unreliable (due to e.g. EXDEV), we can fall back
+-			// on Read+Write+Remove.
+-			name := qualifiedName(name, *cpuProfile)
+-			if err := os.Rename(profFile, name); err != nil {
+-				b.Fatalf("renaming profile file: %v", err)
+-			}
+-		}
+-	}
+-}
+-
+-// totalCPUForProfile reads the pprof profile with the given file name, parses,
+-// and aggregates the total CPU sampled during the profile.
+-func totalCPUForProfile(filename string) (time.Duration, error) {
+-	protoGz, err := os.ReadFile(filename)
+-	if err != nil {
+-		return 0, err
+-	}
+-	rd, err := gzip.NewReader(bytes.NewReader(protoGz))
+-	if err != nil {
+-		return 0, fmt.Errorf("creating gzip reader for %s: %v", filename, err)
+-	}
+-	data, err := io.ReadAll(rd)
+-	if err != nil {
+-		return 0, fmt.Errorf("reading %s: %v", filename, err)
+-	}
+-	return pprof.TotalTime(data)
+-}
+-
+-// closeBuffer stops the benchmark timer and closes the buffer with the given
+-// name.
+-//
+-// It may be used to clean up files opened in the shared environment during
+-// benchmarking.
+-func closeBuffer(b *testing.B, env *regtest.Env, name string) {
+-	b.StopTimer()
+-	env.CloseBuffer(name)
+-	env.AfterChange()
+-	b.StartTimer()
+-}
+diff -urN a/gopls/internal/regtest/bench/codeaction_test.go b/gopls/internal/regtest/bench/codeaction_test.go
+--- a/gopls/internal/regtest/bench/codeaction_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/bench/codeaction_test.go	1970-01-01 08:00:00
+@@ -1,69 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
@@ -107504,6 +113683,81 @@
 -
 -import (
 -	"fmt"
+-	"sync/atomic"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
+-
+-func BenchmarkCodeAction(b *testing.B) {
+-	for _, test := range didChangeTests {
+-		b.Run(test.repo, func(b *testing.B) {
+-			env := getRepo(b, test.repo).sharedEnv(b)
+-			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-			env.AfterChange()
+-
+-			env.CodeAction(test.file, nil) // pre-warm
+-
+-			b.ResetTimer()
+-
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "hover")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
+-			for i := 0; i < b.N; i++ {
+-				env.CodeAction(test.file, nil)
+-			}
+-		})
+-	}
+-}
+-
+-func BenchmarkCodeActionFollowingEdit(b *testing.B) {
+-	for _, test := range didChangeTests {
+-		b.Run(test.repo, func(b *testing.B) {
+-			env := getRepo(b, test.repo).sharedEnv(b)
+-			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-			env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"})
+-			env.AfterChange()
+-
+-			env.CodeAction(test.file, nil) // pre-warm
+-
+-			b.ResetTimer()
+-
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "hover")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
+-			for i := 0; i < b.N; i++ {
+-				edits := atomic.AddInt64(&editID, 1)
+-				env.EditBuffer(test.file, protocol.TextEdit{
+-					Range: protocol.Range{
+-						Start: protocol.Position{Line: 0, Character: 0},
+-						End:   protocol.Position{Line: 1, Character: 0},
+-					},
+-					// Increment the placeholder text, to ensure cache misses.
+-					NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits),
+-				})
+-				env.CodeAction(test.file, nil)
+-			}
+-		})
+-	}
+-}
+diff -urN a/gopls/internal/regtest/bench/completion_test.go b/gopls/internal/regtest/bench/completion_test.go
+--- a/gopls/internal/regtest/bench/completion_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/bench/completion_test.go	1970-01-01 08:00:00
+@@ -1,290 +0,0 @@
+-// Copyright 2020 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package bench
+-
+-import (
+-	"flag"
+-	"fmt"
+-	"sync/atomic"
 -	"testing"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
@@ -107523,7 +113777,8 @@
 -
 -func benchmarkCompletion(options completionBenchOptions, b *testing.B) {
 -	repo := getRepo(b, "tools")
--	env := repo.newEnv(b, "completion.tools", fake.EditorConfig{})
+-	_ = repo.sharedEnv(b) // ensure cache is warm
+-	env := repo.newEnv(b, fake.EditorConfig{}, "completion", false)
 -	defer env.Close()
 -
 -	// Run edits required for this completion.
@@ -107543,6 +113798,10 @@
 -	}
 -
 -	b.Run("tools", func(b *testing.B) {
+-		if stopAndRecord := startProfileIfSupported(b, env, qualifiedName("tools", "completion")); stopAndRecord != nil {
+-			defer stopAndRecord()
+-		}
+-
 -		for i := 0; i < b.N; i++ {
 -			if options.beforeCompletion != nil {
 -				options.beforeCompletion(env)
@@ -107624,7 +113883,8 @@
 -		env.OpenFile(file)
 -		originalBuffer := env.BufferText(file)
 -		env.EditBuffer(file, protocol.TextEdit{
--			Range:   endRangeInBuffer(env, file),
+-			Range: endRangeInBuffer(env, file),
+-			// TODO(rfindley): this is a bug: it should just be fileContent.
 -			NewText: originalBuffer + fileContent,
 -		})
 -	}
@@ -107636,43 +113896,152 @@
 -	}, b)
 -}
 -
+-type completionFollowingEditTest struct {
+-	repo           string
+-	name           string
+-	file           string // repo-relative file to create
+-	content        string // file content
+-	locationRegexp string // regexp for completion
+-}
+-
+-var completionFollowingEditTests = []completionFollowingEditTest{
+-	{
+-		"tools",
+-		"selector",
+-		"internal/lsp/source/completion/completion2.go",
+-		`
+-package completion
+-
+-func (c *completer) _() {
+-	c.inference.kindMatches(c.)
+-}
+-`,
+-		`func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)`,
+-	},
+-	{
+-		"kubernetes",
+-		"selector",
+-		"pkg/kubelet/kubelet2.go",
+-		`
+-package kubelet
+-
+-func (kl *Kubelet) _() {
+-	kl.
+-}
+-`,
+-		`kl\.()`,
+-	},
+-	{
+-		"kubernetes",
+-		"identifier",
+-		"pkg/kubelet/kubelet2.go",
+-		`
+-package kubelet
+-
+-func (kl *Kubelet) _() {
+-	k // here
+-}
+-`,
+-		`k() // here`,
+-	},
+-	{
+-		"oracle",
+-		"selector",
+-		"dataintegration/pivot2.go",
+-		`
+-package dataintegration
+-
+-func (p *Pivot) _() {
+-	p.
+-}
+-`,
+-		`p\.()`,
+-	},
+-}
+-
 -// Benchmark completion following an arbitrary edit.
 -//
 -// Edits force type-checked packages to be invalidated, so we want to measure
 -// how long it takes before completion results are available.
 -func BenchmarkCompletionFollowingEdit(b *testing.B) {
--	file := "internal/lsp/source/completion/completion2.go"
--	fileContent := `
--package completion
--
--func (c *completer) _() {
--	c.inference.kindMatches(c.)
--	// __MAGIC_STRING_1
+-	for _, test := range completionFollowingEditTests {
+-		b.Run(fmt.Sprintf("%s_%s", test.repo, test.name), func(b *testing.B) {
+-			for _, completeUnimported := range []bool{true, false} {
+-				b.Run(fmt.Sprintf("completeUnimported=%v", completeUnimported), func(b *testing.B) {
+-					for _, budget := range []string{"0s", "100ms"} {
+-						b.Run(fmt.Sprintf("budget=%s", budget), func(b *testing.B) {
+-							runCompletionFollowingEdit(b, test, completeUnimported, budget)
+-						})
+-					}
+-				})
+-			}
+-		})
+-	}
 -}
--`
--	setup := func(env *Env) {
--		env.CreateBuffer(file, fileContent)
+-
+-var gomodcache = flag.String("gomodcache", "", "optional GOMODCACHE for unimported completion benchmarks")
+-
+-func runCompletionFollowingEdit(b *testing.B, test completionFollowingEditTest, completeUnimported bool, budget string) {
+-	repo := getRepo(b, test.repo)
+-	sharedEnv := repo.sharedEnv(b) // ensure cache is warm
+-	envvars := map[string]string{
+-		"GOPATH": sharedEnv.Sandbox.GOPATH(), // use the warm cache
 -	}
 -
--	n := 1
--	beforeCompletion := func(env *Env) {
--		old := fmt.Sprintf("__MAGIC_STRING_%d", n)
--		new := fmt.Sprintf("__MAGIC_STRING_%d", n+1)
--		n++
--		env.RegexpReplace(file, old, new)
+-	if *gomodcache != "" {
+-		envvars["GOMODCACHE"] = *gomodcache
 -	}
 -
--	benchmarkCompletion(completionBenchOptions{
--		file:             file,
--		locationRegexp:   `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)`,
--		setup:            setup,
--		beforeCompletion: beforeCompletion,
--	}, b)
+-	env := repo.newEnv(b, fake.EditorConfig{
+-		Env: envvars,
+-		Settings: map[string]interface{}{
+-			"completeUnimported": completeUnimported,
+-			"completionBudget":   budget,
+-		},
+-	}, "completionFollowingEdit", false)
+-	defer env.Close()
+-
+-	env.CreateBuffer(test.file, "// __REGTEST_PLACEHOLDER_0__\n"+test.content)
+-	editPlaceholder := func() {
+-		edits := atomic.AddInt64(&editID, 1)
+-		env.EditBuffer(test.file, protocol.TextEdit{
+-			Range: protocol.Range{
+-				Start: protocol.Position{Line: 0, Character: 0},
+-				End:   protocol.Position{Line: 1, Character: 0},
+-			},
+-			// Increment the placeholder text, to ensure cache misses.
+-			NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits),
+-		})
+-	}
+-	env.AfterChange()
+-
+-	// Run a completion to make sure the system is warm.
+-	loc := env.RegexpSearch(test.file, test.locationRegexp)
+-	completions := env.Completion(loc)
+-
+-	if testing.Verbose() {
+-		fmt.Println("Results:")
+-		for i, item := range completions.Items {
+-			fmt.Printf("\t%d. %v\n", i, item)
+-		}
+-	}
+-
+-	b.ResetTimer()
+-
+-	if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "completionFollowingEdit")); stopAndRecord != nil {
+-		defer stopAndRecord()
+-	}
+-
+-	for i := 0; i < b.N; i++ {
+-		editPlaceholder()
+-		loc := env.RegexpSearch(test.file, test.locationRegexp)
+-		env.Completion(loc)
+-	}
 -}
 diff -urN a/gopls/internal/regtest/bench/definition_test.go b/gopls/internal/regtest/bench/definition_test.go
 --- a/gopls/internal/regtest/bench/definition_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/definition_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,39 +0,0 @@
++++ b/gopls/internal/regtest/bench/definition_test.go	1970-01-01 08:00:00
+@@ -1,46 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107690,6 +114059,7 @@
 -		regexp string
 -	}{
 -		{"istio", "pkg/config/model.go", `gogotypes\.(MarshalAny)`},
+-		{"google-cloud-go", "httpreplay/httpreplay.go", `proxy\.(ForRecording)`},
 -		{"kubernetes", "pkg/controller/lookup_cache.go", `hashutil\.(DeepHashObject)`},
 -		{"kuma", "api/generic/insights.go", `proto\.(Message)`},
 -		{"pkgsite", "internal/log/log.go", `derrors\.(Wrap)`},
@@ -107701,11 +114071,17 @@
 -		b.Run(test.repo, func(b *testing.B) {
 -			env := getRepo(b, test.repo).sharedEnv(b)
 -			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
 -			loc := env.RegexpSearch(test.file, test.regexp)
 -			env.Await(env.DoneWithOpen())
 -			env.GoToDefinition(loc) // pre-warm the query, and open the target file
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "definition")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				env.GoToDefinition(loc) // pre-warm the query
 -			}
@@ -107714,8 +114090,8 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/didchange_test.go b/gopls/internal/regtest/bench/didchange_test.go
 --- a/gopls/internal/regtest/bench/didchange_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/didchange_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,99 +0,0 @@
++++ b/gopls/internal/regtest/bench/didchange_test.go	1970-01-01 08:00:00
+@@ -1,142 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107737,16 +114113,21 @@
 -// shared file cache.
 -var editID int64 = time.Now().UnixNano()
 -
--var didChangeTests = []struct {
--	repo string
--	file string
--}{
--	{"istio", "pkg/fuzz/util.go"},
--	{"kubernetes", "pkg/controller/lookup_cache.go"},
--	{"kuma", "api/generic/insights.go"},
--	{"pkgsite", "internal/frontend/server.go"},
--	{"starlark", "starlark/eval.go"},
--	{"tools", "internal/lsp/cache/snapshot.go"},
+-type changeTest struct {
+-	repo    string
+-	file    string
+-	canSave bool
+-}
+-
+-var didChangeTests = []changeTest{
+-	{"google-cloud-go", "internal/annotate.go", true},
+-	{"istio", "pkg/fuzz/util.go", true},
+-	{"kubernetes", "pkg/controller/lookup_cache.go", true},
+-	{"kuma", "api/generic/insights.go", true},
+-	{"oracle", "dataintegration/data_type.go", false}, // diagnoseSave fails because this package is generated
+-	{"pkgsite", "internal/frontend/server.go", true},
+-	{"starlark", "starlark/eval.go", true},
+-	{"tools", "internal/lsp/cache/snapshot.go", true},
 -}
 -
 -// BenchmarkDidChange benchmarks modifications of a single file by making
@@ -107758,11 +114139,17 @@
 -		b.Run(test.repo, func(b *testing.B) {
 -			env := getRepo(b, test.repo).sharedEnv(b)
 -			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
 -			// Insert the text we'll be modifying at the top of the file.
 -			env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"})
 -			env.AfterChange()
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "didchange")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				edits := atomic.AddInt64(&editID, 1)
 -				env.EditBuffer(test.file, protocol.TextEdit{
@@ -107781,44 +114168,76 @@
 -
 -func BenchmarkDiagnoseChange(b *testing.B) {
 -	for _, test := range didChangeTests {
--		b.Run(test.repo, func(b *testing.B) {
--			// Use a new env to avoid the diagnostic delay: we want to measure how
--			// long it takes to produce the diagnostics.
--			env := repos[test.repo].newEnv(b, "diagnoseChange", fake.EditorConfig{
--				Settings: map[string]interface{}{
--					"diagnosticsDelay": "0s",
--				},
--			})
--			env.OpenFile(test.file)
--			// Insert the text we'll be modifying at the top of the file.
--			env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"})
--			env.AfterChange()
--			b.ResetTimer()
--
--			// We must use an extra subtest layer here, so that we only set up the
--			// shared env once (otherwise we pay additional overhead and the profiling
--			// flags don't work).
--			b.Run("diagnose", func(b *testing.B) {
--				for i := 0; i < b.N; i++ {
--					edits := atomic.AddInt64(&editID, 1)
--					env.EditBuffer(test.file, protocol.TextEdit{
--						Range: protocol.Range{
--							Start: protocol.Position{Line: 0, Character: 0},
--							End:   protocol.Position{Line: 1, Character: 0},
--						},
--						// Increment the placeholder text, to ensure cache misses.
--						NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits),
--					})
--					env.AfterChange()
--				}
--			})
--		})
+-		runChangeDiagnosticsBenchmark(b, test, false, "diagnoseChange")
 -	}
 -}
+-
+-// TODO(rfindley): add a benchmark for with a metadata-affecting change, when
+-// this matters.
+-func BenchmarkDiagnoseSave(b *testing.B) {
+-	for _, test := range didChangeTests {
+-		runChangeDiagnosticsBenchmark(b, test, true, "diagnoseSave")
+-	}
+-}
+-
+-// runChangeDiagnosticsBenchmark runs a benchmark to edit the test file and
+-// await the resulting diagnostics pass. If save is set, the file is also saved.
+-func runChangeDiagnosticsBenchmark(b *testing.B, test changeTest, save bool, operation string) {
+-	b.Run(test.repo, func(b *testing.B) {
+-		if !test.canSave {
+-			b.Skipf("skipping as %s cannot be saved", test.file)
+-		}
+-		sharedEnv := getRepo(b, test.repo).sharedEnv(b)
+-		config := fake.EditorConfig{
+-			Env: map[string]string{
+-				"GOPATH": sharedEnv.Sandbox.GOPATH(),
+-			},
+-			Settings: map[string]interface{}{
+-				"diagnosticsDelay": "0s",
+-			},
+-		}
+-		// Use a new env to avoid the diagnostic delay: we want to measure how
+-		// long it takes to produce the diagnostics.
+-		env := getRepo(b, test.repo).newEnv(b, config, operation, false)
+-		defer env.Close()
+-		env.OpenFile(test.file)
+-		// Insert the text we'll be modifying at the top of the file.
+-		env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"})
+-		if save {
+-			env.SaveBuffer(test.file)
+-		}
+-		env.AfterChange()
+-		b.ResetTimer()
+-
+-		// We must use an extra subtest layer here, so that we only set up the
+-		// shared env once (otherwise we pay additional overhead and the profiling
+-		// flags don't work).
+-		b.Run("diagnose", func(b *testing.B) {
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, operation)); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-			for i := 0; i < b.N; i++ {
+-				edits := atomic.AddInt64(&editID, 1)
+-				env.EditBuffer(test.file, protocol.TextEdit{
+-					Range: protocol.Range{
+-						Start: protocol.Position{Line: 0, Character: 0},
+-						End:   protocol.Position{Line: 1, Character: 0},
+-					},
+-					// Increment the placeholder text, to ensure cache misses.
+-					NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits),
+-				})
+-				if save {
+-					env.SaveBuffer(test.file)
+-				}
+-				env.AfterChange()
+-			}
+-		})
+-	})
+-}
 diff -urN a/gopls/internal/regtest/bench/doc.go b/gopls/internal/regtest/bench/doc.go
 --- a/gopls/internal/regtest/bench/doc.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/doc.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,33 +0,0 @@
++++ b/gopls/internal/regtest/bench/doc.go	1970-01-01 08:00:00
+@@ -1,40 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107835,27 +114254,34 @@
 -//
 -// # Profiling
 -//
--// As benchmark functions run gopls in a separate process, the normal test
--// flags for profiling are not useful. Instead the -gopls_cpuprofile,
--// -gopls_memprofile, and -gopls_trace flags may be used to pass through
--// profiling flags to the gopls process. Each of these flags sets a suffix
--// for the respective gopls profiling flag, which is prefixed with a name
--// corresponding to the shared repository or (in some cases) benchmark name.
--// For example, settings -gopls_cpuprofile=cpu.out will result in profiles
--// named tools.cpu.out, BenchmarkInitialWorkspaceLoad.cpu.out, etc. Here,
--// tools.cpu.out is the cpu profile for the shared x/tools session, which may
--// be used by multiple benchmark functions, and BenchmarkInitialWorkspaceLoad
--// is the cpu profile for the last iteration of the initial workspace load
--// test, which starts a new editor session for each iteration.
+-// Benchmark functions run gopls in a separate process, which means the normal
+-// test flags for profiling aren't useful. Instead the -gopls_cpuprofile,
+-// -gopls_memprofile, -gopls_allocprofile, and -gopls_trace flags may be used
+-// to pass through profiling to the gopls subproces.
+-//
+-// Each of these flags sets a suffix for the respective gopls profile, which is
+-// named according to the schema <repo>.<operation>.<suffix>. For example,
+-// setting -gopls_cpuprofile=cpu will result in profiles named tools.iwl.cpu,
+-// tools.rename.cpu, etc. In some cases, these profiles are for the entire
+-// gopls subprocess (as in the initial workspace load), whereas in others they
+-// span only the critical section of the benchmark. It is up to each benchmark
+-// to implement profiling as appropriate.
+-//
+-// # Integration with perf.golang.org
+-//
+-// Benchmarks that run with -short are automatically tracked by
+-// perf.golang.org, at
+-// https://perf.golang.org/dashboard/?benchmark=all&repository=tools&branch=release-branch.go1.20
 -//
 -// # TODO
 -//   - add more benchmarks, and more repositories
+-//   - fix the perf dashboard to not require the branch= parameter
 -//   - improve this documentation
 -package bench
 diff -urN a/gopls/internal/regtest/bench/hover_test.go b/gopls/internal/regtest/bench/hover_test.go
 --- a/gopls/internal/regtest/bench/hover_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/hover_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,39 +0,0 @@
++++ b/gopls/internal/regtest/bench/hover_test.go	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107872,6 +114298,7 @@
 -		file   string
 -		regexp string
 -	}{
+-		{"google-cloud-go", "httpreplay/httpreplay.go", `proxy\.(ForRecording)`},
 -		{"istio", "pkg/config/model.go", `gogotypes\.(MarshalAny)`},
 -		{"kubernetes", "pkg/apis/core/types.go", "type (Pod)"},
 -		{"kuma", "api/generic/insights.go", `proto\.(Message)`},
@@ -107884,11 +114311,18 @@
 -		b.Run(test.repo, func(b *testing.B) {
 -			env := getRepo(b, test.repo).sharedEnv(b)
 -			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
 -			loc := env.RegexpSearch(test.file, test.regexp)
--			env.Await(env.DoneWithOpen())
+-			env.AfterChange()
+-
 -			env.Hover(loc) // pre-warm the query
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "hover")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				env.Hover(loc) // pre-warm the query
 -			}
@@ -107897,8 +114331,8 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/implementations_test.go b/gopls/internal/regtest/bench/implementations_test.go
 --- a/gopls/internal/regtest/bench/implementations_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/implementations_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
++++ b/gopls/internal/regtest/bench/implementations_test.go	1970-01-01 08:00:00
+@@ -1,44 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107913,6 +114347,7 @@
 -		file   string
 -		regexp string
 -	}{
+-		{"google-cloud-go", "httpreplay/httpreplay.go", `type (Recorder)`},
 -		{"istio", "pkg/config/mesh/watcher.go", `type (Watcher)`},
 -		{"kubernetes", "pkg/controller/lookup_cache.go", `objectWithMeta`},
 -		{"kuma", "api/generic/insights.go", `type (Insight)`},
@@ -107925,11 +114360,17 @@
 -		b.Run(test.repo, func(b *testing.B) {
 -			env := getRepo(b, test.repo).sharedEnv(b)
 -			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
 -			loc := env.RegexpSearch(test.file, test.regexp)
--			env.Await(env.DoneWithOpen())
+-			env.AfterChange()
 -			env.Implementations(loc) // pre-warm the query
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "implementations")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				env.Implementations(loc)
 -			}
@@ -107938,8 +114379,8 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/iwl_test.go b/gopls/internal/regtest/bench/iwl_test.go
 --- a/gopls/internal/regtest/bench/iwl_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/iwl_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,77 +0,0 @@
++++ b/gopls/internal/regtest/bench/iwl_test.go	1970-01-01 08:00:00
+@@ -1,76 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -107958,21 +114399,19 @@
 -// BenchmarkInitialWorkspaceLoad benchmarks the initial workspace load time for
 -// a new editing session.
 -func BenchmarkInitialWorkspaceLoad(b *testing.B) {
--	if testing.Short() {
--		// TODO(rfindley): remove this skip once the released gopls version
--		// supports the memstats command.
--		b.Skip("temporarily skipping as baseline gopls versions do not support the memstats command")
--	}
 -	tests := []struct {
 -		repo string
 -		file string
 -	}{
--		{"tools", "internal/lsp/cache/snapshot.go"},
+-		{"google-cloud-go", "httpreplay/httpreplay.go"},
+-		{"istio", "pkg/fuzz/util.go"},
 -		{"kubernetes", "pkg/controller/lookup_cache.go"},
+-		{"kuma", "api/generic/insights.go"},
+-		{"oracle", "dataintegration/data_type.go"},
 -		{"pkgsite", "internal/frontend/server.go"},
 -		{"starlark", "starlark/eval.go"},
--		{"istio", "pkg/fuzz/util.go"},
--		{"kuma", "api/generic/insights.go"},
+-		{"tools", "internal/lsp/cache/snapshot.go"},
+-		{"hashiform", "internal/provider/provider.go"},
 -	}
 -
 -	for _, test := range tests {
@@ -107996,31 +114435,32 @@
 -	// involve installing gopls and/or checking out the repo dir.
 -	b.StopTimer()
 -	config := fake.EditorConfig{Env: map[string]string{"GOPATH": gopath}}
--	env := repo.newEnv(b, "iwl."+repo.name, config)
+-	env := repo.newEnv(b, config, "iwl", true)
 -	defer env.Close()
 -	b.StartTimer()
 -
--	// Open an arbitrary file to ensure that gopls starts working.
--	//
--	// In the future, this may matter if gopls doesn't eagerly construct
--	// the workspace.
--	env.OpenFile(file)
+-	// Note: in the future, we may need to open a file in order to cause gopls to
+-	// start loading the workspace.
 -
 -	env.Await(InitialWorkspaceLoad)
--	b.StopTimer()
--	params := &protocol.ExecuteCommandParams{
--		Command: command.MemStats.ID(),
+-
+-	if env.Editor.HasCommand(command.MemStats.ID()) {
+-		b.StopTimer()
+-		params := &protocol.ExecuteCommandParams{
+-			Command: command.MemStats.ID(),
+-		}
+-		var memstats command.MemStatsResult
+-		env.ExecuteCommand(params, &memstats)
+-		b.ReportMetric(float64(memstats.HeapAlloc), "alloc_bytes")
+-		b.ReportMetric(float64(memstats.HeapInUse), "in_use_bytes")
+-		b.ReportMetric(float64(memstats.TotalAlloc), "total_alloc_bytes")
+-		b.StartTimer()
 -	}
--	var memstats command.MemStatsResult
--	env.ExecuteCommand(params, &memstats)
--	b.ReportMetric(float64(memstats.HeapAlloc), "alloc_bytes")
--	b.ReportMetric(float64(memstats.HeapInUse), "in_use_bytes")
--	b.StartTimer()
 -}
 diff -urN a/gopls/internal/regtest/bench/references_test.go b/gopls/internal/regtest/bench/references_test.go
 --- a/gopls/internal/regtest/bench/references_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/references_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
++++ b/gopls/internal/regtest/bench/references_test.go	1970-01-01 08:00:00
+@@ -1,44 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -108035,8 +114475,9 @@
 -		file   string
 -		regexp string
 -	}{
+-		{"google-cloud-go", "httpreplay/httpreplay.go", `func (NewRecorder)`},
 -		{"istio", "pkg/config/model.go", "type (Meta)"},
--		{"kubernetes", "pkg/controller/lookup_cache.go", "type (objectWithMeta)"},
+-		{"kubernetes", "pkg/controller/lookup_cache.go", "type (objectWithMeta)"}, // TODO: choose an exported identifier
 -		{"kuma", "pkg/events/interfaces.go", "type (Event)"},
 -		{"pkgsite", "internal/log/log.go", "func (Infof)"},
 -		{"starlark", "syntax/syntax.go", "type (Ident)"},
@@ -108047,21 +114488,83 @@
 -		b.Run(test.repo, func(b *testing.B) {
 -			env := getRepo(b, test.repo).sharedEnv(b)
 -			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
 -			loc := env.RegexpSearch(test.file, test.regexp)
--			env.Await(env.DoneWithOpen())
+-			env.AfterChange()
 -			env.References(loc) // pre-warm the query
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "references")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				env.References(loc)
 -			}
 -		})
 -	}
 -}
+diff -urN a/gopls/internal/regtest/bench/reload_test.go b/gopls/internal/regtest/bench/reload_test.go
+--- a/gopls/internal/regtest/bench/reload_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/bench/reload_test.go	1970-01-01 08:00:00
+@@ -1,52 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-package bench
+-
+-import (
+-	"testing"
+-
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-)
+-
+-// BenchmarkReload benchmarks reloading a file metadata after a change to an import.
+-//
+-// This ensures we are able to diagnose a changed file without reloading all
+-// invalidated packages. See also golang/go#61344
+-func BenchmarkReload(b *testing.B) {
+-	// TODO(rfindley): add more tests, make this test table-driven
+-	const (
+-		repo = "kubernetes"
+-		// pkg/util/hash is transitively imported by a large number of packages.
+-		// We should not need to reload those packages to get a diagnostic.
+-		file = "pkg/util/hash/hash.go"
+-	)
+-	b.Run(repo, func(b *testing.B) {
+-		env := getRepo(b, repo).sharedEnv(b)
+-
+-		env.OpenFile(file)
+-		defer closeBuffer(b, env, file)
+-
+-		env.AfterChange()
+-
+-		if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(repo, "reload")); stopAndRecord != nil {
+-			defer stopAndRecord()
+-		}
+-
+-		b.ResetTimer()
+-		for i := 0; i < b.N; i++ {
+-			// Change the "hash" import. This may result in cache hits, but that's
+-			// OK: the goal is to ensure that we don't reload more than just the
+-			// current package.
+-			env.RegexpReplace(file, `"hash"`, `"hashx"`)
+-			// Note: don't use env.AfterChange() here: we only want to await the
+-			// first diagnostic.
+-			//
+-			// Awaiting a full diagnosis would await diagnosing everything, which
+-			// would require reloading everything.
+-			env.Await(Diagnostics(ForFile(file)))
+-			env.RegexpReplace(file, `"hashx"`, `"hash"`)
+-			env.Await(NoDiagnostics(ForFile(file)))
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/bench/rename_test.go b/gopls/internal/regtest/bench/rename_test.go
 --- a/gopls/internal/regtest/bench/rename_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/rename_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,44 +0,0 @@
++++ b/gopls/internal/regtest/bench/rename_test.go	1970-01-01 08:00:00
+@@ -1,49 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -108080,9 +114583,10 @@
 -		regexp   string
 -		baseName string
 -	}{
+-		{"google-cloud-go", "httpreplay/httpreplay.go", `func (NewRecorder)`, "NewRecorder"},
+-		{"istio", "pkg/config/model.go", `(Namespace) string`, "Namespace"},
 -		{"kubernetes", "pkg/controller/lookup_cache.go", `hashutil\.(DeepHashObject)`, "DeepHashObject"},
 -		{"kuma", "pkg/events/interfaces.go", `Delete`, "Delete"},
--		{"istio", "pkg/config/model.go", `(Namespace) string`, "Namespace"},
 -		{"pkgsite", "internal/log/log.go", `func (Infof)`, "Infof"},
 -		{"starlark", "starlark/eval.go", `Program\) (Filename)`, "Filename"},
 -		{"tools", "internal/lsp/cache/snapshot.go", `meta \*(metadataGraph)`, "metadataGraph"},
@@ -108098,6 +114602,10 @@
 -			env.Rename(loc, test.baseName+"X") // pre-warm the query
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "rename")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				names++
 -				newName := fmt.Sprintf("%s%d", test.baseName, names)
@@ -108108,8 +114616,8 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/repo_test.go b/gopls/internal/regtest/bench/repo_test.go
 --- a/gopls/internal/regtest/bench/repo_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/repo_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,231 +0,0 @@
++++ b/gopls/internal/regtest/bench/repo_test.go	1970-01-01 08:00:00
+@@ -1,290 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -108120,6 +114628,7 @@
 -	"bytes"
 -	"context"
 -	"errors"
+-	"flag"
 -	"fmt"
 -	"log"
 -	"os"
@@ -108137,11 +114646,20 @@
 -// These repos were selected to represent a variety of different types of
 -// codebases.
 -var repos = map[string]*repo{
+-	// google-cloud-go has 145 workspace modules (!), and is quite large.
+-	"google-cloud-go": {
+-		name:   "google-cloud-go",
+-		url:    "https://github.com/googleapis/google-cloud-go.git",
+-		commit: "07da765765218debf83148cc7ed8a36d6e8921d5",
+-		inDir:  flag.String("cloud_go_dir", "", "if set, reuse this directory as google-cloud-go@07da7657"),
+-	},
+-
 -	// Used by x/benchmarks; large.
 -	"istio": {
 -		name:   "istio",
 -		url:    "https://github.com/istio/istio",
 -		commit: "1.17.0",
+-		inDir:  flag.String("istio_dir", "", "if set, reuse this directory as istio@v1.17.0"),
 -	},
 -
 -	// Kubernetes is a large repo with many dependencies, and in the past has
@@ -108150,6 +114668,8 @@
 -		name:   "kubernetes",
 -		url:    "https://github.com/kubernetes/kubernetes",
 -		commit: "v1.24.0",
+-		short:  true,
+-		inDir:  flag.String("kubernetes_dir", "", "if set, reuse this directory as kubernetes@v1.24.0"),
 -	},
 -
 -	// A large, industrial application.
@@ -108157,6 +114677,16 @@
 -		name:   "kuma",
 -		url:    "https://github.com/kumahq/kuma",
 -		commit: "2.1.1",
+-		inDir:  flag.String("kuma_dir", "", "if set, reuse this directory as kuma@v2.1.1"),
+-	},
+-
+-	// A repo containing a very large package (./dataintegration).
+-	"oracle": {
+-		name:   "oracle",
+-		url:    "https://github.com/oracle/oci-go-sdk.git",
+-		commit: "v65.43.0",
+-		short:  true,
+-		inDir:  flag.String("oracle_dir", "", "if set, reuse this directory as oracle/oci-go-sdk@v65.43.0"),
 -	},
 -
 -	// x/pkgsite is familiar and represents a common use case (a webserver). It
@@ -108166,6 +114696,7 @@
 -		url:    "https://go.googlesource.com/pkgsite",
 -		commit: "81f6f8d4175ad0bf6feaa03543cc433f8b04b19b",
 -		short:  true,
+-		inDir:  flag.String("pkgsite_dir", "", "if set, reuse this directory as pkgsite@81f6f8d4"),
 -	},
 -
 -	// A tiny self-contained project.
@@ -108174,6 +114705,7 @@
 -		url:    "https://github.com/google/starlark-go",
 -		commit: "3f75dec8e4039385901a30981e3703470d77e027",
 -		short:  true,
+-		inDir:  flag.String("starlark_dir", "", "if set, reuse this directory as starlark@3f75dec8"),
 -	},
 -
 -	// The current repository, which is medium-small and has very few dependencies.
@@ -108182,6 +114714,16 @@
 -		url:    "https://go.googlesource.com/tools",
 -		commit: "gopls/v0.9.0",
 -		short:  true,
+-		inDir:  flag.String("tools_dir", "", "if set, reuse this directory as x/tools@v0.9.0"),
+-	},
+-
+-	// A repo of similar size to kubernetes, but with substantially more
+-	// complex types that led to a serious performance regression (issue #60621).
+-	"hashiform": {
+-		name:   "hashiform",
+-		url:    "https://github.com/hashicorp/terraform-provider-aws",
+-		commit: "ac55de2b1950972d93feaa250d7505d9ed829c7c",
+-		inDir:  flag.String("hashiform_dir", "", "if set, reuse this directory as hashiform@ac55de2"),
 -	},
 -}
 -
@@ -108194,7 +114736,7 @@
 -		tb.Fatalf("repo %s does not exist", name)
 -	}
 -	if !repo.short && testing.Short() {
--		tb.Skipf("large repo %s does not run whith -short", repo.name)
+-		tb.Skipf("large repo %s does not run with -short", repo.name)
 -	}
 -	return repo
 -}
@@ -108206,10 +114748,11 @@
 -// codebase.
 -type repo struct {
 -	// static configuration
--	name   string // must be unique, used for subdirectory
--	url    string // repo url
--	commit string // full commit hash or tag
--	short  bool   // whether this repo runs with -short
+-	name   string  // must be unique, used for subdirectory
+-	url    string  // repo url
+-	commit string  // full commit hash or tag
+-	short  bool    // whether this repo runs with -short
+-	inDir  *string // if set, use this dir as url@commit, and don't delete
 -
 -	dirOnce sync.Once
 -	dir     string // directory contaning source code checked out to url@commit
@@ -108221,14 +114764,37 @@
 -	awaiter    *Awaiter
 -}
 -
+-// reusableDir return a reusable directory for benchmarking, or "".
+-//
+-// If the user specifies a directory, the test will create and populate it
+-// on the first run an re-use it on subsequent runs. Otherwise it will
+-// create, populate, and delete a temporary directory.
+-func (r *repo) reusableDir() string {
+-	if r.inDir == nil {
+-		return ""
+-	}
+-	return *r.inDir
+-}
+-
 -// getDir returns directory containing repo source code, creating it if
 -// necessary. It is safe for concurrent use.
 -func (r *repo) getDir() string {
 -	r.dirOnce.Do(func() {
--		r.dir = filepath.Join(getTempDir(), r.name)
--		log.Printf("cloning %s@%s into %s", r.url, r.commit, r.dir)
--		if err := shallowClone(r.dir, r.url, r.commit); err != nil {
+-		if r.dir = r.reusableDir(); r.dir == "" {
+-			r.dir = filepath.Join(getTempDir(), r.name)
+-		}
+-
+-		_, err := os.Stat(r.dir)
+-		switch {
+-		case os.IsNotExist(err):
+-			log.Printf("cloning %s@%s into %s", r.url, r.commit, r.dir)
+-			if err := shallowClone(r.dir, r.url, r.commit); err != nil {
+-				log.Fatal(err)
+-			}
+-		case err != nil:
 -			log.Fatal(err)
+-		default:
+-			log.Printf("reusing %s as %s@%s", r.dir, r.url, r.commit)
 -		}
 -	})
 -	return r.dir
@@ -108249,7 +114815,7 @@
 -
 -		start := time.Now()
 -		log.Printf("starting initial workspace load for %s", r.name)
--		ts, err := newGoplsServer(r.name)
+-		ts, err := newGoplsConnector(profileArgs(r.name, false))
 -		if err != nil {
 -			log.Fatal(err)
 -		}
@@ -108278,10 +114844,11 @@
 -//
 -// It is the caller's responsibility to call Close on the resulting Env when it
 -// is no longer needed.
--func (r *repo) newEnv(tb testing.TB, name string, config fake.EditorConfig) *Env {
+-func (r *repo) newEnv(tb testing.TB, config fake.EditorConfig, forOperation string, cpuProfile bool) *Env {
 -	dir := r.getDir()
 -
--	ts, err := newGoplsServer(name)
+-	args := profileArgs(qualifiedName(r.name, forOperation), cpuProfile)
+-	ts, err := newGoplsConnector(args)
 -	if err != nil {
 -		tb.Fatal(err)
 -	}
@@ -108312,7 +114879,7 @@
 -			fmt.Fprintf(&errBuf, "closing sandbox: %v", err)
 -		}
 -	}
--	if r.dir != "" {
+-	if r.dir != "" && r.reusableDir() == "" {
 -		if err := os.RemoveAll(r.dir); err != nil {
 -			fmt.Fprintf(&errBuf, "cleaning dir: %v", err)
 -		}
@@ -108343,7 +114910,7 @@
 -}
 diff -urN a/gopls/internal/regtest/bench/stress_test.go b/gopls/internal/regtest/bench/stress_test.go
 --- a/gopls/internal/regtest/bench/stress_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/stress_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/bench/stress_test.go	1970-01-01 08:00:00
 @@ -1,94 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -108439,10 +115006,77 @@
 -		i++
 -	}
 -}
+diff -urN a/gopls/internal/regtest/bench/typing_test.go b/gopls/internal/regtest/bench/typing_test.go
+--- a/gopls/internal/regtest/bench/typing_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/bench/typing_test.go	1970-01-01 08:00:00
+@@ -1,63 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package bench
+-
+-import (
+-	"fmt"
+-	"sync/atomic"
+-	"testing"
+-	"time"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
+-
+-// BenchmarkTyping simulates typing steadily in a single file at different
+-// paces.
+-//
+-// The key metric for this benchmark is not latency, but cpu_seconds per
+-// operation.
+-func BenchmarkTyping(b *testing.B) {
+-	for _, test := range didChangeTests {
+-		b.Run(test.repo, func(b *testing.B) {
+-			env := getRepo(b, test.repo).sharedEnv(b)
+-			env.OpenFile(test.file)
+-			defer closeBuffer(b, env, test.file)
+-
+-			// Insert the text we'll be modifying at the top of the file.
+-			env.EditBuffer(test.file, protocol.TextEdit{NewText: "// __REGTEST_PLACEHOLDER_0__\n"})
+-			env.AfterChange()
+-
+-			delays := []time.Duration{
+-				10 * time.Millisecond,  // automated changes
+-				50 * time.Millisecond,  // very fast mashing, or fast key sequences
+-				150 * time.Millisecond, // avg interval for 80wpm typing.
+-			}
+-
+-			for _, delay := range delays {
+-				b.Run(delay.String(), func(b *testing.B) {
+-					if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(test.repo, "typing")); stopAndRecord != nil {
+-						defer stopAndRecord()
+-					}
+-					ticker := time.NewTicker(delay)
+-					for i := 0; i < b.N; i++ {
+-						edits := atomic.AddInt64(&editID, 1)
+-						env.EditBuffer(test.file, protocol.TextEdit{
+-							Range: protocol.Range{
+-								Start: protocol.Position{Line: 0, Character: 0},
+-								End:   protocol.Position{Line: 1, Character: 0},
+-							},
+-							// Increment the placeholder text, to ensure cache misses.
+-							NewText: fmt.Sprintf("// __REGTEST_PLACEHOLDER_%d__\n", edits),
+-						})
+-						<-ticker.C
+-					}
+-					b.StopTimer()
+-					ticker.Stop()
+-					env.AfterChange() // wait for all change processing to complete
+-				})
+-			}
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/regtest/bench/workspace_symbols_test.go b/gopls/internal/regtest/bench/workspace_symbols_test.go
 --- a/gopls/internal/regtest/bench/workspace_symbols_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/bench/workspace_symbols_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,37 +0,0 @@
++++ b/gopls/internal/regtest/bench/workspace_symbols_test.go	1970-01-01 08:00:00
+@@ -1,41 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -108474,6 +115108,10 @@
 -
 -			b.ResetTimer()
 -
+-			if stopAndRecord := startProfileIfSupported(b, env, qualifiedName(name, "workspaceSymbols")); stopAndRecord != nil {
+-				defer stopAndRecord()
+-			}
+-
 -			for i := 0; i < b.N; i++ {
 -				env.Symbol(*symbolQuery)
 -			}
@@ -108482,8 +115120,8 @@
 -}
 diff -urN a/gopls/internal/regtest/codelens/codelens_test.go b/gopls/internal/regtest/codelens/codelens_test.go
 --- a/gopls/internal/regtest/codelens/codelens_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/codelens/codelens_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,336 +0,0 @@
++++ b/gopls/internal/regtest/codelens/codelens_test.go	1970-01-01 08:00:00
+@@ -1,348 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -108494,10 +115132,10 @@
 -	"fmt"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
--	"golang.org/x/tools/internal/bug"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
@@ -108685,13 +115323,25 @@
 -	}
 -	for _, vendoring := range []bool{false, true} {
 -		t.Run(fmt.Sprintf("Upgrade individual dependency vendoring=%v", vendoring), func(t *testing.T) {
--			WithOptions(ProxyFiles(proxyWithLatest)).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
+-			WithOptions(
+-				ProxyFiles(proxyWithLatest),
+-			).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
 -				if vendoring {
--					env.RunGoCommandInDir("a", "mod", "vendor")
+-					env.RunGoCommandInDirWithEnv("a", []string{"GOWORK=off"}, "mod", "vendor")
 -				}
 -				env.AfterChange()
 -				env.OpenFile("a/go.mod")
 -				env.OpenFile("b/go.mod")
+-
+-				// Await the diagnostics resulting from opening the modfiles, because
+-				// otherwise they may cause races when running asynchronously to the
+-				// explicit re-diagnosing below.
+-				//
+-				// TODO(golang/go#58750): there is still a race here, inherent to
+-				// accessing state on the View; we should create a new snapshot when
+-				// the view diagnostics change.
+-				env.AfterChange()
+-
 -				env.ExecuteCodeLensCommand("a/go.mod", command.CheckUpgrades, nil)
 -				d := &protocol.PublishDiagnosticsParams{}
 -				env.OnceMet(
@@ -108822,7 +115472,7 @@
 -}
 diff -urN a/gopls/internal/regtest/codelens/gcdetails_test.go b/gopls/internal/regtest/codelens/gcdetails_test.go
 --- a/gopls/internal/regtest/codelens/gcdetails_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/codelens/gcdetails_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/codelens/gcdetails_test.go	1970-01-01 08:00:00
 @@ -1,127 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -108835,11 +115485,11 @@
 -	"strings"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -func TestGCDetails_Toggle(t *testing.T) {
@@ -108953,7 +115603,7 @@
 -}
 diff -urN a/gopls/internal/regtest/completion/completion18_test.go b/gopls/internal/regtest/completion/completion18_test.go
 --- a/gopls/internal/regtest/completion/completion18_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/completion/completion18_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/completion/completion18_test.go	1970-01-01 08:00:00
 @@ -1,124 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -109081,8 +115731,8 @@
 -}
 diff -urN a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go
 --- a/gopls/internal/regtest/completion/completion_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/completion/completion_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,754 +0,0 @@
++++ b/gopls/internal/regtest/completion/completion_test.go	1970-01-01 08:00:00
+@@ -1,1005 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -109091,16 +115741,18 @@
 -
 -import (
 -	"fmt"
+-	"sort"
 -	"strings"
 -	"testing"
+-	"time"
 -
 -	"github.com/google/go-cmp/cmp"
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
--	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
--	"golang.org/x/tools/internal/testenv"
--
+-	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -func TestMain(m *testing.M) {
@@ -109600,6 +116252,7 @@
 -`
 -	WithOptions(
 -		WindowsLineEndings(),
+-		Settings{"ui.completion.usePlaceholders": true},
 -	).Run(t, src, func(t *testing.T, env *Env) {
 -		// Trigger unimported completions for the mod.com package.
 -		env.OpenFile("main.go")
@@ -109612,13 +116265,67 @@
 -		env.AcceptCompletion(loc, completions.Items[0])
 -		env.Await(env.DoneWithChange())
 -		got := env.BufferText("main.go")
--		want := "package main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"math\"\r\n)\r\n\r\nfunc main() {\r\n\tfmt.Println(\"a\")\r\n\tmath.Sqrt(${1:})\r\n}\r\n"
+-		want := "package main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"math\"\r\n)\r\n\r\nfunc main() {\r\n\tfmt.Println(\"a\")\r\n\tmath.Sqrt(${1:x float64})\r\n}\r\n"
 -		if diff := cmp.Diff(want, got); diff != "" {
 -			t.Errorf("unimported completion (-want +got):\n%s", diff)
 -		}
 -	})
 -}
 -
+-func TestUnimportedCompletionHasPlaceholders60269(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // uses type params
+-
+-	// We can't express this as a marker test because it doesn't support AcceptCompletion.
+-	const src = `
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-var _ = b.F
+-
+--- b/b.go --
+-package b
+-
+-func F0(a, b int, c float64) {}
+-func F1(int, chan *string) {}
+-func F2[K, V any](map[K]V, chan V) {} // missing type parameters was issue #60959
+-func F3[K comparable, V any](map[K]V, chan V) {}
+-`
+-	WithOptions(
+-		WindowsLineEndings(),
+-		Settings{"ui.completion.usePlaceholders": true},
+-	).Run(t, src, func(t *testing.T, env *Env) {
+-		env.OpenFile("a/a.go")
+-		env.Await(env.DoneWithOpen())
+-
+-		// The table lists the expected completions of b.F as they appear in Items.
+-		const common = "package a\r\n\r\nimport \"example.com/b\"\r\n\r\nvar _ = "
+-		for i, want := range []string{
+-			common + "b.F0(${1:a int}, ${2:b int}, ${3:c float64})\r\n",
+-			common + "b.F1(${1:_ int}, ${2:_ chan *string})\r\n",
+-			common + "b.F2[${1:K any}, ${2:V any}](${3:_ map[K]V}, ${4:_ chan V})\r\n",
+-			common + "b.F3[${1:K comparable}, ${2:V any}](${3:_ map[K]V}, ${4:_ chan V})\r\n",
+-		} {
+-			loc := env.RegexpSearch("a/a.go", "b.F()")
+-			completions := env.Completion(loc)
+-			if len(completions.Items) == 0 {
+-				t.Fatalf("no completion items")
+-			}
+-			saved := env.BufferText("a/a.go")
+-			env.AcceptCompletion(loc, completions.Items[i])
+-			env.Await(env.DoneWithChange())
+-			got := env.BufferText("a/a.go")
+-			if diff := cmp.Diff(want, got); diff != "" {
+-				t.Errorf("%d: unimported completion (-want +got):\n%s", i, diff)
+-			}
+-			env.SetBufferContent("a/a.go", saved) // restore
+-		}
+-	})
+-}
+-
 -func TestPackageMemberCompletionAfterSyntaxError(t *testing.T) {
 -	// This test documents the current broken behavior due to golang/go#58833.
 -	const src = `
@@ -109660,6 +116367,66 @@
 -	})
 -}
 -
+-func TestCompleteAllFields(t *testing.T) {
+-	// This test verifies that completion results always include all struct fields.
+-	// See golang/go#53992.
+-
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+-
+--- p/p.go --
+-package p
+-
+-import (
+-	"fmt"
+-
+-	. "net/http"
+-	. "runtime"
+-	. "go/types"
+-	. "go/parser"
+-	. "go/ast"
+-)
+-
+-type S struct {
+-	a, b, c, d, e, f, g, h, i, j, k, l, m int
+-	n, o, p, q, r, s, t, u, v, w, x, y, z int
+-}
+-
+-func _() {
+-	var s S
+-	fmt.Println(s.)
+-}
+-`
+-
+-	WithOptions(Settings{
+-		"completionBudget": "1ns", // must be non-zero as 0 => infinity
+-	}).Run(t, src, func(t *testing.T, env *Env) {
+-		wantFields := make(map[string]bool)
+-		for c := 'a'; c <= 'z'; c++ {
+-			wantFields[string(c)] = true
+-		}
+-
+-		env.OpenFile("p/p.go")
+-		// Make an arbitrary edit to ensure we're not hitting the cache.
+-		env.EditBuffer("p/p.go", fake.NewEdit(0, 0, 0, 0, fmt.Sprintf("// current time: %v\n", time.Now())))
+-		loc := env.RegexpSearch("p/p.go", `s\.()`)
+-		completions := env.Completion(loc)
+-		gotFields := make(map[string]bool)
+-		for _, item := range completions.Items {
+-			if item.Kind == protocol.FieldCompletion {
+-				gotFields[item.Label] = true
+-			}
+-		}
+-
+-		if diff := cmp.Diff(wantFields, gotFields); diff != "" {
+-			t.Errorf("Completion(...) returned mismatching fields (-want +got):\n%s", diff)
+-		}
+-	})
+-}
+-
 -func TestDefinition(t *testing.T) {
 -	testenv.NeedsGo1Point(t, 17) // in go1.16, The FieldList in func x is not empty
 -	files := `
@@ -109837,10 +116604,144 @@
 -		}
 -	})
 -}
+-
+-func TestBuiltinCompletion(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+--- a.go --
+-package a
+-
+-func _() {
+-	// here
+-}
+-`
+-
+-	Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("a.go")
+-		result := env.Completion(env.RegexpSearch("a.go", `// here`))
+-		builtins := []string{
+-			"any", "append", "bool", "byte", "cap", "close",
+-			"comparable", "complex", "complex128", "complex64", "copy", "delete",
+-			"error", "false", "float32", "float64", "imag", "int", "int16", "int32",
+-			"int64", "int8", "len", "make", "new", "panic", "print", "println", "real",
+-			"recover", "rune", "string", "true", "uint", "uint16", "uint32", "uint64",
+-			"uint8", "uintptr", "nil",
+-		}
+-		if testenv.Go1Point() >= 21 {
+-			builtins = append(builtins, "clear", "max", "min")
+-		}
+-		sort.Strings(builtins)
+-		var got []string
+-
+-		for _, item := range result.Items {
+-			// TODO(rfindley): for flexibility, ignore zero while it is being
+-			// implemented. Remove this if/when zero lands.
+-			if item.Label != "zero" {
+-				got = append(got, item.Label)
+-			}
+-		}
+-		sort.Strings(got)
+-
+-		if diff := cmp.Diff(builtins, got); diff != "" {
+-			t.Errorf("Completion: unexpected mismatch (-want +got):\n%s", diff)
+-		}
+-	})
+-}
+-
+-func TestOverlayCompletion(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module foo.test
+-
+-go 1.18
+-
+--- foo/foo.go --
+-package foo
+-
+-type Foo struct{}
+-`
+-
+-	Run(t, files, func(t *testing.T, env *Env) {
+-		env.CreateBuffer("nodisk/nodisk.go", `
+-package nodisk
+-
+-import (
+-	"foo.test/foo"
+-)
+-
+-func _() {
+-	foo.Foo()
+-}
+-`)
+-		list := env.Completion(env.RegexpSearch("nodisk/nodisk.go", "foo.(Foo)"))
+-		want := []string{"Foo"}
+-		var got []string
+-		for _, item := range list.Items {
+-			got = append(got, item.Label)
+-		}
+-		if diff := cmp.Diff(want, got); diff != "" {
+-			t.Errorf("Completion: unexpected mismatch (-want +got):\n%s", diff)
+-		}
+-	})
+-}
+-
+-// Fix for golang/go#60062: unimported completion included "golang.org/toolchain" results.
+-func TestToolchainCompletions(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module foo.test/foo
+-
+-go 1.21
+-
+--- foo.go --
+-package foo
+-
+-func _() {
+-	os.Open
+-}
+-
+-func _() {
+-	strings
+-}
+-`
+-
+-	const proxy = `
+--- golang.org/toolchain@v0.0.1-go1.21.1.linux-amd64/go.mod --
+-module golang.org/toolchain
+--- golang.org/toolchain@v0.0.1-go1.21.1.linux-amd64/src/os/os.go --
+-package os
+-
+-func Open() {}
+--- golang.org/toolchain@v0.0.1-go1.21.1.linux-amd64/src/strings/strings.go --
+-package strings
+-
+-func Join() {}
+-`
+-
+-	WithOptions(
+-		ProxyFiles(proxy),
+-	).Run(t, files, func(t *testing.T, env *Env) {
+-		env.RunGoCommand("mod", "download", "golang.org/toolchain@v0.0.1-go1.21.1.linux-amd64")
+-		env.OpenFile("foo.go")
+-
+-		for _, pattern := range []string{"os.Open()", "string()"} {
+-			loc := env.RegexpSearch("foo.go", pattern)
+-			res := env.Completion(loc)
+-			for _, item := range res.Items {
+-				if strings.Contains(item.Detail, "golang.org/toolchain") {
+-					t.Errorf("Completion(...) returned toolchain item %#v", item)
+-				}
+-			}
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/completion/postfix_snippet_test.go b/gopls/internal/regtest/completion/postfix_snippet_test.go
 --- a/gopls/internal/regtest/completion/postfix_snippet_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/completion/postfix_snippet_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,464 +0,0 @@
++++ b/gopls/internal/regtest/completion/postfix_snippet_test.go	1970-01-01 08:00:00
+@@ -1,590 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -110273,6 +117174,132 @@
 -	return strings.Join(x, "$0")
 -}`,
 -		},
+-		{
+-			name: "if not nil interface",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo error
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo error
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
+-		{
+-			name: "if not nil pointer",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo *int
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo *int
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
+-		{
+-			name: "if not nil slice",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo []int
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo []int
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
+-		{
+-			name: "if not nil map",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo map[string]any
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo map[string]any
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
+-		{
+-			name: "if not nil channel",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo chan int
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo chan int
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
+-		{
+-			name: "if not nil function",
+-			before: `
+-package foo
+-
+-func _() {
+-	var foo func()
+-	foo.ifnotnil
+-}
+-`,
+-			after: `
+-package foo
+-
+-func _() {
+-	var foo func()
+-	if foo != nil {
+-	$0
+-}
+-}
+-`,
+-		},
 -	}
 -
 -	r := WithOptions(
@@ -110307,8 +117334,8 @@
 -}
 diff -urN a/gopls/internal/regtest/debug/debug_test.go b/gopls/internal/regtest/debug/debug_test.go
 --- a/gopls/internal/regtest/debug/debug_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/debug/debug_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,30 +0,0 @@
++++ b/gopls/internal/regtest/debug/debug_test.go	1970-01-01 08:00:00
+@@ -1,101 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -110316,11 +117343,18 @@
 -package debug
 -
 -import (
+-	"context"
+-	"encoding/json"
+-	"io"
+-	"net/http"
+-	"strings"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -func TestMain(m *testing.M) {
@@ -110335,14 +117369,78 @@
 -		Settings{"showBugReports": true},
 -	).Run(t, "", func(t *testing.T, env *Env) {
 -		const desc = "got a bug"
--		bug.Report(desc, nil)
+-		bug.Report(desc)
 -		env.Await(ShownMessage(desc))
 -	})
 -}
+-
+-// TestStartDebugging executes a gopls.start_debugging command to
+-// start the internal web server.
+-func TestStartDebugging(t *testing.T) {
+-	WithOptions(
+-		Modes(Default|Experimental), // doesn't work in Forwarded mode
+-	).Run(t, "", func(t *testing.T, env *Env) {
+-		// Start a debugging server.
+-		res, err := startDebugging(env.Ctx, env.Editor.Server, &command.DebuggingArgs{
+-			Addr: "", // any free port
+-		})
+-		if err != nil {
+-			t.Fatalf("startDebugging: %v", err)
+-		}
+-
+-		// Assert that the server requested that the
+-		// client show the debug page in a browser.
+-		debugURL := res.URLs[0]
+-		env.Await(ShownDocument(debugURL))
+-
+-		// Send a request to the debug server and ensure it responds.
+-		resp, err := http.Get(debugURL)
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-		defer resp.Body.Close()
+-		data, err := io.ReadAll(resp.Body)
+-		if err != nil {
+-			t.Fatalf("reading HTTP response body: %v", err)
+-		}
+-		const want = "<title>GoPls"
+-		if !strings.Contains(string(data), want) {
+-			t.Errorf("GET %s response does not contain %q: <<%s>>", debugURL, want, data)
+-		}
+-	})
+-}
+-
+-// startDebugging starts a debugging server.
+-// TODO(adonovan): move into command package?
+-func startDebugging(ctx context.Context, server protocol.Server, args *command.DebuggingArgs) (*command.DebuggingResult, error) {
+-	rawArgs, err := command.MarshalArgs(args)
+-	if err != nil {
+-		return nil, err
+-	}
+-	res0, err := server.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
+-		Command:   command.StartDebugging.ID(),
+-		Arguments: rawArgs,
+-	})
+-	if err != nil {
+-		return nil, err
+-	}
+-	// res0 is the result of a schemaless (map[string]any) JSON decoding.
+-	// Re-encode and decode into the correct Go struct type.
+-	// TODO(adonovan): fix (*serverDispatcher).ExecuteCommand.
+-	data, err := json.Marshal(res0)
+-	if err != nil {
+-		return nil, err
+-	}
+-	var res *command.DebuggingResult
+-	if err := json.Unmarshal(data, &res); err != nil {
+-		return nil, err
+-	}
+-	return res, nil
+-}
 diff -urN a/gopls/internal/regtest/diagnostics/analysis_test.go b/gopls/internal/regtest/diagnostics/analysis_test.go
 --- a/gopls/internal/regtest/diagnostics/analysis_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/analysis_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,49 +0,0 @@
++++ b/gopls/internal/regtest/diagnostics/analysis_test.go	1970-01-01 08:00:00
+@@ -1,127 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -110350,8 +117448,10 @@
 -package diagnostics
 -
 -import (
+-	"fmt"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -)
@@ -110392,9 +117492,85 @@
 -		env.AfterChange(NoDiagnostics(ForFile("main.go")))
 -	})
 -}
+-
+-func TestAnalysisProgressReporting(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+-
+--- main.go --
+-package main
+-
+-func main() {
+-}`
+-
+-	tests := []struct {
+-		setting bool
+-		want    Expectation
+-	}{
+-		{true, CompletedWork(cache.AnalysisProgressTitle, 1, true)},
+-		{false, Not(CompletedWork(cache.AnalysisProgressTitle, 1, true))},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(fmt.Sprint(test.setting), func(t *testing.T) {
+-			WithOptions(
+-				Settings{
+-					"reportAnalysisProgressAfter": "0s",
+-					"analysisProgressReporting":   test.setting,
+-				},
+-			).Run(t, files, func(t *testing.T, env *Env) {
+-				env.OpenFile("main.go")
+-				env.AfterChange(test.want)
+-			})
+-		})
+-	}
+-}
+-
+-// Test the embed directive analyzer.
+-//
+-// There is a fix for missing imports, but it should not trigger for other
+-// kinds of issues reported by the analayzer, here the variable
+-// declaration following the embed directive is wrong.
+-func TestNoSuggestedFixesForEmbedDirectiveDeclaration(t *testing.T) {
+-	const generated = `
+--- go.mod --
+-module mod.com
+-
+-go 1.20
+-
+--- foo.txt --
+-FOO
+-
+--- main.go --
+-package main
+-
+-import _ "embed"
+-
+-//go:embed foo.txt
+-var foo, bar string
+-
+-func main() {
+-	_ = foo
+-}
+-`
+-	Run(t, generated, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-		var d protocol.PublishDiagnosticsParams
+-		env.AfterChange(
+-			Diagnostics(env.AtRegexp("main.go", "//go:embed")),
+-			ReadDiagnostics("main.go", &d),
+-		)
+-		if fixes := env.GetQuickFixes("main.go", d.Diagnostics); len(fixes) != 0 {
+-			t.Errorf("got quick fixes %v, wanted none", fixes)
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/diagnostics/builtin_test.go b/gopls/internal/regtest/diagnostics/builtin_test.go
 --- a/gopls/internal/regtest/diagnostics/builtin_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/builtin_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/diagnostics/builtin_test.go	1970-01-01 08:00:00
 @@ -1,35 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -110433,8 +117609,8 @@
 -}
 diff -urN a/gopls/internal/regtest/diagnostics/diagnostics_test.go b/gopls/internal/regtest/diagnostics/diagnostics_test.go
 --- a/gopls/internal/regtest/diagnostics/diagnostics_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,2048 +0,0 @@
++++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go	1970-01-01 08:00:00
+@@ -1,2114 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -110447,12 +117623,12 @@
 -	"os/exec"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp"
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/testenv"
 -)
 -
@@ -110736,7 +117912,7 @@
 -				InitialWorkspaceLoad,
 -				Diagnostics(env.AtRegexp("main.go", `"mod.com/bob"`)),
 -			)
--			if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, true); err != nil {
+-			if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, nil, true); err != nil {
 -				t.Fatal(err)
 -			}
 -			env.AfterChange(
@@ -110869,7 +118045,11 @@
 -func TestMissingDependency(t *testing.T) {
 -	Run(t, testPackageWithRequire, func(t *testing.T, env *Env) {
 -		env.OpenFile("print.go")
--		env.Await(LogMatching(protocol.Error, "initial workspace load failed", 1, false))
+-		env.Await(
+-			// Log messages are asynchronous to other events on the LSP stream, so we
+-			// can't use OnceMet or AfterChange here.
+-			LogMatching(protocol.Error, "initial workspace load failed", 1, false),
+-		)
 -	})
 -}
 -
@@ -110992,7 +118172,7 @@
 -		// Deleting the import dismisses the warning.
 -		env.RegexpReplace("a.go", `import "mod.com/hello"`, "")
 -		env.AfterChange(
--			NoOutstandingWork(),
+-			NoOutstandingWork(IgnoreTelemetryPromptWork),
 -		)
 -	})
 -}
@@ -111009,7 +118189,7 @@
 -			).Run(t, files, func(t *testing.T, env *Env) {
 -				env.OnceMet(
 -					InitialWorkspaceLoad,
--					NoOutstandingWork(),
+-					NoOutstandingWork(IgnoreTelemetryPromptWork),
 -				)
 -			})
 -		})
@@ -111711,7 +118891,7 @@
 -	})
 -}
 -
--func TestNotifyOrphanedFiles(t *testing.T) {
+-func TestOrphanedFiles(t *testing.T) {
 -	const files = `
 --- go.mod --
 -module mod.com
@@ -111738,9 +118918,26 @@
 -			Diagnostics(env.AtRegexp("a/a.go", "x")),
 -		)
 -		env.OpenFile("a/a_exclude.go")
--		env.AfterChange(
--			Diagnostics(env.AtRegexp("a/a_exclude.go", "package (a)")),
--		)
+-
+-		loadOnce := LogMatching(protocol.Info, "query=.*file=.*a_exclude.go", 1, false)
+-
+-		// can't use OnceMet or AfterChange as logs are async
+-		env.Await(loadOnce)
+-		// ...but ensure that the change has been fully processed before editing.
+-		// Otherwise, there may be a race where the snapshot is cloned before all
+-		// state changes resulting from the load have been processed
+-		// (golang/go#61521).
+-		env.AfterChange()
+-
+-		// Check that orphaned files are not reloaded, by making a change in
+-		// a.go file and confirming that the workspace diagnosis did not reload
+-		// a_exclude.go.
+-		//
+-		// This is racy (but fails open) because logs are asynchronous to other LSP
+-		// operations. There's a chance gopls _did_ log, and we just haven't seen
+-		// it yet.
+-		env.RegexpReplace("a/a.go", "package a", "package a // arbitrary comment")
+-		env.AfterChange(loadOnce)
 -	})
 -}
 -
@@ -111885,7 +119082,7 @@
 -		env.RegexpReplace("foo/foo_test.go", "_t", "_test")
 -		env.AfterChange(
 -			NoDiagnostics(ForFile("foo/foo_test.go")),
--			NoOutstandingWork(),
+-			NoOutstandingWork(IgnoreTelemetryPromptWork),
 -		)
 -	})
 -}
@@ -111919,7 +119116,7 @@
 -		env.RegexpReplace("go.mod", "go 1.hello", "go 1.12")
 -		env.SaveBufferWithoutActions("go.mod")
 -		env.AfterChange(
--			NoOutstandingWork(),
+-			NoOutstandingWork(IgnoreTelemetryPromptWork),
 -		)
 -	})
 -}
@@ -111943,7 +119140,13 @@
 -	bob.Hello()
 -}
 -`
--	Run(t, mod, func(t *testing.T, env *Env) {
+-	WithOptions(
+-		Settings{
+-			// Now that we don't watch subdirs by default (except for VS Code),
+-			// we must explicitly ask gopls to requests subdir watch patterns.
+-			"subdirWatchPatterns": "on",
+-		},
+-	).Run(t, mod, func(t *testing.T, env *Env) {
 -		env.OnceMet(
 -			InitialWorkspaceLoad,
 -			FileWatchMatching("bob"),
@@ -112132,8 +119335,7 @@
 -		env.OpenFile("nested/hello/hello.go")
 -		env.AfterChange(
 -			Diagnostics(env.AtRegexp("nested/hello/hello.go", "helloHelper")),
--			Diagnostics(env.AtRegexp("nested/hello/hello.go", "package hello"), WithMessage("nested module")),
--			OutstandingWork(lsp.WorkspaceLoadFailure, "nested module"),
+-			Diagnostics(env.AtRegexp("nested/hello/hello.go", "package (hello)"), WithMessage("not included in your workspace")),
 -		)
 -	})
 -}
@@ -112250,8 +119452,11 @@
 -`
 -	Run(t, files, func(t *testing.T, env *Env) {
 -		env.OpenFile("go.mod")
--		env.AfterChange(
--			LogMatching(protocol.Info, `.*query=\[builtin mod.com/...\].*`, 1, false),
+-		env.Await(
+-			// Check that we have only loaded "<dir>/..." once.
+-			// Log messages are asynchronous to other events on the LSP stream, so we
+-			// can't use OnceMet or AfterChange here.
+-			LogMatching(protocol.Info, `.*query=.*\.\.\..*`, 1, false),
 -		)
 -	})
 -}
@@ -112483,9 +119688,46 @@
 -		}
 -	})
 -}
+-
+-// This test demonstrates the deprecated symbol analyzer
+-// produces deprecation notices with expected severity and tags.
+-func TestDeprecatedAnalysis(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module example.com
+--- a/a.go --
+-package a
+-
+-import "example.com/b"
+-
+-func _() {
+-	new(b.B).Obsolete() // deprecated
+-}
+-
+--- b/b.go --
+-package b
+-
+-type B struct{}
+-
+-// Deprecated: use New instead.
+-func (B) Obsolete() {}
+-
+-func (B) New() {}
+-`
+-	Run(t, src, func(t *testing.T, env *Env) {
+-		env.OpenFile("a/a.go")
+-		env.AfterChange(
+-			Diagnostics(
+-				env.AtRegexp("a/a.go", "new.*Obsolete"),
+-				WithMessage("use New instead."),
+-				WithSeverityTags("deprecated", protocol.SeverityHint, []protocol.DiagnosticTag{protocol.Deprecated}),
+-			),
+-		)
+-	})
+-}
 diff -urN a/gopls/internal/regtest/diagnostics/golist_test.go b/gopls/internal/regtest/diagnostics/golist_test.go
 --- a/gopls/internal/regtest/diagnostics/golist_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/golist_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/diagnostics/golist_test.go	1970-01-01 08:00:00
 @@ -1,71 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -112560,7 +119802,7 @@
 -}
 diff -urN a/gopls/internal/regtest/diagnostics/invalidation_test.go b/gopls/internal/regtest/diagnostics/invalidation_test.go
 --- a/gopls/internal/regtest/diagnostics/invalidation_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/invalidation_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/diagnostics/invalidation_test.go	1970-01-01 08:00:00
 @@ -1,111 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -112675,7 +119917,7 @@
 -}
 diff -urN a/gopls/internal/regtest/diagnostics/undeclared_test.go b/gopls/internal/regtest/diagnostics/undeclared_test.go
 --- a/gopls/internal/regtest/diagnostics/undeclared_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/diagnostics/undeclared_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/diagnostics/undeclared_test.go	1970-01-01 08:00:00
 @@ -1,73 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -112752,7 +119994,7 @@
 -}
 diff -urN a/gopls/internal/regtest/inlayhints/inlayhints_test.go b/gopls/internal/regtest/inlayhints/inlayhints_test.go
 --- a/gopls/internal/regtest/inlayhints/inlayhints_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/inlayhints/inlayhints_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/inlayhints/inlayhints_test.go	1970-01-01 08:00:00
 @@ -1,69 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -112762,10 +120004,10 @@
 -import (
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -func TestMain(m *testing.M) {
@@ -112825,8 +120067,8 @@
 -}
 diff -urN a/gopls/internal/regtest/marker/marker_test.go b/gopls/internal/regtest/marker/marker_test.go
 --- a/gopls/internal/regtest/marker/marker_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/marker_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,21 +0,0 @@
++++ b/gopls/internal/regtest/marker/marker_test.go	1970-01-01 08:00:00
+@@ -1,30 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -112834,11 +120076,20 @@
 -package marker
 -
 -import (
+-	"os"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
+-func TestMain(m *testing.M) {
+-	bug.PanicOnBugs = true
+-	testenv.ExitIfSmallMachine()
+-	os.Exit(m.Run())
+-}
+-
 -// Note: we use a separate package for the marker tests so that we can easily
 -// compare their performance to the existing marker tests in ./internal/lsp.
 -
@@ -112848,9 +120099,2016 @@
 -func TestMarkers(t *testing.T) {
 -	RunMarkerTests(t, "testdata")
 -}
+diff -urN a/gopls/internal/regtest/marker/testdata/codeaction/functionextraction.txt b/gopls/internal/regtest/marker/testdata/codeaction/functionextraction.txt
+--- a/gopls/internal/regtest/marker/testdata/codeaction/functionextraction.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codeaction/functionextraction.txt	1970-01-01 08:00:00
+@@ -1,583 +0,0 @@
+-This test verifies various behaviors of function extraction.
+-
+--- go.mod --
+-module mod.test/extract
+-
+-go 1.18
+-
+--- basic.go --
+-package extract
+-
+-func _() { //@codeaction("refactor.extract", "{", closeBracket, outer)
+-	a := 1    //@codeaction("refactor.extract", "a", end, inner)
+-	_ = a + 4 //@loc(end, "4")
+-} //@loc(closeBracket, "}")
+-
+--- @inner/basic.go --
+-package extract
+-
+-func _() { //@codeaction("refactor.extract", "{", closeBracket, outer)
+-	//@codeaction("refactor.extract", "a", end, inner)
+-	newFunction() //@loc(end, "4")
+-}
+-
+-func newFunction() {
+-	a := 1
+-	_ = a + 4
+-} //@loc(closeBracket, "}")
+-
+--- @outer/basic.go --
+-package extract
+-
+-func _() { //@codeaction("refactor.extract", "{", closeBracket, outer)
+-	//@codeaction("refactor.extract", "a", end, inner)
+-	newFunction() //@loc(end, "4")
+-}
+-
+-func newFunction() {
+-	a := 1
+-	_ = a + 4
+-} //@loc(closeBracket, "}")
+-
+--- return.go --
+-package extract
+-
+-func _() bool {
+-	x := 1
+-	if x == 0 { //@codeaction("refactor.extract", "if", ifend, return)
+-		return true
+-	} //@loc(ifend, "}")
+-	return false
+-}
+-
+--- @return/return.go --
+-package extract
+-
+-func _() bool {
+-	x := 1
+-	//@codeaction("refactor.extract", "if", ifend, return)
+-	shouldReturn, returnValue := newFunction(x)
+-	if shouldReturn {
+-		return returnValue
+-	} //@loc(ifend, "}")
+-	return false
+-}
+-
+-func newFunction(x int) (bool, bool) {
+-	if x == 0 {
+-		return true, true
+-	}
+-	return false, false
+-}
+-
+--- return_nonnested.go --
+-package extract
+-
+-func _() bool {
+-	x := 1 //@codeaction("refactor.extract", "x", rnnEnd, rnn)
+-	if x == 0 {
+-		return true
+-	}
+-	return false //@loc(rnnEnd, "false")
+-}
+-
+--- @rnn/return_nonnested.go --
+-package extract
+-
+-func _() bool {
+-	//@codeaction("refactor.extract", "x", rnnEnd, rnn)
+-	return newFunction() //@loc(rnnEnd, "false")
+-}
+-
+-func newFunction() bool {
+-	x := 1
+-	if x == 0 {
+-		return true
+-	}
+-	return false
+-}
+-
+--- return_complex.go --
+-package extract
+-
+-import "fmt"
+-
+-func _() (int, string, error) {
+-	x := 1
+-	y := "hello"
+-	z := "bye" //@codeaction("refactor.extract", "z", rcEnd, rc)
+-	if y == z {
+-		return x, y, fmt.Errorf("same")
+-	} else if false {
+-		z = "hi"
+-		return x, z, nil
+-	} //@loc(rcEnd, "}")
+-	return x, z, nil
+-}
+-
+--- @rc/return_complex.go --
+-package extract
+-
+-import "fmt"
+-
+-func _() (int, string, error) {
+-	x := 1
+-	y := "hello"
+-	//@codeaction("refactor.extract", "z", rcEnd, rc)
+-	z, shouldReturn, returnValue, returnValue1, returnValue2 := newFunction(y, x)
+-	if shouldReturn {
+-		return returnValue, returnValue1, returnValue2
+-	} //@loc(rcEnd, "}")
+-	return x, z, nil
+-}
+-
+-func newFunction(y string, x int) (string, bool, int, string, error) {
+-	z := "bye"
+-	if y == z {
+-		return "", true, x, y, fmt.Errorf("same")
+-	} else if false {
+-		z = "hi"
+-		return "", true, x, z, nil
+-	}
+-	return z, false, 0, "", nil
+-}
+-
+--- return_complex_nonnested.go --
+-package extract
+-
+-import "fmt"
+-
+-func _() (int, string, error) {
+-	x := 1
+-	y := "hello"
+-	z := "bye" //@codeaction("refactor.extract", "z", rcnnEnd, rcnn)
+-	if y == z {
+-		return x, y, fmt.Errorf("same")
+-	} else if false {
+-		z = "hi"
+-		return x, z, nil
+-	}
+-	return x, z, nil //@loc(rcnnEnd, "nil")
+-}
+-
+--- @rcnn/return_complex_nonnested.go --
+-package extract
+-
+-import "fmt"
+-
+-func _() (int, string, error) {
+-	x := 1
+-	y := "hello"
+-	//@codeaction("refactor.extract", "z", rcnnEnd, rcnn)
+-	return newFunction(y, x) //@loc(rcnnEnd, "nil")
+-}
+-
+-func newFunction(y string, x int) (int, string, error) {
+-	z := "bye"
+-	if y == z {
+-		return x, y, fmt.Errorf("same")
+-	} else if false {
+-		z = "hi"
+-		return x, z, nil
+-	}
+-	return x, z, nil
+-}
+-
+--- return_func_lit.go --
+-package extract
+-
+-import "go/ast"
+-
+-func _() {
+-	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+-		if n == nil { //@codeaction("refactor.extract", "if", rflEnd, rfl)
+-			return true
+-		} //@loc(rflEnd, "}")
+-		return false
+-	})
+-}
+-
+--- @rfl/return_func_lit.go --
+-package extract
+-
+-import "go/ast"
+-
+-func _() {
+-	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+-		//@codeaction("refactor.extract", "if", rflEnd, rfl)
+-		shouldReturn, returnValue := newFunction(n)
+-		if shouldReturn {
+-			return returnValue
+-		} //@loc(rflEnd, "}")
+-		return false
+-	})
+-}
+-
+-func newFunction(n ast.Node) (bool, bool) {
+-	if n == nil {
+-		return true, true
+-	}
+-	return false, false
+-}
+-
+--- return_func_lit_nonnested.go --
+-package extract
+-
+-import "go/ast"
+-
+-func _() {
+-	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+-		if n == nil { //@codeaction("refactor.extract", "if", rflnnEnd, rflnn)
+-			return true
+-		}
+-		return false //@loc(rflnnEnd, "false")
+-	})
+-}
+-
+--- @rflnn/return_func_lit_nonnested.go --
+-package extract
+-
+-import "go/ast"
+-
+-func _() {
+-	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+-		//@codeaction("refactor.extract", "if", rflnnEnd, rflnn)
+-		return newFunction(n) //@loc(rflnnEnd, "false")
+-	})
+-}
+-
+-func newFunction(n ast.Node) bool {
+-	if n == nil {
+-		return true
+-	}
+-	return false
+-}
+-
+--- return_init.go --
+-package extract
+-
+-func _() string {
+-	x := 1
+-	if x == 0 { //@codeaction("refactor.extract", "if", riEnd, ri)
+-		x = 3
+-		return "a"
+-	} //@loc(riEnd, "}")
+-	x = 2
+-	return "b"
+-}
+-
+--- @ri/return_init.go --
+-package extract
+-
+-func _() string {
+-	x := 1
+-	//@codeaction("refactor.extract", "if", riEnd, ri)
+-	shouldReturn, returnValue := newFunction(x)
+-	if shouldReturn {
+-		return returnValue
+-	} //@loc(riEnd, "}")
+-	x = 2
+-	return "b"
+-}
+-
+-func newFunction(x int) (bool, string) {
+-	if x == 0 {
+-		x = 3
+-		return true, "a"
+-	}
+-	return false, ""
+-}
+-
+--- return_init_nonnested.go --
+-package extract
+-
+-func _() string {
+-	x := 1
+-	if x == 0 { //@codeaction("refactor.extract", "if", rinnEnd, rinn)
+-		x = 3
+-		return "a"
+-	}
+-	x = 2
+-	return "b" //@loc(rinnEnd, "\"b\"")
+-}
+-
+--- @rinn/return_init_nonnested.go --
+-package extract
+-
+-func _() string {
+-	x := 1
+-	//@codeaction("refactor.extract", "if", rinnEnd, rinn)
+-	return newFunction(x) //@loc(rinnEnd, "\"b\"")
+-}
+-
+-func newFunction(x int) string {
+-	if x == 0 {
+-		x = 3
+-		return "a"
+-	}
+-	x = 2
+-	return "b"
+-}
+-
+--- args_returns.go --
+-package extract
+-
+-func _() {
+-	a := 1
+-	a = 5     //@codeaction("refactor.extract", "a", araend, ara)
+-	a = a + 2 //@loc(araend, "2")
+-
+-	b := a * 2 //@codeaction("refactor.extract", "b", arbend, arb)
+-	_ = b + 4  //@loc(arbend, "4")
+-}
+-
+--- @ara/args_returns.go --
+-package extract
+-
+-func _() {
+-	a := 1
+-	//@codeaction("refactor.extract", "a", araend, ara)
+-	a = newFunction(a) //@loc(araend, "2")
+-
+-	b := a * 2 //@codeaction("refactor.extract", "b", arbend, arb)
+-	_ = b + 4  //@loc(arbend, "4")
+-}
+-
+-func newFunction(a int) int {
+-	a = 5
+-	a = a + 2
+-	return a
+-}
+-
+--- @arb/args_returns.go --
+-package extract
+-
+-func _() {
+-	a := 1
+-	a = 5     //@codeaction("refactor.extract", "a", araend, ara)
+-	a = a + 2 //@loc(araend, "2")
+-
+-	//@codeaction("refactor.extract", "b", arbend, arb)
+-	newFunction(a)  //@loc(arbend, "4")
+-}
+-
+-func newFunction(a int) {
+-	b := a * 2
+-	_ = b + 4
+-}
+-
+--- scope.go --
+-package extract
+-
+-func _() {
+-	newFunction := 1
+-	a := newFunction //@codeaction("refactor.extract", "a", "newFunction", scope)
+-	_ = a // avoid diagnostic
+-}
+-
+-func newFunction1() int {
+-	return 1
+-}
+-
+--- @scope/scope.go --
+-package extract
+-
+-func _() {
+-	newFunction := 1
+-	a := newFunction2(newFunction) //@codeaction("refactor.extract", "a", "newFunction", scope)
+-	_ = a // avoid diagnostic
+-}
+-
+-func newFunction2(newFunction int) int {
+-	a := newFunction
+-	return a
+-}
+-
+-func newFunction1() int {
+-	return 1
+-}
+-
+--- smart_initialization.go --
+-package extract
+-
+-func _() {
+-	var a []int
+-	a = append(a, 2) //@codeaction("refactor.extract", "a", siEnd, si)
+-	b := 4           //@loc(siEnd, "4")
+-	a = append(a, b)
+-}
+-
+--- @si/smart_initialization.go --
+-package extract
+-
+-func _() {
+-	var a []int
+-	//@codeaction("refactor.extract", "a", siEnd, si)
+-	a, b := newFunction(a)           //@loc(siEnd, "4")
+-	a = append(a, b)
+-}
+-
+-func newFunction(a []int) ([]int, int) {
+-	a = append(a, 2)
+-	b := 4
+-	return a, b
+-}
+-
+--- smart_return.go --
+-package extract
+-
+-func _() {
+-	var b []int
+-	var a int
+-	a = 2 //@codeaction("refactor.extract", "a", srEnd, sr)
+-	b = []int{}
+-	b = append(b, a) //@loc(srEnd, ")")
+-	b[0] = 1
+-}
+-
+--- @sr/smart_return.go --
+-package extract
+-
+-func _() {
+-	var b []int
+-	var a int
+-	//@codeaction("refactor.extract", "a", srEnd, sr)
+-	b = newFunction(a, b) //@loc(srEnd, ")")
+-	b[0] = 1
+-}
+-
+-func newFunction(a int, b []int) []int {
+-	a = 2
+-	b = []int{}
+-	b = append(b, a)
+-	return b
+-}
+-
+--- unnecessary_param.go --
+-package extract
+-
+-func _() {
+-	var b []int
+-	a := 2 //@codeaction("refactor.extract", "a", upEnd, up)
+-	b = []int{}
+-	b = append(b, a) //@loc(upEnd, ")")
+-	b[0] = 1
+-	if a == 2 {
+-		return
+-	}
+-}
+-
+--- @up/unnecessary_param.go --
+-package extract
+-
+-func _() {
+-	var b []int
+-	//@codeaction("refactor.extract", "a", upEnd, up)
+-	a, b := newFunction(b) //@loc(upEnd, ")")
+-	b[0] = 1
+-	if a == 2 {
+-		return
+-	}
+-}
+-
+-func newFunction(b []int) (int, []int) {
+-	a := 2
+-	b = []int{}
+-	b = append(b, a)
+-	return a, b
+-}
+-
+--- comment.go --
+-package extract
+-
+-func _() {
+-	a := /* comment in the middle of a line */ 1 //@codeaction("refactor.extract", "a", commentEnd, comment1)
+-	// Comment on its own line  //@codeaction("refactor.extract", "Comment", commentEnd, comment2)
+-	_ = a + 4 //@loc(commentEnd, "4"),codeaction("refactor.extract", "_", lastComment, comment3)
+-	// Comment right after 3 + 4
+-
+-	// Comment after with space //@loc(lastComment, "Comment")
+-}
+-
+--- @comment1/comment.go --
+-package extract
+-
+-func _() {
+-	/* comment in the middle of a line */
+-	//@codeaction("refactor.extract", "a", commentEnd, comment1)
+-	// Comment on its own line  //@codeaction("refactor.extract", "Comment", commentEnd, comment2)
+-	newFunction() //@loc(commentEnd, "4"),codeaction("refactor.extract", "_", lastComment, comment3)
+-	// Comment right after 3 + 4
+-
+-	// Comment after with space //@loc(lastComment, "Comment")
+-}
+-
+-func newFunction() {
+-	a := 1
+-
+-	_ = a + 4
+-}
+-
+--- @comment2/comment.go --
+-package extract
+-
+-func _() {
+-	a := /* comment in the middle of a line */ 1 //@codeaction("refactor.extract", "a", commentEnd, comment1)
+-	// Comment on its own line  //@codeaction("refactor.extract", "Comment", commentEnd, comment2)
+-	newFunction(a) //@loc(commentEnd, "4"),codeaction("refactor.extract", "_", lastComment, comment3)
+-	// Comment right after 3 + 4
+-
+-	// Comment after with space //@loc(lastComment, "Comment")
+-}
+-
+-func newFunction(a int) {
+-	_ = a + 4
+-}
+-
+--- @comment3/comment.go --
+-package extract
+-
+-func _() {
+-	a := /* comment in the middle of a line */ 1 //@codeaction("refactor.extract", "a", commentEnd, comment1)
+-	// Comment on its own line  //@codeaction("refactor.extract", "Comment", commentEnd, comment2)
+-	newFunction(a) //@loc(commentEnd, "4"),codeaction("refactor.extract", "_", lastComment, comment3)
+-	// Comment right after 3 + 4
+-
+-	// Comment after with space //@loc(lastComment, "Comment")
+-}
+-
+-func newFunction(a int) {
+-	_ = a + 4
+-}
+-
+--- redefine.go --
+-package extract
+-
+-import "strconv"
+-
+-func _() {
+-	i, err := strconv.Atoi("1")
+-	u, err := strconv.Atoi("2") //@codeaction("refactor.extract", "u", ")", redefine)
+-	if i == u || err == nil {
+-		return
+-	}
+-}
+-
+--- @redefine/redefine.go --
+-package extract
+-
+-import "strconv"
+-
+-func _() {
+-	i, err := strconv.Atoi("1")
+-	u, err := newFunction() //@codeaction("refactor.extract", "u", ")", redefine)
+-	if i == u || err == nil {
+-		return
+-	}
+-}
+-
+-func newFunction() (int, error) {
+-	u, err := strconv.Atoi("2")
+-	return u, err
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/codeaction/functionextraction_issue44813.txt b/gopls/internal/regtest/marker/testdata/codeaction/functionextraction_issue44813.txt
+--- a/gopls/internal/regtest/marker/testdata/codeaction/functionextraction_issue44813.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codeaction/functionextraction_issue44813.txt	1970-01-01 08:00:00
+@@ -1,42 +0,0 @@
+-This test verifies the fix for golang/go#44813: extraction failure when there
+-are blank identifiers.
+-
+--- go.mod --
+-module mod.test/extract
+-
+-go 1.18
+-
+--- p.go --
+-package extract
+-
+-import "fmt"
+-
+-func main() {
+-	x := []rune{} //@codeaction("refactor.extract", "x", end, ext)
+-	s := "HELLO"
+-	for _, c := range s {
+-		x = append(x, c)
+-	} //@loc(end, "}")
+-	fmt.Printf("%x\n", x)
+-}
+-
+--- @ext/p.go --
+-package extract
+-
+-import "fmt"
+-
+-func main() {
+-	//@codeaction("refactor.extract", "x", end, ext)
+-	x := newFunction() //@loc(end, "}")
+-	fmt.Printf("%x\n", x)
+-}
+-
+-func newFunction() []rune {
+-	x := []rune{}
+-	s := "HELLO"
+-	for _, c := range s {
+-		x = append(x, c)
+-	}
+-	return x
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/codeaction/imports.txt b/gopls/internal/regtest/marker/testdata/codeaction/imports.txt
+--- a/gopls/internal/regtest/marker/testdata/codeaction/imports.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codeaction/imports.txt	1970-01-01 08:00:00
+@@ -1,175 +0,0 @@
+-This test verifies the behavior of the 'source.organizeImports' code action.
+-
+--- go.mod --
+-module mod.test/imports
+-
+-go 1.18
+-
+--- add.go --
+-package imports //@codeaction("source.organizeImports", "imports", "", add)
+-
+-import (
+-	"fmt"
+-)
+-
+-func _() {
+-	fmt.Println("")
+-	bytes.NewBuffer(nil) //@diag("bytes", re"(undeclared|undefined)")
+-}
+-
+--- @add/add.go --
+-package imports //@codeaction("source.organizeImports", "imports", "", add)
+-
+-import (
+-	"bytes"
+-	"fmt"
+-)
+-
+-func _() {
+-	fmt.Println("")
+-	bytes.NewBuffer(nil) //@diag("bytes", re"(undeclared|undefined)")
+-}
+-
+--- good.go --
+-package imports //@codeactionerr("source.organizeImports", "imports", "", re"found 0 CodeActions")
+-
+-import "fmt"
+-
+-func _() {
+-fmt.Println("")
+-}
+-
+--- issue35458.go --
+-
+-
+-
+-
+-
+-// package doc
+-package imports //@codeaction("source.organizeImports", "imports", "", issue35458)
+-
+-
+-
+-
+-
+-
+-func _() {
+-	println("Hello, world!")
+-}
+-
+-
+-
+-
+-
+-
+-
+-
+--- @issue35458/issue35458.go --
+-// package doc
+-package imports //@codeaction("source.organizeImports", "imports", "", issue35458)
+-
+-
+-
+-
+-
+-
+-func _() {
+-	println("Hello, world!")
+-}
+-
+-
+-
+-
+-
+-
+-
+-
+--- multi.go --
+-package imports //@codeaction("source.organizeImports", "imports", "", multi)
+-
+-import "fmt"
+-
+-import "bytes" //@diag("\"bytes\"", re"not used")
+-
+-func _() {
+-	fmt.Println("")
+-}
+-
+--- @multi/multi.go --
+-package imports //@codeaction("source.organizeImports", "imports", "", multi)
+-
+-import "fmt"
+-
+-//@diag("\"bytes\"", re"not used")
+-
+-func _() {
+-	fmt.Println("")
+-}
+-
+--- needs.go --
+-package imports //@codeaction("source.organizeImports", "package", "", needs)
+-
+-func goodbye() {
+-	fmt.Printf("HI") //@diag("fmt", re"(undeclared|undefined)")
+-	log.Printf("byeeeee") //@diag("log", re"(undeclared|undefined)")
+-}
+-
+--- @needs/needs.go --
+-package imports //@codeaction("source.organizeImports", "package", "", needs)
+-
+-import (
+-	"fmt"
+-	"log"
+-)
+-
+-func goodbye() {
+-	fmt.Printf("HI") //@diag("fmt", re"(undeclared|undefined)")
+-	log.Printf("byeeeee") //@diag("log", re"(undeclared|undefined)")
+-}
+-
+--- remove.go --
+-package imports //@codeaction("source.organizeImports", "package", "", remove)
+-
+-import (
+-	"bytes" //@diag("\"bytes\"", re"not used")
+-	"fmt"
+-)
+-
+-func _() {
+-	fmt.Println("")
+-}
+-
+--- @remove/remove.go --
+-package imports //@codeaction("source.organizeImports", "package", "", remove)
+-
+-import (
+-	"fmt"
+-)
+-
+-func _() {
+-	fmt.Println("")
+-}
+-
+--- removeall.go --
+-package imports //@codeaction("source.organizeImports", "package", "", removeall)
+-
+-import (
+-	"bytes" //@diag("\"bytes\"", re"not used")
+-	"fmt" //@diag("\"fmt\"", re"not used")
+-
+-)
+-
+-func _() {
+-}
+-
+--- @removeall/removeall.go --
+-package imports //@codeaction("source.organizeImports", "package", "", removeall)
+-
+-//@diag("\"fmt\"", re"not used")
+-
+-func _() {
+-}
+-
+--- twolines.go --
+-package imports
+-func main()  {} //@codeactionerr("source.organizeImports", "main", "", re"found 0")
+diff -urN a/gopls/internal/regtest/marker/testdata/codeaction/infertypeargs.txt b/gopls/internal/regtest/marker/testdata/codeaction/infertypeargs.txt
+--- a/gopls/internal/regtest/marker/testdata/codeaction/infertypeargs.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codeaction/infertypeargs.txt	1970-01-01 08:00:00
+@@ -1,38 +0,0 @@
+-This test verifies the infertypeargs refactoring.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module mod.test/infertypeargs
+-
+-go 1.18
+-
+--- p.go --
+-package infertypeargs
+-
+-func app[S interface{ ~[]E }, E interface{}](s S, e E) S {
+-	return append(s, e)
+-}
+-
+-func _() {
+-	_ = app[[]int]
+-	_ = app[[]int, int]
+-	_ = app[[]int]([]int{}, 0) //@codeaction("refactor.rewrite", "app", ")", infer)
+-	_ = app([]int{}, 0)
+-}
+-
+--- @infer/p.go --
+-package infertypeargs
+-
+-func app[S interface{ ~[]E }, E interface{}](s S, e E) S {
+-	return append(s, e)
+-}
+-
+-func _() {
+-	_ = app[[]int]
+-	_ = app[[]int, int]
+-	_ = app([]int{}, 0) //@codeaction("refactor.rewrite", "app", ")", infer)
+-	_ = app([]int{}, 0)
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/codeaction/inline.txt b/gopls/internal/regtest/marker/testdata/codeaction/inline.txt
+--- a/gopls/internal/regtest/marker/testdata/codeaction/inline.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codeaction/inline.txt	1970-01-01 08:00:00
+@@ -1,23 +0,0 @@
+-This is a minimal test of the refactor.inline code action.
+-
+--- go.mod --
+-module testdata/codeaction
+-go 1.18
+-
+--- a/a.go --
+-package a
+-
+-func _() {
+-	println(add(1, 2)) //@codeaction("refactor.inline", "add", ")", inline)
+-}
+-
+-func add(x, y int) int { return x + y }
+-
+--- @inline/a/a.go --
+-package a
+-
+-func _() {
+-	println(1 + 2) //@codeaction("refactor.inline", "add", ")", inline)
+-}
+-
+-func add(x, y int) int { return x + y }
+diff -urN a/gopls/internal/regtest/marker/testdata/codelens/generate.txt b/gopls/internal/regtest/marker/testdata/codelens/generate.txt
+--- a/gopls/internal/regtest/marker/testdata/codelens/generate.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codelens/generate.txt	1970-01-01 08:00:00
+@@ -1,9 +0,0 @@
+-This test exercises the "generate" codelens.
+-
+--- generate.go --
+-//@codelenses()
+-
+-package generate
+-
+-//go:generate echo Hi //@ codelens("//go:generate", "run go generate"), codelens("//go:generate", "run go generate ./...")
+-//go:generate echo I shall have no CodeLens
+diff -urN a/gopls/internal/regtest/marker/testdata/codelens/test.txt b/gopls/internal/regtest/marker/testdata/codelens/test.txt
+--- a/gopls/internal/regtest/marker/testdata/codelens/test.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/codelens/test.txt	1970-01-01 08:00:00
+@@ -1,31 +0,0 @@
+-This file tests codelenses for test functions.
+-
+-TODO: for some reason these code lens have zero width. Does that affect their
+-utility/visibility in various LSP clients?
+-
+--- settings.json --
+-{
+-	"codelenses": {
+-		"test": true
+-	}
+-}
+-
+--- p_test.go --
+-//@codelenses()
+-
+-package codelens //@codelens(re"()package codelens", "run file benchmarks")
+-
+-import "testing"
+-
+-func TestMain(m *testing.M) {} // no code lens for TestMain
+-
+-func TestFuncWithCodeLens(t *testing.T) { //@codelens(re"()func", "run test")
+-}
+-
+-func thisShouldNotHaveACodeLens(t *testing.T) {
+-}
+-
+-func BenchmarkFuncWithCodeLens(b *testing.B) { //@codelens(re"()func", "run benchmark")
+-}
+-
+-func helper() {} // expect no code lens
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/bad.txt b/gopls/internal/regtest/marker/testdata/completion/bad.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/bad.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/bad.txt	1970-01-01 08:00:00
+@@ -1,68 +0,0 @@
+-This test exercises completion in the presence of type errors.
+-
+-Note: this test was ported from the old marker tests, which did not enable
+-unimported completion. Enabling it causes matches in e.g. crypto/rand.
+-
+--- settings.json --
+-{
+-	"completeUnimported": false
+-}
+-
+--- go.mod --
+-module bad.test
+-
+-go 1.18
+-
+--- bad/bad0.go --
+-package bad
+-
+-func stuff() { //@item(stuff, "stuff", "func()", "func")
+-	x := "heeeeyyyy"
+-	random2(x) //@diag("x", re"cannot use x \\(variable of type string\\) as int value in argument to random2")
+-	random2(1) //@complete("dom", random, random2, random3)
+-	y := 3     //@diag("y", re"y declared (and|but) not used")
+-}
+-
+-type bob struct { //@item(bob, "bob", "struct{...}", "struct")
+-	x int
+-}
+-
+-func _() {
+-	var q int
+-	_ = &bob{
+-		f: q, //@diag("f: q", re"unknown field f in struct literal")
+-	}
+-}
+-
+--- bad/bad1.go --
+-package bad
+-
+-// See #36637
+-type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFunc", "type")
+-
+-var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", re"(undeclared name|undefined): unknown")
+-
+-func random() int { //@item(random, "random", "func() int", "func")
+-	//@complete("", global_a, bob, random, random2, random3, stateFunc, stuff)
+-	return 0
+-}
+-
+-func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var")
+-	x := 6       //@item(x, "x", "int", "var"),diag("x", re"x declared (and|but) not used")
+-	var q blah   //@item(q, "q", "blah", "var"),diag("q", re"q declared (and|but) not used"),diag("blah", re"(undeclared name|undefined): blah")
+-	var t **blob //@item(t, "t", "**blob", "var"),diag("t", re"t declared (and|but) not used"),diag("blob", re"(undeclared name|undefined): blob")
+-	//@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+-
+-	return y
+-}
+-
+-func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var")
+-	//@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+-
+-	var ch chan (favType1)   //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", re"ch declared (and|but) not used"),diag("favType1", re"(undeclared name|undefined): favType1")
+-	var m map[keyType]int    //@item(m, "m", "map[keyType]int", "var"),diag("m", re"m declared (and|but) not used"),diag("keyType", re"(undeclared name|undefined): keyType")
+-	var arr []favType2       //@item(arr, "arr", "[]favType2", "var"),diag("arr", re"arr declared (and|but) not used"),diag("favType2", re"(undeclared name|undefined): favType2")
+-	var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", re"fn1 declared (and|but) not used"),diag("badResult", re"(undeclared name|undefined): badResult")
+-	var fn2 func(badParam)   //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", re"fn2 declared (and|but) not used"),diag("badParam", re"(undeclared name|undefined): badParam")
+-	//@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/foobarbaz.txt b/gopls/internal/regtest/marker/testdata/completion/foobarbaz.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/foobarbaz.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/foobarbaz.txt	1970-01-01 08:00:00
+@@ -1,541 +0,0 @@
+-This test ports some arbitrary tests from the old marker framework, that were
+-*mostly* about completion.
+-
+--- flags --
+--ignore_extra_diags
+--min_go=go1.20
+-
+--- settings.json --
+-{
+-	"completeUnimported": false,
+-	"deepCompletion": false,
+-	"experimentalPostfixCompletions": false
+-}
+-
+--- go.mod --
+-module foobar.test
+-
+-go 1.18
+-
+--- foo/foo.go --
+-package foo //@loc(PackageFoo, "foo"),item(PackageFooItem, "foo", "\"foobar.test/foo\"", "package")
+-
+-type StructFoo struct { //@loc(StructFooLoc, "StructFoo"), item(StructFoo, "StructFoo", "struct{...}", "struct")
+-	Value int //@item(Value, "Value", "int", "field")
+-}
+-
+-// Pre-set this marker, as we don't have a "source" for it in this package.
+-/* Error() */ //@item(Error, "Error", "func() string", "method")
+-
+-func Foo() { //@item(Foo, "Foo", "func()", "func")
+-	var err error
+-	err.Error() //@complete("E", Error)
+-}
+-
+-func _() {
+-	var sFoo StructFoo           //@complete("t", StructFoo)
+-	if x := sFoo; x.Value == 1 { //@complete("V", Value), typedef("sFoo", StructFooLoc)
+-		return
+-	}
+-}
+-
+-func _() {
+-	shadowed := 123
+-	{
+-		shadowed := "hi" //@item(shadowed, "shadowed", "string", "var")
+-		sha              //@complete("a", shadowed), diag("sha", re"(undefined|undeclared)")
+-		_ = shadowed
+-	}
+-}
+-
+-type IntFoo int //@loc(IntFooLoc, "IntFoo"), item(IntFoo, "IntFoo", "int", "type")
+-
+--- bar/bar.go --
+-package bar
+-
+-import (
+-	"foobar.test/foo" //@item(foo, "foo", "\"foobar.test/foo\"", "package")
+-)
+-
+-func helper(i foo.IntFoo) {} //@item(helper, "helper", "func(i foo.IntFoo)", "func")
+-
+-func _() {
+-	help //@complete("l", helper)
+-	_ = foo.StructFoo{} //@complete("S", IntFoo, StructFoo)
+-}
+-
+-// Bar is a function.
+-func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.")
+-	foo.Foo()        //@complete("F", Foo, IntFoo, StructFoo)
+-	var _ foo.IntFoo //@complete("I", IntFoo, StructFoo)
+-	foo.()           //@complete("(", Foo, IntFoo, StructFoo), diag(")", re"expected type")
+-}
+-
+-// These items weren't present in the old marker tests (due to settings), but
+-// we may as well include them.
+-//@item(intConversion, "int()"), item(fooFoo, "foo.Foo")
+-//@item(fooIntFoo, "foo.IntFoo"), item(fooStructFoo, "foo.StructFoo")
+-
+-func _() {
+-	var Valentine int //@item(Valentine, "Valentine", "int", "var")
+-
+-	_ = foo.StructFoo{ //@diag("foo", re"unkeyed fields")
+-		Valu //@complete(" //", Value)
+-	}
+-  	_ = foo.StructFoo{ //@diag("foo", re"unkeyed fields")
+-		Va        //@complete("a", Value, Valentine)
+-
+-	}
+-	_ = foo.StructFoo{
+-		Value: 5, //@complete("a", Value)
+-	}
+-	_ = foo.StructFoo{
+-		//@complete("//", Value, Valentine, intConversion, foo, helper, Bar)
+-	}
+-	_ = foo.StructFoo{
+-		Value: Valen //@complete("le", Valentine)
+-	}
+-	_ = foo.StructFoo{
+-		Value:       //@complete(" //", Valentine, intConversion, foo, helper, Bar)
+-	}
+-	_ = foo.StructFoo{
+-		Value:       //@complete(" ", Valentine, intConversion, foo, helper, Bar)
+-	}
+-}
+-
+--- baz/baz.go --
+-package baz
+-
+-import (
+-	"foobar.test/bar"
+-
+-	f "foobar.test/foo"
+-)
+-
+-var FooStruct f.StructFoo
+-
+-func Baz() {
+-	defer bar.Bar() //@complete("B", Bar)
+-	// TODO: Test completion here.
+-	defer bar.B //@diag(re"bar.B()", re"must be function call")
+-	var x f.IntFoo  //@complete("n", IntFoo), typedef("x", IntFooLoc)
+-	bar.Bar()       //@complete("B", Bar)
+-}
+-
+-func _() {
+-	bob := f.StructFoo{Value: 5}
+-	if x := bob. //@complete(" //", Value)
+-	switch true == false {
+-		case true:
+-			if x := bob. //@complete(" //", Value)
+-		case false:
+-	}
+-	if x := bob.Va //@complete("a", Value)
+-	switch true == true {
+-		default:
+-	}
+-}
+-
+--- arraytype/arraytype.go --
+-package arraytype
+-
+-import (
+-	"foobar.test/foo"
+-)
+-
+-func _() {
+-	var (
+-		val string //@item(atVal, "val", "string", "var")
+-	)
+-
+-	[] //@complete(" //", atVal, PackageFooItem)
+-
+-	[]val //@complete(" //")
+-
+-	[]foo.StructFoo //@complete(" //", StructFoo)
+-
+-	[]foo.StructFoo(nil) //@complete("(", StructFoo)
+-
+-	[]*foo.StructFoo //@complete(" //", StructFoo)
+-
+-	[...]foo.StructFoo //@complete(" //", StructFoo)
+-
+-	[2][][4]foo.StructFoo //@complete(" //", StructFoo)
+-
+-	[]struct { f []foo.StructFoo } //@complete(" }", StructFoo)
+-}
+-
+-func _() {
+-	type myInt int //@item(atMyInt, "myInt", "int", "type")
+-
+-	var mark []myInt //@item(atMark, "mark", "[]myInt", "var")
+-
+-	var s []myInt //@item(atS, "s", "[]myInt", "var")
+-	s = []m //@complete(" //", atMyInt)
+-
+-	var a [1]myInt
+-	a = [1]m //@complete(" //", atMyInt)
+-
+-	var ds [][]myInt
+-	ds = [][]m //@complete(" //", atMyInt)
+-}
+-
+-func _() {
+-	var b [0]byte //@item(atByte, "b", "[0]byte", "var")
+-	var _ []byte = b //@snippet(" //", atByte, "b[:]")
+-}
+-
+--- badstmt/badstmt.go --
+-package badstmt
+-
+-import (
+-	"foobar.test/foo"
+-)
+-
+-// (The syntax error causes suppression of diagnostics for type errors.
+-// See issue #59888.)
+-
+-func _(x int) {
+-	defer foo.F //@complete(" //", Foo, IntFoo, StructFoo)
+-	defer foo.F //@complete(" //", Foo, IntFoo, StructFoo)
+-}
+-
+-func _() {
+-	switch true {
+-	case true:
+-		go foo.F //@complete(" //", Foo, IntFoo, StructFoo)
+-	}
+-}
+-
+-func _() {
+-	defer func() {
+-		foo.F //@complete(" //", Foo, IntFoo, StructFoo), snippet(" //", Foo, "Foo()")
+-
+-		foo. //@rank(" //", Foo)
+-	}
+-}
+-
+--- badstmt/badstmt_2.go --
+-package badstmt
+-
+-import (
+-	"foobar.test/foo"
+-)
+-
+-func _() {
+-	defer func() { foo. } //@rank(" }", Foo)
+-}
+-
+--- badstmt/badstmt_3.go --
+-package badstmt
+-
+-import (
+-	"foobar.test/foo"
+-)
+-
+-func _() {
+-	go foo. //@rank(" //", Foo, IntFoo), snippet(" //", Foo, "Foo()")
+-}
+-
+--- badstmt/badstmt_4.go --
+-package badstmt
+-
+-import (
+-	"foobar.test/foo"
+-)
+-
+-func _() {
+-	go func() {
+-		defer foo. //@rank(" //", Foo, IntFoo)
+-	}
+-}
+-
+--- selector/selector.go --
+-package selector
+-
+-import (
+-	"foobar.test/bar"
+-)
+-
+-type S struct {
+-	B, A, C int //@item(Bf, "B", "int", "field"),item(Af, "A", "int", "field"),item(Cf, "C", "int", "field")
+-}
+-
+-func _() {
+-	_ = S{}.; //@complete(";", Af, Bf, Cf)
+-}
+-
+-type bob struct { a int } //@item(a, "a", "int", "field")
+-type george struct { b int }
+-type jack struct { c int } //@item(c, "c", "int", "field")
+-type jill struct { d int }
+-
+-func (b *bob) george() *george {} //@item(george, "george", "func() *george", "method")
+-func (g *george) jack() *jack {}
+-func (j *jack) jill() *jill {} //@item(jill, "jill", "func() *jill", "method")
+-
+-func _() {
+-	b := &bob{}
+-	y := b.george().
+-		jack();
+-	y.; //@complete(";", c, jill)
+-}
+-
+-func _() {
+-	bar. //@complete(" /", Bar)
+-	x := 5
+-
+-	var b *bob
+-	b. //@complete(" /", a, george)
+-	y, z := 5, 6
+-
+-	b. //@complete(" /", a, george)
+-	y, z, a, b, c := 5, 6
+-}
+-
+-func _() {
+-	bar. //@complete(" /", Bar)
+-	bar.Bar()
+-
+-	bar. //@complete(" /", Bar)
+-	go f()
+-}
+-
+-func _() {
+-	var b *bob
+-	if y != b. //@complete(" /", a, george)
+-	z := 5
+-
+-	if z + y + 1 + b. //@complete(" /", a, george)
+-	r, s, t := 4, 5
+-
+-	if y != b. //@complete(" /", a, george)
+-	z = 5
+-
+-	if z + y + 1 + b. //@complete(" /", a, george)
+-	r = 4
+-}
+-
+--- literal_snippets/literal_snippets.go --
+-package literal_snippets
+-
+-import (
+-	"bytes"
+-	"context"
+-	"go/ast"
+-	"net/http"
+-	"sort"
+-
+-	"golang.org/lsptests/foo"
+-)
+-
+-func _() {
+-	[]int{}        //@item(litIntSlice, "[]int{}", "", "var")
+-	&[]int{}       //@item(litIntSliceAddr, "&[]int{}", "", "var")
+-	make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func")
+-
+-	var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}")
+-	var _ **[]int = in //@complete(" //")
+-
+-	var slice []int
+-	slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}")
+-	slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})")
+-}
+-
+-func _() {
+-	type namedInt []int
+-
+-	namedInt{}        //@item(litNamedSlice, "namedInt{}", "", "var")
+-	make(namedInt, 0) //@item(makeNamedSlice, "make(namedInt, 0)", "", "func")
+-
+-	var namedSlice namedInt
+-	namedSlice = n //@snippet(" //", litNamedSlice, "namedInt{$0\\}")
+-	namedSlice = m //@snippet(" //", makeNamedSlice, "make(namedInt, ${1:})")
+-}
+-
+-func _() {
+-	make(chan int) //@item(makeChan, "make(chan int)", "", "func")
+-
+-	var ch chan int
+-	ch = m //@snippet(" //", makeChan, "make(chan int)")
+-}
+-
+-func _() {
+-	map[string]struct{}{}     //@item(litMap, "map[string]struct{}{}", "", "var")
+-	make(map[string]struct{}) //@item(makeMap, "make(map[string]struct{})", "", "func")
+-
+-	var m map[string]struct{}
+-	m = m //@snippet(" //", litMap, "map[string]struct{\\}{$0\\}")
+-	m = m //@snippet(" //", makeMap, "make(map[string]struct{\\})")
+-
+-	struct{}{} //@item(litEmptyStruct, "struct{}{}", "", "var")
+-
+-	m["hi"] = s //@snippet(" //", litEmptyStruct, "struct{\\}{\\}")
+-}
+-
+-func _() {
+-	type myStruct struct{ i int } //@item(myStructType, "myStruct", "struct{...}", "struct")
+-
+-	myStruct{}  //@item(litStruct, "myStruct{}", "", "var")
+-	&myStruct{} //@item(litStructPtr, "&myStruct{}", "", "var")
+-
+-	var ms myStruct
+-	ms = m //@snippet(" //", litStruct, "myStruct{$0\\}")
+-
+-	var msPtr *myStruct
+-	msPtr = m //@snippet(" //", litStructPtr, "&myStruct{$0\\}")
+-
+-	msPtr = &m //@snippet(" //", litStruct, "myStruct{$0\\}")
+-
+-	type myStructCopy struct { i int } //@item(myStructCopyType, "myStructCopy", "struct{...}", "struct")
+-
+-	// Don't offer literal completion for convertible structs.
+-	ms = myStruct //@complete(" //", litStruct, myStructType, myStructCopyType)
+-}
+-
+-type myImpl struct{}
+-
+-func (myImpl) foo() {}
+-
+-func (*myImpl) bar() {}
+-
+-type myBasicImpl string
+-
+-func (myBasicImpl) foo() {}
+-
+-func _() {
+-	type myIntf interface {
+-		foo()
+-	}
+-
+-	myImpl{} //@item(litImpl, "myImpl{}", "", "var")
+-
+-	var mi myIntf
+-	mi = m //@snippet(" //", litImpl, "myImpl{\\}")
+-
+-	myBasicImpl() //@item(litBasicImpl, "myBasicImpl()", "string", "var")
+-
+-	mi = m //@snippet(" //", litBasicImpl, "myBasicImpl($0)")
+-
+-	// only satisfied by pointer to myImpl
+-	type myPtrIntf interface {
+-		bar()
+-	}
+-
+-	&myImpl{} //@item(litImplPtr, "&myImpl{}", "", "var")
+-
+-	var mpi myPtrIntf
+-	mpi = m //@snippet(" //", litImplPtr, "&myImpl{\\}")
+-}
+-
+-func _() {
+-	var s struct{ i []int } //@item(litSliceField, "i", "[]int", "field")
+-	var foo []int
+-	// no literal completions after selector
+-	foo = s.i //@complete(" //", litSliceField)
+-}
+-
+-func _() {
+-	type myStruct struct{ i int } //@item(litMyStructType, "myStruct", "struct{...}", "struct")
+-	myStruct{} //@item(litMyStruct, "myStruct{}", "", "var")
+-
+-	foo := func(s string, args ...myStruct) {}
+-	// Don't give literal slice candidate for variadic arg.
+-	// Do give literal candidates for variadic element.
+-	foo("", myStruct) //@complete(")", litMyStruct, litMyStructType)
+-}
+-
+-func _() {
+-	Buffer{} //@item(litBuffer, "Buffer{}", "", "var")
+-
+-	var b *bytes.Buffer
+-	b = bytes.Bu //@snippet(" //", litBuffer, "Buffer{\\}")
+-}
+-
+-func _() {
+-	_ = "func(...) {}" //@item(litFunc, "func(...) {}", "", "var")
+-
+-	// no literal "func" completions
+-	http.Handle("", fun) //@complete(")")
+-
+-	var namedReturn func(s string) (b bool)
+-	namedReturn = f //@snippet(" //", litFunc, "func(s string) (b bool) {$0\\}")
+-
+-	var multiReturn func() (bool, int)
+-	multiReturn = f //@snippet(" //", litFunc, "func() (bool, int) {$0\\}")
+-
+-	var multiNamedReturn func() (b bool, i int)
+-	multiNamedReturn = f //@snippet(" //", litFunc, "func() (b bool, i int) {$0\\}")
+-
+-	var duplicateParams func(myImpl, int, myImpl)
+-	duplicateParams = f //@snippet(" //", litFunc, "func(mi1 myImpl, i int, mi2 myImpl) {$0\\}")
+-
+-	type aliasImpl = myImpl
+-	var aliasParams func(aliasImpl) aliasImpl
+-	aliasParams = f //@snippet(" //", litFunc, "func(ai aliasImpl) aliasImpl {$0\\}")
+-
+-	const two = 2
+-	var builtinTypes func([]int, [two]bool, map[string]string, struct{ i int }, interface{ foo() }, <-chan int)
+-	builtinTypes = f //@snippet(" //", litFunc, "func(i1 []int, b [two]bool, m map[string]string, s struct{ i int \\}, i2 interface{ foo() \\}, c <-chan int) {$0\\}")
+-
+-	var _ func(ast.Node) = f //@snippet(" //", litFunc, "func(n ast.Node) {$0\\}")
+-	var _ func(error) = f //@snippet(" //", litFunc, "func(err error) {$0\\}")
+-	var _ func(context.Context) = f //@snippet(" //", litFunc, "func(ctx context.Context) {$0\\}")
+-
+-	type context struct {}
+-	var _ func(context) = f //@snippet(" //", litFunc, "func(ctx context) {$0\\}")
+-}
+-
+-func _() {
+-	float64() //@item(litFloat64, "float64()", "float64", "var")
+-
+-	// don't complete to "&float64()"
+-	var _ *float64 = float64 //@complete(" //")
+-
+-	var f float64
+-	f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)")
+-
+-	type myInt int
+-	myInt() //@item(litMyInt, "myInt()", "", "var")
+-
+-	var mi myInt
+-	mi = my //@snippet(" //", litMyInt, "myInt($0)")
+-}
+-
+-func _() {
+-	type ptrStruct struct {
+-		p *ptrStruct
+-	}
+-
+-	ptrStruct{} //@item(litPtrStruct, "ptrStruct{}", "", "var")
+-
+-	ptrStruct{
+-		p: &ptrSt, //@rank(",", litPtrStruct)
+-	}
+-
+-	&ptrStruct{} //@item(litPtrStructPtr, "&ptrStruct{}", "", "var")
+-
+-	&ptrStruct{
+-		p: ptrSt, //@rank(",", litPtrStructPtr)
+-	}
+-}
+-
+-func _() {
+-	f := func(...[]int) {}
+-	f() //@snippet(")", litIntSlice, "[]int{$0\\}")
+-}
+-
+-
+-func _() {
+-	// don't complete to "untyped int()"
+-	[]int{}[untyped] //@complete("] //")
+-}
+-
+-type Tree[T any] struct{}
+-
+-func (tree Tree[T]) Do(f func(s T)) {}
+-
+-func _() {
+-	var t Tree[string]
+-	t.Do(fun) //@complete(")", litFunc), snippet(")", litFunc, "func(s string) {$0\\}")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/issue59096.txt b/gopls/internal/regtest/marker/testdata/completion/issue59096.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/issue59096.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/issue59096.txt	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
+-This test exercises the panic in golang/go#59096: completing at a syntactic
+-type-assert expression was panicking because gopls was translating it into
+-a (malformed) selector expr.
+-
+--- go.mod --
+-module example.com
+-
+--- a/a.go --
+-package a
+-
+-func _() {
+-	b.(foo) //@complete(re"b.()", B), diag("b", re"(undefined|undeclared name): b")
+-}
+-
+-//@item(B, "B", "const (from \"example.com/b\")", "const")
+-
+--- b/b.go --
+-package b
+-
+-const B = 0
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/issue60545.txt b/gopls/internal/regtest/marker/testdata/completion/issue60545.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/issue60545.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/issue60545.txt	1970-01-01 08:00:00
+@@ -1,28 +0,0 @@
+-This test checks that unimported completion is case-insensitive.
+-
+--- go.mod --
+-module mod.test
+-
+-go 1.18
+-
+--- main.go --
+-package main
+-
+-//@item(Print, "Print", "func (from \"fmt\")", "func")
+-//@item(Printf, "Printf", "func (from \"fmt\")", "func")
+-//@item(Println, "Println", "func (from \"fmt\")", "func")
+-
+-func main() {
+-	fmt.p //@complete(re"fmt.p()", Print, Printf, Println), diag("fmt", re"(undefined|undeclared)")
+-}
+-
+--- other.go --
+-package main
+-
+-// Including another package that imports "fmt" causes completion to use the
+-// existing metadata, which is the codepath leading to golang/go#60545.
+-import "fmt"
+-
+-func _() {
+-	fmt.Println()
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/issue62141.txt b/gopls/internal/regtest/marker/testdata/completion/issue62141.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/issue62141.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/issue62141.txt	1970-01-01 08:00:00
+@@ -1,39 +0,0 @@
+-This test checks that we don't suggest completion to an untyped conversion such
+-as "untyped float(abcdef)".
+-
+--- main.go --
+-package main
+-
+-func main() {
+-	abcdef := 32 //@diag("abcdef", re"not used")
+-	x := 1.0 / abcd //@acceptcompletion(re"abcd()", "abcdef", int), diag("x", re"not used"), diag("abcd", re"(undefined|undeclared)")
+-
+-	// Verify that we don't suggest converting compatible untyped constants.
+-	const untypedConst = 42
+-	y := 1.1 / untypedC //@acceptcompletion(re"untypedC()", "untypedConst", untyped), diag("y", re"not used"), diag("untypedC", re"(undefined|undeclared)")
+-}
+-
+--- @int/main.go --
+-package main
+-
+-func main() {
+-	abcdef := 32 //@diag("abcdef", re"not used")
+-	x := 1.0 / float64(abcdef) //@acceptcompletion(re"abcd()", "abcdef", int), diag("x", re"not used"), diag("abcd", re"(undefined|undeclared)")
+-
+-	// Verify that we don't suggest converting compatible untyped constants.
+-	const untypedConst = 42
+-	y := 1.1 / untypedC //@acceptcompletion(re"untypedC()", "untypedConst", untyped), diag("y", re"not used"), diag("untypedC", re"(undefined|undeclared)")
+-}
+-
+--- @untyped/main.go --
+-package main
+-
+-func main() {
+-	abcdef := 32 //@diag("abcdef", re"not used")
+-	x := 1.0 / abcd //@acceptcompletion(re"abcd()", "abcdef", int), diag("x", re"not used"), diag("abcd", re"(undefined|undeclared)")
+-
+-	// Verify that we don't suggest converting compatible untyped constants.
+-	const untypedConst = 42
+-	y := 1.1 / untypedConst //@acceptcompletion(re"untypedC()", "untypedConst", untyped), diag("y", re"not used"), diag("untypedC", re"(undefined|undeclared)")
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/issue62560.txt b/gopls/internal/regtest/marker/testdata/completion/issue62560.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/issue62560.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/issue62560.txt	1970-01-01 08:00:00
+@@ -1,19 +0,0 @@
+-This test verifies that completion of package members in unimported packages
+-reflects their fuzzy score, even when those members are present in the
+-transitive import graph of the main module. (For technical reasons, this was
+-the nature of the regression in golang/go#62560.)
+-
+--- go.mod --
+-module mod.test
+-
+--- foo/foo.go --
+-package foo
+-
+-func _() {
+-	json.U //@rankl(re"U()", "Unmarshal", "InvalidUTF8Error"), diag("json", re"(undefined|undeclared)")
+-}
+-
+--- bar/bar.go --
+-package bar
+-
+-import _ "encoding/json"
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/issue62676.txt b/gopls/internal/regtest/marker/testdata/completion/issue62676.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/issue62676.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/issue62676.txt	1970-01-01 08:00:00
+@@ -1,63 +0,0 @@
+-This test verifies that unimported completion respects the usePlaceholders setting.
+-
+--- flags --
+--ignore_extra_diags
+-
+--- settings.json --
+-{
+-	"usePlaceholders": false
+-}
+-
+--- go.mod --
+-module mod.test
+-
+-go 1.21
+-
+--- foo/foo.go --
+-package foo
+-
+-func _() {
+-	// This uses goimports-based completion; TODO: this should insert snippets.
+-	os.Open //@acceptcompletion(re"Open()", "Open", open)
+-}
+-
+-func _() {
+-	// This uses metadata-based completion.
+-	errors.New //@acceptcompletion(re"New()", "New", new)
+-}
+-
+--- bar/bar.go --
+-package bar
+-
+-import _ "errors" // important: doesn't transitively import os.
+-
+--- @new/foo/foo.go --
+-package foo
+-
+-import "errors"
+-
+-func _() {
+-	// This uses goimports-based completion; TODO: this should insert snippets.
+-	os.Open //@acceptcompletion(re"Open()", "Open", open)
+-}
+-
+-func _() {
+-	// This uses metadata-based completion.
+-	errors.New(${1:}) //@acceptcompletion(re"New()", "New", new)
+-}
+-
+--- @open/foo/foo.go --
+-package foo
+-
+-import "os"
+-
+-func _() {
+-	// This uses goimports-based completion; TODO: this should insert snippets.
+-	os.Open //@acceptcompletion(re"Open()", "Open", open)
+-}
+-
+-func _() {
+-	// This uses metadata-based completion.
+-	errors.New //@acceptcompletion(re"New()", "New", new)
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/lit.txt b/gopls/internal/regtest/marker/testdata/completion/lit.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/lit.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/lit.txt	1970-01-01 08:00:00
+@@ -1,49 +0,0 @@
+-
+--- flags --
+--ignore_extra_diags
+-
+--- go.mod --
+-module mod.test
+-
+-go 1.18
+-
+--- foo/foo.go --
+-package foo
+-
+-type StructFoo struct{ F int }
+-
+--- a.go --
+-package a
+-
+-import "mod.test/foo"
+-
+-func _() {
+-	StructFoo{} //@item(litStructFoo, "StructFoo{}", "struct{...}", "struct")
+-
+-	var sfp *foo.StructFoo
+-	// Don't insert the "&" before "StructFoo{}".
+-	sfp = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}")
+-
+-	var sf foo.StructFoo
+-	sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}")
+-	sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}")
+-}
+-
+--- http.go --
+-package a
+-
+-import (
+-	"net/http"
+-	"sort"
+-)
+-
+-func _() {
+-	sort.Slice(nil, fun) //@snippet(")", litFunc, "func(i, j int) bool {$0\\}")
+-
+-	http.HandleFunc("", f) //@snippet(")", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}")
+-
+-	//@item(litFunc, "func(...) {}", "", "var")
+-	http.HandlerFunc() //@item(handlerFunc, "http.HandlerFunc()", "", "var")
+-	http.Handle("", http.HandlerFunc()) //@snippet("))", litFunc, "func(w http.ResponseWriter, r *http.Request) {$0\\}")
+-	http.Handle("", h) //@snippet(")", handlerFunc, "http.HandlerFunc($0)")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/testy.txt b/gopls/internal/regtest/marker/testdata/completion/testy.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/testy.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/testy.txt	1970-01-01 08:00:00
+@@ -1,57 +0,0 @@
+-
+--- flags --
+--ignore_extra_diags
+-
+--- go.mod --
+-module testy.test
+-
+-go 1.18
+-
+--- types/types.go --
+-package types
+-
+-
+--- signature/signature.go --
+-package signature
+-
+-type Alias = int
+-
+--- snippets/snippets.go --
+-package snippets
+-
+-import (
+-	"testy.test/signature"
+-	t "testy.test/types"
+-)
+-
+-func X(_ map[signature.Alias]t.CoolAlias) (map[signature.Alias]t.CoolAlias) {
+-	return nil
+-}
+-
+--- testy/testy.go --
+-package testy
+-
+-func a() { //@item(funcA, "a", "func()", "func")
+-	//@complete("", funcA)
+-}
+-
+-
+--- testy/testy_test.go --
+-package testy
+-
+-import (
+-	"testing"
+-
+-	sig "testy.test/signature"
+-	"testy.test/snippets"
+-)
+-
+-func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func")
+-	var x int //@loc(testyX, "x"), diag("x", re"x declared (and|but) not used")
+-	a()       //@loc(testyA, "a")
+-}
+-
+-func _() {
+-	_ = snippets.X(nil) //@signature("nil", "X(_ map[sig.Alias]types.CoolAlias) map[sig.Alias]types.CoolAlias")
+-	var _ sig.Alias
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/completion/unimported.txt b/gopls/internal/regtest/marker/testdata/completion/unimported.txt
+--- a/gopls/internal/regtest/marker/testdata/completion/unimported.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/completion/unimported.txt	1970-01-01 08:00:00
+@@ -1,88 +0,0 @@
+-
+--- flags --
+--ignore_extra_diags
+-
+--- go.mod --
+-module unimported.test
+-
+-go 1.18
+-
+--- unimported/export_test.go --
+-package unimported
+-
+-var TestExport int //@item(testexport, "TestExport", "var (from \"unimported.test/unimported\")", "var")
+-
+--- signature/signature.go --
+-package signature
+-
+-func Foo() {}
+-
+--- foo/foo.go --
+-package foo
+-
+-type StructFoo struct{ F int }
+-
+--- baz/baz.go --
+-package baz
+-
+-import (
+-	f "unimported.test/foo"
+-)
+-
+-var FooStruct f.StructFoo
+-
+--- unimported/unimported.go --
+-package unimported
+-
+-func _() {
+-	http //@complete("p", http, httptest, httptrace, httputil)
+-	// container/ring is extremely unlikely to be imported by anything, so shouldn't have type information.
+-	ring.Ring     //@complete(re"R()ing", ringring)
+-	signature.Foo //@complete("Foo", signaturefoo)
+-
+-	context.Bac //@complete(" //", contextBackground)
+-}
+-
+-// Create markers for unimported std lib packages. Only for use by this test.
+-/* http */ //@item(http, "http", "\"net/http\"", "package")
+-/* httptest */ //@item(httptest, "httptest", "\"net/http/httptest\"", "package")
+-/* httptrace */ //@item(httptrace, "httptrace", "\"net/http/httptrace\"", "package")
+-/* httputil */ //@item(httputil, "httputil", "\"net/http/httputil\"", "package")
+-
+-/* ring.Ring */ //@item(ringring, "Ring", "(from \"container/ring\")", "var")
+-
+-/* signature.Foo */ //@item(signaturefoo, "Foo", "func (from \"unimported.test/signature\")", "func")
+-
+-/* context.Background */ //@item(contextBackground, "Background", "func (from \"context\")", "func")
+-
+-// Now that we no longer type-check imported completions,
+-// we don't expect the context.Background().Err method (see golang/go#58663).
+-/* context.Background().Err */ //@item(contextBackgroundErr, "Background().Err", "func (from \"context\")", "method")
+-
+--- unimported/unimported_cand_type.go --
+-package unimported
+-
+-import (
+-	_ "context"
+-
+-	"unimported.test/baz"
+-)
+-
+-func _() {
+-	foo.StructFoo{} //@item(litFooStructFoo, "foo.StructFoo{}", "struct{...}", "struct")
+-
+-	// We get the literal completion for "foo.StructFoo{}" even though we haven't
+-	// imported "foo" yet.
+-	baz.FooStruct = f //@snippet(" //", litFooStructFoo, "foo.StructFoo{$0\\}")
+-}
+-
+--- unimported/x_test.go --
+-package unimported_test
+-
+-import (
+-	"testing"
+-)
+-
+-func TestSomething(t *testing.T) {
+-	_ = unimported.TestExport //@complete("TestExport", testexport)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/definition/cgo.txt b/gopls/internal/regtest/marker/testdata/definition/cgo.txt
+--- a/gopls/internal/regtest/marker/testdata/definition/cgo.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/definition/cgo.txt	1970-01-01 08:00:00
+@@ -1,62 +0,0 @@
+-This test is ported from the old marker tests.
+-It tests hover and definition for cgo declarations.
+-
+--- flags --
+--cgo
+-
+--- go.mod --
+-module cgo.test
+-
+-go 1.18
+-
+--- cgo/cgo.go --
+-package cgo
+-
+-/*
+-#include <stdio.h>
+-#include <stdlib.h>
+-
+-void myprint(char* s) {
+-	printf("%s\n", s);
+-}
+-*/
+-import "C"
+-
+-import (
+-	"fmt"
+-	"unsafe"
+-)
+-
+-func Example() { //@loc(cgoexample, "Example"), item(cgoexampleItem, "Example", "func()", "func")
+-	fmt.Println()
+-	cs := C.CString("Hello from stdio\n")
+-	C.myprint(cs)
+-	C.free(unsafe.Pointer(cs))
+-}
+-
+-func _() {
+-	Example() //@hover("ample", "Example", hoverExample), def("ample", cgoexample), complete("ample", cgoexampleItem)
+-}
+-
+--- @hoverExample/hover.md --
+-```go
+-func Example()
+-```
+-
+-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/cgo.test/cgo#Example)
+--- usecgo/usecgo.go --
+-package cgoimport
+-
+-import (
+-	"cgo.test/cgo"
+-)
+-
+-func _() {
+-	cgo.Example() //@hover("ample", "Example", hoverImportedExample), def("ample", cgoexample), complete("ample", cgoexampleItem)
+-}
+--- @hoverImportedExample/hover.md --
+-```go
+-func cgo.Example()
+-```
+-
+-[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/cgo.test/cgo#Example)
 diff -urN a/gopls/internal/regtest/marker/testdata/definition/embed.txt b/gopls/internal/regtest/marker/testdata/definition/embed.txt
 --- a/gopls/internal/regtest/marker/testdata/definition/embed.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/definition/embed.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/definition/embed.txt	1970-01-01 08:00:00
 @@ -1,254 +0,0 @@
 -This test checks definition and hover operations over embedded fields and methods.
 -
@@ -113108,7 +122366,7 @@
 -@loc(aAlias, "aAlias")
 diff -urN a/gopls/internal/regtest/marker/testdata/definition/import.txt b/gopls/internal/regtest/marker/testdata/definition/import.txt
 --- a/gopls/internal/regtest/marker/testdata/definition/import.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/definition/import.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/definition/import.txt	1970-01-01 08:00:00
 @@ -1,52 +0,0 @@
 -This test checks definition and hover over imports.
 --- go.mod --
@@ -113164,7 +122422,7 @@
 -[`myFoo` on pkg.go.dev](https://pkg.go.dev/mod.com/foo)
 diff -urN a/gopls/internal/regtest/marker/testdata/definition/misc.txt b/gopls/internal/regtest/marker/testdata/definition/misc.txt
 --- a/gopls/internal/regtest/marker/testdata/definition/misc.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/definition/misc.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/definition/misc.txt	1970-01-01 08:00:00
 @@ -1,230 +0,0 @@
 -This test exercises miscellaneous definition and hover requests.
 --- go.mod --
@@ -113396,27 +122654,1232 @@
 -```
 -
 -z is a variable too.
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/addgowork.txt b/gopls/internal/regtest/marker/testdata/diagnostics/addgowork.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/addgowork.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/addgowork.txt	1970-01-01 08:00:00
+@@ -1,50 +0,0 @@
+-This test demonstrates diagnostics for adding a go.work file.
+-
+-Quick-fixes change files on disk, so are tested by regtests.
+-
+-TODO(rfindley): improve the "cannot find package" import errors.
+-
+--- skip --
+-Skipping due to go.dev/issue/60584#issuecomment-1622238115.
+-There appears to be a real race in the critical error logic causing this test
+-to flake with high frequency.
+-
+--- flags --
+--min_go=go1.18
+-
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main //@diag("main", re"add a go.work file")
+-
+-import "mod.com/a/lib" //@diag("\"mod.com", re"cannot find package")
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- a/lib/lib.go --
+-package lib //@diag("lib", re"add a go.work file")
+-
+-const C = "b"
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main //@diag("main", re"add a go.work file")
+-
+-import "mod.com/b/lib" //@diag("\"mod.com", re"cannot find package")
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- b/lib/lib.go --
+-package lib //@diag("lib", re"add a go.work file")
+-
+-const C = "b"
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/analyzers.txt b/gopls/internal/regtest/marker/testdata/diagnostics/analyzers.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/analyzers.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/analyzers.txt	1970-01-01 08:00:00
+@@ -1,51 +0,0 @@
+-Test of warning diagnostics from various analyzers:
+-copylocks, printf, slog, tests, and timeformat.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- flags --
+--min_go=go1.21
+-
+--- bad_test.go --
+-package analyzer
+-
+-import (
+-	"fmt"
+-	"log/slog"
+-	"sync"
+-	"testing"
+-	"time"
+-)
+-
+-// copylocks
+-func _() {
+-	var x sync.Mutex
+-	_ = x //@diag("x", re"assignment copies lock value to _: sync.Mutex")
+-}
+-
+-// printf
+-func _() {
+-	printfWrapper("%s") //@diag(re`printfWrapper\(.*\)`, re"example.com.printfWrapper format %s reads arg #1, but call has 0 args")
+-}
+-
+-func printfWrapper(format string, args ...interface{}) {
+-	fmt.Printf(format, args...)
+-}
+-
+-// slog
+-func _() {
+-	slog.Info("msg", 1) //@diag("1", re`slog.Info arg "1" should be a string or a slog.Attr`)
+-}
+-
+-// tests
+-func Testbad(t *testing.T) { //@diag("", re"Testbad has malformed name: first letter after 'Test' must not be lowercase")
+-}
+-
+-// timeformat
+-func _() {
+-	now := time.Now()
+-	fmt.Println(now.Format("2006-02-01")) //@diag("2006-02-01", re"2006-02-01 should be 2006-01-02")
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/excludedfile.txt b/gopls/internal/regtest/marker/testdata/diagnostics/excludedfile.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/excludedfile.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/excludedfile.txt	1970-01-01 08:00:00
+@@ -1,38 +0,0 @@
+-This test demonstrates diagnostics for various forms of file exclusion.
+-
+-Skip on plan9, an arbitrary GOOS, so that we can exercise GOOS exclusions
+-resulting from file suffixes.
+-
+--- flags --
+--min_go=go1.18
+--skip_goos=plan9
+-
+--- go.work --
+-go 1.21
+-
+-use (
+-	./a
+-)
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/a.go --
+-package a
+-
+--- a/a_plan9.go --
+-package a //@diag(re"package (a)", re"excluded due to its GOOS/GOARCH")
+-
+--- a/a_ignored.go --
+-//go:build skip
+-package a //@diag(re"package (a)", re"excluded due to its build tags")
+-
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/b.go --
+-package b //@diag(re"package (b)", re"add this module to your go.work")
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/generated.txt b/gopls/internal/regtest/marker/testdata/diagnostics/generated.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/generated.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/generated.txt	1970-01-01 08:00:00
+@@ -1,21 +0,0 @@
+-Test of "undeclared" diagnostic in generated code.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- generated.go --
+-package generated
+-
+-// Code generated by generator.go. DO NOT EDIT.
+-
+-func _() {
+-	var y int //@diag("y", re"y declared (and|but) not used")
+-}
+-
+--- generator.go --
+-package generated
+-
+-func _() {
+-	var x int //@diag("x", re"x declared (and|but) not used")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/issue56943.txt b/gopls/internal/regtest/marker/testdata/diagnostics/issue56943.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/issue56943.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/issue56943.txt	1970-01-01 08:00:00
+@@ -1,22 +0,0 @@
+-This test verifies that we produce diagnostics related to mismatching
+-unexported interface methods in non-workspace packages.
+-
+-Previously, we would fail to produce a diagnostic because we trimmed the AST.
+-See golang/go#56943.
+--- main.go --
+-package main
+-
+-import (
+-	"go/ast"
+-	"go/token"
+-)
+-
+-func main() {
+-	var a int               //@diag(re"(a) int", re"a declared.*not used")
+-	var _ ast.Expr = node{} //@diag("node{}", re"missing.*exprNode")
+-}
+-
+-type node struct{}
+-
+-func (node) Pos() token.Pos { return 0 }
+-func (node) End() token.Pos { return 0 }
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/issue59005.txt b/gopls/internal/regtest/marker/testdata/diagnostics/issue59005.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/issue59005.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/issue59005.txt	1970-01-01 08:00:00
+@@ -1,20 +0,0 @@
+-This test verifies that we don't drop type checking errors on the floor when we
+-fail to compute positions for their related errors.
+-
+--- go.mod --
+-module play.ground
+-
+--- p.go --
+-package p
+-
+-import (
+-	. "play.ground/foo"
+-)
+-
+-const C = 1 //@diag("C", re"C already declared through dot-import")
+-var _ = C
+-
+--- foo/foo.go --
+-package foo
+-
+-const C = 2
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/issue60544.txt b/gopls/internal/regtest/marker/testdata/diagnostics/issue60544.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/issue60544.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/issue60544.txt	1970-01-01 08:00:00
+@@ -1,13 +0,0 @@
+-This test exercises a crash due to treatment of "comparable" in methodset
+-calculation (golang/go#60544).
+-
+--min_go is 1.19 as the error message changed at this Go version.
+--- flags --
+--min_go=go1.19
+-
+--- main.go --
+-package main
+-
+-type X struct{}
+-
+-func (X) test(x comparable) {} //@diag("comparable", re"outside a type constraint")
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/issue60605.txt b/gopls/internal/regtest/marker/testdata/diagnostics/issue60605.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/issue60605.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/issue60605.txt	1970-01-01 08:00:00
+@@ -1,12 +0,0 @@
+-This test verifies that we can export constants with unknown kind.
+-Previously, the exporter would panic while attempting to convert such constants
+-to their target type (float64, in this case).
+-
+--- go.mod --
+-module mod.txt/p
+-
+-go 1.20
+--- p.go --
+-package p
+-
+-const EPSILON float64 = 1e- //@diag(re"1e-()", re"exponent has no digits")
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/parseerr.txt b/gopls/internal/regtest/marker/testdata/diagnostics/parseerr.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/parseerr.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/parseerr.txt	1970-01-01 08:00:00
+@@ -1,27 +0,0 @@
+-
+-This test exercises diagnostics produced for syntax errors.
+-
+-Because parser error recovery can be quite lossy, diagnostics
+-for type errors are suppressed in files with syntax errors;
+-see issue #59888. But diagnostics are reported for type errors
+-in well-formed files of the same package.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- bad.go --
+-package p
+-
+-func f() {
+-	append("") // no diagnostic for type error in file containing syntax error
+-}
+-
+-func .() {} //@diag(re"func ().", re"expected 'IDENT', found '.'")
+-
+--- good.go --
+-package p
+-
+-func g() {
+-	append("") //@diag(re`""`, re"a slice")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/rundespiteerrors.txt b/gopls/internal/regtest/marker/testdata/diagnostics/rundespiteerrors.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/rundespiteerrors.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/rundespiteerrors.txt	1970-01-01 08:00:00
+@@ -1,27 +0,0 @@
+-This test verifies that analyzers without RunDespiteErrors are not
+-executed on a package containing type errors (see issue #54762).
+-
+-We require go1.18 because the range of the `1 + ""` go/types error
+-changed then, and the new @diag marker is quite particular.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- flags --
+--min_go=go1.18
+-
+--- a.go --
+-package a
+-
+-func _() {
+-	// A type error.
+-	_ = 1 + "" //@diag(`1 + ""`, re"mismatched types|cannot convert")
+-
+-	// A violation of an analyzer for which RunDespiteErrors=false:
+-	// no (simplifyrange, warning) diagnostic is produced; the diag
+-	// comment is merely illustrative.
+-	for _ = range "" { //diag("for _", "simplify range expression", )
+-
+-	}
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/typeerr.txt b/gopls/internal/regtest/marker/testdata/diagnostics/typeerr.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/typeerr.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/typeerr.txt	1970-01-01 08:00:00
+@@ -1,33 +0,0 @@
+-
+-This test exercises diagnostics produced for type errors
+-in the absence of syntax errors.
+-
+-The type error was chosen to exercise the 'nonewvars' type-error analyzer.
+-(The 'undeclaredname' analyzer depends on the text of the go/types
+-"undeclared name" error, which changed in go1.20.)
+-
+-The append() type error was also carefully chosen to have text and
+-position that are invariant across all versions of Go run by the builders.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- typeerr.go --
+-package a
+-
+-func f(x int) {
+-	append("") //@diag(re`""`, re"a slice")
+-
+-	x := 123 //@diag(re"x := 123", re"no new variables"), suggestedfix(re"():", re"no new variables", "quickfix", fix)
+-}
+-
+--- @fix/typeerr.go --
+-package a
+-
+-func f(x int) {
+-	append("") //@diag(re`""`, re"a slice")
+-
+-	x = 123 //@diag(re"x := 123", re"no new variables"), suggestedfix(re"():", re"no new variables", "quickfix", fix)
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/useinternal.txt b/gopls/internal/regtest/marker/testdata/diagnostics/useinternal.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/useinternal.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/useinternal.txt	1970-01-01 08:00:00
+@@ -1,21 +0,0 @@
+-This test checks a diagnostic for invalid use of internal packages.
+-
+-This list error changed in Go 1.21.
+-
+--- flags --
+--min_go=go1.21
+-
+--- go.mod --
+-module bad.test
+-
+-go 1.18
+-
+--- assign/internal/secret/secret.go --
+-package secret
+-
+-func Hello() {}
+-
+--- bad/bad.go --
+-package bad
+-
+-import _ "bad.test/assign/internal/secret" //@diag("\"bad.test/assign/internal/secret\"", re"could not import bad.test/assign/internal/secret \\(invalid use of internal package \"bad.test/assign/internal/secret\"\\)"),diag("_", re"use of internal package bad.test/assign/internal/secret not allowed")
+diff -urN a/gopls/internal/regtest/marker/testdata/diagnostics/usemodule.txt b/gopls/internal/regtest/marker/testdata/diagnostics/usemodule.txt
+--- a/gopls/internal/regtest/marker/testdata/diagnostics/usemodule.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/diagnostics/usemodule.txt	1970-01-01 08:00:00
+@@ -1,51 +0,0 @@
+-This test demonstrates diagnostics for a module that is missing from the
+-go.work file.
+-
+-Quick-fixes change files on disk, so are tested by regtests.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.work --
+-go 1.21
+-
+-use (
+-	./a
+-)
+-
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main
+-
+-import "mod.com/a/lib"
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- a/lib/lib.go --
+-package lib
+-
+-const C = "b"
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main //@diag("main", re"add this module to your go.work")
+-
+-import "mod.com/b/lib" //@diag("\"mod.com", re"not included in a workspace module")
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- b/lib/lib.go --
+-package lib //@diag("lib", re"add this module to your go.work")
+-
+-const C = "b"
+diff -urN a/gopls/internal/regtest/marker/testdata/fixedbugs/issue59318.txt b/gopls/internal/regtest/marker/testdata/fixedbugs/issue59318.txt
+--- a/gopls/internal/regtest/marker/testdata/fixedbugs/issue59318.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/fixedbugs/issue59318.txt	1970-01-01 08:00:00
+@@ -1,22 +0,0 @@
+-This test verifies that we can load multiple orphaned files as
+-command-line-arguments packages.
+-
+-Previously, we would load only one because go/packages returns at most one
+-command-line-arguments package per query.
+-
+--- a/main.go --
+-package main
+-
+-func main() {
+-	var a int //@diag(re"var (a)", re"not used")
+-}
+--- b/main.go --
+-package main
+-
+-func main() {
+-	var b int //@diag(re"var (b)", re"not used")
+-}
+--- c/go.mod --
+-module c.com // The existence of this module avoids a workspace error.
+-
+-go 1.18
+diff -urN a/gopls/internal/regtest/marker/testdata/fixedbugs/issue59944.txt b/gopls/internal/regtest/marker/testdata/fixedbugs/issue59944.txt
+--- a/gopls/internal/regtest/marker/testdata/fixedbugs/issue59944.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/fixedbugs/issue59944.txt	1970-01-01 08:00:00
+@@ -1,33 +0,0 @@
+-This test verifies that gopls does not panic when encountering the go/types
+-bug described in golang/go#59944: the Bindingf function is not included in
+-the methodset of its receiver type.
+-
+-Adapted from the code in question from the issue.
+-
+--- flags --
+--cgo
+-
+--- go.mod --
+-module example.com
+-
+-go 1.12
+-
+--- cgo.go --
+-package x
+-
+-import "fmt"
+-
+-/*
+-struct layout {
+-	int field;
+-};
+-*/
+-import "C"
+-
+-type Layout = C.struct_layout
+-
+-// Bindingf is a printf wrapper. This was necessary to trigger the panic in
+-// objectpath while encoding facts.
+-func (l *Layout) Bindingf(format string, args ...interface{}) {
+-	fmt.Printf(format, args...)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/foldingrange/a.txt b/gopls/internal/regtest/marker/testdata/foldingrange/a.txt
+--- a/gopls/internal/regtest/marker/testdata/foldingrange/a.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/foldingrange/a.txt	1970-01-01 08:00:00
+@@ -1,154 +0,0 @@
+-This test checks basic behavior of textDocument/foldingRange.
+-
+--- a.go --
+-package folding //@foldingrange(raw)
+-
+-import (
+-	"fmt"
+-	_ "log"
+-)
+-
+-import _ "os"
+-
+-// bar is a function.
+-// With a multiline doc comment.
+-func bar() string {
+-	/* This is a single line comment */
+-	switch {
+-	case true:
+-		if true {
+-			fmt.Println("true")
+-		} else {
+-			fmt.Println("false")
+-		}
+-	case false:
+-		fmt.Println("false")
+-	default:
+-		fmt.Println("default")
+-	}
+-	/* This is a multiline
+-	block
+-	comment */
+-
+-	/* This is a multiline
+-	block
+-	comment */
+-	// Followed by another comment.
+-	_ = []int{
+-		1,
+-		2,
+-		3,
+-	}
+-	_ = [2]string{"d",
+-		"e",
+-	}
+-	_ = map[string]int{
+-		"a": 1,
+-		"b": 2,
+-		"c": 3,
+-	}
+-	type T struct {
+-		f string
+-		g int
+-		h string
+-	}
+-	_ = T{
+-		f: "j",
+-		g: 4,
+-		h: "i",
+-	}
+-	x, y := make(chan bool), make(chan bool)
+-	select {
+-	case val := <-x:
+-		if val {
+-			fmt.Println("true from x")
+-		} else {
+-			fmt.Println("false from x")
+-		}
+-	case <-y:
+-		fmt.Println("y")
+-	default:
+-		fmt.Println("default")
+-	}
+-	// This is a multiline comment
+-	// that is not a doc comment.
+-	return `
+-this string
+-is not indented`
+-}
+--- @raw --
+-package folding //@foldingrange(raw)
+-
+-import (<0 kind="imports">
+-	"fmt"
+-	_ "log"
+-</0>)
+-
+-import _ "os"
+-
+-// bar is a function.<1 kind="comment">
+-// With a multiline doc comment.</1>
+-func bar(<2 kind=""></2>) string {<3 kind="">
+-	/* This is a single line comment */
+-	switch {<4 kind="">
+-	case true:<5 kind="">
+-		if true {<6 kind="">
+-			fmt.Println(<7 kind="">"true"</7>)
+-		</6>} else {<8 kind="">
+-			fmt.Println(<9 kind="">"false"</9>)
+-		</8>}</5>
+-	case false:<10 kind="">
+-		fmt.Println(<11 kind="">"false"</11>)</10>
+-	default:<12 kind="">
+-		fmt.Println(<13 kind="">"default"</13>)</12>
+-	</4>}
+-	/* This is a multiline<14 kind="comment">
+-	block
+-	comment */</14>
+-
+-	/* This is a multiline<15 kind="comment">
+-	block
+-	comment */
+-	// Followed by another comment.</15>
+-	_ = []int{<16 kind="">
+-		1,
+-		2,
+-		3,
+-	</16>}
+-	_ = [2]string{<17 kind="">"d",
+-		"e",
+-	</17>}
+-	_ = map[string]int{<18 kind="">
+-		"a": 1,
+-		"b": 2,
+-		"c": 3,
+-	</18>}
+-	type T struct {<19 kind="">
+-		f string
+-		g int
+-		h string
+-	</19>}
+-	_ = T{<20 kind="">
+-		f: "j",
+-		g: 4,
+-		h: "i",
+-	</20>}
+-	x, y := make(<21 kind="">chan bool</21>), make(<22 kind="">chan bool</22>)
+-	select {<23 kind="">
+-	case val := <-x:<24 kind="">
+-		if val {<25 kind="">
+-			fmt.Println(<26 kind="">"true from x"</26>)
+-		</25>} else {<27 kind="">
+-			fmt.Println(<28 kind="">"false from x"</28>)
+-		</27>}</24>
+-	case <-y:<29 kind="">
+-		fmt.Println(<30 kind="">"y"</30>)</29>
+-	default:<31 kind="">
+-		fmt.Println(<32 kind="">"default"</32>)</31>
+-	</23>}
+-	// This is a multiline comment<33 kind="comment">
+-	// that is not a doc comment.</33>
+-	return <34 kind="">`
+-this string
+-is not indented`</34>
+-</3>}
+diff -urN a/gopls/internal/regtest/marker/testdata/foldingrange/a_lineonly.txt b/gopls/internal/regtest/marker/testdata/foldingrange/a_lineonly.txt
+--- a/gopls/internal/regtest/marker/testdata/foldingrange/a_lineonly.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/foldingrange/a_lineonly.txt	1970-01-01 08:00:00
+@@ -1,163 +0,0 @@
+-This test checks basic behavior of the textDocument/foldingRange, when the
+-editor only supports line folding.
+-
+--- capabilities.json --
+-{
+-	"textDocument": {
+-		"foldingRange": {
+-			"lineFoldingOnly": true
+-		}
+-	}
+-}
+--- a.go --
+-package folding //@foldingrange(raw)
+-
+-import (
+-	"fmt"
+-	_ "log"
+-)
+-
+-import _ "os"
+-
+-// bar is a function.
+-// With a multiline doc comment.
+-func bar() string {
+-	/* This is a single line comment */
+-	switch {
+-	case true:
+-		if true {
+-			fmt.Println("true")
+-		} else {
+-			fmt.Println("false")
+-		}
+-	case false:
+-		fmt.Println("false")
+-	default:
+-		fmt.Println("default")
+-	}
+-	/* This is a multiline
+-	block
+-	comment */
+-
+-	/* This is a multiline
+-	block
+-	comment */
+-	// Followed by another comment.
+-	_ = []int{
+-		1,
+-		2,
+-		3,
+-	}
+-	_ = [2]string{"d",
+-		"e",
+-	}
+-	_ = map[string]int{
+-		"a": 1,
+-		"b": 2,
+-		"c": 3,
+-	}
+-	type T struct {
+-		f string
+-		g int
+-		h string
+-	}
+-	_ = T{
+-		f: "j",
+-		g: 4,
+-		h: "i",
+-	}
+-	x, y := make(chan bool), make(chan bool)
+-	select {
+-	case val := <-x:
+-		if val {
+-			fmt.Println("true from x")
+-		} else {
+-			fmt.Println("false from x")
+-		}
+-	case <-y:
+-		fmt.Println("y")
+-	default:
+-		fmt.Println("default")
+-	}
+-	// This is a multiline comment
+-	// that is not a doc comment.
+-	return `
+-this string
+-is not indented`
+-}
+--- @raw --
+-package folding //@foldingrange(raw)
+-
+-import (<0 kind="imports">
+-	"fmt"
+-	_ "log"</0>
+-)
+-
+-import _ "os"
+-
+-// bar is a function.<1 kind="comment">
+-// With a multiline doc comment.</1>
+-func bar() string {<2 kind="">
+-	/* This is a single line comment */
+-	switch {<3 kind="">
+-	case true:<4 kind="">
+-		if true {<5 kind="">
+-			fmt.Println("true")</5>
+-		} else {<6 kind="">
+-			fmt.Println("false")</6>
+-		}</4>
+-	case false:<7 kind="">
+-		fmt.Println("false")</7>
+-	default:<8 kind="">
+-		fmt.Println("default")</3></8>
+-	}
+-	/* This is a multiline<9 kind="comment">
+-	block
+-	comment */</9>
+-
+-	/* This is a multiline<10 kind="comment">
+-	block
+-	comment */
+-	// Followed by another comment.</10>
+-	_ = []int{<11 kind="">
+-		1,
+-		2,
+-		3</11>,
+-	}
+-	_ = [2]string{"d",
+-		"e",
+-	}
+-	_ = map[string]int{<12 kind="">
+-		"a": 1,
+-		"b": 2,
+-		"c": 3</12>,
+-	}
+-	type T struct {<13 kind="">
+-		f string
+-		g int
+-		h string</13>
+-	}
+-	_ = T{<14 kind="">
+-		f: "j",
+-		g: 4,
+-		h: "i"</14>,
+-	}
+-	x, y := make(chan bool), make(chan bool)
+-	select {<15 kind="">
+-	case val := <-x:<16 kind="">
+-		if val {<17 kind="">
+-			fmt.Println("true from x")</17>
+-		} else {<18 kind="">
+-			fmt.Println("false from x")</18>
+-		}</16>
+-	case <-y:<19 kind="">
+-		fmt.Println("y")</19>
+-	default:<20 kind="">
+-		fmt.Println("default")</15></20>
+-	}
+-	// This is a multiline comment<21 kind="comment">
+-	// that is not a doc comment.</21>
+-	return <22 kind="">`
+-this string
+-is not indented`</2></22>
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/foldingrange/bad.txt b/gopls/internal/regtest/marker/testdata/foldingrange/bad.txt
+--- a/gopls/internal/regtest/marker/testdata/foldingrange/bad.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/foldingrange/bad.txt	1970-01-01 08:00:00
+@@ -1,41 +0,0 @@
+-This test verifies behavior of textDocument/foldingRange in the presence of
+-unformatted syntax.
+-
+--- a.go --
+-package folding //@foldingrange(raw)
+-
+-import ( "fmt"
+-	_ "log"
+-)
+-
+-import ( 
+-	_ "os" )
+-	
+-// badBar is a function.
+-func badBar() string { x := true
+-	if x { 
+-		// This is the only foldable thing in this file when lineFoldingOnly
+-		fmt.Println("true")
+-	} else {
+-		fmt.Println("false") }
+-	return ""
+-}
+--- @raw --
+-package folding //@foldingrange(raw)
+-
+-import (<0 kind="imports"> "fmt"
+-	_ "log"
+-</0>)
+-
+-import (<1 kind="imports"> 
+-	_ "os" </1>)
+-	
+-// badBar is a function.
+-func badBar(<2 kind=""></2>) string {<3 kind=""> x := true
+-	if x {<4 kind=""> 
+-		// This is the only foldable thing in this file when lineFoldingOnly
+-		fmt.Println(<5 kind="">"true"</5>)
+-	</4>} else {<6 kind="">
+-		fmt.Println(<7 kind="">"false"</7>) </6>}
+-	return ""
+-</3>}
+diff -urN a/gopls/internal/regtest/marker/testdata/format/format.txt b/gopls/internal/regtest/marker/testdata/format/format.txt
+--- a/gopls/internal/regtest/marker/testdata/format/format.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/format/format.txt	1970-01-01 08:00:00
+@@ -1,80 +0,0 @@
+-This test checks basic behavior of textDocument/formatting requests.
+-
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+--- good.go --
+-package format //@format(good)
+-
+-import (
+-	"log"
+-)
+-
+-func goodbye() {
+-	log.Printf("byeeeee")
+-}
+-
+--- @good --
+-package format //@format(good)
+-
+-import (
+-	"log"
+-)
+-
+-func goodbye() {
+-	log.Printf("byeeeee")
+-}
+--- bad.go --
+-package format //@format(bad)
+-
+-import (
+-	"runtime"
+-	"fmt"
+-	"log"
+-)
+-
+-func hello() {
+-
+-
+-
+-
+-	var x int //@diag("x", re"x declared (and|but) not used")
+-}
+-
+-func hi() {
+-	runtime.GOROOT()
+-	fmt.Printf("")
+-
+-	log.Printf("")
+-}
+--- @bad --
+-package format //@format(bad)
+-
+-import (
+-	"fmt"
+-	"log"
+-	"runtime"
+-)
+-
+-func hello() {
+-
+-	var x int //@diag("x", re"x declared (and|but) not used")
+-}
+-
+-func hi() {
+-	runtime.GOROOT()
+-	fmt.Printf("")
+-
+-	log.Printf("")
+-}
+--- newline.go --
+-package format //@format(newline)
+-func _() {}
+--- @newline --
+-package format //@format(newline)
+-func _()       {}
+--- oneline.go --
+-package format //@format(oneline)
+--- @oneline --
+-package format //@format(oneline)
+diff -urN a/gopls/internal/regtest/marker/testdata/format/issue59554.txt b/gopls/internal/regtest/marker/testdata/format/issue59554.txt
+--- a/gopls/internal/regtest/marker/testdata/format/issue59554.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/format/issue59554.txt	1970-01-01 08:00:00
+@@ -1,33 +0,0 @@
+-Test case for golang/go#59554: data corruption on formatting due to line
+-directives.
+-
+-Note that gofumpt is needed for this test case, as it reformats var decls into
+-short var decls.
+-
+-Note that gofumpt requires Go 1.18.
+-
+--- flags --
+--min_go=go1.18
+-
+--- settings.json --
+-{
+-	"formatting.gofumpt": true
+-}
+--- main.go --
+-package main //@format(main)
+-
+-func Match(data []byte) int {
+-//line :1
+-	var idx = ^uint(0)
+-	_ = idx
+-	return -1
+-}
+--- @main --
+-package main //@format(main)
+-
+-func Match(data []byte) int {
+-//line :1
+-	idx := ^uint(0)
+-	_ = idx
+-	return -1
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/format/noparse.txt b/gopls/internal/regtest/marker/testdata/format/noparse.txt
+--- a/gopls/internal/regtest/marker/testdata/format/noparse.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/format/noparse.txt	1970-01-01 08:00:00
+@@ -1,27 +0,0 @@
+-This test checks that formatting does not run on code that has parse errors.
+-
+--- parse.go --
+-package noparse_format //@format(parse)
+-
+-func _() {
+-f() //@diag("f", re"(undefined|undeclared name): f")
+-}
+--- @parse --
+-package noparse_format //@format(parse)
+-
+-func _() {
+-	f() //@diag("f", re"(undefined|undeclared name): f")
+-}
+--- noparse.go --
+-package noparse_format //@format(noparse)
+-
+-// The nonewvars expectation asserts that the go/analysis framework ran.
+-
+-func what() {
+-	var hi func()
+-	if {		hi() //@diag(re"(){", re".*missing.*")
+-	}
+-	hi := nil
+-}
+--- @noparse --
+-7:5: missing condition in if statement
+diff -urN a/gopls/internal/regtest/marker/testdata/highlight/highlight.txt b/gopls/internal/regtest/marker/testdata/highlight/highlight.txt
+--- a/gopls/internal/regtest/marker/testdata/highlight/highlight.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/highlight/highlight.txt	1970-01-01 08:00:00
+@@ -1,158 +0,0 @@
+-This test checks basic functionality of the textDocument/highlight request.
+-
+--- highlights.go --
+-package highlights
+-
+-import (
+-	"fmt"         //@loc(fmtImp, "\"fmt\""),highlight(fmtImp, fmtImp, fmt1, fmt2, fmt3, fmt4)
+-	h2 "net/http" //@loc(hImp, "h2"),highlight(hImp, hImp, hUse)
+-	"sort"
+-)
+-
+-type F struct{ bar int } //@loc(barDeclaration, "bar"),highlight(barDeclaration, barDeclaration, bar1, bar2, bar3)
+-
+-func _() F {
+-	return F{
+-		bar: 123, //@loc(bar1, "bar"),highlight(bar1, barDeclaration, bar1, bar2, bar3)
+-	}
+-}
+-
+-var foo = F{bar: 52} //@loc(fooDeclaration, "foo"),loc(bar2, "bar"),highlight(fooDeclaration, fooDeclaration, fooUse),highlight(bar2, barDeclaration, bar1, bar2, bar3)
+-
+-func Print() { //@loc(printFunc, "Print"),highlight(printFunc, printFunc, printTest)
+-	_ = h2.Client{} //@loc(hUse, "h2"),highlight(hUse, hImp, hUse)
+-
+-	fmt.Println(foo) //@loc(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse),loc(fmt1, "fmt"),highlight(fmt1, fmtImp, fmt1, fmt2, fmt3, fmt4)
+-	fmt.Print("yo")  //@loc(printSep, "Print"),highlight(printSep, printSep, print1, print2),loc(fmt2, "fmt"),highlight(fmt2, fmtImp, fmt1, fmt2, fmt3, fmt4)
+-}
+-
+-func (x *F) Inc() { //@loc(xRightDecl, "x"),loc(xLeftDecl, " *"),highlight(xRightDecl, xRightDecl, xUse),highlight(xLeftDecl, xRightDecl, xUse)
+-	x.bar++ //@loc(xUse, "x"),loc(bar3, "bar"),highlight(xUse, xRightDecl, xUse),highlight(bar3, barDeclaration, bar1, bar2, bar3)
+-}
+-
+-func testFunctions() {
+-	fmt.Print("main start") //@loc(print1, "Print"),highlight(print1, printSep, print1, print2),loc(fmt3, "fmt"),highlight(fmt3, fmtImp, fmt1, fmt2, fmt3, fmt4)
+-	fmt.Print("ok")         //@loc(print2, "Print"),highlight(print2, printSep, print1, print2),loc(fmt4, "fmt"),highlight(fmt4, fmtImp, fmt1, fmt2, fmt3, fmt4)
+-	Print()                 //@loc(printTest, "Print"),highlight(printTest, printFunc, printTest)
+-}
+-
+-// DocumentHighlight is undefined, so its uses below are type errors.
+-// Nevertheless, document highlighting should still work.
+-//@diag(doc1, re"undefined|undeclared"), diag(doc2, re"undefined|undeclared"), diag(doc3, re"undefined|undeclared")
+-
+-func toProtocolHighlight(rngs []int) []DocumentHighlight { //@loc(doc1, "DocumentHighlight"),loc(docRet1, "[]DocumentHighlight"),highlight(doc1, docRet1, doc1, doc2, doc3, result)
+-	result := make([]DocumentHighlight, 0, len(rngs)) //@loc(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3)
+-	for _, rng := range rngs {
+-		result = append(result, DocumentHighlight{ //@loc(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3)
+-			Range: rng,
+-		})
+-	}
+-	return result //@loc(result, "result")
+-}
+-
+-func testForLoops() {
+-	for i := 0; i < 10; i++ { //@loc(forDecl1, "for"),highlight(forDecl1, forDecl1, brk1, cont1)
+-		if i > 8 {
+-			break //@loc(brk1, "break"),highlight(brk1, forDecl1, brk1, cont1)
+-		}
+-		if i < 2 {
+-			for j := 1; j < 10; j++ { //@loc(forDecl2, "for"),highlight(forDecl2, forDecl2, cont2)
+-				if j < 3 {
+-					for k := 1; k < 10; k++ { //@loc(forDecl3, "for"),highlight(forDecl3, forDecl3, cont3)
+-						if k < 3 {
+-							continue //@loc(cont3, "continue"),highlight(cont3, forDecl3, cont3)
+-						}
+-					}
+-					continue //@loc(cont2, "continue"),highlight(cont2, forDecl2, cont2)
+-				}
+-			}
+-			continue //@loc(cont1, "continue"),highlight(cont1, forDecl1, brk1, cont1)
+-		}
+-	}
+-
+-	arr := []int{}
+-	for i := range arr { //@loc(forDecl4, "for"),highlight(forDecl4, forDecl4, brk4, cont4)
+-		if i > 8 {
+-			break //@loc(brk4, "break"),highlight(brk4, forDecl4, brk4, cont4)
+-		}
+-		if i < 4 {
+-			continue //@loc(cont4, "continue"),highlight(cont4, forDecl4, brk4, cont4)
+-		}
+-	}
+-
+-Outer:
+-	for i := 0; i < 10; i++ { //@loc(forDecl5, "for"),highlight(forDecl5, forDecl5, brk5, brk6, brk8)
+-		break //@loc(brk5, "break"),highlight(brk5, forDecl5, brk5, brk6, brk8)
+-		for { //@loc(forDecl6, "for"),highlight(forDecl6, forDecl6, cont5), diag("for", re"unreachable")
+-			if i == 1 {
+-				break Outer //@loc(brk6, "break Outer"),highlight(brk6, forDecl5, brk5, brk6, brk8)
+-			}
+-			switch i { //@loc(switch1, "switch"),highlight(switch1, switch1, brk7)
+-			case 5:
+-				break //@loc(brk7, "break"),highlight(brk7, switch1, brk7)
+-			case 6:
+-				continue //@loc(cont5, "continue"),highlight(cont5, forDecl6, cont5)
+-			case 7:
+-				break Outer //@loc(brk8, "break Outer"),highlight(brk8, forDecl5, brk5, brk6, brk8)
+-			}
+-		}
+-	}
+-}
+-
+-func testSwitch() {
+-	var i, j int
+-
+-L1:
+-	for { //@loc(forDecl7, "for"),highlight(forDecl7, forDecl7, brk10, cont6)
+-	L2:
+-		switch i { //@loc(switch2, "switch"),highlight(switch2, switch2, brk11, brk12, brk13)
+-		case 1:
+-			switch j { //@loc(switch3, "switch"),highlight(switch3, switch3, brk9)
+-			case 1:
+-				break //@loc(brk9, "break"),highlight(brk9, switch3, brk9)
+-			case 2:
+-				break L1 //@loc(brk10, "break L1"),highlight(brk10, forDecl7, brk10, cont6)
+-			case 3:
+-				break L2 //@loc(brk11, "break L2"),highlight(brk11, switch2, brk11, brk12, brk13)
+-			default:
+-				continue //@loc(cont6, "continue"),highlight(cont6, forDecl7, brk10, cont6)
+-			}
+-		case 2:
+-			break //@loc(brk12, "break"),highlight(brk12, switch2, brk11, brk12, brk13)
+-		default:
+-			break L2 //@loc(brk13, "break L2"),highlight(brk13, switch2, brk11, brk12, brk13)
+-		}
+-	}
+-}
+-
+-func testReturn() bool { //@loc(func1, "func"),loc(bool1, "bool"),highlight(func1, func1, fullRet11, fullRet12),highlight(bool1, bool1, false1, bool2, true1)
+-	if 1 < 2 {
+-		return false //@loc(ret11, "return"),loc(fullRet11, "return false"),loc(false1, "false"),highlight(ret11, func1, fullRet11, fullRet12)
+-	}
+-	candidates := []int{}
+-	sort.SliceStable(candidates, func(i, j int) bool { //@loc(func2, "func"),loc(bool2, "bool"),highlight(func2, func2, fullRet2)
+-		return candidates[i] > candidates[j] //@loc(ret2, "return"),loc(fullRet2, "return candidates[i] > candidates[j]"),highlight(ret2, func2, fullRet2)
+-	})
+-	return true //@loc(ret12, "return"),loc(fullRet12, "return true"),loc(true1, "true"),highlight(ret12, func1, fullRet11, fullRet12)
+-}
+-
+-func testReturnFields() float64 { //@loc(retVal1, "float64"),highlight(retVal1, retVal1, retVal11, retVal21)
+-	if 1 < 2 {
+-		return 20.1 //@loc(retVal11, "20.1"),highlight(retVal11, retVal1, retVal11, retVal21)
+-	}
+-	z := 4.3 //@loc(zDecl, "z")
+-	return z //@loc(retVal21, "z"),highlight(retVal21, retVal1, retVal11, zDecl, retVal21)
+-}
+-
+-func testReturnMultipleFields() (float32, string) { //@loc(retVal31, "float32"),loc(retVal32, "string"),highlight(retVal31, retVal31, retVal41, retVal51),highlight(retVal32, retVal32, retVal42, retVal52)
+-	y := "im a var" //@loc(yDecl, "y"),
+-	if 1 < 2 {
+-		return 20.1, y //@loc(retVal41, "20.1"),loc(retVal42, "y"),highlight(retVal41, retVal31, retVal41, retVal51),highlight(retVal42, retVal32, yDecl, retVal42, retVal52)
+-	}
+-	return 4.9, "test" //@loc(retVal51, "4.9"),loc(retVal52, "\"test\""),highlight(retVal51, retVal31, retVal41, retVal51),highlight(retVal52, retVal32, retVal42, retVal52)
+-}
+-
+-func testReturnFunc() int32 { //@loc(retCall, "int32")
+-	mulch := 1          //@loc(mulchDec, "mulch"),highlight(mulchDec, mulchDec, mulchRet)
+-	return int32(mulch) //@loc(mulchRet, "mulch"),loc(retFunc, "int32"),loc(retTotal, "int32(mulch)"),highlight(mulchRet, mulchDec, mulchRet),highlight(retFunc, retCall, retFunc, retTotal)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/highlight/issue60435.txt b/gopls/internal/regtest/marker/testdata/highlight/issue60435.txt
+--- a/gopls/internal/regtest/marker/testdata/highlight/issue60435.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/highlight/issue60435.txt	1970-01-01 08:00:00
+@@ -1,15 +0,0 @@
+-This is a regression test for issue 60435:
+-Highlighting "net/http" shouldn't have any effect
+-on an import path that contains it as a substring,
+-such as httptest.
+-
+--- highlights.go --
+-package highlights
+-
+-import (
+-	"net/http"          //@loc(httpImp, `"net/http"`)
+-	"net/http/httptest" //@loc(httptestImp, `"net/http/httptest"`)
+-)
+-
+-var _ = httptest.NewRequest
+-var _ = http.NewRequest //@loc(here, "http"), highlight(here, here, httpImp)
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/basiclit.txt b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/basiclit.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt	1970-01-01 00:00:00.000000000 +0000
-@@ -1,60 +0,0 @@
++++ b/gopls/internal/regtest/marker/testdata/hover/basiclit.txt	1970-01-01 08:00:00
+@@ -1,81 +0,0 @@
 -This test checks gopls behavior when hovering over basic literals.
 --- basiclit.go --
 -package basiclit
 -
 -func _() {
 -	_ = 'a' //@hover("'a'", "'a'", latinA)
--	_ = 0x61 //@hover("0x61", "0x61", latinA)
+-	_ = 0x61 //@hover("0x61", "0x61", latinAHex)
 -
 -	_ = '\u2211' //@hover("'\\u2211'", "'\\u2211'", summation)
--	_ = 0x2211 //@hover("0x2211", "0x2211", summation)
+-	_ = 0x2211 //@hover("0x2211", "0x2211", summationHex)
 -	_ = "foo \u2211 bar" //@hover("\\u2211", "\\u2211", summation)
 -
 -	_ = '\a' //@hover("'\\a'", "'\\a'", control)
 -	_ = "foo \a bar" //@hover("\\a", "\\a", control)
 -
 -	_ = '\U0001F30A' //@hover("'\\U0001F30A'", "'\\U0001F30A'", waterWave)
--	_ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWave)
+-	_ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWaveHex)
+-	_ = 0X0001F30A //@hover("0X0001F30A", "0X0001F30A", waterWaveHex)
 -	_ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "\\U0001F30A", waterWave)
 -
 -	_ = '\x7E' //@hover("'\\x7E'", "'\\x7E'", tilde)
@@ -113446,33 +123909,127 @@
 -	_ = 1.2 //@hover("1.2", _, _)
 -	_ = 1.2i //@hover("1.2i", _, _)
 -	_ = 0123 //@hover("0123", _, _)
--	_ = 0x1234567890 //@hover("0x1234567890", _, _)
+-	_ = 0b1001 //@hover("0b", "0b1001", binaryNumber)
+-	_ = 0B1001 //@hover("0B", "0B1001", binaryNumber)
+-	_ = 0o77 //@hover("0o", "0o77", octalNumber)
+-	_ = 0O77 //@hover("0O", "0O77", octalNumber)
+-	_ = 0x1234567890 //@hover("0x1234567890", "0x1234567890", hexNumber)
+-	_ = 0X1234567890 //@hover("0X1234567890", "0X1234567890", hexNumber)
+-	_ = 0x1000000000000000000 //@hover("0x1", "0x1000000000000000000", bigHex)
 -)
+--- @bigHex/hover.md --
+-4722366482869645213696
+--- @binaryNumber/hover.md --
+-9
 --- @control/hover.md --
 -U+0007, control
+--- @hexNumber/hover.md --
+-78187493520
 --- @latinA/hover.md --
 -'a', U+0061, LATIN SMALL LETTER A
+--- @latinAHex/hover.md --
+-97, 'a', U+0061, LATIN SMALL LETTER A
 --- @leftCurly/hover.md --
 -'{', U+007B, LEFT CURLY BRACKET
+--- @octalNumber/hover.md --
+-63
 --- @summation/hover.md --
 -'∑', U+2211, N-ARY SUMMATION
+--- @summationHex/hover.md --
+-8721, '∑', U+2211, N-ARY SUMMATION
 --- @tilde/hover.md --
 -'~', U+007E, TILDE
 --- @waterWave/hover.md --
 -'🌊', U+1F30A, WATER WAVE
+--- @waterWaveHex/hover.md --
+-127754, '🌊', U+1F30A, WATER WAVE
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/const.txt b/gopls/internal/regtest/marker/testdata/hover/const.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/const.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/const.txt	1970-01-01 00:00:00.000000000 +0000
-@@ -1,18 +0,0 @@
++++ b/gopls/internal/regtest/marker/testdata/hover/const.txt	1970-01-01 08:00:00
+@@ -1,157 +0,0 @@
 -This test checks hovering over constants.
+-
+--- flags --
+--min_go=go1.17
+-
 --- go.mod --
 -module mod.com
 -
--go 1.18
+-go 1.17
+-
 --- c.go --
 -package c
 -
+-import (
+-	"math"
+-	"time"
+-)
+-
 -const X = 0 //@hover("X", "X", bX)
+-
+-// dur is a constant of type time.Duration.
+-const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@hover("dur", "dur", dur)
+-
+-// MaxFloat32 is used in another package.
+-const MaxFloat32 = 0x1p127 * (1 + (1 - 0x1p-23))
+-
+-// Numbers.
+-func _() {
+-	const hex, bin = 0xe34e, 0b1001001
+-
+-	const (
+-		// no inline comment
+-		decimal = 153
+-
+-		numberWithUnderscore int64 = 10_000_000_000
+-		octal                      = 0o777
+-		expr                       = 2 << (0b111&0b101 - 2)
+-		boolean                    = (55 - 3) == (26 * 2)
+-	)
+-
+-	_ = decimal              //@hover("decimal", "decimal", decimalConst)
+-	_ = hex                  //@hover("hex", "hex", hexConst)
+-	_ = bin                  //@hover("bin", "bin", binConst)
+-	_ = numberWithUnderscore //@hover("numberWithUnderscore", "numberWithUnderscore", numberWithUnderscoreConst)
+-	_ = octal                //@hover("octal", "octal", octalConst)
+-	_ = expr                 //@hover("expr", "expr", exprConst)
+-	_ = boolean              //@hover("boolean", "boolean", boolConst)
+-
+-	const ln10 = 2.30258509299404568401799145468436420760110148862877297603332790
+-
+-	_ = ln10 //@hover("ln10", "ln10", ln10Const)
+-}
+-
+-// Iota.
+-func _() {
+-	const (
+-		a = 1 << iota
+-		b
+-	)
+-
+-	_ = a //@hover("a", "a", aIota)
+-	_ = b //@hover("b", "b", bIota)
+-}
+-
+-// Strings.
+-func _() {
+-	const (
+-		str     = "hello" + " " + "world"
+-		longStr = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eget ipsum non nunc
+-molestie mattis id quis augue. Mauris dictum tincidunt ipsum, in auctor arcu congue eu.
+-Morbi hendrerit fringilla libero commodo varius. Vestibulum in enim rutrum, rutrum tellus
+-aliquet, luctus enim. Nunc sem ex, consectetur id porta nec, placerat vel urna.`
+-	)
+-
+-	_ = str     //@hover("str", "str", strConst)
+-	_ = longStr //@hover("longStr", "longStr", longStrConst)
+-}
+-
+-// Constants from other packages.
+-func _() {
+-	_ = math.Log2E //@hover("Log2E", "Log2E", log2eConst)
+-}
+-
 --- @bX/hover.md --
 -```go
 -const X untyped int = 0
@@ -113482,10 +124039,75 @@
 -
 -
 -[`c.X` on pkg.go.dev](https://pkg.go.dev/mod.com#X)
+--- @dur/hover.md --
+-```go
+-const dur time.Duration = 15*time.Minute + 10*time.Second + 350*time.Millisecond // 15m10.35s
+-```
+-
+-dur is a constant of type time.Duration.
+--- @decimalConst/hover.md --
+-```go
+-const decimal untyped int = 153
+-```
+-
+-no inline comment
+--- @hexConst/hover.md --
+-```go
+-const hex untyped int = 0xe34e // 58190
+-```
+--- @binConst/hover.md --
+-```go
+-const bin untyped int = 0b1001001 // 73
+-```
+--- @numberWithUnderscoreConst/hover.md --
+-```go
+-const numberWithUnderscore int64 = 10_000_000_000 // 10000000000
+-```
+--- @octalConst/hover.md --
+-```go
+-const octal untyped int = 0o777 // 511
+-```
+--- @exprConst/hover.md --
+-```go
+-const expr untyped int = 2 << (0b111&0b101 - 2) // 16
+-```
+--- @boolConst/hover.md --
+-```go
+-const boolean untyped bool = (55 - 3) == (26 * 2) // true
+-```
+--- @ln10Const/hover.md --
+-```go
+-const ln10 untyped float = 2.30258509299404568401799145468436420760110148862877297603332790 // 2.30259
+-```
+--- @aIota/hover.md --
+-```go
+-const a untyped int = 1 << iota // 1
+-```
+--- @bIota/hover.md --
+-```go
+-const b untyped int = 2
+-```
+--- @strConst/hover.md --
+-```go
+-const str untyped string = "hello world"
+-```
+--- @longStrConst/hover.md --
+-```go
+-const longStr untyped string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur e...
+-```
+--- @log2eConst/hover.md --
+-```go
+-const math.Log2E untyped float = 1 / Ln2 // 1.4427
+-```
+-
+-Mathematical constants.
+-
+-
+-[`math.Log2E` on pkg.go.dev](https://pkg.go.dev/math#Log2E)
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/generics.txt b/gopls/internal/regtest/marker/testdata/hover/generics.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/generics.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/generics.txt	1970-01-01 00:00:00.000000000 +0000
-@@ -1,77 +0,0 @@
++++ b/gopls/internal/regtest/marker/testdata/hover/generics.txt	1970-01-01 08:00:00
+@@ -1,76 +0,0 @@
 -This file contains tests for hovering over generic Go code.
 -
 --- flags --
@@ -113527,8 +124149,7 @@
 -func _() {
 -	_ = app[[]int]             //@hover("app", "app", appint)
 -	_ = app[[]int, int]        //@hover("app", "app", appint)
--	// TODO(rfindley): eliminate this diagnostic.
--	_ = app[[]int]([]int{}, 0) //@hover("app", "app", appint),diag("[[]int]", re"unnecessary type arguments")
+-	_ = app[[]int]([]int{}, 0) //@hover("app", "app", appint)
 -	_ = app([]int{}, 0)        //@hover("app", "app", appint)
 -}
 -
@@ -113563,9 +124184,419 @@
 -```go
 -type parameter T any
 -```
+diff -urN a/gopls/internal/regtest/marker/testdata/hover/godef.txt b/gopls/internal/regtest/marker/testdata/hover/godef.txt
+--- a/gopls/internal/regtest/marker/testdata/hover/godef.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/hover/godef.txt	1970-01-01 08:00:00
+@@ -1,406 +0,0 @@
+-This test was ported from 'godef' in the old marker tests.
+-It tests various hover and definition requests.
+-
+--- flags --
+--min_go=go1.20
+-
+--- go.mod --
+-module godef.test
+-
+-go 1.18
+-
+--- a/a_x_test.go --
+-package a_test
+-
+-import (
+-	"testing"
+-)
+-
+-func TestA2(t *testing.T) { //@hover("TestA2", "TestA2", TestA2)
+-	Nonexistant() //@diag("Nonexistant", re"(undeclared name|undefined): Nonexistant")
+-}
+-
+--- @TestA2/hover.md --
+-```go
+-func TestA2(t *testing.T)
+-```
+--- @ember/hover.md --
+-```go
+-field Member string
+-```
+-
+-@loc(Member, "Member")
+-
+-
+-[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/godef.test/a#Thing.Member)
+--- a/d.go --
+-package a //@hover("a", _, a)
+-
+-import "fmt"
+-
+-type Thing struct { //@loc(Thing, "Thing")
+-	Member string //@loc(Member, "Member")
+-}
+-
+-var Other Thing //@loc(Other, "Other")
+-
+-func Things(val []string) []Thing { //@loc(Things, "Things")
+-	return nil
+-}
+-
+-func (t Thing) Method(i int) string { //@loc(Method, "Method")
+-	return t.Member
+-}
+-
+-func (t Thing) Method3() {
+-}
+-
+-func (t *Thing) Method2(i int, j int) (error, string) {
+-	return nil, t.Member
+-}
+-
+-func (t *Thing) private() {
+-}
+-
+-func useThings() {
+-	t := Thing{ //@hover("ing", "Thing", ing)
+-		Member: "string", //@hover("ember", "Member", ember), def("ember", Member)
+-	}
+-	fmt.Print(t.Member) //@hover("ember", "Member", ember), def("ember", Member)
+-	fmt.Print(Other)    //@hover("ther", "Other", ther), def("ther", Other)
+-	Things(nil)         //@hover("ings", "Things", ings), def("ings", Things)
+-	t.Method(0)         //@hover("eth", "Method", eth), def("eth", Method)
+-}
+-
+-type NextThing struct { //@loc(NextThing, "NextThing")
+-	Thing
+-	Value int
+-}
+-
+-func (n NextThing) another() string {
+-	return n.Member
+-}
+-
+-// Shadows Thing.Method3
+-func (n *NextThing) Method3() int {
+-	return n.Value
+-}
+-
+-var nextThing NextThing //@hover("NextThing", "NextThing", NextThing), def("NextThing", NextThing)
+-
+--- @ings/hover.md --
+-```go
+-func Things(val []string) []Thing
+-```
+-
+-[`a.Things` on pkg.go.dev](https://pkg.go.dev/godef.test/a#Things)
+--- @ther/hover.md --
+-```go
+-var Other Thing
+-```
+-
+-@loc(Other, "Other")
+-
+-
+-[`a.Other` on pkg.go.dev](https://pkg.go.dev/godef.test/a#Other)
+--- @a/hover.md --
+--- @ing/hover.md --
+-```go
+-type Thing struct {
+-	Member string //@loc(Member, "Member")
+-}
+-
+-func (Thing).Method(i int) string
+-func (*Thing).Method2(i int, j int) (error, string)
+-func (Thing).Method3()
+-func (*Thing).private()
+-```
+-
+-[`a.Thing` on pkg.go.dev](https://pkg.go.dev/godef.test/a#Thing)
+--- @NextThing/hover.md --
+-```go
+-type NextThing struct {
+-	Thing
+-	Value int
+-}
+-
+-func (*NextThing).Method3() int
+-func (NextThing).another() string
+-```
+-
+-[`a.NextThing` on pkg.go.dev](https://pkg.go.dev/godef.test/a#NextThing)
+--- @eth/hover.md --
+-```go
+-func (Thing).Method(i int) string
+-```
+-
+-[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/godef.test/a#Thing.Method)
+--- a/f.go --
+-// Package a is a package for testing go to definition.
+-package a
+-
+-import "fmt"
+-
+-func TypeStuff() {
+-	var x string
+-
+-	switch y := interface{}(x).(type) { //@loc(y, "y"), hover("y", "y", y) , def("y", y)
+-	case int: //@loc(intY, "int")
+-		fmt.Printf("%v", y) //@hover("y", "y", inty), def("y", y)
+-	case string: //@loc(stringY, "string")
+-		fmt.Printf("%v", y) //@hover("y", "y", stringy), def("y", y)
+-	}
+-
+-}
+--- @inty/hover.md --
+-```go
+-var y int
+-```
+--- @stringy/hover.md --
+-```go
+-var y string
+-```
+--- @y/hover.md --
+-```go
+-var y interface{}
+-```
+--- a/h.go --
+-package a
+-
+-func _() {
+-	type s struct {
+-		nested struct {
+-			// nested number
+-			number int64 //@loc(nestedNumber, "number")
+-		}
+-		nested2 []struct {
+-			// nested string
+-			str string //@loc(nestedString, "str")
+-		}
+-		x struct {
+-			x struct {
+-				x struct {
+-					x struct {
+-						x struct {
+-							// nested map
+-							m map[string]float64 //@loc(nestedMap, "m")
+-						}
+-					}
+-				}
+-			}
+-		}
+-	}
+-
+-	var t s
+-	_ = t.nested.number  //@hover("number", "number", nestedNumber), def("number", nestedNumber)
+-	_ = t.nested2[0].str //@hover("str", "str", nestedString), def("str", nestedString)
+-	_ = t.x.x.x.x.x.m    //@hover("m", "m", nestedMap), def("m", nestedMap)
+-}
+-
+-func _() {
+-	var s struct {
+-		// a field
+-		a int //@loc(structA, "a")
+-		// b nested struct
+-		b struct { //@loc(structB, "b")
+-			// c field of nested struct
+-			c int //@loc(structC, "c")
+-		}
+-	}
+-	_ = s.a   //@def("a", structA)
+-	_ = s.b   //@def("b", structB)
+-	_ = s.b.c //@def("c", structC)
+-
+-	var arr []struct {
+-		// d field
+-		d int //@loc(arrD, "d")
+-		// e nested struct
+-		e struct { //@loc(arrE, "e")
+-			// f field of nested struct
+-			f int //@loc(arrF, "f")
+-		}
+-	}
+-	_ = arr[0].d   //@def("d", arrD)
+-	_ = arr[0].e   //@def("e", arrE)
+-	_ = arr[0].e.f //@def("f", arrF)
+-
+-	var complex []struct {
+-		c <-chan map[string][]struct {
+-			// h field
+-			h int //@loc(complexH, "h")
+-			// i nested struct
+-			i struct { //@loc(complexI, "i")
+-				// j field of nested struct
+-				j int //@loc(complexJ, "j")
+-			}
+-		}
+-	}
+-	_ = (<-complex[0].c)["0"][0].h   //@def("h", complexH)
+-	_ = (<-complex[0].c)["0"][0].i   //@def("i", complexI)
+-	_ = (<-complex[0].c)["0"][0].i.j //@def("j", complexJ)
+-
+-	var mapWithStructKey map[struct { //@diag("struct", re"invalid map key")
+-		// X key field
+-		x []string //@loc(mapStructKeyX, "x")
+-	}]int
+-	for k := range mapWithStructKey {
+-		_ = k.x //@def("x", mapStructKeyX)
+-	}
+-
+-	var mapWithStructKeyAndValue map[struct {
+-		// Y key field
+-		y string //@loc(mapStructKeyY, "y")
+-	}]struct {
+-		// X value field
+-		x string //@loc(mapStructValueX, "x")
+-	}
+-	for k, v := range mapWithStructKeyAndValue {
+-		// TODO: we don't show docs for y field because both map key and value
+-		// are structs. And in this case, we parse only map value
+-		_ = k.y //@hover("y", "y", hoverStructKeyY), def("y", mapStructKeyY)
+-		_ = v.x //@hover("x", "x", hoverStructKeyX), def("x", mapStructValueX)
+-	}
+-
+-	var i []map[string]interface {
+-		// open method comment
+-		open() error //@loc(openMethod, "open")
+-	}
+-	i[0]["1"].open() //@hover("pen","open", openMethod), def("open", openMethod)
+-}
+-
+-func _() {
+-	test := struct {
+-		// test description
+-		desc string //@loc(testDescription, "desc")
+-	}{}
+-	_ = test.desc //@def("desc", testDescription)
+-
+-	for _, tt := range []struct {
+-		// test input
+-		in map[string][]struct { //@loc(testInput, "in")
+-			// test key
+-			key string //@loc(testInputKey, "key")
+-			// test value
+-			value interface{} //@loc(testInputValue, "value")
+-		}
+-		result struct {
+-			v <-chan struct {
+-				// expected test value
+-				value int //@loc(testResultValue, "value")
+-			}
+-		}
+-	}{} {
+-		_ = tt.in               //@def("in", testInput)
+-		_ = tt.in["0"][0].key   //@def("key", testInputKey)
+-		_ = tt.in["0"][0].value //@def("value", testInputValue)
+-
+-		_ = (<-tt.result.v).value //@def("value", testResultValue)
+-	}
+-}
+-
+-func _() {
+-	getPoints := func() []struct {
+-		// X coord
+-		x int //@loc(returnX, "x")
+-		// Y coord
+-		y int //@loc(returnY, "y")
+-	} {
+-		return nil
+-	}
+-
+-	r := getPoints()
+-	_ = r[0].x //@def("x", returnX)
+-	_ = r[0].y //@def("y", returnY)
+-}
+--- @hoverStructKeyX/hover.md --
+-```go
+-field x string
+-```
+-
+-X value field
+--- @hoverStructKeyY/hover.md --
+-```go
+-field y string
+-```
+-
+-Y key field
+--- @nestedNumber/hover.md --
+-```go
+-field number int64
+-```
+-
+-nested number
+--- @nestedString/hover.md --
+-```go
+-field str string
+-```
+-
+-nested string
+--- @openMethod/hover.md --
+-```go
+-func (interface).open() error
+-```
+-
+-open method comment
+--- @nestedMap/hover.md --
+-```go
+-field m map[string]float64
+-```
+-
+-nested map
+--- b/e.go --
+-package b
+-
+-import (
+-	"fmt"
+-
+-	"godef.test/a"
+-)
+-
+-func useThings() {
+-	t := a.Thing{}      //@loc(bStructType, "ing")
+-	fmt.Print(t.Member) //@loc(bMember, "ember")
+-	fmt.Print(a.Other)  //@loc(bVar, "ther")
+-	a.Things(nil)          //@loc(bFunc, "ings")
+-}
+-
+-/*@
+-def(bStructType, Thing)
+-def(bMember, Member)
+-def(bVar, Other)
+-def(bFunc, Things)
+-*/
+-
+-func _() {
+-	var x interface{}
+-	switch x := x.(type) { //@hover("x", "x", xInterface)
+-	case string: //@loc(eString, "string")
+-		fmt.Println(x) //@hover("x", "x", xString)
+-	case int: //@loc(eInt, "int")
+-		fmt.Println(x) //@hover("x", "x", xInt)
+-	}
+-}
+--- @xInt/hover.md --
+-```go
+-var x int
+-```
+--- @xInterface/hover.md --
+-```go
+-var x interface{}
+-```
+--- @xString/hover.md --
+-```go
+-var x string
+-```
+--- broken/unclosedIf.go --
+-package broken
+-
+-import "fmt"
+-
+-func unclosedIf() {
+-	if false {
+-		var myUnclosedIf string              //@loc(myUnclosedIf, "myUnclosedIf")
+-		fmt.Printf("s = %v\n", myUnclosedIf) //@def("my", myUnclosedIf)
+-}
+-
+-func _() {} //@diag("_", re"expected")
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/goprivate.txt b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/goprivate.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/hover/goprivate.txt	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -This test checks that links in hover obey GOPRIVATE.
 --- env --
@@ -113596,7 +124627,7 @@
 -T should not be linked, as it is private.
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/hover.txt b/gopls/internal/regtest/marker/testdata/hover/hover.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/hover.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/hover.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/hover/hover.txt	1970-01-01 08:00:00
 @@ -1,29 +0,0 @@
 -This test demonstrates some features of the new marker test runner.
 --- a.go --
@@ -113615,7 +124646,7 @@
 -}
 --- @abc/hover.md --
 -```go
--const abc untyped int = 42
+-const abc untyped int = 0x2a // 42
 -```
 -
 -@hover("b", "abc", abc),hover(" =", "abc", abc)
@@ -113627,9 +124658,133 @@
 -```go
 -var x int
 -```
+diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkable.txt b/gopls/internal/regtest/marker/testdata/hover/linkable.txt
+--- a/gopls/internal/regtest/marker/testdata/hover/linkable.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/hover/linkable.txt	1970-01-01 08:00:00
+@@ -1,120 +0,0 @@
+-This test checks that we correctly determine pkgsite links for various
+-identifiers.
+-
+-We should only produce links that work, meaning the object is reachable via the
+-package's public API.
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+--- p.go --
+-package p
+-
+-type E struct {
+-	Embed int
+-}
+-
+-// T is in the package scope, and so should be linkable.
+-type T struct{ //@hover("T", "T", T)
+-	// Only exported fields should be linkable
+-
+-	f int //@hover("f", "f", f)
+-	F int //@hover("F", "F", F)
+-
+-	E
+-
+-	// TODO(rfindley): is the link here correct? It ignores N.
+-	N struct {
+-		// Nested fields should also be linkable.
+-		Nested int //@hover("Nested", "Nested", Nested)
+-	}
+-}
+-// M is an exported method, and so should be linkable.
+-func (T) M() {}
+-
+-// m is not exported, and so should not be linkable.
+-func (T) m() {}
+-
+-func _() {
+-	var t T
+-
+-	// Embedded fields should be linkable.
+-	_ = t.Embed //@hover("Embed", "Embed", Embed)
+-
+-	// Local variables should not be linkable, even if they are capitalized.
+-	var X int //@hover("X", "X", X)
+-	_ = X
+-
+-	// Local types should not be linkable, even if they are capitalized.
+-	type Local struct { //@hover("Local", "Local", Local)
+-		E
+-	}
+-
+-	// But the embedded field should still be linkable.
+-	var l Local
+-	_ = l.Embed //@hover("Embed", "Embed", Embed)
+-}
+--- @Embed/hover.md --
+-```go
+-field Embed int
+-```
+-
+-[`(p.E).Embed` on pkg.go.dev](https://pkg.go.dev/mod.com#E.Embed)
+--- @F/hover.md --
+-```go
+-field F int
+-```
+-
+-@hover("F", "F", F)
+-
+-
+-[`(p.T).F` on pkg.go.dev](https://pkg.go.dev/mod.com#T.F)
+--- @Local/hover.md --
+-```go
+-type Local struct {
+-	E
+-}
+-```
+-
+-Local types should not be linkable, even if they are capitalized.
+--- @Nested/hover.md --
+-```go
+-field Nested int
+-```
+-
+-Nested fields should also be linkable.
+--- @T/hover.md --
+-```go
+-type T struct {
+-	f int //@hover("f", "f", f)
+-	F int //@hover("F", "F", F)
+-
+-	E
+-
+-	// TODO(rfindley): is the link here correct? It ignores N.
+-	N struct {
+-		// Nested fields should also be linkable.
+-		Nested int //@hover("Nested", "Nested", Nested)
+-	}
+-}
+-
+-func (T).M()
+-func (T).m()
+-```
+-
+-T is in the package scope, and so should be linkable.
+-
+-
+-[`p.T` on pkg.go.dev](https://pkg.go.dev/mod.com#T)
+--- @X/hover.md --
+-```go
+-var X int
+-```
+-
+-Local variables should not be linkable, even if they are capitalized.
+--- @f/hover.md --
+-```go
+-field f int
+-```
+-
+-@hover("f", "f", f)
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/hover/linkable_generics.txt	1970-01-01 08:00:00
 @@ -1,145 +0,0 @@
 -This file contains tests for documentation links to generic code in hover.
 -
@@ -113776,133 +124931,42 @@
 -
 -
 -[`generic.GT` on pkg.go.dev](https://pkg.go.dev/mod.com/generic#GT)
-diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkable.txt b/gopls/internal/regtest/marker/testdata/hover/linkable.txt
---- a/gopls/internal/regtest/marker/testdata/hover/linkable.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/linkable.txt	1970-01-01 00:00:00.000000000 +0000
-@@ -1,120 +0,0 @@
--This test checks that we correctly determine pkgsite links for various
--identifiers.
--
--We should only produce links that work, meaning the object is reachable via the
--package's public API.
+diff -urN a/gopls/internal/regtest/marker/testdata/hover/linkname.txt b/gopls/internal/regtest/marker/testdata/hover/linkname.txt
+--- a/gopls/internal/regtest/marker/testdata/hover/linkname.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/hover/linkname.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-This test check hover on the 2nd argument in go:linkname directives.
 --- go.mod --
 -module mod.com
 -
--go 1.18
---- p.go --
--package p
+--- upper/upper.go --
+-package upper
 -
--type E struct {
--	Embed int
+-import (
+-	_ "unsafe"
+-	_ "mod.com/lower"
+-)
+-
+-//go:linkname foo mod.com/lower.bar //@hover("mod.com/lower.bar", "mod.com/lower.bar", bar)
+-func foo() string
+-
+--- lower/lower.go --
+-package lower
+-
+-// bar does foo.
+-func bar() string {
+-	return "foo by bar"
 -}
 -
--// T is in the package scope, and so should be linkable.
--type T struct{ //@hover("T", "T", T)
--	// Only exported fields should be linkable
--
--	f int //@hover("f", "f", f)
--	F int //@hover("F", "F", F)
--
--	E
--
--	// TODO(rfindley): is the link here correct? It ignores N.
--	N struct {
--		// Nested fields should also be linkable.
--		Nested int //@hover("Nested", "Nested", Nested)
--	}
--}
--// M is an exported method, and so should be linkable.
--func (T) M() {}
--
--// m is not exported, and so should not be linkable.
--func (T) m() {}
--
--func _() {
--	var t T
--
--	// Embedded fields should be linkable.
--	_ = t.Embed //@hover("Embed", "Embed", Embed)
--
--	// Local variables should not be linkable, even if they are capitalized.
--	var X int //@hover("X", "X", X)
--	_ = X
--
--	// Local types should not be linkable, even if they are capitalized.
--	type Local struct { //@hover("Local", "Local", Local)
--		E
--	}
--
--	// But the embedded field should still be linkable.
--	var l Local
--	_ = l.Embed //@hover("Embed", "Embed", Embed)
--}
---- @Embed/hover.md --
+--- @bar/hover.md --
 -```go
--field Embed int
+-func bar() string
 -```
 -
--[`(p.E).Embed` on pkg.go.dev](https://pkg.go.dev/mod.com#E.Embed)
---- @F/hover.md --
--```go
--field F int
--```
--
--@hover("F", "F", F)
--
--
--[`(p.T).F` on pkg.go.dev](https://pkg.go.dev/mod.com#T.F)
---- @Local/hover.md --
--```go
--type Local struct {
--	E
--}
--```
--
--Local types should not be linkable, even if they are capitalized.
---- @Nested/hover.md --
--```go
--field Nested int
--```
--
--Nested fields should also be linkable.
---- @T/hover.md --
--```go
--type T struct {
--	f int //@hover("f", "f", f)
--	F int //@hover("F", "F", F)
--
--	E
--
--	// TODO(rfindley): is the link here correct? It ignores N.
--	N struct {
--		// Nested fields should also be linkable.
--		Nested int //@hover("Nested", "Nested", Nested)
--	}
--}
--
--func (T).M()
--func (T).m()
--```
--
--T is in the package scope, and so should be linkable.
--
--
--[`p.T` on pkg.go.dev](https://pkg.go.dev/mod.com#T)
---- @X/hover.md --
--```go
--var X int
--```
--
--Local variables should not be linkable, even if they are capitalized.
---- @f/hover.md --
--```go
--field f int
--```
--
--@hover("f", "f", f)
+-bar does foo.
 diff -urN a/gopls/internal/regtest/marker/testdata/hover/std.txt b/gopls/internal/regtest/marker/testdata/hover/std.txt
 --- a/gopls/internal/regtest/marker/testdata/hover/std.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/hover/std.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/hover/std.txt	1970-01-01 08:00:00
 @@ -1,80 +0,0 @@
 -This test checks hover results for built-in or standard library symbols.
 -
@@ -113984,35 +125048,834 @@
 -
 -
 -[`string` on pkg.go.dev](https://pkg.go.dev/builtin#string)
+diff -urN a/gopls/internal/regtest/marker/testdata/implementation/basic.txt b/gopls/internal/regtest/marker/testdata/implementation/basic.txt
+--- a/gopls/internal/regtest/marker/testdata/implementation/basic.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/implementation/basic.txt	1970-01-01 08:00:00
+@@ -1,73 +0,0 @@
+-Basic test of implementation query.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- implementation/implementation.go --
+-package implementation
+-
+-import "example.com/other"
+-
+-type ImpP struct{} //@loc(ImpP, "ImpP"),implementation("ImpP", Laugher, OtherLaugher)
+-
+-func (*ImpP) Laugh() { //@loc(LaughP, "Laugh"),implementation("Laugh", Laugh, OtherLaugh)
+-}
+-
+-type ImpS struct{} //@loc(ImpS, "ImpS"),implementation("ImpS", Laugher, OtherLaugher)
+-
+-func (ImpS) Laugh() { //@loc(LaughS, "Laugh"),implementation("Laugh", Laugh, OtherLaugh)
+-}
+-
+-type Laugher interface { //@loc(Laugher, "Laugher"),implementation("Laugher", ImpP, OtherImpP, ImpS, OtherImpS, embedsImpP)
+-	Laugh() //@loc(Laugh, "Laugh"),implementation("Laugh", LaughP, OtherLaughP, LaughS, OtherLaughS)
+-}
+-
+-type Foo struct { //@implementation("Foo", Joker)
+-	other.Foo
+-}
+-
+-type Joker interface { //@loc(Joker, "Joker")
+-	Joke() //@loc(Joke, "Joke"),implementation("Joke", ImpJoker)
+-}
+-
+-type cryer int //@implementation("cryer", Cryer)
+-
+-func (cryer) Cry(other.CryType) {} //@loc(CryImpl, "Cry"),implementation("Cry", Cry)
+-
+-type Empty interface{} //@implementation("Empty")
+-
+-var _ interface{ Joke() } //@implementation("Joke", ImpJoker)
+-
+-type embedsImpP struct { //@loc(embedsImpP, "embedsImpP")
+-	ImpP //@implementation("ImpP", Laugher, OtherLaugher)
+-}
+-
+--- other/other.go --
+-package other
+-
+-type ImpP struct{} //@loc(OtherImpP, "ImpP")
+-
+-func (*ImpP) Laugh() { //@loc(OtherLaughP, "Laugh")
+-}
+-
+-type ImpS struct{} //@loc(OtherImpS, "ImpS")
+-
+-func (ImpS) Laugh() { //@loc(OtherLaughS, "Laugh")
+-}
+-
+-type ImpI interface { //@loc(OtherLaugher, "ImpI")
+-	Laugh() //@loc(OtherLaugh, "Laugh")
+-}
+-
+-type Foo struct { //@implementation("Foo", Joker)
+-}
+-
+-func (Foo) Joke() { //@loc(ImpJoker, "Joke"),implementation("Joke", Joke)
+-}
+-
+-type CryType int
+-
+-type Cryer interface { //@loc(Cryer, "Cryer")
+-	Cry(CryType) //@loc(Cry, "Cry"),implementation("Cry", CryImpl)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/implementation/generics.txt b/gopls/internal/regtest/marker/testdata/implementation/generics.txt
+--- a/gopls/internal/regtest/marker/testdata/implementation/generics.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/implementation/generics.txt	1970-01-01 08:00:00
+@@ -1,34 +0,0 @@
+-Test of 'implementation' query on generic types.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module example.com
+-go 1.18
+-
+--- implementation/implementation.go --
+-package implementation
+-
+-type GenIface[T any] interface { //@loc(GenIface, "GenIface"),implementation("GenIface", GC)
+-	F(int, string, T) //@loc(GenIfaceF, "F"),implementation("F", GCF)
+-}
+-
+-type GenConc[U any] int //@loc(GenConc, "GenConc"),implementation("GenConc", GI)
+-
+-func (GenConc[V]) F(int, string, V) {} //@loc(GenConcF, "F"),implementation("F", GIF)
+-
+-type GenConcString struct{ GenConc[string] } //@loc(GenConcString, "GenConcString"),implementation(GenConcString, GIString)
+-
+--- other/other.go --
+-package other
+-
+-type GI[T any] interface { //@loc(GI, "GI"),implementation("GI", GenConc)
+-	F(int, string, T) //@loc(GIF, "F"),implementation("F", GenConcF)
+-}
+-
+-type GIString GI[string] //@loc(GIString, "GIString"),implementation("GIString", GenConcString)
+-
+-type GC[U any] int //@loc(GC, "GC"),implementation("GC", GenIface)
+-
+-func (GC[V]) F(int, string, V) {} //@loc(GCF, "F"),implementation("F", GenIfaceF)
+diff -urN a/gopls/internal/regtest/marker/testdata/implementation/issue43655.txt b/gopls/internal/regtest/marker/testdata/implementation/issue43655.txt
+--- a/gopls/internal/regtest/marker/testdata/implementation/issue43655.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/implementation/issue43655.txt	1970-01-01 08:00:00
+@@ -1,22 +0,0 @@
+-This test verifies that we fine implementations of the built-in error interface.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- p.go --
+-package p
+-
+-type errA struct{ error } //@loc(errA, "errA")
+-
+-type errB struct{} //@loc(errB, "errB")
+-func (errB) Error() string{ return "" } //@loc(errBError, "Error")
+-
+-type notAnError struct{}
+-func (notAnError) Error() int { return 0 }
+-
+-func _() {
+-	var _ error //@implementation("error", errA, errB)
+-	var a errA
+-	_ = a.Error //@implementation("Error", errBError)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/quickfix/undeclared.txt b/gopls/internal/regtest/marker/testdata/quickfix/undeclared.txt
+--- a/gopls/internal/regtest/marker/testdata/quickfix/undeclared.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/quickfix/undeclared.txt	1970-01-01 08:00:00
+@@ -1,62 +0,0 @@
+-Tests of suggested fixes for "undeclared name" diagnostics,
+-which are of ("compiler", "error") type.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a.go --
+-package p
+-
+-func a() {
+-	z, _ := 1+y, 11 //@suggestedfix("y", re"(undeclared name|undefined): y", "quickfix", a)
+-	_ = z
+-}
+-
+--- @a/a.go --
+-package p
+-
+-func a() {
+-	y := 
+-	z, _ := 1+y, 11 //@suggestedfix("y", re"(undeclared name|undefined): y", "quickfix", a)
+-	_ = z
+-}
+-
+--- b.go --
+-package p
+-
+-func b() {
+-	if 100 < 90 {
+-	} else if 100 > n+2 { //@suggestedfix("n", re"(undeclared name|undefined): n", "quickfix", b)
+-	}
+-}
+-
+--- @b/b.go --
+-package p
+-
+-func b() {
+-	n := 
+-	if 100 < 90 {
+-	} else if 100 > n+2 { //@suggestedfix("n", re"(undeclared name|undefined): n", "quickfix", b)
+-	}
+-}
+-
+--- c.go --
+-package p
+-
+-func c() {
+-	for i < 200 { //@suggestedfix("i", re"(undeclared name|undefined): i", "quickfix", c)
+-	}
+-	r() //@diag("r", re"(undeclared name|undefined): r")
+-}
+-
+--- @c/c.go --
+-package p
+-
+-func c() {
+-	i := 
+-	for i < 200 { //@suggestedfix("i", re"(undeclared name|undefined): i", "quickfix", c)
+-	}
+-	r() //@diag("r", re"(undeclared name|undefined): r")
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire.txt b/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire.txt
+--- a/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire.txt	1970-01-01 08:00:00
+@@ -1,24 +0,0 @@
+-This test checks the suggested fix to remove unused require statements from
+-go.mod files.
+-
+--- flags --
+--write_sumfile=a
+-
+--- proxy/example.com@v1.0.0/x.go --
+-package pkg
+-const X = 1
+-
+--- a/go.mod --
+-module mod.com
+-
+-go 1.14
+-
+-require example.com v1.0.0 //@suggestedfix("require", re"not used", "quickfix", a)
+-
+--- @a/a/go.mod --
+-module mod.com
+-
+-go 1.14
+--- a/main.go --
+-package main
+-func main() {}
+diff -urN a/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire_gowork.txt b/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire_gowork.txt
+--- a/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire_gowork.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/quickfix/unusedrequire_gowork.txt	1970-01-01 08:00:00
+@@ -1,49 +0,0 @@
+-This test checks the suggested fix to remove unused require statements from
+-go.mod files, when a go.work file is used.
+-
+-Note that unlike unusedrequire.txt, we need not write go.sum files when
+-a go.work file is used.
+-
+--- flags --
+--min_go=go1.18
+-
+--- proxy/example.com@v1.0.0/x.go --
+-package pkg
+-const X = 1
+-
+--- go.work --
+-go 1.21
+-
+-use (
+-	./a
+-	./b
+-)
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.14
+-
+-require example.com v1.0.0 //@suggestedfix("require", re"not used", "quickfix", a)
+-
+--- @a/a/go.mod --
+-module mod.com/a
+-
+-go 1.14
+--- a/main.go --
+-package main
+-func main() {}
+-
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.14
+-
+-require example.com v1.0.0 //@suggestedfix("require", re"not used", "quickfix", b)
+-
+--- @b/b/go.mod --
+-module mod.com/b
+-
+-go 1.14
+--- b/main.go --
+-package main
+-func main() {}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/crosspackage.txt b/gopls/internal/regtest/marker/testdata/references/crosspackage.txt
+--- a/gopls/internal/regtest/marker/testdata/references/crosspackage.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/crosspackage.txt	1970-01-01 08:00:00
+@@ -1,37 +0,0 @@
+-Test of basic cross-package references.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type X struct {
+-	Y int //@loc(typeXY, "Y")
+-}
+-
+--- b/b.go --
+-package b
+-
+-import "example.com/a"
+-
+-func GetXes() []a.X {
+-	return []a.X{
+-		{
+-			Y: 1, //@loc(GetXesY, "Y"), refs("Y", typeXY, GetXesY, anotherXY)
+-		},
+-	}
+-}
+-
+--- c/c.go --
+-package c
+-
+-import "example.com/b"
+-
+-func _() {
+-        xes := b.GetXes()
+-        for _, x := range xes { //@loc(defX, "x")
+-                _ = x.Y //@loc(useX, "x"), loc(anotherXY, "Y"), refs("Y", typeXY, anotherXY, GetXesY), refs(".", defX, useX), refs("x", defX, useX)
+-        }
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/imports.txt b/gopls/internal/regtest/marker/testdata/references/imports.txt
+--- a/gopls/internal/regtest/marker/testdata/references/imports.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/imports.txt	1970-01-01 08:00:00
+@@ -1,17 +0,0 @@
+-Test of references to local package names (imports).
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-import "os" //@loc(osDef, `"os"`), refs("os", osDef, osUse)
+-
+-import fmt2 "fmt" //@loc(fmt2Def, `fmt2`), refs("fmt2", fmt2Def, fmt2Use)
+-
+-func _() {
+-	os.Getwd() //@loc(osUse, "os")
+-	fmt2.Println() //@loc(fmt2Use, "fmt2")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/interfaces.txt b/gopls/internal/regtest/marker/testdata/references/interfaces.txt
+--- a/gopls/internal/regtest/marker/testdata/references/interfaces.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/interfaces.txt	1970-01-01 08:00:00
+@@ -1,42 +0,0 @@
+-Test of references applied to concrete and interface types that are
+-related by assignability. The result includes references to both.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type first interface {
+-	common() //@loc(firCommon, "common"), refs("common", firCommon, xCommon, zCommon)
+-	firstMethod() //@loc(firMethod, "firstMethod"), refs("firstMethod", firMethod, xfMethod, zfMethod)
+-}
+-
+-type second interface {
+-	common() //@loc(secCommon, "common"), refs("common", secCommon, yCommon, zCommon)
+-	secondMethod() //@loc(secMethod, "secondMethod"), refs("secondMethod", secMethod, ysMethod, zsMethod)
+-}
+-
+-type s struct {}
+-
+-func (*s) common() {} //@loc(sCommon, "common"), refs("common", sCommon, xCommon, yCommon, zCommon)
+-
+-func (*s) firstMethod() {} //@loc(sfMethod, "firstMethod"), refs("firstMethod", sfMethod, xfMethod, zfMethod)
+-
+-func (*s) secondMethod() {} //@loc(ssMethod, "secondMethod"), refs("secondMethod", ssMethod, ysMethod, zsMethod)
+-
+-func main() {
+-	var x first = &s{}
+-	var y second = &s{}
+-
+-	x.common() //@loc(xCommon, "common"), refs("common", firCommon, xCommon, zCommon)
+-	x.firstMethod() //@loc(xfMethod, "firstMethod"), refs("firstMethod", firMethod, xfMethod, zfMethod)
+-	y.common() //@loc(yCommon, "common"), refs("common", secCommon, yCommon, zCommon)
+-	y.secondMethod() //@loc(ysMethod, "secondMethod"), refs("secondMethod", secMethod, ysMethod, zsMethod)
+-
+-	var z *s = &s{}
+-	z.firstMethod() //@loc(zfMethod, "firstMethod"), refs("firstMethod", sfMethod, xfMethod, zfMethod)
+-	z.secondMethod() //@loc(zsMethod, "secondMethod"), refs("secondMethod", ssMethod, ysMethod, zsMethod)
+-	z.common() //@loc(zCommon, "common"), refs("common", sCommon, xCommon, yCommon, zCommon)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/intrapackage.txt b/gopls/internal/regtest/marker/testdata/references/intrapackage.txt
+--- a/gopls/internal/regtest/marker/testdata/references/intrapackage.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/intrapackage.txt	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
+-Basic test of references within a single package.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type i int //@loc(decli, "i"), refs("i", decli, argi, returni, embeddedi)
+-
+-func _(_ i) []bool { //@loc(argi, "i")
+-	return nil
+-}
+-
+-func _(_ []byte) i { //@loc(returni, "i")
+-	return 0
+-}
+-
+-var q string //@loc(declq, "q"), refs("q", declq, assignq, bobq)
+-
+-var Q string //@loc(declQ, "Q"), refs("Q", declQ)
+-
+-func _() {
+-	q = "hello" //@loc(assignq, "q")
+-	bob := func(_ string) {}
+-	bob(q) //@loc(bobq, "q")
+-}
+-
+-type e struct {
+-	i //@loc(embeddedi, "i"), refs("i", embeddedi, embeddediref)
+-}
+-
+-func _() {
+-	_ = e{}.i //@loc(embeddediref, "i")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue58506.txt b/gopls/internal/regtest/marker/testdata/references/issue58506.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue58506.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue58506.txt	1970-01-01 08:00:00
+@@ -1,56 +0,0 @@
+-Regression test for 'references' bug golang/go#58506.
+-
+-The 'references' query below, applied to method A.F, implicitly uses
+-the 'implementation' operation. The correct response includes two
+-references to B.F, one from package b and one from package d.
+-However, the incremental 'implementation' algorithm had a bug that
+-cause it to fail to report the reference from package b.
+-
+-The reason was that the incremental implementation uses different
+-algorithms for the local and global cases (with disjoint results), and
+-that when it discovered that type A satisfies interface B and thus
+-that B.F must be included among the global search targets, the
+-implementation forgot to also search package b for local references
+-to B.F.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type A int
+-
+-func (A) F() {} //@loc(refa, "F"), refs("F", refa, refb, refd)
+-
+--- b/b.go --
+-package b
+-
+-import (
+-	"example.com/a"
+-	"example.com/c"
+-)
+-
+-type B interface{ F() }
+-
+-var _ B = a.A(0)
+-var _ B = c.C(0)
+-
+-var _ = B.F //@loc(refb, "F")
+-
+--- c/c.go --
+-package c
+-
+-type C int
+-
+-// Even though C.F is "rename coupled" to A.F by B.F,
+-// it should not be among the results.
+-func (C) F() {}
+-
+--- d/d.go --
+-package d
+-
+-import "example.com/b"
+-
+-var _ interface{} = b.B.F //@loc(refd, "F")
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue59851.txt b/gopls/internal/regtest/marker/testdata/references/issue59851.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue59851.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue59851.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-Regression test for 'references' bug golang/go#59851.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type Iface interface {
+-     Method()
+-}
+-
+-type implOne struct{}
+-
+-func (implOne) Method() {} //@loc(def1, "Method"), refs(def1, def1, ref1, iref, ireftest)
+-
+-var _ = implOne.Method //@loc(ref1, "Method")
+-var _ = Iface(nil).Method //@loc(iref, "Method")
+-
+--- a/a_test.go --
+-package a
+-
+-type implTwo struct{}
+-
+-func (implTwo) Method() {} //@loc(def2, "Method"), refs(def2, def2, iref, ref2, ireftest)
+-
+-var _ = implTwo.Method //@loc(ref2, "Method")
+-var _ = Iface(nil).Method //@loc(ireftest, "Method")
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue60369.txt b/gopls/internal/regtest/marker/testdata/references/issue60369.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue60369.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue60369.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-Regression test for 'references' bug golang/go#60369: a references
+-query on the embedded type name T in struct{p.T} instead reports all
+-references to the package name p.
+-
+-The bug was fixed in release go1.21 of go/types.
+-
+--- flags --
+--min_go=go1.21
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type A struct{}
+-const C = 0
+-
+--- b/b.go --
+-package b
+-
+-import a "example.com/a" //@loc(adef, "a")
+-type s struct {
+-	a.A //@loc(Aref1, "A"), loc(aref1, "a"), refs(Aref1, Aref1, Aref3), refs(aref1, adef, aref1, aref2, aref3)
+-}
+-var _ a.A //@loc(aref2, re" (a)"), loc(Aref2, "A")
+-var _ = s{}.A //@loc(Aref3, "A")
+-const c = a.C //@loc(aref3, "a")
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue60622.txt b/gopls/internal/regtest/marker/testdata/references/issue60622.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue60622.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue60622.txt	1970-01-01 08:00:00
+@@ -1,25 +0,0 @@
+-Regression test for 'references' bug golang/go#60622:
+-references to methods of generics were missing.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module example.com
+-go 1.18
+-
+--- a/a.go --
+-package a
+-
+-type G[T any] struct{}
+-
+-func (G[T]) M() {} //@loc(Mdef, "M"), refs(Mdef, Mdef, Mref)
+-
+--- b/b.go --
+-package b
+-
+-import "example.com/a"
+-
+-func _() {
+-	new(a.G[int]).M() //@loc(Mref, "M")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue60676.txt b/gopls/internal/regtest/marker/testdata/references/issue60676.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue60676.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue60676.txt	1970-01-01 08:00:00
+@@ -1,69 +0,0 @@
+-This test verifies that even after importing from export data, the references
+-algorithm is able to find all references to struct fields or methods that are
+-shared by types from multiple packages. See golang/go#60676.
+-
+-Note that the marker test runner awaits the initial workspace load, so export
+-data should be populated at the time references are requested.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module mod.test
+-
+-go 1.18
+-
+--- a/a.go --
+-package a
+-
+-type A struct {
+-	F int //@loc(FDef, "F")
+-	E //@loc(EDef, "E")
+-}
+-
+-type E struct {
+-	G string //@loc(GDef, "G")
+-}
+-
+-type AI interface {
+-	M() //@loc(MDef, "M")
+-	EI
+-	error
+-}
+-
+-type EI interface {
+-	N() //@loc(NDef, "N")
+-}
+-
+-type T[P any] struct{ f P }
+-
+-type Error error
+-
+-
+--- b/b.go --
+-package b
+-
+-import "mod.test/a"
+-
+-type B a.A
+-
+-type BI a.AI
+-
+-type T a.T[int] // must not panic
+-
+--- c/c.go --
+-package c
+-
+-import "mod.test/b"
+-
+-func _() {
+-	x := b.B{
+-		F: 42, //@refs("F", FDef, "F")
+-	}
+-	x.G = "hi" //@refs("G", GDef, "G")
+-	_ = x.E //@refs("E", EDef, "E")
+-
+-	var y b.BI
+-	_ = y.M //@refs("M", MDef, "M")
+-	_ = y.N //@refs("N", NDef, "N")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/issue61618.txt b/gopls/internal/regtest/marker/testdata/references/issue61618.txt
+--- a/gopls/internal/regtest/marker/testdata/references/issue61618.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/issue61618.txt	1970-01-01 08:00:00
+@@ -1,39 +0,0 @@
+-Regression test for 'references' bug golang/go#61618:
+-references to instantiated fields were missing.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module example.com
+-go 1.18
+-
+--- a.go --
+-package a
+-
+-// This file is adapted from the example in the issue.
+-
+-type builder[S ~[]F, F ~string] struct {
+-	name string
+-	elements S //@loc(def, "elements"), refs(def, def, assign, use)
+-	elemData map[F][]ElemData[F]
+-}
+-
+-type ElemData[F ~string] struct {
+-  Name F
+-}
+-
+-type BuilderImpl[S ~[]F, F ~string] struct{ builder[S, F] }
+-
+-func NewBuilderImpl[S ~[]F, F ~string](name string)  *BuilderImpl[S, F] {
+-  impl := &BuilderImpl[S,F]{
+-	builder[S, F]{
+-	  name: name,
+-	  elements: S{}, //@loc(assign, "elements"), refs(assign, def, assign, use)
+-	  elemData: map[F][]ElemData[F]{},
+-	},
+-  }
+-
+-  _ = impl.elements //@loc(use, "elements"), refs(use, def, assign, use)
+-  return impl
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/shadow.txt b/gopls/internal/regtest/marker/testdata/references/shadow.txt
+--- a/gopls/internal/regtest/marker/testdata/references/shadow.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/shadow.txt	1970-01-01 08:00:00
+@@ -1,17 +0,0 @@
+-Test of references in the presence of shadowing.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-func _() {
+-	x := 123 //@loc(x1, "x"), refs("x", x1, x1ref)
+-	_ = x //@loc(x1ref, "x")
+-	{
+-		x := "hi" //@loc(x2, "x"), refs("x", x2, x2ref)
+-		_ = x //@loc(x2ref, "x")
+-	}
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/references/test.txt b/gopls/internal/regtest/marker/testdata/references/test.txt
+--- a/gopls/internal/regtest/marker/testdata/references/test.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/test.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-Test of references between the extra files of a test variant
+-and the regular package.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-func fn() {} //@loc(def, "fn"), refs("fn", def, use)
+-
+-type t struct { g int } //@loc(gdef, "g")
+-type u struct { t }
+-
+-var _ = new(u).g //@loc(gref, "g"), refs("g", gdef, gref)
+-// TODO(adonovan): fix: gref2 and gdef2 are missing.
+-
+--- a/a_test.go --
+-package a
+-
+-func _() {
+-	fn() //@loc(use, "fn")
+-
+-	_ = new(u).g //@loc(gref2, "g"), refs("g", gdef2, gref, gref2)
+-}
+-
+-// This declaration changes the meaning of u.t in the test.
+-func (u) g() {} //@loc(gdef2, "g")
+diff -urN a/gopls/internal/regtest/marker/testdata/references/typeswitch.txt b/gopls/internal/regtest/marker/testdata/references/typeswitch.txt
+--- a/gopls/internal/regtest/marker/testdata/references/typeswitch.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/references/typeswitch.txt	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
+-Tests of reference to implicit type switch vars, which are
+-a special case in go/types.Info{Def,Use,Implicits}.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-func _(x interface{}) {
+-	switch y := x.(type) { //@loc(yDecl, "y"), refs("y", yDecl, yInt, yDefault)
+-	case int:
+-		println(y) //@loc(yInt, "y"), refs("y", yDecl, yInt, yDefault)
+-	default:
+-		println(y) //@loc(yDefault, "y")
+-	}
+-}
 diff -urN a/gopls/internal/regtest/marker/testdata/rename/basic.txt b/gopls/internal/regtest/marker/testdata/rename/basic.txt
 --- a/gopls/internal/regtest/marker/testdata/rename/basic.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/rename/basic.txt	1970-01-01 00:00:00.000000000 +0000
-@@ -1,22 +0,0 @@
++++ b/gopls/internal/regtest/marker/testdata/rename/basic.txt	1970-01-01 08:00:00
+@@ -1,38 +0,0 @@
 -This test performs basic coverage of 'rename' within a single package.
 -
 --- basic.go --
 -package p
 -
--func f(x int) { println(x) } //@rename("x", y, param_x)
+-func f(x int) { println(x) } //@rename("x", "y", xToy)
 -
---- @param_x/basic.go --
+--- @xToy/basic.go --
 -package p
 -
--func f(y int) { println(y) } //@rename("x", y, param_x)
+-func f(y int) { println(y) } //@rename("x", "y", xToy)
+-
+--- alias.go --
+-package p
+-
+-// from golang/go#61625
+-type LongNameHere struct{}
+-type A = LongNameHere //@rename("A", "B", AToB)
+-func Foo() A
 -
 --- errors.go --
 -package p
 -
--func _(x []int) { //@renameerr("_", blank, `can't rename "_"`)
--	x = append(x, 1) //@renameerr("append", blank, "built in and cannot be renamed")
--	x = nil //@renameerr("nil", blank, "built in and cannot be renamed")
--	x = nil //@renameerr("x", x, "old and new names are the same: x")
--	_ = 1 //@renameerr("1", x, "no identifier found")
+-func _(x []int) { //@renameerr("_", "blank", `can't rename "_"`)
+-	x = append(x, 1) //@renameerr("append", "blank", "built in and cannot be renamed")
+-	x = nil //@renameerr("nil", "blank", "built in and cannot be renamed")
+-	x = nil //@renameerr("x", "x", "old and new names are the same: x")
+-	_ = 1 //@renameerr("1", "x", "no identifier found")
 -}
 -
+--- @AToB/alias.go --
+-package p
+-
+-// from golang/go#61625
+-type LongNameHere struct{}
+-type B = LongNameHere //@rename("A", "B", AToB)
+-func Foo() B
+-
 diff -urN a/gopls/internal/regtest/marker/testdata/rename/conflict.txt b/gopls/internal/regtest/marker/testdata/rename/conflict.txt
 --- a/gopls/internal/regtest/marker/testdata/rename/conflict.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/rename/conflict.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/rename/conflict.txt	1970-01-01 08:00:00
 @@ -1,59 +0,0 @@
 -This test exercises some renaming conflict scenarios
 -and ensures that the errors are informative.
@@ -114028,7 +125891,7 @@
 -
 -func f(y int) {
 -	println(x)
--	println(y) //@renameerr("y", x, errSuperBlockConflict)
+-	println(y) //@renameerr("y", "x", errSuperBlockConflict)
 -}
 -
 --- @errSuperBlockConflict --
@@ -114041,7 +125904,7 @@
 -var a int
 -
 -func f2(b int) {
--	println(a) //@renameerr("a", b, errSubBlockConflict)
+-	println(a) //@renameerr("a", "b", errSubBlockConflict)
 -	println(b)
 -}
 -
@@ -114052,7 +125915,7 @@
 --- pkgname/p.go --
 -package pkgname
 -
--import e1 "errors" //@renameerr("e1", errors, errImportConflict)
+-import e1 "errors" //@renameerr("e1", "errors", errImportConflict)
 -import "errors"
 -
 -var _ = errors.New
@@ -114067,7 +125930,7 @@
 -
 --- pkgname2/p2.go --
 -package pkgname2
--import "errors" //@renameerr("errors", x, errImportConflict2)
+-import "errors" //@renameerr("errors", "x", errImportConflict2)
 -var _ = errors.New
 -
 --- @errImportConflict2 --
@@ -114075,7 +125938,7 @@
 -pkgname2/p1.go:2:5:	with this package member var
 diff -urN a/gopls/internal/regtest/marker/testdata/rename/embed.txt b/gopls/internal/regtest/marker/testdata/rename/embed.txt
 --- a/gopls/internal/regtest/marker/testdata/rename/embed.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/rename/embed.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/rename/embed.txt	1970-01-01 08:00:00
 @@ -1,36 +0,0 @@
 -This test exercises renaming of types used as embedded fields.
 -
@@ -114086,36 +125949,426 @@
 --- a/a.go --
 -package a
 -
--type A int //@rename("A", A2, type)
+-type A int //@rename("A", "A2", type)
 -
 --- b/b.go --
 -package b
 -
 -import "example.com/a"
 -
--type B struct { a.A } //@renameerr("A", A3, errAnonField)
+-type B struct { a.A } //@renameerr("A", "A3", errAnonField)
 -
--var _ = new(B).A //@renameerr("A", A4, errAnonField)
+-var _ = new(B).A //@renameerr("A", "A4", errAnonField)
 -
 --- @errAnonField --
 -can't rename embedded fields: rename the type directly or name the field
 --- @type/a/a.go --
 -package a
 -
--type A2 int //@rename("A", A2, type)
+-type A2 int //@rename("A", "A2", type)
 -
 --- @type/b/b.go --
 -package b
 -
 -import "example.com/a"
 -
--type B struct { a.A2 } //@renameerr("A", A3, errAnonField)
+-type B struct { a.A2 } //@renameerr("A", "A3", errAnonField)
 -
--var _ = new(B).A2 //@renameerr("A", A4, errAnonField)
+-var _ = new(B).A2 //@renameerr("A", "A4", errAnonField)
 -
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/generics.txt b/gopls/internal/regtest/marker/testdata/rename/generics.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/generics.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/generics.txt	1970-01-01 08:00:00
+@@ -1,240 +0,0 @@
+-This test exercises various renaming features on generic code.
+-
+-Fixed bugs:
+-
+-- golang/go#61614: renaming a method of a type in a package that uses type
+-  parameter composite lits used to panic, because previous iterations of the
+-  satisfy analysis did not account for this language feature.
+-
+-- golang/go#61635: renaming type parameters did not work when they were
+-  capitalized and the package was imported by another package.
+-
+--- flags --
+--min_go=go1.18
+-
+--- go.mod --
+-module example.com
+-go 1.20
+-
+--- a.go --
+-package a
+-
+-type I int
+-
+-func (I) m() {} //@rename("m", "M", mToM)
+-
+-func _[P ~[]int]() {
+-	_ = P{}
+-}
+-
+--- @mToM/a.go --
+-package a
+-
+-type I int
+-
+-func (I) M() {} //@rename("m", "M", mToM)
+-
+-func _[P ~[]int]() {
+-	_ = P{}
+-}
+-
+--- g.go --
+-package a
+-
+-type S[P any] struct { //@rename("P", "Q", PToQ)
+-	P P
+-	F func(P) P
+-}
+-
+-func F[R any](r R) {
+-	var _ R //@rename("R", "S", RToS)
+-}
+-
+--- @PToQ/g.go --
+-package a
+-
+-type S[Q any] struct { //@rename("P", "Q", PToQ)
+-	P Q
+-	F func(Q) Q
+-}
+-
+-func F[R any](r R) {
+-	var _ R //@rename("R", "S", RToS)
+-}
+-
+--- @RToS/g.go --
+-package a
+-
+-type S[P any] struct { //@rename("P", "Q", PToQ)
+-	P P
+-	F func(P) P
+-}
+-
+-func F[S any](r S) {
+-	var _ S //@rename("R", "S", RToS)
+-}
+-
+--- issue61635/p.go --
+-package issue61635
+-
+-type builder[S ~[]F, F ~string] struct { //@rename("S", "T", SToT)
+-	name string
+-	elements S
+-	elemData map[F][]ElemData[F]
+-	// other fields...
+-}
+-
+-type ElemData[F ~string] struct {
+-  Name F
+-  // other fields...
+-}
+-
+-type BuilderImpl[S ~[]F, F ~string] struct{ builder[S, F] }
+-
+--- importer/i.go --
+-package importer
+-
+-import "example.com/issue61635" // importing is necessary to repro golang/go#61635
+-
+-var _ issue61635.ElemData[string]
+-
+--- @SToT/issue61635/p.go --
+-package issue61635
+-
+-type builder[T ~[]F, F ~string] struct { //@rename("S", "T", SToT)
+-	name string
+-	elements T
+-	elemData map[F][]ElemData[F]
+-	// other fields...
+-}
+-
+-type ElemData[F ~string] struct {
+-  Name F
+-  // other fields...
+-}
+-
+-type BuilderImpl[S ~[]F, F ~string] struct{ builder[S, F] }
+-
+--- instances/type.go --
+-package instances
+-
+-type R[P any] struct { //@rename("R", "u", Rtou)
+-	Next *R[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv R[P]) Do(R[P]) R[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x R[P]
+-	return rv.Do(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x R[int] //@rename("R", "r", RTor)
+-	x = x.Do(x)
+-}
+-
+--- @RTos/instances/type.go --
+-package instances
+-
+-type s[P any] struct { //@rename("R", "u", Rtou)
+-	Next *s[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv s[P]) Do(s[P]) s[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x s[P]
+-	return rv.Do(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x s[int] //@rename("R", "r", RTor)
+-	x = x.Do(x)
+-}
+-
+--- @Rtou/instances/type.go --
+-package instances
+-
+-type u[P any] struct { //@rename("R", "u", Rtou)
+-	Next *u[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv u[P]) Do(u[P]) u[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x u[P]
+-	return rv.Do(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x u[int] //@rename("R", "r", RTor)
+-	x = x.Do(x)
+-}
+-
+--- @DoToDo1/instances/type.go --
+-package instances
+-
+-type R[P any] struct { //@rename("R", "u", Rtou)
+-	Next *R[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv R[P]) Do1(R[P]) R[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x R[P]
+-	return rv.Do1(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x R[int] //@rename("R", "r", RTor)
+-	x = x.Do1(x)
+-}
+-
+--- @DoToDo2/instances/type.go --
+-package instances
+-
+-type R[P any] struct { //@rename("R", "u", Rtou)
+-	Next *R[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv R[P]) Do2(R[P]) R[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x R[P]
+-	return rv.Do2(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x R[int] //@rename("R", "r", RTor)
+-	x = x.Do2(x)
+-}
+-
+--- instances/func.go --
+-package instances
+-
+-func Foo[P any](p P) { //@rename("Foo", "Bar", FooToBar)
+-	Foo(p) //@rename("Foo", "Baz", FooToBaz)
+-}
+-
+--- @FooToBar/instances/func.go --
+-package instances
+-
+-func Bar[P any](p P) { //@rename("Foo", "Bar", FooToBar)
+-	Bar(p) //@rename("Foo", "Baz", FooToBaz)
+-}
+-
+--- @FooToBaz/instances/func.go --
+-package instances
+-
+-func Baz[P any](p P) { //@rename("Foo", "Bar", FooToBar)
+-	Baz(p) //@rename("Foo", "Baz", FooToBaz)
+-}
+-
+--- @RTor/instances/type.go --
+-package instances
+-
+-type r[P any] struct { //@rename("R", "u", Rtou)
+-	Next *r[P] //@rename("R", "s", RTos)
+-}
+-
+-func (rv r[P]) Do(r[P]) r[P] { //@rename("Do", "Do1", DoToDo1)
+-	var x r[P]
+-	return rv.Do(x) //@rename("Do", "Do2", DoToDo2)
+-}
+-
+-func _() {
+-	var x r[int] //@rename("R", "r", RTor)
+-	x = x.Do(x)
+-}
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/issue60789.txt b/gopls/internal/regtest/marker/testdata/rename/issue60789.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/issue60789.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/issue60789.txt	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
+-
+-This test renames an exported method of an unexported type,
+-which is an edge case for objectpath, since it computes a path
+-from a syntax package that is no good when applied to an
+-export data package.
+-
+-See issue #60789.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-type unexported int
+-func (unexported) F() {} //@rename("F", "G", fToG)
+-
+-var _ = unexported(0).F
+-
+--- b/b.go --
+-package b
+-
+-// The existence of this package is sufficient to exercise
+-// the bug even though it cannot reference a.unexported.
+-
+-import _ "example.com/a"
+-
+--- @fToG/a/a.go --
+-package a
+-
+-type unexported int
+-func (unexported) G() {} //@rename("F", "G", fToG)
+-
+-var _ = unexported(0).G
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/issue61294.txt b/gopls/internal/regtest/marker/testdata/rename/issue61294.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/issue61294.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/issue61294.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-
+-This test renames a parameter var whose name is the same as a
+-package-level var, which revealed a bug in isLocal.
+-
+-This is a regression test for issue #61294.
+-
+--- go.mod --
+-module example.com
+-go 1.18
+-
+--- a/a.go --
+-package a
+-
+-func One()
+-
+-func Two(One int) //@rename("One", "Three", OneToThree)
+-
+--- b/b.go --
+-package b
+-
+-import _ "example.com/a"
+-
+--- @OneToThree/a/a.go --
+-package a
+-
+-func One()
+-
+-func Two(Three int) //@rename("One", "Three", OneToThree)
+-
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/issue61640.txt b/gopls/internal/regtest/marker/testdata/rename/issue61640.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/issue61640.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/issue61640.txt	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
+-This test verifies that gopls can rename instantiated fields.
+-
+--- flags --
+--min_go=go1.18
+-
+--- a.go --
+-package a
+-
+-// This file is adapted from the example in the issue.
+-
+-type builder[S ~[]int] struct {
+-	elements S //@rename("elements", "elements2", OneToTwo)
+-}
+-
+-type BuilderImpl[S ~[]int] struct{ builder[S] }
+-
+-func NewBuilderImpl[S ~[]int](name string)  *BuilderImpl[S] {
+-  impl := &BuilderImpl[S]{
+-	builder[S]{
+-	  elements: S{},
+-	},
+-  }
+-
+-  _ = impl.elements
+-  return impl
+-}
+--- @OneToTwo/a.go --
+-package a
+-
+-// This file is adapted from the example in the issue.
+-
+-type builder[S ~[]int] struct {
+-	elements2 S //@rename("elements", "elements2", OneToTwo)
+-}
+-
+-type BuilderImpl[S ~[]int] struct{ builder[S] }
+-
+-func NewBuilderImpl[S ~[]int](name string)  *BuilderImpl[S] {
+-  impl := &BuilderImpl[S]{
+-	builder[S]{
+-	  elements2: S{},
+-	},
+-  }
+-
+-  _ = impl.elements2
+-  return impl
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/issue61813.txt b/gopls/internal/regtest/marker/testdata/rename/issue61813.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/issue61813.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/issue61813.txt	1970-01-01 08:00:00
+@@ -1,18 +0,0 @@
+-This test exercises the panic reported in golang/go#61813.
+-
+--- p.go --
+-package p
+-
+-type P struct{}
+-
+-func (P) M() {} //@rename("M", "N", MToN)
+-
+-var x = []*P{{}}
+--- @MToN/p.go --
+-package p
+-
+-type P struct{}
+-
+-func (P) N() {} //@rename("M", "N", MToN)
+-
+-var x = []*P{{}}
 diff -urN a/gopls/internal/regtest/marker/testdata/rename/methods.txt b/gopls/internal/regtest/marker/testdata/rename/methods.txt
 --- a/gopls/internal/regtest/marker/testdata/rename/methods.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/rename/methods.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/rename/methods.txt	1970-01-01 08:00:00
 @@ -1,67 +0,0 @@
 -This test exercises renaming of interface methods.
 -
@@ -114131,7 +126384,7 @@
 -
 -type A int
 -
--func (A) F() {} //@renameerr("F", G, errAfToG)
+-func (A) F() {} //@renameerr("F", "G", errAfToG)
 -
 --- b/b.go --
 -package b
@@ -114139,7 +126392,7 @@
 -import "example.com/a"
 -import "example.com/c"
 -
--type B interface { F() } //@rename("F", G, BfToG)
+-type B interface { F() } //@rename("F", "G", BfToG)
 -
 -var _ B = a.A(0)
 -var _ B = c.C(0)
@@ -114149,7 +126402,7 @@
 -
 -type C int
 -
--func (C) F() {} //@renameerr("F", G, errCfToG)
+-func (C) F() {} //@renameerr("F", "G", errCfToG)
 -
 --- d/d.go --
 -package d
@@ -114168,7 +126421,7 @@
 -import "example.com/a"
 -import "example.com/c"
 -
--type B interface { G() } //@rename("F", G, BfToG)
+-type B interface { G() } //@rename("F", "G", BfToG)
 -
 -var _ B = a.A(0)
 -var _ B = c.C(0)
@@ -114186,7 +126439,7 @@
 -b/b.go:6:20:	(rename example.com/b.B.F if you intend to change both types)
 diff -urN a/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt
 --- a/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/rename/typeswitch.txt	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -This test covers the special case of renaming a type switch var.
 -
@@ -114194,11 +126447,11 @@
 -package p
 -
 -func _(x interface{}) {
--	switch y := x.(type) { //@rename("y", z, yToZ)
+-	switch y := x.(type) { //@rename("y", "z", yToZ)
 -	case string:
--		print(y) //@rename("y", z, yToZ)
+-		print(y) //@rename("y", "z", yToZ)
 -	default:
--		print(y) //@rename("y", z, yToZ)
+-		print(y) //@rename("y", "z", yToZ)
 -	}
 -}
 -
@@ -114206,17 +126459,46 @@
 -package p
 -
 -func _(x interface{}) {
--	switch z := x.(type) { //@rename("y", z, yToZ)
+-	switch z := x.(type) { //@rename("y", "z", yToZ)
 -	case string:
--		print(z) //@rename("y", z, yToZ)
+-		print(z) //@rename("y", "z", yToZ)
 -	default:
--		print(z) //@rename("y", z, yToZ)
+-		print(z) //@rename("y", "z", yToZ)
 -	}
 -}
 -
+diff -urN a/gopls/internal/regtest/marker/testdata/rename/unexported.txt b/gopls/internal/regtest/marker/testdata/rename/unexported.txt
+--- a/gopls/internal/regtest/marker/testdata/rename/unexported.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/rename/unexported.txt	1970-01-01 08:00:00
+@@ -1,25 +0,0 @@
+-
+-This test attempts to rename a.S.X to x, which would make it
+-inaccessible from its external test package. The rename tool
+-should report an error rather than wrecking the program.
+-See issue #59403.
+-
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a/a.go --
+-package a
+-
+-var S struct{ X int } //@renameerr("X", "x", oops)
+-
+--- a/a_test.go --
+-package a_test
+-
+-import "example.com/a"
+-
+-var Y = a.S.X
+-
+--- @oops --
+-a/a.go:3:15: renaming "X" to "x" would make it unexported
+-a/a_test.go:5:13:	breaking references from packages such as "example.com/a_test"
 diff -urN a/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt
 --- a/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/marker/testdata/stubmethods/basic.txt	1970-01-01 08:00:00
 @@ -1,24 +0,0 @@
 -This test exercises basic 'stub methods' functionality.
 -
@@ -114229,22 +126511,648 @@
 -
 -type C int
 -
--var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub)
+-var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "quickfix", stub)
 -
 --- @stub/a/a.go --
 -package a
 -
 -type C int
 -
--// Error implements error
+-// Error implements error.
 -func (C) Error() string {
 -	panic("unimplemented")
 -}
 -
--var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "refactor.rewrite", stub)
+-var _ error = C(0) //@suggestedfix(re"C.0.", re"missing method Error", "quickfix", stub)
+diff -urN a/gopls/internal/regtest/marker/testdata/stubmethods/issue61693.txt b/gopls/internal/regtest/marker/testdata/stubmethods/issue61693.txt
+--- a/gopls/internal/regtest/marker/testdata/stubmethods/issue61693.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/stubmethods/issue61693.txt	1970-01-01 08:00:00
+@@ -1,35 +0,0 @@
+-This test exercises stub methods functionality with variadic parameters.
+-
+-In golang/go#61693 stubmethods was panicking in this case.
+-
+--- go.mod --
+-module mod.com
+-
+-go 1.18
+--- main.go --
+-package main
+-
+-type C int
+-
+-func F(err ...error) {}
+-
+-func _() {
+-	var x error
+-	F(x, C(0)) //@suggestedfix(re"C.0.", re"missing method Error", "quickfix", stub)
+-}
+--- @stub/main.go --
+-package main
+-
+-type C int
+-
+-// Error implements error.
+-func (C) Error() string {
+-	panic("unimplemented")
+-}
+-
+-func F(err ...error) {}
+-
+-func _() {
+-	var x error
+-	F(x, C(0)) //@suggestedfix(re"C.0.", re"missing method Error", "quickfix", stub)
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/stubmethods/issue61830.txt b/gopls/internal/regtest/marker/testdata/stubmethods/issue61830.txt
+--- a/gopls/internal/regtest/marker/testdata/stubmethods/issue61830.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/stubmethods/issue61830.txt	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
+-This test verifies that method stubbing qualifies types relative to the current
+-package.
+-
+--- p.go --
+-package p
+-
+-import "io"
+-
+-type B struct{}
+-
+-type I interface {
+-	M(io.Reader, B)
+-}
+-
+-type A struct{}
+-
+-var _ I = &A{} //@suggestedfix(re"&A..", re"missing method M", "quickfix", stub)
+--- @stub/p.go --
+-package p
+-
+-import "io"
+-
+-type B struct{}
+-
+-type I interface {
+-	M(io.Reader, B)
+-}
+-
+-type A struct{}
+-
+-// M implements I.
+-func (*A) M(io.Reader, B) {
+-	panic("unimplemented")
+-}
+-
+-var _ I = &A{} //@suggestedfix(re"&A..", re"missing method M", "quickfix", stub)
+diff -urN a/gopls/internal/regtest/marker/testdata/symbol/basic.txt b/gopls/internal/regtest/marker/testdata/symbol/basic.txt
+--- a/gopls/internal/regtest/marker/testdata/symbol/basic.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/symbol/basic.txt	1970-01-01 08:00:00
+@@ -1,114 +0,0 @@
+-Basic tests of textDocument/documentSymbols.
+-
+--- symbol.go --
+-package main
+-
+-//@symbol(want)
+-
+-import "io"
+-
+-var _ = 1
+-
+-var x = 42
+-
+-var nested struct {
+-	nestedField struct {
+-		f int
+-	}
+-}
+-
+-const y = 43
+-
+-type Number int
+-
+-type Alias = string
+-
+-type NumberAlias = Number
+-
+-type (
+-	Boolean   bool
+-	BoolAlias = bool
+-)
+-
+-type Foo struct {
+-	Quux
+-	W         io.Writer
+-	Bar       int
+-	baz       string
+-	funcField func(int) int
+-}
+-
+-type Quux struct {
+-	X, Y float64
+-}
+-
+-type EmptyStruct struct{}
+-
+-func (f Foo) Baz() string {
+-	return f.baz
+-}
+-
+-func _() {}
+-
+-func (q *Quux) Do() {}
+-
+-func main() {
+-}
+-
+-type Stringer interface {
+-	String() string
+-}
+-
+-type ABer interface {
+-	B()
+-	A() string
+-}
+-
+-type WithEmbeddeds interface {
+-	Do()
+-	ABer
+-	io.Writer
+-}
+-
+-type EmptyInterface interface{}
+-
+-func Dunk() int { return 0 }
+-
+-func dunk() {}
+-
+--- @want --
+-(*Quux).Do "func()"
+-(Foo).Baz "func() string" +2 lines
+-ABer "interface{...}" +3 lines
+-ABer.A "func() string"
+-ABer.B "func()"
+-Alias "string"
+-BoolAlias "bool"
+-Boolean "bool"
+-Dunk "func() int"
+-EmptyInterface "interface{}"
+-EmptyStruct "struct{}"
+-Foo "struct{...}" +6 lines
+-Foo.Bar "int"
+-Foo.Quux "Quux"
+-Foo.W "io.Writer"
+-Foo.baz "string"
+-Foo.funcField "func(int) int"
+-Number "int"
+-NumberAlias "Number"
+-Quux "struct{...}" +2 lines
+-Quux.X "float64"
+-Quux.Y "float64"
+-Stringer "interface{...}" +2 lines
+-Stringer.String "func() string"
+-WithEmbeddeds "interface{...}" +4 lines
+-WithEmbeddeds.ABer "ABer"
+-WithEmbeddeds.Do "func()"
+-WithEmbeddeds.Writer "io.Writer"
+-dunk "func()"
+-main "func()" +1 lines
+-nested "struct{...}" +4 lines
+-nested.nestedField "struct{...}" +2 lines
+-nested.nestedField.f "int"
+-x ""
+-y ""
+diff -urN a/gopls/internal/regtest/marker/testdata/symbol/generic.txt b/gopls/internal/regtest/marker/testdata/symbol/generic.txt
+--- a/gopls/internal/regtest/marker/testdata/symbol/generic.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/symbol/generic.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-Basic tests of textDocument/documentSymbols with generics.
+-
+--- flags --
+--min_go=go1.18
+-
+--- symbol.go --
+-//@symbol(want)
+-
+-//go:build go1.18
+-// +build go1.18
+-
+-package main
+-
+-type T[P any] struct {
+-	F P
+-}
+-
+-type Constraint interface {
+-	~int | struct{ int }
+-	interface{ M() }
+-}
+-
+--- @want --
+-Constraint "interface{...}" +3 lines
+-Constraint.interface{...} ""
+-Constraint.interface{...}.M "func()"
+-Constraint.~int | struct{int} ""
+-T "struct{...}" +2 lines
+-T.F "P"
+diff -urN a/gopls/internal/regtest/marker/testdata/typedef/typedef.txt b/gopls/internal/regtest/marker/testdata/typedef/typedef.txt
+--- a/gopls/internal/regtest/marker/testdata/typedef/typedef.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/typedef/typedef.txt	1970-01-01 08:00:00
+@@ -1,68 +0,0 @@
+-This test exercises the textDocument/typeDefinition action.
+-
+--- typedef.go --
+-package typedef
+-
+-type Struct struct { //@loc(Struct, "Struct"),
+-	Field string
+-}
+-
+-type Int int //@loc(Int, "Int")
+-
+-func _() {
+-	var (
+-		value Struct
+-		point *Struct
+-	)
+-	_ = value //@typedef("value", Struct)
+-	_ = point //@typedef("point", Struct)
+-
+-	var (
+-		array   [3]Struct
+-		slice   []Struct
+-		ch      chan Struct
+-		complex [3]chan *[5][]Int
+-	)
+-	_ = array   //@typedef("array", Struct)
+-	_ = slice   //@typedef("slice", Struct)
+-	_ = ch      //@typedef("ch", Struct)
+-	_ = complex //@typedef("complex", Int)
+-
+-	var s struct {
+-		x struct {
+-			xx struct {
+-				field1 []Struct
+-				field2 []Int
+-			}
+-		}
+-	}
+-	_ = s.x.xx.field1 //@typedef("field1", Struct)
+-	_ = s.x.xx.field2 //@typedef("field2", Int)
+-}
+-
+-func F1() Int                              { return 0 }
+-func F2() (Int, float64)                   { return 0, 0 }
+-func F3() (Struct, int, bool, error)       { return Struct{}, 0, false, nil }
+-func F4() (**int, Int, bool, *error)       { return nil, 0, false, nil }
+-func F5() (int, float64, error, Struct)    { return 0, 0, nil, Struct{} }
+-func F6() (int, float64, ***Struct, error) { return 0, 0, nil, nil }
+-
+-func _() {
+-	F1() //@typedef("F1", Int)
+-	F2() //@typedef("F2", Int)
+-	F3() //@typedef("F3", Struct)
+-	F4() //@typedef("F4", Int)
+-	F5() //@typedef("F5", Struct)
+-	F6() //@typedef("F6", Struct)
+-
+-	f := func() Int { return 0 }
+-	f() //@typedef("f", Int)
+-}
+-
+-// https://github.com/golang/go/issues/38589#issuecomment-620350922
+-func _() {
+-	type myFunc func(int) Int //@loc(myFunc, "myFunc")
+-
+-	var foo myFunc
+-	_ = foo() //@typedef("foo", myFunc), diag(")", re"not enough arguments")
+-}
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/allscope.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/allscope.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/allscope.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/allscope.txt	1970-01-01 08:00:00
+@@ -1,30 +0,0 @@
+-This test verifies behavior when "symbolScope" is set to "all".
+-
+--- settings.json --
+-{
+-	"symbolStyle": "full",
+-	"symbolMatcher": "casesensitive",
+-	"symbolScope": "all"
+-}
+-
+--- go.mod --
+-module mod.test/symbols
+-
+-go 1.18
+-
+--- query.go --
+-package symbols
+-
+-//@workspacesymbol("fmt.Println", println)
+-
+--- fmt/fmt.go --
+-package fmt
+-
+-import "fmt"
+-
+-func Println(s string) {
+-	fmt.Println(s)
+-}
+--- @println --
+-fmt/fmt.go:5:6-13 mod.test/symbols/fmt.Println Function
+-<unknown> fmt.Println Function
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/caseinsensitive.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/caseinsensitive.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/caseinsensitive.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/caseinsensitive.txt	1970-01-01 08:00:00
+@@ -1,26 +0,0 @@
+-This file contains test for symbol matches using the caseinsensitive matcher.
+-
+--- settings.json --
+-{
+-	"symbolMatcher": "caseinsensitive"
+-}
+-
+--- go.mod --
+-module mod.test/caseinsensitive
+-
+-go 1.18
+-
+--- p.go --
+-package caseinsensitive
+-
+-//@workspacesymbol("", blank)
+-//@workspacesymbol("randomgophervar", randomgophervar)
+-
+-var RandomGopherVariableA int
+-var randomgopherVariableB int
+-var RandomGopherOtherVariable int
+-
+--- @blank --
+--- @randomgophervar --
+-p.go:6:5-26 RandomGopherVariableA Variable
+-p.go:7:5-26 randomgopherVariableB Variable
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/casesensitive.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/casesensitive.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/casesensitive.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/casesensitive.txt	1970-01-01 08:00:00
+@@ -1,116 +0,0 @@
+-This file contains tests for symbol matches using the casesensitive matcher.
+-
+-For historical reasons, it also verifies general behavior of the symbol search.
+-
+--- settings.json --
+-{
+-	"symbolMatcher": "casesensitive"
+-}
+-
+--- go.mod --
+-module mod.test/casesensitive
+-
+-go 1.18
+-
+--- main.go --
+-package main
+-
+-//@workspacesymbol("main.main", main)
+-//@workspacesymbol("p.Message", Message)
+-//@workspacesymbol("main.myvar", myvar)
+-//@workspacesymbol("main.myType", myType)
+-//@workspacesymbol("main.myType.Blahblah", blahblah)
+-//@workspacesymbol("main.myStruct", myStruct)
+-//@workspacesymbol("main.myStruct.myStructField", myStructField)
+-//@workspacesymbol("main.myInterface", myInterface)
+-//@workspacesymbol("main.myInterface.DoSomeCoolStuff", DoSomeCoolStuff)
+-//@workspacesymbol("main.embed.myStruct", embeddedStruct)
+-//@workspacesymbol("main.embed.nestedStruct.nestedStruct2.int", int)
+-//@workspacesymbol("main.embed.nestedInterface.myInterface", nestedInterface)
+-//@workspacesymbol("main.embed.nestedInterface.nestedMethod", nestedMethod)
+-//@workspacesymbol("dunk", dunk)
+-//@workspacesymbol("Dunk", Dunk)
+-
+-import (
+-	"encoding/json"
+-	"fmt"
+-)
+-
+-func main() { // function
+-	fmt.Println("Hello")
+-}
+-
+-var myvar int // variable
+-
+-type myType string // basic type
+-
+-type myDecoder json.Decoder // to use the encoding/json import
+-
+-func (m *myType) Blahblah() {} // method
+-
+-type myStruct struct { // struct type
+-	myStructField int // struct field
+-}
+-
+-type myInterface interface { // interface
+-	DoSomeCoolStuff() string // interface method
+-}
+-
+-type embed struct {
+-	myStruct
+-
+-	nestedStruct struct {
+-		nestedField int
+-
+-		nestedStruct2 struct {
+-			int
+-		}
+-	}
+-
+-	nestedInterface interface {
+-		myInterface
+-		nestedMethod()
+-	}
+-}
+-
+-func Dunk() int { return 0 }
+-
+-func dunk() {}
+-
+--- p/p.go --
+-package p
+-
+-const Message = "Hello World." // constant
+--- @DoSomeCoolStuff --
+-main.go:41:2-17 main.myInterface.DoSomeCoolStuff Method
+--- @Dunk --
+-main.go:61:6-10 Dunk Function
+--- @Message --
+-p/p.go:3:7-14 p.Message Constant
+--- @blahblah --
+-main.go:34:18-26 main.myType.Blahblah Method
+--- @dunk --
+-main.go:63:6-10 dunk Function
+--- @int --
+-main.go:51:4-7 main.embed.nestedStruct.nestedStruct2.int Field
+--- @main --
+-main.go:24:6-10 main.main Function
+--- @myInterface --
+-main.go:40:6-17 main.myInterface Interface
+-main.go:41:2-17 main.myInterface.DoSomeCoolStuff Method
+--- @myStruct --
+-main.go:36:6-14 main.myStruct Struct
+-main.go:37:2-15 main.myStruct.myStructField Field
+--- @myStructField --
+-main.go:37:2-15 main.myStruct.myStructField Field
+--- @myType --
+-main.go:30:6-12 main.myType Class
+-main.go:34:18-26 main.myType.Blahblah Method
+--- @myvar --
+-main.go:28:5-10 main.myvar Variable
+--- @nestedInterface --
+-main.go:56:3-14 main.embed.nestedInterface.myInterface Interface
+--- @nestedMethod --
+-main.go:57:3-15 main.embed.nestedInterface.nestedMethod Method
+--- @embeddedStruct --
+-main.go:45:2-10 main.embed.myStruct Field
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/issue44806.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/issue44806.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/issue44806.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/issue44806.txt	1970-01-01 08:00:00
+@@ -1,27 +0,0 @@
+-This test verifies the fix for the crash encountered in golang/go#44806.
+-
+--- go.mod --
+-module mod.test/symbol
+-
+-go 1.18
+--- symbol.go --
+-package symbol
+-
+-//@workspacesymbol("m", m)
+-
+-type T struct{}
+-
+-// We should accept all valid receiver syntax when scanning symbols.
+-func (*(T)) m1() {}
+-func (*T) m2()   {}
+-func (T) m3()    {}
+-func ((T)) m4()    {}
+-func ((*T)) m5()   {}
+-
+--- @m --
+-symbol.go:8:13-15 T.m1 Method
+-symbol.go:9:11-13 T.m2 Method
+-symbol.go:10:10-12 T.m3 Method
+-symbol.go:11:12-14 T.m4 Method
+-symbol.go:12:13-15 T.m5 Method
+-symbol.go:5:6-7 symbol.T Struct
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/workspacesymbol.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/workspacesymbol.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/workspacesymbol.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/workspacesymbol.txt	1970-01-01 08:00:00
+@@ -1,72 +0,0 @@
+-This test contains tests for basic functionality of the workspace/symbol
+-request.
+-
+-TODO(rfindley): add a test for the legacy 'fuzzy' symbol matcher using setting ("symbolMatcher": "fuzzy"). This test uses the default matcher ("fastFuzzy").
+-
+--- go.mod --
+-module mod.test/symbols
+-
+-go 1.18
+-
+--- query.go --
+-package symbols
+-
+-//@workspacesymbol("rgop", rgop)
+-//@workspacesymbol("randoma", randoma)
+-//@workspacesymbol("randomb", randomb)
+-
+--- a/a.go --
+-package a
+-
+-var RandomGopherVariableA = "a"
+-
+-const RandomGopherConstantA = "a"
+-
+-const (
+-	randomgopherinvariable = iota
+-)
+-
+--- a/a_test.go --
+-package a
+-
+-var RandomGopherTestVariableA = "a"
+-
+--- a/a_x_test.go --
+-package a_test
+-
+-var RandomGopherXTestVariableA = "a"
+-
+--- b/b.go --
+-package b
+-
+-var RandomGopherVariableB = "b"
+-
+-type RandomGopherStructB struct {
+-	Bar int
+-}
+-
+--- @rgop --
+-b/b.go:5:6-25 RandomGopherStructB Struct
+-a/a.go:5:7-28 RandomGopherConstantA Constant
+-a/a.go:3:5-26 RandomGopherVariableA Variable
+-b/b.go:3:5-26 RandomGopherVariableB Variable
+-a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+-a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+-a/a.go:8:2-24 randomgopherinvariable Constant
+-b/b.go:6:2-5 RandomGopherStructB.Bar Field
+--- @randoma --
+-a/a.go:5:7-28 RandomGopherConstantA Constant
+-a/a.go:3:5-26 RandomGopherVariableA Variable
+-b/b.go:3:5-26 RandomGopherVariableB Variable
+-a/a.go:8:2-24 randomgopherinvariable Constant
+-a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+-a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+-b/b.go:6:2-5 RandomGopherStructB.Bar Field
+--- @randomb --
+-b/b.go:5:6-25 RandomGopherStructB Struct
+-a/a.go:3:5-26 RandomGopherVariableA Variable
+-b/b.go:3:5-26 RandomGopherVariableB Variable
+-a/a.go:8:2-24 randomgopherinvariable Constant
+-a/a_test.go:3:5-30 RandomGopherTestVariableA Variable
+-a/a_x_test.go:3:5-31 RandomGopherXTestVariableA Variable
+-b/b.go:6:2-5 RandomGopherStructB.Bar Field
+diff -urN a/gopls/internal/regtest/marker/testdata/workspacesymbol/wsscope.txt b/gopls/internal/regtest/marker/testdata/workspacesymbol/wsscope.txt
+--- a/gopls/internal/regtest/marker/testdata/workspacesymbol/wsscope.txt	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/marker/testdata/workspacesymbol/wsscope.txt	1970-01-01 08:00:00
+@@ -1,29 +0,0 @@
+-This test verifies behavior when "symbolScope" is set to "workspace".
+-
+--- settings.json --
+-{
+-	"symbolStyle": "full",
+-	"symbolMatcher": "casesensitive",
+-	"symbolScope": "workspace"
+-}
+-
+--- go.mod --
+-module mod.test/symbols
+-
+-go 1.18
+-
+--- query.go --
+-package symbols
+-
+-//@workspacesymbol("fmt.Println", println)
+-
+--- fmt/fmt.go --
+-package fmt
+-
+-import "fmt"
+-
+-func Println(s string) {
+-	fmt.Println(s)
+-}
+--- @println --
+-fmt/fmt.go:5:6-13 mod.test/symbols/fmt.Println Function
 diff -urN a/gopls/internal/regtest/misc/call_hierarchy_test.go b/gopls/internal/regtest/misc/call_hierarchy_test.go
 --- a/gopls/internal/regtest/misc/call_hierarchy_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/call_hierarchy_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/call_hierarchy_test.go	1970-01-01 08:00:00
 @@ -1,35 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -114283,8 +127191,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/configuration_test.go b/gopls/internal/regtest/misc/configuration_test.go
 --- a/gopls/internal/regtest/misc/configuration_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/configuration_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,159 +0,0 @@
++++ b/gopls/internal/regtest/misc/configuration_test.go	1970-01-01 08:00:00
+@@ -1,153 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -114329,10 +127237,8 @@
 -		cfg.Settings = map[string]interface{}{
 -			"staticcheck": true,
 -		}
--		// TODO(rfindley): support waiting on diagnostics following a configuration
--		// change.
 -		env.ChangeConfiguration(cfg)
--		env.Await(
+-		env.AfterChange(
 -			Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")),
 -		)
 -	})
@@ -114344,9 +127250,7 @@
 -//
 -// Gopls should not get confused about buffer content when recreating the view.
 -func TestMajorOptionsChange(t *testing.T) {
--	t.Skip("broken due to golang/go#57934")
--
--	testenv.NeedsGo1Point(t, 17)
+-	testenv.NeedsGo1Point(t, 19) // needs staticcheck
 -
 -	const files = `
 --- go.mod --
@@ -114378,10 +127282,8 @@
 -		cfg.Settings = map[string]interface{}{
 -			"staticcheck": true,
 -		}
--		// TODO(rfindley): support waiting on diagnostics following a configuration
--		// change.
 -		env.ChangeConfiguration(cfg)
--		env.Await(
+-		env.AfterChange(
 -			Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)")),
 -		)
 -	})
@@ -114446,7 +127348,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/debugserver_test.go b/gopls/internal/regtest/misc/debugserver_test.go
 --- a/gopls/internal/regtest/misc/debugserver_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/debugserver_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/debugserver_test.go	1970-01-01 08:00:00
 @@ -1,46 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -114496,8 +127398,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/definition_test.go b/gopls/internal/regtest/misc/definition_test.go
 --- a/gopls/internal/regtest/misc/definition_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/definition_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,512 +0,0 @@
++++ b/gopls/internal/regtest/misc/definition_test.go	1970-01-01 08:00:00
+@@ -1,571 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -114851,7 +127753,7 @@
 -			Run(t, mod, func(t *testing.T, env *Env) {
 -				env.OpenFile("main.go")
 -
--				loc, err := env.Editor.GoToTypeDefinition(env.Ctx, env.RegexpSearch("main.go", tt.re))
+-				loc, err := env.Editor.TypeDefinition(env.Ctx, env.RegexpSearch("main.go", tt.re))
 -				if tt.wantError {
 -					if err == nil {
 -						t.Fatal("expected error, got nil")
@@ -114871,6 +127773,25 @@
 -	}
 -}
 -
+-func TestGoToTypeDefinition_Issue60544(t *testing.T) {
+-	const mod = `
+--- go.mod --
+-module mod.com
+-
+-go 1.19
+--- main.go --
+-package main
+-
+-func F[T comparable]() {}
+-`
+-
+-	Run(t, mod, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-
+-		_ = env.TypeDefinition(env.RegexpSearch("main.go", "comparable")) // must not panic
+-	})
+-}
+-
 -// Test for golang/go#47825.
 -func TestImportTestVariant(t *testing.T) {
 -	const mod = `
@@ -114976,7 +127897,7 @@
 -		}
 -
 -		// Run 'go mod vendor' outside the editor.
--		if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, true); err != nil {
+-		if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, nil, true); err != nil {
 -			t.Fatalf("go mod vendor: %v", err)
 -		}
 -
@@ -115010,9 +127931,49 @@
 -		}
 -	})
 -}
+-
+-const embedDefinition = `
+--- go.mod --
+-module mod.com
+-
+--- main.go --
+-package main
+-
+-import (
+-	"embed"
+-)
+-
+-//go:embed *.txt
+-var foo embed.FS
+-
+-func main() {}
+-
+--- skip.sql --
+-SKIP
+-
+--- foo.txt --
+-FOO
+-
+--- skip.bat --
+-SKIP
+-`
+-
+-func TestGoToEmbedDefinition(t *testing.T) {
+-	Run(t, embedDefinition, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-
+-		start := env.RegexpSearch("main.go", `\*.txt`)
+-		loc := env.GoToDefinition(start)
+-
+-		name := env.Sandbox.Workdir.URIToPath(loc.URI)
+-		if want := "foo.txt"; name != want {
+-			t.Errorf("GoToDefinition: got file %q, want %q", name, want)
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/misc/embed_test.go b/gopls/internal/regtest/misc/embed_test.go
 --- a/gopls/internal/regtest/misc/embed_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/embed_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/embed_test.go	1970-01-01 08:00:00
 @@ -1,40 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -115056,7 +128017,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/extract_test.go b/gopls/internal/regtest/misc/extract_test.go
 --- a/gopls/internal/regtest/misc/extract_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/extract_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/extract_test.go	1970-01-01 08:00:00
 @@ -1,65 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -115125,8 +128086,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/failures_test.go b/gopls/internal/regtest/misc/failures_test.go
 --- a/gopls/internal/regtest/misc/failures_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/failures_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,84 +0,0 @@
++++ b/gopls/internal/regtest/misc/failures_test.go	1970-01-01 08:00:00
+@@ -1,82 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -115144,7 +128105,6 @@
 -// that includes a line directive, which makes no difference since
 -// gopls ignores line directives.
 -func TestHoverFailure(t *testing.T) {
--	t.Skip("line directives //line ")
 -	const mod = `
 --- go.mod --
 -module mod.com
@@ -115177,7 +128137,6 @@
 -// This test demonstrates a case where gopls is not at all confused by
 -// line directives, because it completely ignores them.
 -func TestFailingDiagnosticClearingOnEdit(t *testing.T) {
--	t.Skip("line directives //line ")
 -	// badPackageDup contains a duplicate definition of the 'a' const.
 -	// This is a minor variant of TestDiagnosticClearingOnEdit from
 -	// diagnostics_test.go, with a line directive, which makes no difference.
@@ -115213,7 +128172,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/fix_test.go b/gopls/internal/regtest/misc/fix_test.go
 --- a/gopls/internal/regtest/misc/fix_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/fix_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/fix_test.go	1970-01-01 08:00:00
 @@ -1,103 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -115320,8 +128279,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/formatting_test.go b/gopls/internal/regtest/misc/formatting_test.go
 --- a/gopls/internal/regtest/misc/formatting_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/formatting_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,368 +0,0 @@
++++ b/gopls/internal/regtest/misc/formatting_test.go	1970-01-01 08:00:00
+@@ -1,395 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -115690,10 +128649,37 @@
 -		}
 -	})
 -}
+-
+-func TestGofumpt_Issue61692(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 21)
+-
+-	const input = `
+--- go.mod --
+-module foo
+-
+-go 1.21rc3
+--- foo.go --
+-package foo
+-
+-func _() {
+-	foo :=
+-		"bar"
+-}
+-`
+-
+-	WithOptions(
+-		Settings{
+-			"gofumpt": true,
+-		},
+-	).Run(t, input, func(t *testing.T, env *Env) {
+-		env.OpenFile("foo.go")
+-		env.FormatBuffer("foo.go") // golang/go#61692: must not panic
+-	})
+-}
 diff -urN a/gopls/internal/regtest/misc/generate_test.go b/gopls/internal/regtest/misc/generate_test.go
 --- a/gopls/internal/regtest/misc/generate_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/generate_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,72 +0,0 @@
++++ b/gopls/internal/regtest/misc/generate_test.go	1970-01-01 08:00:00
+@@ -1,71 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -115723,12 +128709,11 @@
 -package main
 -
 -import (
--	"io/ioutil"
 -	"os"
 -)
 -
 -func main() {
--	ioutil.WriteFile("generated.go", []byte("package " + os.Args[1] + "\n\nconst Answer = 21"), 0644)
+-	os.WriteFile("generated.go", []byte("package " + os.Args[1] + "\n\nconst Answer = 21"), 0644)
 -}
 -
 --- lib1/lib.go --
@@ -115768,7 +128753,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/highlight_test.go b/gopls/internal/regtest/misc/highlight_test.go
 --- a/gopls/internal/regtest/misc/highlight_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/highlight_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/highlight_test.go	1970-01-01 08:00:00
 @@ -1,153 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -115925,8 +128910,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/hover_test.go b/gopls/internal/regtest/misc/hover_test.go
 --- a/gopls/internal/regtest/misc/hover_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/hover_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,384 +0,0 @@
++++ b/gopls/internal/regtest/misc/hover_test.go	1970-01-01 08:00:00
+@@ -1,493 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -116013,12 +128998,6 @@
 -}
 -
 -func TestHoverIntLiteral(t *testing.T) {
--	// TODO(rfindley): this behavior doesn't actually make sense for vars. It is
--	// misleading to format their value when it is (of course) variable.
--	//
--	// Instead, we should allow hovering on numeric literals.
--	t.Skip("golang/go#58220: broken due to new hover logic")
--
 -	const source = `
 --- main.go --
 -package main
@@ -116035,13 +129014,13 @@
 -	Run(t, source, func(t *testing.T, env *Env) {
 -		env.OpenFile("main.go")
 -		hexExpected := "58190"
--		got, _ := env.Hover(env.RegexpSearch("main.go", "hex"))
+-		got, _ := env.Hover(env.RegexpSearch("main.go", "0xe"))
 -		if got != nil && !strings.Contains(got.Value, hexExpected) {
 -			t.Errorf("Hover: missing expected field '%s'. Got:\n%q", hexExpected, got.Value)
 -		}
 -
 -		binExpected := "73"
--		got, _ = env.Hover(env.RegexpSearch("main.go", "bigBin"))
+-		got, _ = env.Hover(env.RegexpSearch("main.go", "0b1"))
 -		if got != nil && !strings.Contains(got.Value, binExpected) {
 -			t.Errorf("Hover: missing expected field '%s'. Got:\n%q", binExpected, got.Value)
 -		}
@@ -116311,271 +129290,124 @@
 -		})
 -	}
 -}
-diff -urN a/gopls/internal/regtest/misc/imports_test.go b/gopls/internal/regtest/misc/imports_test.go
---- a/gopls/internal/regtest/misc/imports_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/imports_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,258 +0,0 @@
--// Copyright 2020 The Go Authors. All rights reserved.
--// Use of this source code is governed by a BSD-style
--// license that can be found in the LICENSE file.
 -
--package misc
--
--import (
--	"io/ioutil"
--	"os"
--	"path/filepath"
--	"strings"
--	"testing"
--
--	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/testenv"
--)
--
--// Tests golang/go#38815.
--func TestIssue38815(t *testing.T) {
--	const needs = `
+-const linknameHover = `
 --- go.mod --
--module foo
+-module mod.com
 -
--go 1.12
---- a.go --
--package main
--func f() {}
--`
--	const ntest = `package main
--func TestZ(t *testing.T) {
--	f()
--}
--`
--	const want = `package main
--
--import "testing"
--
--func TestZ(t *testing.T) {
--	f()
--}
--`
--
--	// it was returning
--	// "package main\nimport \"testing\"\npackage main..."
--	Run(t, needs, func(t *testing.T, env *Env) {
--		env.CreateBuffer("a_test.go", ntest)
--		env.SaveBuffer("a_test.go")
--		got := env.BufferText("a_test.go")
--		if want != got {
--			t.Errorf("got\n%q, wanted\n%q", got, want)
--		}
--	})
--}
--
--func TestVim1(t *testing.T) {
--	const vim1 = `package main
--
--import "fmt"
--
--var foo = 1
--var bar = 2
--
--func main() {
--	fmt.Printf("This is a test %v\n", foo)
--	fmt.Printf("This is another test %v\n", foo)
--	fmt.Printf("This is also a test %v\n", foo)
--}
--`
--
--	// The file remains unchanged, but if there are any CodeActions returned, they confuse vim.
--	// Therefore check for no CodeActions
--	Run(t, "", func(t *testing.T, env *Env) {
--		env.CreateBuffer("main.go", vim1)
--		env.OrganizeImports("main.go")
--		actions := env.CodeAction("main.go", nil)
--		if len(actions) > 0 {
--			got := env.BufferText("main.go")
--			t.Errorf("unexpected actions %#v", actions)
--			if got == vim1 {
--				t.Errorf("no changes")
--			} else {
--				t.Errorf("got\n%q", got)
--				t.Errorf("was\n%q", vim1)
--			}
--		}
--	})
--}
--
--func TestVim2(t *testing.T) {
--	const vim2 = `package main
+--- upper/upper.go --
+-package upper
 -
 -import (
--	"fmt"
--
--	"example.com/blah"
--
--	"rubbish.com/useless"
+-	_ "unsafe"
+-	_ "mod.com/lower"
 -)
 -
--func main() {
--	fmt.Println(blah.Name, useless.Name)
--}
--`
+-//go:linkname foo mod.com/lower.bar
+-func foo() string
 -
--	Run(t, "", func(t *testing.T, env *Env) {
--		env.CreateBuffer("main.go", vim2)
--		env.OrganizeImports("main.go")
--		actions := env.CodeAction("main.go", nil)
--		if len(actions) > 0 {
--			t.Errorf("unexpected actions %#v", actions)
+--- lower/lower.go --
+-package lower
+-
+-// bar does foo.
+-func bar() string {
+-	return "foo by bar"
+-}`
+-
+-func TestHoverLinknameDirective(t *testing.T) {
+-	Run(t, linknameHover, func(t *testing.T, env *Env) {
+-		// Jump from directives 2nd arg.
+-		env.OpenFile("upper/upper.go")
+-		from := env.RegexpSearch("upper/upper.go", `lower.bar`)
+-
+-		hover, _ := env.Hover(from)
+-		content := hover.Value
+-
+-		expect := "bar does foo"
+-		if !strings.Contains(content, expect) {
+-			t.Errorf("hover: %q does not contain: %q", content, expect)
 -		}
 -	})
 -}
 -
--func TestGOMODCACHE(t *testing.T) {
--	const proxy = `
---- example.com@v1.2.3/go.mod --
--module example.com
--
--go 1.12
---- example.com@v1.2.3/x/x.go --
--package x
--
--const X = 1
---- example.com@v1.2.3/y/y.go --
--package y
--
--const Y = 2
--`
+-func TestHoverGoWork_Issue60821(t *testing.T) {
 -	const files = `
---- go.mod --
--module mod.com
--
--go 1.12
--
--require example.com v1.2.3
---- go.sum --
--example.com v1.2.3 h1:6vTQqzX+pnwngZF1+5gcO3ZEWmix1jJ/h+pWS8wUxK0=
--example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
---- main.go --
--package main
--
--import "example.com/x"
--
--var _, _ = x.X, y.Y
--`
--	modcache, err := ioutil.TempDir("", "TestGOMODCACHE-modcache")
--	if err != nil {
--		t.Fatal(err)
--	}
--	defer os.RemoveAll(modcache)
--	WithOptions(
--		EnvVars{"GOMODCACHE": modcache},
--		ProxyFiles(proxy),
--	).Run(t, files, func(t *testing.T, env *Env) {
--		env.OpenFile("main.go")
--		env.AfterChange(Diagnostics(env.AtRegexp("main.go", `y.Y`)))
--		env.SaveBuffer("main.go")
--		env.AfterChange(NoDiagnostics(ForFile("main.go")))
--		loc := env.GoToDefinition(env.RegexpSearch("main.go", `y.(Y)`))
--		path := env.Sandbox.Workdir.URIToPath(loc.URI)
--		if !strings.HasPrefix(path, filepath.ToSlash(modcache)) {
--			t.Errorf("found module dependency outside of GOMODCACHE: got %v, wanted subdir of %v", path, filepath.ToSlash(modcache))
--		}
--	})
--}
--
--// Tests golang/go#40685.
--func TestAcceptImportsQuickFixTestVariant(t *testing.T) {
--	const pkg = `
---- go.mod --
--module mod.com
--
--go 1.12
---- a/a.go --
--package a
--
--import (
--	"fmt"
--)
--
--func _() {
--	fmt.Println("")
--	os.Stat("")
--}
---- a/a_test.go --
--package a
--
--import (
--	"os"
--	"testing"
--)
--
--func TestA(t *testing.T) {
--	os.Stat("")
--}
--`
--	Run(t, pkg, func(t *testing.T, env *Env) {
--		env.OpenFile("a/a.go")
--		var d protocol.PublishDiagnosticsParams
--		env.AfterChange(
--			Diagnostics(env.AtRegexp("a/a.go", "os.Stat")),
--			ReadDiagnostics("a/a.go", &d),
--		)
--		env.ApplyQuickFixes("a/a.go", d.Diagnostics)
--		env.AfterChange(
--			NoDiagnostics(ForFile("a/a.go")),
--		)
--	})
--}
--
--// Test for golang/go#52784
--func TestGoWorkImports(t *testing.T) {
--	testenv.NeedsGo1Point(t, 18)
--	const pkg = `
 --- go.work --
 -go 1.19
 -
 -use (
--        ./caller
--        ./mod
+-	moda
+-	modb
 -)
---- caller/go.mod --
--module caller.com
+--- moda/go.mod --
 -
--go 1.18
+-`
+-	Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("go.work")
+-		// Neither of the requests below should crash gopls.
+-		_, _, _ = env.Editor.Hover(env.Ctx, env.RegexpSearch("go.work", "moda"))
+-		_, _, _ = env.Editor.Hover(env.Ctx, env.RegexpSearch("go.work", "modb"))
+-	})
+-}
 -
--require mod.com v0.0.0
--
--replace mod.com => ../mod
---- caller/caller.go --
+-const embedHover = `
+--- go.mod --
+-module mod.com
+-go 1.19
+--- main.go --
 -package main
 -
+-import "embed"
+-
+-//go:embed *.txt
+-var foo embed.FS
+-
 -func main() {
--        a.Test()
 -}
---- mod/go.mod --
--module mod.com
--
--go 1.18
---- mod/a/a.go --
--package a
--
--func Test() {
--}
+--- foo.txt --
+-FOO
+--- bar.txt --
+-BAR
+--- baz.txt --
+-BAZ
+--- other.sql --
+-SKIPPED
+--- dir.txt/skip.txt --
+-SKIPPED
 -`
--	Run(t, pkg, func(t *testing.T, env *Env) {
--		env.OpenFile("caller/caller.go")
--		env.AfterChange(Diagnostics(env.AtRegexp("caller/caller.go", "a.Test")))
 -
--		// Saving caller.go should trigger goimports, which should find a.Test in
--		// the mod.com module, thanks to the go.work file.
--		env.SaveBuffer("caller/caller.go")
--		env.AfterChange(NoDiagnostics(ForFile("caller/caller.go")))
+-func TestHoverEmbedDirective(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 19)
+-	Run(t, embedHover, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-		from := env.RegexpSearch("main.go", `\*.txt`)
+-
+-		got, _ := env.Hover(from)
+-		if got == nil {
+-			t.Fatalf("hover over //go:embed arg not found")
+-		}
+-		content := got.Value
+-
+-		wants := []string{"foo.txt", "bar.txt", "baz.txt"}
+-		for _, want := range wants {
+-			if !strings.Contains(content, want) {
+-				t.Errorf("hover: %q does not contain: %q", content, want)
+-			}
+-		}
+-
+-		// A directory should never be matched, even if it happens to have a matching name.
+-		// Content in subdirectories should not match on only one asterisk.
+-		skips := []string{"other.sql", "dir.txt", "skip.txt"}
+-		for _, skip := range skips {
+-			if strings.Contains(content, skip) {
+-				t.Errorf("hover: %q should not contain: %q", content, skip)
+-			}
+-		}
 -	})
 -}
 diff -urN a/gopls/internal/regtest/misc/import_test.go b/gopls/internal/regtest/misc/import_test.go
 --- a/gopls/internal/regtest/misc/import_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/import_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/import_test.go	1970-01-01 08:00:00
 @@ -1,133 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -116710,102 +129542,299 @@
 -
 -	})
 -}
-diff -urN a/gopls/internal/regtest/misc/leak_test.go b/gopls/internal/regtest/misc/leak_test.go
---- a/gopls/internal/regtest/misc/leak_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/leak_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,89 +0,0 @@
--// Copyright 2022 The Go Authors. All rights reserved.
+diff -urN a/gopls/internal/regtest/misc/imports_test.go b/gopls/internal/regtest/misc/imports_test.go
+--- a/gopls/internal/regtest/misc/imports_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/misc/imports_test.go	1970-01-01 08:00:00
+@@ -1,286 +0,0 @@
+-// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
 -package misc
 -
 -import (
--	"context"
+-	"os"
+-	"path/filepath"
+-	"strings"
 -	"testing"
 -
--	"github.com/google/go-cmp/cmp"
--	"golang.org/x/tools/gopls/internal/hooks"
--	"golang.org/x/tools/gopls/internal/lsp/cache"
--	"golang.org/x/tools/gopls/internal/lsp/debug"
--	"golang.org/x/tools/gopls/internal/lsp/fake"
--	"golang.org/x/tools/gopls/internal/lsp/lsprpc"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/jsonrpc2"
--	"golang.org/x/tools/internal/jsonrpc2/servertest"
+-	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
--// Test for golang/go#57222.
--func TestCacheLeak(t *testing.T) {
--	// TODO(rfindley): either fix this test with additional instrumentation, or
--	// delete it.
--	t.Skip("This test races with cache eviction.")
--	const files = `-- a.go --
--package a
+-// Tests golang/go#38815.
+-func TestIssue38815(t *testing.T) {
+-	const needs = `
+--- go.mod --
+-module foo
 -
--func _() {
--	println("1")
+-go 1.12
+--- a.go --
+-package main
+-func f() {}
+-`
+-	const ntest = `package main
+-func TestZ(t *testing.T) {
+-	f()
 -}
 -`
--	c := cache.New(nil)
--	env := setupEnv(t, files, c)
--	env.Await(InitialWorkspaceLoad)
--	env.OpenFile("a.go")
+-	const want = `package main
 -
--	// Make a couple edits to stabilize cache state.
--	//
--	// For some reason, after only one edit we're left with two parsed files
--	// (perhaps because something had to ParseHeader). If this test proves flaky,
--	// we'll need to investigate exactly what is causing various parse modes to
--	// be present (or rewrite the test to be more tolerant, for example make ~100
--	// modifications and assert that we're within a few of where we're started).
--	env.RegexpReplace("a.go", "1", "2")
--	env.RegexpReplace("a.go", "2", "3")
--	env.AfterChange()
+-import "testing"
 -
--	// Capture cache state, make an arbitrary change, and wait for gopls to do
--	// its work. Afterward, we should have the exact same number of parsed
--	before := c.MemStats()
--	env.RegexpReplace("a.go", "3", "4")
--	env.AfterChange()
--	after := c.MemStats()
+-func TestZ(t *testing.T) {
+-	f()
+-}
+-`
 -
--	if diff := cmp.Diff(before, after); diff != "" {
--		t.Errorf("store objects differ after change (-before +after)\n%s", diff)
--	}
+-	// it was returning
+-	// "package main\nimport \"testing\"\npackage main..."
+-	Run(t, needs, func(t *testing.T, env *Env) {
+-		env.CreateBuffer("a_test.go", ntest)
+-		env.SaveBuffer("a_test.go")
+-		got := env.BufferText("a_test.go")
+-		if want != got {
+-			t.Errorf("got\n%q, wanted\n%q", got, want)
+-		}
+-	})
 -}
 -
--// setupEnv creates a new sandbox environment for editing the txtar encoded
--// content of files. It uses a new gopls instance backed by the Cache c.
--func setupEnv(t *testing.T, files string, c *cache.Cache) *Env {
--	ctx := debug.WithInstance(context.Background(), "", "off")
--	server := lsprpc.NewStreamServer(c, false, hooks.Options)
--	ts := servertest.NewPipeServer(server, jsonrpc2.NewRawStream)
--	s, err := fake.NewSandbox(&fake.SandboxConfig{
--		Files: fake.UnpackTxt(files),
+-func TestIssue59124(t *testing.T) {
+-	const stuff = `
+--- go.mod --
+-module foo
+-go 1.19
+--- a.go --
+-//line foo.y:102
+-package main
+-
+-import "fmt"
+-
+-//this comment is necessary for failure
+-func a() {
+-	fmt.Println("hello")
+-}
+-`
+-	Run(t, stuff, func(t *testing.T, env *Env) {
+-		env.OpenFile("a.go")
+-		was := env.BufferText("a.go")
+-		env.Await(NoDiagnostics())
+-		env.OrganizeImports("a.go")
+-		is := env.BufferText("a.go")
+-		if diff := compare.Text(was, is); diff != "" {
+-			t.Errorf("unexpected diff after organizeImports:\n%s", diff)
+-		}
 -	})
+-}
+-
+-func TestVim1(t *testing.T) {
+-	const vim1 = `package main
+-
+-import "fmt"
+-
+-var foo = 1
+-var bar = 2
+-
+-func main() {
+-	fmt.Printf("This is a test %v\n", foo)
+-	fmt.Printf("This is another test %v\n", foo)
+-	fmt.Printf("This is also a test %v\n", foo)
+-}
+-`
+-
+-	// The file remains unchanged, but if there are any CodeActions returned, they confuse vim.
+-	// Therefore check for no CodeActions
+-	Run(t, "", func(t *testing.T, env *Env) {
+-		env.CreateBuffer("main.go", vim1)
+-		env.OrganizeImports("main.go")
+-		actions := env.CodeAction("main.go", nil)
+-		if len(actions) > 0 {
+-			got := env.BufferText("main.go")
+-			t.Errorf("unexpected actions %#v", actions)
+-			if got == vim1 {
+-				t.Errorf("no changes")
+-			} else {
+-				t.Errorf("got\n%q", got)
+-				t.Errorf("was\n%q", vim1)
+-			}
+-		}
+-	})
+-}
+-
+-func TestVim2(t *testing.T) {
+-	const vim2 = `package main
+-
+-import (
+-	"fmt"
+-
+-	"example.com/blah"
+-
+-	"rubbish.com/useless"
+-)
+-
+-func main() {
+-	fmt.Println(blah.Name, useless.Name)
+-}
+-`
+-
+-	Run(t, "", func(t *testing.T, env *Env) {
+-		env.CreateBuffer("main.go", vim2)
+-		env.OrganizeImports("main.go")
+-		actions := env.CodeAction("main.go", nil)
+-		if len(actions) > 0 {
+-			t.Errorf("unexpected actions %#v", actions)
+-		}
+-	})
+-}
+-
+-func TestGOMODCACHE(t *testing.T) {
+-	const proxy = `
+--- example.com@v1.2.3/go.mod --
+-module example.com
+-
+-go 1.12
+--- example.com@v1.2.3/x/x.go --
+-package x
+-
+-const X = 1
+--- example.com@v1.2.3/y/y.go --
+-package y
+-
+-const Y = 2
+-`
+-	const files = `
+--- go.mod --
+-module mod.com
+-
+-go 1.12
+-
+-require example.com v1.2.3
+--- go.sum --
+-example.com v1.2.3 h1:6vTQqzX+pnwngZF1+5gcO3ZEWmix1jJ/h+pWS8wUxK0=
+-example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
+--- main.go --
+-package main
+-
+-import "example.com/x"
+-
+-var _, _ = x.X, y.Y
+-`
+-	modcache, err := os.MkdirTemp("", "TestGOMODCACHE-modcache")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
+-	defer os.RemoveAll(modcache)
+-	WithOptions(
+-		EnvVars{"GOMODCACHE": modcache},
+-		ProxyFiles(proxy),
+-	).Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-		env.AfterChange(Diagnostics(env.AtRegexp("main.go", `y.Y`)))
+-		env.SaveBuffer("main.go")
+-		env.AfterChange(NoDiagnostics(ForFile("main.go")))
+-		loc := env.GoToDefinition(env.RegexpSearch("main.go", `y.(Y)`))
+-		path := env.Sandbox.Workdir.URIToPath(loc.URI)
+-		if !strings.HasPrefix(path, filepath.ToSlash(modcache)) {
+-			t.Errorf("found module dependency outside of GOMODCACHE: got %v, wanted subdir of %v", path, filepath.ToSlash(modcache))
+-		}
+-	})
+-}
 -
--	a := NewAwaiter(s.Workdir)
--	const skipApplyEdits = false
--	editor, err := fake.NewEditor(s, fake.EditorConfig{}).Connect(ctx, ts, a.Hooks(), skipApplyEdits)
--	if err != nil {
--		t.Fatal(err)
--	}
+-// Tests golang/go#40685.
+-func TestAcceptImportsQuickFixTestVariant(t *testing.T) {
+-	const pkg = `
+--- go.mod --
+-module mod.com
 -
--	return &Env{
--		T:       t,
--		Ctx:     ctx,
--		Editor:  editor,
--		Sandbox: s,
--		Awaiter: a,
--	}
+-go 1.12
+--- a/a.go --
+-package a
+-
+-import (
+-	"fmt"
+-)
+-
+-func _() {
+-	fmt.Println("")
+-	os.Stat("")
+-}
+--- a/a_test.go --
+-package a
+-
+-import (
+-	"os"
+-	"testing"
+-)
+-
+-func TestA(t *testing.T) {
+-	os.Stat("")
+-}
+-`
+-	Run(t, pkg, func(t *testing.T, env *Env) {
+-		env.OpenFile("a/a.go")
+-		var d protocol.PublishDiagnosticsParams
+-		env.AfterChange(
+-			Diagnostics(env.AtRegexp("a/a.go", "os.Stat")),
+-			ReadDiagnostics("a/a.go", &d),
+-		)
+-		env.ApplyQuickFixes("a/a.go", d.Diagnostics)
+-		env.AfterChange(
+-			NoDiagnostics(ForFile("a/a.go")),
+-		)
+-	})
+-}
+-
+-// Test for golang/go#52784
+-func TestGoWorkImports(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18)
+-	const pkg = `
+--- go.work --
+-go 1.19
+-
+-use (
+-        ./caller
+-        ./mod
+-)
+--- caller/go.mod --
+-module caller.com
+-
+-go 1.18
+-
+-require mod.com v0.0.0
+-
+-replace mod.com => ../mod
+--- caller/caller.go --
+-package main
+-
+-func main() {
+-        a.Test()
+-}
+--- mod/go.mod --
+-module mod.com
+-
+-go 1.18
+--- mod/a/a.go --
+-package a
+-
+-func Test() {
+-}
+-`
+-	Run(t, pkg, func(t *testing.T, env *Env) {
+-		env.OpenFile("caller/caller.go")
+-		env.AfterChange(Diagnostics(env.AtRegexp("caller/caller.go", "a.Test")))
+-
+-		// Saving caller.go should trigger goimports, which should find a.Test in
+-		// the mod.com module, thanks to the go.work file.
+-		env.SaveBuffer("caller/caller.go")
+-		env.AfterChange(NoDiagnostics(ForFile("caller/caller.go")))
+-	})
 -}
 diff -urN a/gopls/internal/regtest/misc/link_test.go b/gopls/internal/regtest/misc/link_test.go
 --- a/gopls/internal/regtest/misc/link_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/link_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/link_test.go	1970-01-01 08:00:00
 @@ -1,96 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -116871,11 +129900,11 @@
 -			t.Errorf("hover: got %v in go.mod, want contains %q", content, pkgLink)
 -		}
 -		links := env.DocumentLink("main.go")
--		if len(links) != 1 || links[0].Target != pkgLink {
+-		if len(links) != 1 || *links[0].Target != pkgLink {
 -			t.Errorf("documentLink: got links %+v for main.go, want one link with target %q", links, pkgLink)
 -		}
 -		links = env.DocumentLink("go.mod")
--		if len(links) != 1 || links[0].Target != modLink {
+-		if len(links) != 1 || *links[0].Target != modLink {
 -			t.Errorf("documentLink: got links %+v for go.mod, want one link with target %q", links, modLink)
 -		}
 -
@@ -116905,7 +129934,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/misc_test.go b/gopls/internal/regtest/misc/misc_test.go
 --- a/gopls/internal/regtest/misc/misc_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/misc_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/misc_test.go	1970-01-01 08:00:00
 @@ -1,18 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -116916,9 +129945,9 @@
 -import (
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -func TestMain(m *testing.M) {
@@ -116927,7 +129956,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/multiple_adhoc_test.go b/gopls/internal/regtest/misc/multiple_adhoc_test.go
 --- a/gopls/internal/regtest/misc/multiple_adhoc_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/multiple_adhoc_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/multiple_adhoc_test.go	1970-01-01 08:00:00
 @@ -1,44 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -116973,10 +130002,245 @@
 -		}
 -	})
 -}
+diff -urN a/gopls/internal/regtest/misc/prompt_test.go b/gopls/internal/regtest/misc/prompt_test.go
+--- a/gopls/internal/regtest/misc/prompt_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/misc/prompt_test.go	1970-01-01 08:00:00
+@@ -1,231 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package misc
+-
+-import (
+-	"fmt"
+-	"os"
+-	"path/filepath"
+-	"regexp"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-)
+-
+-// Test that gopls prompts for telemetry only when it is supposed to.
+-func TestTelemetryPrompt_Conditions(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.12
+--- main.go --
+-package main
+-
+-func main() {
+-}
+-`
+-
+-	for _, enabled := range []bool{true, false} {
+-		t.Run(fmt.Sprintf("telemetryPrompt=%v", enabled), func(t *testing.T) {
+-			for _, initialMode := range []string{"", "off", "on"} {
+-				t.Run(fmt.Sprintf("initial_mode=%s", initialMode), func(t *testing.T) {
+-					modeFile := filepath.Join(t.TempDir(), "mode")
+-					if initialMode != "" {
+-						if err := os.WriteFile(modeFile, []byte(initialMode), 0666); err != nil {
+-							t.Fatal(err)
+-						}
+-					}
+-					WithOptions(
+-						Modes(Default), // no need to run this in all modes
+-						EnvVars{
+-							lsp.GoplsConfigDirEnvvar:        t.TempDir(),
+-							lsp.FakeTelemetryModefileEnvvar: modeFile,
+-						},
+-						Settings{
+-							"telemetryPrompt": enabled,
+-						},
+-					).Run(t, src, func(t *testing.T, env *Env) {
+-						wantPrompt := enabled && (initialMode == "" || initialMode == "off")
+-						expectation := ShownMessageRequest(".*Would you like to enable Go telemetry?")
+-						if !wantPrompt {
+-							expectation = Not(expectation)
+-						}
+-						env.OnceMet(
+-							CompletedWork(lsp.TelemetryPromptWorkTitle, 1, true),
+-							expectation,
+-						)
+-					})
+-				})
+-			}
+-		})
+-	}
+-}
+-
+-// Test that responding to the telemetry prompt results in the expected state.
+-func TestTelemetryPrompt_Response(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.12
+--- main.go --
+-package main
+-
+-func main() {
+-}
+-`
+-
+-	tests := []struct {
+-		response string // response to choose for the telemetry dialog
+-		wantMode string // resulting telemetry mode
+-		wantMsg  string // substring contained in the follow-up popup (if empty, no popup is expected)
+-	}{
+-		{lsp.TelemetryYes, "on", "uploading is now enabled"},
+-		{lsp.TelemetryNo, "", ""},
+-		{"", "", ""},
+-	}
+-	for _, test := range tests {
+-		t.Run(fmt.Sprintf("response=%s", test.response), func(t *testing.T) {
+-			modeFile := filepath.Join(t.TempDir(), "mode")
+-			msgRE := regexp.MustCompile(".*Would you like to enable Go telemetry?")
+-			respond := func(m *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) {
+-				if msgRE.MatchString(m.Message) {
+-					for _, item := range m.Actions {
+-						if item.Title == test.response {
+-							return &item, nil
+-						}
+-					}
+-					if test.response != "" {
+-						t.Errorf("action item %q not found", test.response)
+-					}
+-				}
+-				return nil, nil
+-			}
+-			WithOptions(
+-				Modes(Default), // no need to run this in all modes
+-				EnvVars{
+-					lsp.GoplsConfigDirEnvvar:        t.TempDir(),
+-					lsp.FakeTelemetryModefileEnvvar: modeFile,
+-				},
+-				Settings{
+-					"telemetryPrompt": true,
+-				},
+-				MessageResponder(respond),
+-			).Run(t, src, func(t *testing.T, env *Env) {
+-				var postConditions []Expectation
+-				if test.wantMsg != "" {
+-					postConditions = append(postConditions, ShownMessage(test.wantMsg))
+-				}
+-				env.OnceMet(
+-					CompletedWork(lsp.TelemetryPromptWorkTitle, 1, true),
+-					postConditions...,
+-				)
+-				gotMode := ""
+-				if contents, err := os.ReadFile(modeFile); err == nil {
+-					gotMode = string(contents)
+-				} else if !os.IsNotExist(err) {
+-					t.Fatal(err)
+-				}
+-				if gotMode != test.wantMode {
+-					t.Errorf("after prompt, mode=%s, want %s", gotMode, test.wantMode)
+-				}
+-			})
+-		})
+-	}
+-}
+-
+-// Test that we stop asking about telemetry after the user ignores the question
+-// 5 times.
+-func TestTelemetryPrompt_GivingUp(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.12
+--- main.go --
+-package main
+-
+-func main() {
+-}
+-`
+-
+-	// For this test, we want to share state across gopls sessions.
+-	modeFile := filepath.Join(t.TempDir(), "mode")
+-	configDir := t.TempDir()
+-
+-	const maxPrompts = 5 // internal prompt limit defined by gopls
+-
+-	for i := 0; i < maxPrompts+1; i++ {
+-		WithOptions(
+-			Modes(Default), // no need to run this in all modes
+-			EnvVars{
+-				lsp.GoplsConfigDirEnvvar:        configDir,
+-				lsp.FakeTelemetryModefileEnvvar: modeFile,
+-			},
+-			Settings{
+-				"telemetryPrompt": true,
+-			},
+-		).Run(t, src, func(t *testing.T, env *Env) {
+-			wantPrompt := i < maxPrompts
+-			expectation := ShownMessageRequest(".*Would you like to enable Go telemetry?")
+-			if !wantPrompt {
+-				expectation = Not(expectation)
+-			}
+-			env.OnceMet(
+-				CompletedWork(lsp.TelemetryPromptWorkTitle, 1, true),
+-				expectation,
+-			)
+-		})
+-	}
+-}
+-
+-// Test that gopls prompts for telemetry only when it is supposed to.
+-func TestTelemetryPrompt_Conditions2(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.12
+--- main.go --
+-package main
+-
+-func main() {
+-}
+-`
+-	modeFile := filepath.Join(t.TempDir(), "mode")
+-	WithOptions(
+-		Modes(Default), // no need to run this in all modes
+-		EnvVars{
+-			lsp.GoplsConfigDirEnvvar:        t.TempDir(),
+-			lsp.FakeTelemetryModefileEnvvar: modeFile,
+-		},
+-		Settings{
+-			// off because we are testing
+-			// if we can trigger the prompt with command.
+-			"telemetryPrompt": false,
+-		},
+-	).Run(t, src, func(t *testing.T, env *Env) {
+-		cmd, err := command.NewMaybePromptForTelemetryCommand("prompt")
+-		if err != nil {
+-			t.Fatal(err)
+-		}
+-		var result error
+-		env.ExecuteCommand(&protocol.ExecuteCommandParams{
+-			Command: cmd.Command,
+-		}, &result)
+-		if result != nil {
+-			t.Fatal(err)
+-		}
+-		expectation := ShownMessageRequest(".*Would you like to enable Go telemetry?")
+-		env.OnceMet(
+-			CompletedWork(lsp.TelemetryPromptWorkTitle, 2, true),
+-			expectation,
+-		)
+-	})
+-}
 diff -urN a/gopls/internal/regtest/misc/references_test.go b/gopls/internal/regtest/misc/references_test.go
 --- a/gopls/internal/regtest/misc/references_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/references_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,399 +0,0 @@
++++ b/gopls/internal/regtest/misc/references_test.go	1970-01-01 08:00:00
+@@ -1,581 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -116986,13 +130250,17 @@
 -import (
 -	"fmt"
 -	"os"
+-	"path/filepath"
+-	"reflect"
 -	"sort"
 -	"strings"
 -	"testing"
 -
 -	"github.com/google/go-cmp/cmp"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/regtest"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -func TestStdlibReferences(t *testing.T) {
@@ -117077,6 +130345,58 @@
 -	})
 -}
 -
+-func TestDefsRefsBuiltins(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 17) // for unsafe.{Add,Slice}
+-	// TODO(adonovan): add unsafe.{SliceData,String,StringData} in later go versions.
+-	const files = `
+--- go.mod --
+-module example.com
+-go 1.16
+-
+--- a.go --
+-package a
+-
+-import "unsafe"
+-
+-const _ = iota
+-var _ error
+-var _ int
+-var _ = append()
+-var _ = unsafe.Pointer(nil)
+-var _ = unsafe.Add(nil, nil)
+-var _ = unsafe.Sizeof(0)
+-var _ = unsafe.Alignof(0)
+-var _ = unsafe.Slice(nil, 0)
+-`
+-
+-	Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("a.go")
+-		for _, name := range strings.Fields(
+-			"iota error int nil append iota Pointer Sizeof Alignof Add Slice") {
+-			loc := env.RegexpSearch("a.go", `\b`+name+`\b`)
+-
+-			// definition -> {builtin,unsafe}.go
+-			def := env.GoToDefinition(loc)
+-			if (!strings.HasSuffix(string(def.URI), "builtin.go") &&
+-				!strings.HasSuffix(string(def.URI), "unsafe.go")) ||
+-				def.Range.Start.Line == 0 {
+-				t.Errorf("definition(%q) = %v, want {builtin,unsafe}.go",
+-					name, def)
+-			}
+-
+-			// "references to (builtin "Foo"|unsafe.Foo) are not supported"
+-			_, err := env.Editor.References(env.Ctx, loc)
+-			gotErr := fmt.Sprint(err)
+-			if !strings.Contains(gotErr, "references to") ||
+-				!strings.Contains(gotErr, "not supported") ||
+-				!strings.Contains(gotErr, name) {
+-				t.Errorf("references(%q) error: got %q, want %q",
+-					name, gotErr, "references to ... are not supported")
+-			}
+-		}
+-	})
+-}
+-
 -func TestPackageReferences(t *testing.T) {
 -	tests := []struct {
 -		packageName  string
@@ -117229,16 +130549,6 @@
 -	Run(t, files, func(t *testing.T, env *Env) {
 -		env.OpenFile("foo/foo.go")
 -
--		// Helper to map locations relative file paths.
--		fileLocations := func(locs []protocol.Location) []string {
--			var got []string
--			for _, loc := range locs {
--				got = append(got, env.Sandbox.Workdir.URIToPath(loc.URI))
--			}
--			sort.Strings(got)
--			return got
--		}
--
 -		refTests := []struct {
 -			re       string
 -			wantRefs []string
@@ -117248,18 +130558,18 @@
 -			// - inside the foo.mod/bar [foo.mod/bar.test] test variant package
 -			// - from the foo.mod/bar_test [foo.mod/bar.test] x_test package
 -			// - from the foo.mod/foo package
--			{"Blah", []string{"bar/bar.go", "bar/bar_test.go", "bar/bar_x_test.go", "foo/foo.go"}},
+-			{"Blah", []string{"bar/bar.go:3", "bar/bar_test.go:7", "bar/bar_x_test.go:12", "foo/foo.go:12"}},
 -
 -			// Foo is referenced in bar_x_test.go via the intermediate test variant
 -			// foo.mod/foo [foo.mod/bar.test].
--			{"Foo", []string{"bar/bar_x_test.go", "foo/foo.go"}},
+-			{"Foo", []string{"bar/bar_x_test.go:13", "foo/foo.go:5"}},
 -		}
 -
 -		for _, test := range refTests {
 -			loc := env.RegexpSearch("foo/foo.go", test.re)
 -			refs := env.References(loc)
 -
--			got := fileLocations(refs)
+-			got := fileLocations(env, refs)
 -			if diff := cmp.Diff(test.wantRefs, got); diff != "" {
 -				t.Errorf("References(%q) returned unexpected diff (-want +got):\n%s", test.re, diff)
 -			}
@@ -117272,18 +130582,18 @@
 -			// InterfaceM is implemented both in foo.mod/bar [foo.mod/bar.test] (which
 -			// doesn't import foo), and in foo.mod/bar_test [foo.mod/bar.test], which
 -			// imports the test variant of foo.
--			{"InterfaceM", []string{"bar/bar_test.go", "bar/bar_x_test.go"}},
+-			{"InterfaceM", []string{"bar/bar_test.go:3", "bar/bar_x_test.go:8"}},
 -
 -			// A search within the ordinary package to should find implementations
 -			// (Fer) within the augmented test package.
--			{"InterfaceF", []string{"foo/foo_test.go"}},
+-			{"InterfaceF", []string{"foo/foo_test.go:3"}},
 -		}
 -
 -		for _, test := range implTests {
 -			loc := env.RegexpSearch("foo/foo.go", test.re)
 -			impls := env.Implementations(loc)
 -
--			got := fileLocations(impls)
+-			got := fileLocations(env, impls)
 -			if diff := cmp.Diff(test.wantImpls, got); diff != "" {
 -				t.Errorf("Implementations(%q) returned unexpected diff (-want +got):\n%s", test.re, diff)
 -			}
@@ -117350,7 +130660,7 @@
 -		checkVendor(env.Implementations(refLoc), false)
 -
 -		// Run 'go mod vendor' outside the editor.
--		if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, true); err != nil {
+-		if err := env.Sandbox.RunGoCommand(env.Ctx, ".", "mod", []string{"vendor"}, nil, true); err != nil {
 -			t.Fatalf("go mod vendor: %v", err)
 -		}
 -
@@ -117376,9 +130686,145 @@
 -		checkVendor(env.Implementations(refLoc), false)
 -	})
 -}
+-
+-// This test can't be expressed as a marker test because the marker
+-// test framework opens all files (which is a bit of a hack), creating
+-// a <command-line-arguments> package for packages that otherwise
+-// wouldn't be found from the go.work file.
+-func TestReferencesFromWorkspacePackages59674(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // for go.work support
+-	const src = `
+--- a/go.mod --
+-module example.com/a
+-go 1.12
+-
+--- b/go.mod --
+-module example.com/b
+-go 1.12
+-
+--- c/go.mod --
+-module example.com/c
+-go 1.12
+-
+--- lib/go.mod --
+-module example.com/lib
+-go 1.12
+-
+--- go.work --
+-use ./a
+-use ./b
+-// don't use ./c
+-use ./lib
+-
+--- a/a.go --
+-package a
+-
+-import "example.com/lib"
+-
+-var _ = lib.F // query here
+-
+--- b/b.go --
+-package b
+-
+-import "example.com/lib"
+-
+-var _ = lib.F // also found by references
+-
+--- c/c.go --
+-package c
+-
+-import "example.com/lib"
+-
+-var _ = lib.F // this reference should not be reported
+-
+--- lib/lib.go --
+-package lib
+-
+-func F() {} // declaration
+-`
+-	Run(t, src, func(t *testing.T, env *Env) {
+-		env.OpenFile("a/a.go")
+-		refLoc := env.RegexpSearch("a/a.go", "F")
+-		got := fileLocations(env, env.References(refLoc))
+-		want := []string{"a/a.go:5", "b/b.go:5", "lib/lib.go:3"}
+-		if diff := cmp.Diff(want, got); diff != "" {
+-			t.Errorf("incorrect References (-want +got):\n%s", diff)
+-		}
+-	})
+-}
+-
+-// Test an 'implementation' query on a type that implements 'error'.
+-// (Unfortunately builtin locations cannot be expressed using @loc
+-// in the marker test framework.)
+-func TestImplementationsOfError(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module example.com
+-go 1.12
+-
+--- a.go --
+-package a
+-
+-type Error2 interface {
+-	Error() string
+-}
+-
+-type MyError int
+-func (MyError) Error() string { return "" }
+-
+-type MyErrorPtr int
+-func (*MyErrorPtr) Error() string { return "" }
+-`
+-	Run(t, src, func(t *testing.T, env *Env) {
+-		env.OpenFile("a.go")
+-
+-		for _, test := range []struct {
+-			re   string
+-			want []string
+-		}{
+-			// error type
+-			{"Error2", []string{"a.go:10", "a.go:7", "std:builtin/builtin.go"}},
+-			{"MyError", []string{"a.go:3", "std:builtin/builtin.go"}},
+-			{"MyErrorPtr", []string{"a.go:3", "std:builtin/builtin.go"}},
+-			// error.Error method
+-			{"(Error).. string", []string{"a.go:11", "a.go:8", "std:builtin/builtin.go"}},
+-			{"MyError. (Error)", []string{"a.go:4", "std:builtin/builtin.go"}},
+-			{"MyErrorPtr. (Error)", []string{"a.go:4", "std:builtin/builtin.go"}},
+-		} {
+-			matchLoc := env.RegexpSearch("a.go", test.re)
+-			impls := env.Implementations(matchLoc)
+-			got := fileLocations(env, impls)
+-			if !reflect.DeepEqual(got, test.want) {
+-				t.Errorf("Implementations(%q) = %q, want %q",
+-					test.re, got, test.want)
+-			}
+-		}
+-	})
+-}
+-
+-// fileLocations returns a new sorted array of the
+-// relative file name and line number of each location.
+-// Duplicates are not removed.
+-// Standard library filenames are abstracted for robustness.
+-func fileLocations(env *regtest.Env, locs []protocol.Location) []string {
+-	got := make([]string, 0, len(locs))
+-	for _, loc := range locs {
+-		path := env.Sandbox.Workdir.URIToPath(loc.URI) // (slashified)
+-		if i := strings.LastIndex(path, "/src/"); i >= 0 && filepath.IsAbs(path) {
+-			// Absolute path with "src" segment: assume it's in GOROOT.
+-			// Strip directory and don't add line/column since they are fragile.
+-			path = "std:" + path[i+len("/src/"):]
+-		} else {
+-			path = fmt.Sprintf("%s:%d", path, loc.Range.Start.Line+1)
+-		}
+-		got = append(got, path)
+-	}
+-	sort.Strings(got)
+-	return got
+-}
 diff -urN a/gopls/internal/regtest/misc/rename_test.go b/gopls/internal/regtest/misc/rename_test.go
 --- a/gopls/internal/regtest/misc/rename_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/rename_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/rename_test.go	1970-01-01 08:00:00
 @@ -1,935 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118317,7 +131763,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/semantictokens_test.go b/gopls/internal/regtest/misc/semantictokens_test.go
 --- a/gopls/internal/regtest/misc/semantictokens_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/semantictokens_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/semantictokens_test.go	1970-01-01 08:00:00
 @@ -1,204 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118525,7 +131971,7 @@
 -)
 diff -urN a/gopls/internal/regtest/misc/settings_test.go b/gopls/internal/regtest/misc/settings_test.go
 --- a/gopls/internal/regtest/misc/settings_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/settings_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/settings_test.go	1970-01-01 08:00:00
 @@ -1,32 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118561,7 +132007,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/shared_test.go b/gopls/internal/regtest/misc/shared_test.go
 --- a/gopls/internal/regtest/misc/shared_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/shared_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/shared_test.go	1970-01-01 08:00:00
 @@ -1,72 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118637,7 +132083,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/signature_help_test.go b/gopls/internal/regtest/misc/signature_help_test.go
 --- a/gopls/internal/regtest/misc/signature_help_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/signature_help_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/signature_help_test.go	1970-01-01 08:00:00
 @@ -1,69 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118710,7 +132156,7 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/staticcheck_test.go b/gopls/internal/regtest/misc/staticcheck_test.go
 --- a/gopls/internal/regtest/misc/staticcheck_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/staticcheck_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/misc/staticcheck_test.go	1970-01-01 08:00:00
 @@ -1,110 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -118824,8 +132270,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/vendor_test.go b/gopls/internal/regtest/misc/vendor_test.go
 --- a/gopls/internal/regtest/misc/vendor_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/vendor_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,65 +0,0 @@
++++ b/gopls/internal/regtest/misc/vendor_test.go	1970-01-01 08:00:00
+@@ -1,103 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -118891,10 +132337,48 @@
 -		)
 -	})
 -}
+-
+-func TestWindowsVendoring_Issue56291(t *testing.T) {
+-	const src = `
+--- go.mod --
+-module mod.com
+-
+-go 1.14
+-
+-require golang.org/x/hello v1.2.3
+--- go.sum --
+-golang.org/x/hello v1.2.3 h1:EcMp5gSkIhaTkPXp8/3+VH+IFqTpk3ZbpOhqk0Ncmho=
+-golang.org/x/hello v1.2.3/go.mod h1:WW7ER2MRNXWA6c8/4bDIek4Hc/+DofTrMaQQitGXcco=
+--- main.go --
+-package main
+-
+-import "golang.org/x/hello/hi"
+-
+-func main() {
+-	_ = hi.Goodbye
+-}
+-`
+-	WithOptions(
+-		Modes(Default),
+-		ProxyFiles(basicProxy),
+-	).Run(t, src, func(t *testing.T, env *Env) {
+-		env.OpenFile("main.go")
+-		env.AfterChange(NoDiagnostics())
+-		env.RunGoCommand("mod", "tidy")
+-		env.RunGoCommand("mod", "vendor")
+-		env.AfterChange(NoDiagnostics())
+-		env.RegexpReplace("main.go", `import "golang.org/x/hello/hi"`, "")
+-		env.AfterChange(
+-			Diagnostics(env.AtRegexp("main.go", "hi.Goodbye")),
+-		)
+-		env.SaveBuffer("main.go")
+-		env.AfterChange(NoDiagnostics())
+-	})
+-}
 diff -urN a/gopls/internal/regtest/misc/vuln_test.go b/gopls/internal/regtest/misc/vuln_test.go
 --- a/gopls/internal/regtest/misc/vuln_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/vuln_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,977 +0,0 @@
++++ b/gopls/internal/regtest/misc/vuln_test.go	1970-01-01 08:00:00
+@@ -1,952 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -118907,19 +132391,19 @@
 -import (
 -	"context"
 -	"encoding/json"
--	"path/filepath"
 -	"sort"
 -	"strings"
 -	"testing"
 -
 -	"github.com/google/go-cmp/cmp"
--	"golang.org/x/tools/gopls/internal/govulncheck"
+-
 -	"golang.org/x/tools/gopls/internal/lsp/command"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
 -	"golang.org/x/tools/gopls/internal/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/scan"
 -	"golang.org/x/tools/gopls/internal/vulncheck/vulntest"
 -	"golang.org/x/tools/internal/testenv"
 -)
@@ -118982,7 +132466,7 @@
 -		env.Await(
 -			CompletedProgress(result.Token, &ws),
 -		)
--		wantEndMsg, wantMsgPart := "failed", "failed to load packages due to errors"
+-		wantEndMsg, wantMsgPart := "failed", "There are errors with the provided package patterns:"
 -		if ws.EndMsg != "failed" || !strings.Contains(ws.Msg, wantMsgPart) {
 -			t.Errorf("work status = %+v, want {EndMessage: %q, Message: %q}", ws, wantEndMsg, wantMsgPart)
 -		}
@@ -118996,14 +132480,14 @@
 -    versions:
 -      - introduced: 1.0.0
 -      - fixed: 1.0.4
--      - introduced: 1.1.2
 -    packages:
 -      - package: golang.org/amod/avuln
 -        symbols:
 -          - VulnData.Vuln1
 -          - VulnData.Vuln2
 -description: >
--    vuln in amod
+-    vuln in amod is found
+-summary: vuln in amod
 -references:
 -  - href: pkg.go.dev/vuln/GO-2022-01
 --- GO-2022-03.yaml --
@@ -119017,7 +132501,8 @@
 -        symbols:
 -          - nonExisting
 -description: >
--  unaffecting vulnerability  
+-  unaffecting vulnerability is found
+-summary: unaffecting vulnerability
 --- GO-2022-02.yaml --
 -modules:
 -  - module: golang.org/bmod
@@ -119026,10 +132511,11 @@
 -        symbols:
 -          - Vuln
 -description: |
--    vuln in bmod
+-    vuln in bmod is found.
 -    
 -    This is a long description
 -    of this vulnerability.
+-summary: vuln in bmod (no fix)
 -references:
 -  - href: pkg.go.dev/vuln/GO-2022-03
 --- GO-2022-04.yaml --
@@ -119040,7 +132526,8 @@
 -        symbols:
 -          - Vuln
 -description: |
--    vuln in bmod/somtrhingelse
+-    vuln in bmod/somethingelse is found
+-summary: vuln in bmod/somethingelse
 -references:
 -  - href: pkg.go.dev/vuln/GO-2022-04
 --- GOSTDLIB.yaml --
@@ -119052,6 +132539,7 @@
 -      - package: archive/zip
 -        symbols:
 -          - OpenReader
+-summary: vuln in GOSTDLIB
 -references:
 -  - href: pkg.go.dev/vuln/GOSTDLIB
 -`
@@ -119089,7 +132577,7 @@
 -			// When fetchinging stdlib package vulnerability info,
 -			// behave as if our go version is go1.18 for this testing.
 -			// The default behavior is to run `go env GOVERSION` (which isn't mutable env var).
--			vulncheck.GoVersionForVulnTest:    "go1.18",
+-			scan.GoVersionForVulnTest:         "go1.18",
 -			"_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`.
 -		},
 -		Settings{
@@ -119129,7 +132617,7 @@
 -			NoDiagnostics(ForFile("go.mod")),
 -		)
 -		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{
--			"go.mod": {IDs: []string{"GOSTDLIB"}, Mode: govulncheck.ModeGovulncheck}})
+-			"go.mod": {IDs: []string{"GOSTDLIB"}, Mode: vulncheck.ModeGovulncheck}})
 -	})
 -}
 -
@@ -119165,7 +132653,7 @@
 -			"GOVULNDB": db.URI(),
 -			// When fetchinging stdlib package vulnerability info,
 -			// behave as if our go version is go1.18 for this testing.
--			vulncheck.GoVersionForVulnTest:    "go1.18",
+-			scan.GoVersionForVulnTest:         "go1.18",
 -			"_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`.
 -		},
 -		Settings{"ui.diagnostic.vulncheck": "Imports"},
@@ -119178,7 +132666,7 @@
 -		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{
 -			"go.mod": {
 -				IDs:  []string{"GOSTDLIB"},
--				Mode: govulncheck.ModeImports,
+-				Mode: vulncheck.ModeImports,
 -			},
 -		})
 -	})
@@ -119186,13 +132674,13 @@
 -
 -type fetchVulncheckResult struct {
 -	IDs  []string
--	Mode govulncheck.AnalysisMode
+-	Mode vulncheck.AnalysisMode
 -}
 -
 -func testFetchVulncheckResult(t *testing.T, env *Env, want map[string]fetchVulncheckResult) {
 -	t.Helper()
 -
--	var result map[protocol.DocumentURI]*govulncheck.Result
+-	var result map[protocol.DocumentURI]*vulncheck.Result
 -	fetchCmd, err := command.NewFetchVulncheckResultCommand("fetch", command.URIArg{
 -		URI: env.Sandbox.Workdir.URI("go.mod"),
 -	})
@@ -119209,14 +132697,18 @@
 -	}
 -	got := map[string]fetchVulncheckResult{}
 -	for k, r := range result {
--		var osv []string
--		for _, v := range r.Vulns {
--			osv = append(osv, v.OSV.ID)
+-		osv := map[string]bool{}
+-		for _, v := range r.Findings {
+-			osv[v.OSV] = true
 -		}
--		sort.Strings(osv)
+-		ids := make([]string, 0, len(osv))
+-		for id := range osv {
+-			ids = append(ids, id)
+-		}
+-		sort.Strings(ids)
 -		modfile := env.Sandbox.Workdir.RelPath(k.SpanURI().Filename())
 -		got[modfile] = fetchVulncheckResult{
--			IDs:  osv,
+-			IDs:  ids,
 -			Mode: r.Mode,
 -		}
 -	}
@@ -119362,7 +132854,7 @@
 -		// When fetching stdlib package vulnerability info,
 -		// behave as if our go version is go1.18 for this testing.
 -		// The default behavior is to run `go env GOVERSION` (which isn't mutable env var).
--		vulncheck.GoVersionForVulnTest:    "go1.18",
+-		scan.GoVersionForVulnTest:         "go1.18",
 -		"_GOPLS_TEST_BINARY_RUN_AS_GOPLS": "true", // needed to run `gopls vulncheck`.
 -		"GOSUMDB":                         "off",
 -	}
@@ -119390,7 +132882,7 @@
 -		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{
 -			"go.mod": {
 -				IDs:  []string{"GO-2022-01", "GO-2022-02", "GO-2022-03"},
--				Mode: govulncheck.ModeImports,
+-				Mode: vulncheck.ModeImports,
 -			},
 -		})
 -
@@ -119429,7 +132921,7 @@
 -				codeActions: []string{
 -					"Run govulncheck to verify",
 -				},
--				hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."},
+-				hover: []string{"GO-2022-02", "vuln in bmod (no fix)", "No fix is available."},
 -			},
 -		}
 -
@@ -119541,12 +133033,10 @@
 -		)
 -
 -		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{
--			"go.mod": {IDs: []string{"GO-2022-01", "GO-2022-02", "GO-2022-03"}, Mode: govulncheck.ModeGovulncheck},
+-			"go.mod": {IDs: []string{"GO-2022-01", "GO-2022-02", "GO-2022-03"}, Mode: vulncheck.ModeGovulncheck},
 -		})
 -		env.OpenFile("x/x.go")
--		lineX := env.RegexpSearch("x/x.go", `c\.C1\(\)\.Vuln1\(\)`).Range.Start
 -		env.OpenFile("y/y.go")
--		lineY := env.RegexpSearch("y/y.go", `c\.C2\(\)\(\)`).Range.Start
 -		wantDiagnostics := map[string]vulnDiagExpectation{
 -			"golang.org/amod": {
 -				applyAction: "Upgrade to v1.0.6",
@@ -119560,10 +133050,6 @@
 -							"Upgrade to latest",
 -							"Reset govulncheck result",
 -						},
--						relatedInfo: []vulnRelatedInfo{
--							{"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln1
--							{"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln2
--						},
 -					},
 -					{
 -						msg:      "golang.org/amod has a vulnerability GO-2022-03 that is not used in the code.",
@@ -119574,10 +133060,6 @@
 -							"Upgrade to latest",
 -							"Reset govulncheck result",
 -						},
--						relatedInfo: []vulnRelatedInfo{
--							{"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln1
--							{"x.go", uint32(lineX.Line), "[GO-2022-01]"}, // avuln.VulnData.Vuln2
--						},
 -					},
 -				},
 -				codeActions: []string{
@@ -119596,15 +133078,12 @@
 -						codeActions: []string{
 -							"Reset govulncheck result", // no fix, but we should give an option to reset.
 -						},
--						relatedInfo: []vulnRelatedInfo{
--							{"y.go", uint32(lineY.Line), "[GO-2022-02]"}, // bvuln.Vuln
--						},
 -					},
 -				},
 -				codeActions: []string{
 -					"Reset govulncheck result", // no fix, but we should give an option to reset.
 -				},
--				hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."},
+-				hover: []string{"GO-2022-02", "vuln in bmod (no fix)", "No fix is available."},
 -			},
 -		}
 -
@@ -119710,7 +133189,7 @@
 -			ReadDiagnostics("go.mod", gotDiagnostics),
 -		)
 -
--		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{"go.mod": {IDs: []string{"GO-2022-02"}, Mode: govulncheck.ModeGovulncheck}})
+-		testFetchVulncheckResult(t, env, map[string]fetchVulncheckResult{"go.mod": {IDs: []string{"GO-2022-02"}, Mode: vulncheck.ModeGovulncheck}})
 -		// wantDiagnostics maps a module path in the require
 -		// section of a go.mod to diagnostics that will be returned
 -		// when running vulncheck.
@@ -119729,7 +133208,7 @@
 -				codeActions: []string{
 -					"Reset govulncheck result",
 -				},
--				hover: []string{"GO-2022-02", "This is a long description of this vulnerability.", "No fix is available."},
+-				hover: []string{"GO-2022-02", "vuln in bmod (no fix)", "No fix is available."},
 -			},
 -		}
 -
@@ -119786,10 +133265,6 @@
 -		if diag.Severity != w.severity || diag.Source != w.source {
 -			t.Errorf("incorrect (severity, source) for %q, want (%s, %s) got (%s, %s)\n", w.msg, w.severity, w.source, diag.Severity, diag.Source)
 -		}
--		sort.Slice(w.relatedInfo, func(i, j int) bool { return w.relatedInfo[i].less(w.relatedInfo[j]) })
--		if got, want := summarizeRelatedInfo(diag.RelatedInformation), w.relatedInfo; !cmp.Equal(got, want) {
--			t.Errorf("related info for %q do not match, want %v, got %v\n", w.msg, want, got)
--		}
 -		// Check expected code actions appear.
 -		gotActions := env.CodeAction("go.mod", []protocol.Diagnostic{*diag})
 -		if diff := diffCodeActions(gotActions, w.codeActions); diff != "" {
@@ -119810,22 +133285,6 @@
 -	return modPathDiagnostics
 -}
 -
--// summarizeRelatedInfo converts protocol.DiagnosticRelatedInformation to vulnRelatedInfo
--// that captures only the part that we want to test.
--func summarizeRelatedInfo(rinfo []protocol.DiagnosticRelatedInformation) []vulnRelatedInfo {
--	var res []vulnRelatedInfo
--	for _, r := range rinfo {
--		filename := filepath.Base(r.Location.URI.SpanURI().Filename())
--		message, _, _ := strings.Cut(r.Message, " ")
--		line := r.Location.Range.Start.Line
--		res = append(res, vulnRelatedInfo{filename, line, message})
--	}
--	sort.Slice(res, func(i, j int) bool {
--		return res[i].less(res[j])
--	})
--	return res
--}
--
 -type vulnRelatedInfo struct {
 -	Filename string
 -	Line     uint32
@@ -119874,8 +133333,8 @@
 -}
 diff -urN a/gopls/internal/regtest/misc/workspace_symbol_test.go b/gopls/internal/regtest/misc/workspace_symbol_test.go
 --- a/gopls/internal/regtest/misc/workspace_symbol_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/misc/workspace_symbol_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,124 +0,0 @@
++++ b/gopls/internal/regtest/misc/workspace_symbol_test.go	1970-01-01 08:00:00
+@@ -1,114 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -119885,7 +133344,7 @@
 -import (
 -	"testing"
 -
--	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"github.com/google/go-cmp/cmp"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
 -)
@@ -119899,7 +133358,7 @@
 --- a.go --
 -package p
 -
--const C1 = "a.go"
+-const K1 = "a.go"
 --- exclude.go --
 -
 -//go:build exclude
@@ -119907,23 +133366,17 @@
 -
 -package exclude
 -
--const C2 = "exclude.go"
+-const K2 = "exclude.go"
 -`
 -
 -	Run(t, files, func(t *testing.T, env *Env) {
 -		env.OpenFile("a.go")
--		syms := env.Symbol("C")
--		if got, want := len(syms), 1; got != want {
--			t.Errorf("got %d symbols, want %d", got, want)
--		}
+-		checkSymbols(env, "K", "K1")
 -
 -		// Opening up an ignored file will result in an overlay with missing
 -		// metadata, but this shouldn't break workspace symbols requests.
 -		env.OpenFile("exclude.go")
--		syms = env.Symbol("C")
--		if got, want := len(syms), 1; got != want {
--			t.Errorf("got %d symbols, want %d", got, want)
--		}
+-		checkSymbols(env, "K", "K1")
 -	})
 -}
 -
@@ -119949,15 +133402,13 @@
 -	WithOptions(
 -		Settings{"symbolMatcher": symbolMatcher},
 -	).Run(t, files, func(t *testing.T, env *Env) {
--		want := []string{
+-		checkSymbols(env, "Foo",
 -			"Foo",    // prefer exact segment matches first
 -			"FooBar", // ...followed by exact word matches
 -			"Fooex",  // shorter than Fooest, FooBar, lexically before Fooey
 -			"Fooey",  // shorter than Fooest, Foobar
 -			"Fooest",
--		}
--		got := env.Symbol("Foo")
--		compareSymbols(t, got, want...)
+-		)
 -	})
 -}
 -
@@ -119980,30 +133431,28 @@
 -	WithOptions(
 -		Settings{"symbolMatcher": symbolMatcher},
 -	).Run(t, files, func(t *testing.T, env *Env) {
--		compareSymbols(t, env.Symbol("ABC"), "ABC", "AxxBxxCxx")
--		compareSymbols(t, env.Symbol("'ABC"), "ABC")
--		compareSymbols(t, env.Symbol("^mod.com"), "mod.com/a.ABC", "mod.com/a.AxxBxxCxx")
--		compareSymbols(t, env.Symbol("^mod.com Axx"), "mod.com/a.AxxBxxCxx")
--		compareSymbols(t, env.Symbol("C$"), "ABC")
+-		checkSymbols(env, "ABC", "ABC", "AxxBxxCxx")
+-		checkSymbols(env, "'ABC", "ABC")
+-		checkSymbols(env, "^mod.com", "mod.com/a.ABC", "mod.com/a.AxxBxxCxx")
+-		checkSymbols(env, "^mod.com Axx", "mod.com/a.AxxBxxCxx")
+-		checkSymbols(env, "C$", "ABC")
 -	})
 -}
 -
--func compareSymbols(t *testing.T, got []protocol.SymbolInformation, want ...string) {
--	t.Helper()
--	if len(got) != len(want) {
--		t.Errorf("got %d symbols, want %d", len(got), len(want))
+-func checkSymbols(env *Env, query string, want ...string) {
+-	env.T.Helper()
+-	var got []string
+-	for _, info := range env.Symbol(query) {
+-		got = append(got, info.Name)
 -	}
--
--	for i := range got {
--		if got[i].Name != want[i] {
--			t.Errorf("got[%d] = %q, want %q", i, got[i].Name, want[i])
--		}
+-	if diff := cmp.Diff(got, want); diff != "" {
+-		env.T.Errorf("unexpected Symbol(%q) result (+want -got):\n%s", query, diff)
 -	}
 -}
 diff -urN a/gopls/internal/regtest/modfile/modfile_test.go b/gopls/internal/regtest/modfile/modfile_test.go
 --- a/gopls/internal/regtest/modfile/modfile_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/modfile/modfile_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1188 +0,0 @@
++++ b/gopls/internal/regtest/modfile/modfile_test.go	1970-01-01 08:00:00
+@@ -1,1222 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -120016,10 +133465,10 @@
 -	"strings"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
 -	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
--	"golang.org/x/tools/internal/bug"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	"golang.org/x/tools/internal/testenv"
@@ -120342,48 +133791,6 @@
 -	})
 -}
 -
--func TestUnusedDiag(t *testing.T) {
--
--	const proxy = `
---- example.com@v1.0.0/x.go --
--package pkg
--const X = 1
--`
--	const files = `
---- a/go.mod --
--module mod.com
--go 1.14
--require example.com v1.0.0
---- a/go.sum --
--example.com v1.0.0 h1:38O7j5rEBajXk+Q5wzLbRN7KqMkSgEiN9NqcM1O2bBM=
--example.com v1.0.0/go.mod h1:vUsPMGpx9ZXXzECCOsOmYCW7npJTwuA16yl89n3Mgls=
---- a/main.go --
--package main
--func main() {}
--`
--
--	const want = `module mod.com
--
--go 1.14
--`
--
--	RunMultiple{
--		{"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))},
--		{"nested", WithOptions(ProxyFiles(proxy))},
--	}.Run(t, files, func(t *testing.T, env *Env) {
--		env.OpenFile("a/go.mod")
--		var d protocol.PublishDiagnosticsParams
--		env.AfterChange(
--			Diagnostics(env.AtRegexp("a/go.mod", `require example.com`)),
--			ReadDiagnostics("a/go.mod", &d),
--		)
--		env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
--		if got := env.BufferText("a/go.mod"); got != want {
--			t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got))
--		}
--	})
--}
--
 -// Test to reproduce golang/go#39041. It adds a new require to a go.mod file
 -// that already has an unused require.
 -func TestNewDepWithUnusedDep(t *testing.T) {
@@ -120545,6 +133952,7 @@
 -			Diagnostics(env.AtRegexp("a/go.mod", `require example.com/blah/v2`), WithMessage("cannot find module providing")),
 -			ReadDiagnostics("a/go.mod", &modDiags),
 -		)
+-
 -		env.ApplyQuickFixes("a/go.mod", modDiags.Diagnostics)
 -		const want = `module mod.com
 -
@@ -120925,7 +134333,7 @@
 -		}
 -		// Confirm that we no longer have metadata when the file is saved.
 -		env.SaveBufferWithoutActions("go.mod")
--		_, err := env.Editor.GoToDefinition(env.Ctx, env.RegexpSearch("main.go", "hello"))
+-		_, err := env.Editor.Definition(env.Ctx, env.RegexpSearch("main.go", "hello"))
 -		if err == nil {
 -			t.Fatalf("expected error, got none")
 -		}
@@ -121192,9 +134600,129 @@
 -		env.SaveBuffer("go.work") // doesn't fail
 -	})
 -}
+-
+-func TestInconsistentMod(t *testing.T) {
+-	const proxy = `
+--- golang.org/x/mod@v0.7.0/go.mod --
+-go 1.20
+-module golang.org/x/mod
+--- golang.org/x/mod@v0.7.0/a.go --
+-package mod
+-func AutoQuote(string) string { return ""}
+--- golang.org/x/mod@v0.9.0/go.mod --
+-go 1.20
+-module golang.org/x/mod
+--- golang.org/x/mod@v0.9.0/a.go --
+-package mod
+-func AutoQuote(string) string { return ""}
+-`
+-	const files = `
+--- go.work --
+-go 1.20
+-use (
+-	./a
+-	./b
+-)
+-
+--- a/go.mod --
+-module a.mod.com
+-go 1.20
+-require golang.org/x/mod v0.6.0 // yyy
+-replace golang.org/x/mod v0.6.0 => golang.org/x/mod v0.7.0
+--- a/main.go --
+-package main
+-import "golang.org/x/mod"
+-import "fmt"
+-func main() {fmt.Println(mod.AutoQuote(""))}
+-
+--- b/go.mod --
+-module b.mod.com
+-go 1.20
+-require golang.org/x/mod v0.9.0 // xxx
+--- b/main.go --
+-package aaa
+-import "golang.org/x/mod"
+-import "fmt"
+-func main() {fmt.Println(mod.AutoQuote(""))}
+-var A int
+-
+--- b/c/go.mod --
+-module c.b.mod.com
+-go 1.20
+-require b.mod.com v0.4.2
+-replace b.mod.com => ../
+--- b/c/main.go --
+-package main
+-import "b.mod.com/aaa"
+-import "fmt"
+-func main() {fmt.Println(aaa.A)}
+-`
+-	testenv.NeedsGo1Point(t, 18)
+-	WithOptions(
+-		ProxyFiles(proxy),
+-		Modes(Default),
+-	).Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("a/go.mod")
+-		ahints := env.InlayHints("a/go.mod")
+-		if len(ahints) != 1 {
+-			t.Errorf("expected exactly one hint, got %d: %#v", len(ahints), ahints)
+-		}
+-		env.OpenFile("b/c/go.mod")
+-		bhints := env.InlayHints("b/c/go.mod")
+-		if len(bhints) != 0 {
+-			t.Errorf("expected no hints, got %d: %#v", len(bhints), bhints)
+-		}
+-	})
+-
+-}
+diff -urN a/gopls/internal/regtest/modfile/tempmodfile_test.go b/gopls/internal/regtest/modfile/tempmodfile_test.go
+--- a/gopls/internal/regtest/modfile/tempmodfile_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/modfile/tempmodfile_test.go	1970-01-01 08:00:00
+@@ -1,41 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package modfile
+-
+-import (
+-	"testing"
+-
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-)
+-
+-// This test replaces an older, problematic test (golang/go#57784). But it has
+-// been a long time since the go command would mutate go.mod files.
+-//
+-// TODO(golang/go#61970): the tempModfile setting should be removed entirely.
+-func TestTempModfileUnchanged(t *testing.T) {
+-	// badMod has a go.mod file that is missing a go directive.
+-	const badMod = `
+--- go.mod --
+-module badmod.test/p
+--- p.go --
+-package p
+-`
+-
+-	WithOptions(
+-		Modes(Default), // no reason to test this with a remote gopls
+-		ProxyFiles(workspaceProxy),
+-		Settings{
+-			"tempModfile": true,
+-		},
+-	).Run(t, badMod, func(t *testing.T, env *Env) {
+-		env.OpenFile("p.go")
+-		env.AfterChange()
+-		want := "module badmod.test/p\n"
+-		got := env.ReadWorkspaceFile("go.mod")
+-		if got != want {
+-			t.Errorf("go.mod content:\n%s\nwant:\n%s", got, want)
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/template/template_test.go b/gopls/internal/regtest/template/template_test.go
 --- a/gopls/internal/regtest/template/template_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/template/template_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/template/template_test.go	1970-01-01 08:00:00
 @@ -1,231 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -121206,10 +134734,10 @@
 -	"strings"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -)
 -
 -func TestMain(m *testing.M) {
@@ -121427,10 +134955,99 @@
 -}
 -
 -// Hover needs tests
+diff -urN a/gopls/internal/regtest/watch/setting_test.go b/gopls/internal/regtest/watch/setting_test.go
+--- a/gopls/internal/regtest/watch/setting_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/watch/setting_test.go	1970-01-01 08:00:00
+@@ -1,85 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package regtest
+-
+-import (
+-	"fmt"
+-	"testing"
+-
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-)
+-
+-func TestSubdirWatchPatterns(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module mod.test
+-
+-go 1.18
+--- subdir/subdir.go --
+-package subdir
+-`
+-
+-	tests := []struct {
+-		clientName          string
+-		subdirWatchPatterns string
+-		wantWatched         bool
+-	}{
+-		{"other client", "on", true},
+-		{"other client", "off", false},
+-		{"other client", "auto", false},
+-		{"Visual Studio Code", "auto", true},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(fmt.Sprintf("%s_%s", test.clientName, test.subdirWatchPatterns), func(t *testing.T) {
+-			WithOptions(
+-				ClientName(test.clientName),
+-				Settings{
+-					"subdirWatchPatterns": test.subdirWatchPatterns,
+-				},
+-			).Run(t, files, func(t *testing.T, env *Env) {
+-				var expectation Expectation
+-				if test.wantWatched {
+-					expectation = FileWatchMatching("subdir")
+-				} else {
+-					expectation = NoFileWatchMatching("subdir")
+-				}
+-				env.OnceMet(
+-					InitialWorkspaceLoad,
+-					expectation,
+-				)
+-			})
+-		})
+-	}
+-}
+-
+-// This test checks that we surface errors for invalid subdir watch patterns,
+-// as the triple of ("off"|"on"|"auto") may be confusing to users inclined to
+-// use (true|false) or some other truthy value.
+-func TestSubdirWatchPatterns_BadValues(t *testing.T) {
+-	tests := []struct {
+-		badValue    interface{}
+-		wantMessage string
+-	}{
+-		{true, "invalid type bool, expect string"},
+-		{false, "invalid type bool, expect string"},
+-		{"yes", `invalid option "yes"`},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(fmt.Sprint(test.badValue), func(t *testing.T) {
+-			WithOptions(
+-				Settings{
+-					"subdirWatchPatterns": test.badValue,
+-				},
+-			).Run(t, "", func(t *testing.T, env *Env) {
+-				env.OnceMet(
+-					InitialWorkspaceLoad,
+-					ShownMessage(test.wantMessage),
+-				)
+-			})
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/regtest/watch/watch_test.go b/gopls/internal/regtest/watch/watch_test.go
 --- a/gopls/internal/regtest/watch/watch_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/watch/watch_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,702 +0,0 @@
++++ b/gopls/internal/regtest/watch/watch_test.go	1970-01-01 08:00:00
+@@ -1,704 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -121440,9 +135057,9 @@
 -import (
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
--	"golang.org/x/tools/internal/bug"
 -
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
@@ -121816,7 +135433,9 @@
 -		).Run(t, pkg, func(t *testing.T, env *Env) {
 -			env.OpenFile("a/a.go")
 -			env.OpenFile("a/a_unneeded.go")
--			env.AfterChange(
+-			env.Await(
+-				// Log messages are asynchronous to other events on the LSP stream, so we
+-				// can't use OnceMet or AfterChange here.
 -				LogMatching(protocol.Info, "a_unneeded.go", 1, false),
 -			)
 -
@@ -121828,7 +135447,7 @@
 -				Diagnostics(env.AtRegexp("a/a.go", "fmt")),
 -			)
 -			env.SaveBuffer("a/a.go")
--			env.AfterChange(
+-			env.Await(
 -				// There should only be one log message containing
 -				// a_unneeded.go, from the initial workspace load, which we
 -				// check for earlier. If there are more, there's a bug.
@@ -121844,7 +135463,7 @@
 -		).Run(t, pkg, func(t *testing.T, env *Env) {
 -			env.OpenFile("a/a.go")
 -			env.OpenFile("a/a_unneeded.go")
--			env.AfterChange(
+-			env.Await(
 -				LogMatching(protocol.Info, "a_unneeded.go", 1, false),
 -			)
 -
@@ -121856,7 +135475,7 @@
 -				Diagnostics(env.AtRegexp("a/a.go", "fmt")),
 -			)
 -			env.SaveBuffer("a/a.go")
--			env.AfterChange(
+-			env.Await(
 -				// There should only be one log message containing
 -				// a_unneeded.go, from the initial workspace load, which we
 -				// check for earlier. If there are more, there's a bug.
@@ -122010,7 +135629,7 @@
 -		env.AfterChange(
 -			NoDiagnostics(ForFile("main.go")),
 -		)
--		if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, true); err != nil {
+-		if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}, nil, true); err != nil {
 -			t.Fatal(err)
 -		}
 -
@@ -122133,10 +135752,56 @@
 -		)
 -	})
 -}
+diff -urN a/gopls/internal/regtest/workspace/adhoc_test.go b/gopls/internal/regtest/workspace/adhoc_test.go
+--- a/gopls/internal/regtest/workspace/adhoc_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/workspace/adhoc_test.go	1970-01-01 08:00:00
+@@ -1,42 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package workspace
+-
+-import (
+-	"testing"
+-
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-	"golang.org/x/tools/internal/testenv"
+-)
+-
+-// Test for golang/go#57209: editing a file in an ad-hoc package should not
+-// trigger conflicting diagnostics.
+-func TestAdhoc_Edits(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18)
+-
+-	const files = `
+--- a.go --
+-package foo
+-
+-const X = 1
+-
+--- b.go --
+-package foo
+-
+-// import "errors"
+-
+-const Y = X
+-`
+-
+-	Run(t, files, func(t *testing.T, env *Env) {
+-		env.OpenFile("b.go")
+-
+-		for i := 0; i < 10; i++ {
+-			env.RegexpReplace("b.go", `// import "errors"`, `import "errors"`)
+-			env.RegexpReplace("b.go", `import "errors"`, `// import "errors"`)
+-			env.AfterChange(NoDiagnostics())
+-		}
+-	})
+-}
 diff -urN a/gopls/internal/regtest/workspace/broken_test.go b/gopls/internal/regtest/workspace/broken_test.go
 --- a/gopls/internal/regtest/workspace/broken_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/broken_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,264 +0,0 @@
++++ b/gopls/internal/regtest/workspace/broken_test.go	1970-01-01 08:00:00
+@@ -1,263 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -122162,10 +135827,9 @@
 -
 -// Test for golang/go#53933
 -func TestBrokenWorkspace_DuplicateModules(t *testing.T) {
--	testenv.NeedsGo1Point(t, 18)
--
--	// TODO(golang/go#57650): fix this feature.
--	t.Skip("we no longer detect duplicate modules")
+-	// The go command error message was improved in Go 1.20 to mention multiple
+-	// modules.
+-	testenv.NeedsGo1Point(t, 20)
 -
 -	// This proxy module content is replaced by the workspace, but is still
 -	// required for module resolution to function in the Go command.
@@ -122237,8 +135901,8 @@
 -		ProxyFiles(proxy),
 -	).Run(t, src, func(t *testing.T, env *Env) {
 -		env.OpenFile("package1/main.go")
--		env.Await(
--			OutstandingWork(lsp.WorkspaceLoadFailure, `found module "example.com/foo" multiple times in the workspace`),
+-		env.AfterChange(
+-			OutstandingWork(lsp.WorkspaceLoadFailure, `module example.com/foo appears multiple times in workspace`),
 -		)
 -
 -		// Remove the redundant vendored copy of example.com.
@@ -122249,10 +135913,10 @@
 -			./package2/vendor/example.com/foo
 -		)
 -		`)
--		env.Await(NoOutstandingWork())
+-		env.AfterChange(NoOutstandingWork(IgnoreTelemetryPromptWork))
 -
 -		// Check that definitions in package1 go to the copy vendored in package2.
--		location := env.GoToDefinition(env.RegexpSearch("package1/main.go", "CompleteMe")).URI.SpanURI().Filename()
+-		location := string(env.GoToDefinition(env.RegexpSearch("package1/main.go", "CompleteMe")).URI)
 -		const wantLocation = "package2/vendor/example.com/foo/foo.go"
 -		if !strings.HasSuffix(location, wantLocation) {
 -			t.Errorf("got definition of CompleteMe at %q, want %q", location, wantLocation)
@@ -122360,7 +136024,7 @@
 -				env.Await(
 -					NoDiagnostics(ForFile("a/a.go")),
 -					NoDiagnostics(ForFile("b/go.mod")),
--					NoOutstandingWork(),
+-					NoOutstandingWork(IgnoreTelemetryPromptWork),
 -				)
 -
 -				env.ChangeWorkspaceFolders(".")
@@ -122396,14 +136060,14 @@
 -			env.OpenFile("a/a.go")
 -			env.AfterChange(
 -				NoDiagnostics(ForFile("a/a.go")),
--				NoOutstandingWork(),
+-				NoOutstandingWork(IgnoreTelemetryPromptWork),
 -			)
 -		})
 -	})
 -}
 diff -urN a/gopls/internal/regtest/workspace/directoryfilters_test.go b/gopls/internal/regtest/workspace/directoryfilters_test.go
 --- a/gopls/internal/regtest/workspace/directoryfilters_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/directoryfilters_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/workspace/directoryfilters_test.go	1970-01-01 08:00:00
 @@ -1,259 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -122666,8 +136330,8 @@
 -}
 diff -urN a/gopls/internal/regtest/workspace/fromenv_test.go b/gopls/internal/regtest/workspace/fromenv_test.go
 --- a/gopls/internal/regtest/workspace/fromenv_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/fromenv_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,68 +0,0 @@
++++ b/gopls/internal/regtest/workspace/fromenv_test.go	1970-01-01 08:00:00
+@@ -1,79 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -122675,6 +136339,8 @@
 -package workspace
 -
 -import (
+-	"fmt"
+-	"path/filepath"
 -	"testing"
 -
 -	. "golang.org/x/tools/gopls/internal/lsp/regtest"
@@ -122684,7 +136350,12 @@
 -// Test that setting go.work via environment variables or settings works.
 -func TestUseGoWorkOutsideTheWorkspace(t *testing.T) {
 -	testenv.NeedsGo1Point(t, 18)
--	const files = `
+-
+-	// As discussed in
+-	// https://github.com/golang/go/issues/59458#issuecomment-1513794691, we must
+-	// use \-separated paths in go.work use directives for this test to work
+-	// correctly on windows.
+-	var files = fmt.Sprintf(`
 --- work/a/go.mod --
 -module a.com
 -
@@ -122711,15 +136382,19 @@
 -go 1.18
 -
 -use (
--	$SANDBOX_WORKDIR/work/a
--	$SANDBOX_WORKDIR/work/b
--	$SANDBOX_WORKDIR/other/c
+-	%s
+-	%s
+-	%s
 -)
--`
+-`,
+-		filepath.Join("$SANDBOX_WORKDIR", "work", "a"),
+-		filepath.Join("$SANDBOX_WORKDIR", "work", "b"),
+-		filepath.Join("$SANDBOX_WORKDIR", "other", "c"),
+-	)
 -
 -	WithOptions(
 -		WorkspaceFolders("work"), // use a nested workspace dir, so that GOWORK is outside the workspace
--		EnvVars{"GOWORK": "$SANDBOX_WORKDIR/config/go.work"},
+-		EnvVars{"GOWORK": filepath.Join("$SANDBOX_WORKDIR", "config", "go.work")},
 -	).Run(t, files, func(t *testing.T, env *Env) {
 -		// When we have an explicit GOWORK set, we should get a file watch request.
 -		env.OnceMet(
@@ -122738,8 +136413,8 @@
 -}
 diff -urN a/gopls/internal/regtest/workspace/metadata_test.go b/gopls/internal/regtest/workspace/metadata_test.go
 --- a/gopls/internal/regtest/workspace/metadata_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/metadata_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,181 +0,0 @@
++++ b/gopls/internal/regtest/workspace/metadata_test.go	1970-01-01 08:00:00
+@@ -1,245 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -122801,16 +136476,7 @@
 -func main() {}
 -	`
 -
--	WithOptions(
--		// TODO(golang/go#54180): we don't run in 'experimental' mode here, because
--		// with "experimentalUseInvalidMetadata", this test fails because the
--		// orphaned bar.go is diagnosed using stale metadata, and then not
--		// re-diagnosed when new metadata arrives.
--		//
--		// We could fix this by re-running diagnostics after a load, but should
--		// consider whether that is worthwhile.
--		Modes(Default),
--	).Run(t, src, func(t *testing.T, env *Env) {
+-	Run(t, src, func(t *testing.T, env *Env) {
 -		env.OpenFile("foo.go")
 -		env.OpenFile("bar.go")
 -		env.OnceMet(
@@ -122839,7 +136505,7 @@
 -		// packages for bar.go
 -		env.RegexpReplace("bar.go", "ignore", "excluded")
 -		env.AfterChange(
--			Diagnostics(env.AtRegexp("bar.go", "package (main)"), WithMessage("No packages")),
+-			Diagnostics(env.AtRegexp("bar.go", "package (main)"), WithMessage("not included in your workspace")),
 -		)
 -	})
 -}
@@ -122921,9 +136587,82 @@
 -		}
 -	})
 -}
+-
+-// Test for golang/go#59458. With lazy module loading, we may not need
+-// transitively required modules.
+-func TestNestedModuleLoading_Issue59458(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 17) // needs lazy module loading
+-
+-	// In this test, module b.com/nested requires b.com/other, which in turn
+-	// requires b.com, but b.com/nested does not reach b.com through the package
+-	// graph. Therefore, b.com/nested does not need b.com on 1.17 and later,
+-	// thanks to graph pruning.
+-	//
+-	// We verify that we can load b.com/nested successfully. Previously, we
+-	// couldn't, because loading the pattern b.com/nested/... matched the module
+-	// b.com, which exists in the module graph but does not have a go.sum entry.
+-
+-	const proxy = `
+--- b.com@v1.2.3/go.mod --
+-module b.com
+-
+-go 1.18
+--- b.com@v1.2.3/b/b.go --
+-package b
+-
+-func Hello() {}
+-
+--- b.com/other@v1.4.6/go.mod --
+-module b.com/other
+-
+-go 1.18
+-
+-require b.com v1.2.3
+--- b.com/other@v1.4.6/go.sun --
+-b.com v1.2.3 h1:AGjCxWRJLUuJiZ21IUTByr9buoa6+B6Qh5LFhVLKpn4=
+--- b.com/other@v1.4.6/bar/bar.go --
+-package bar
+-
+-import "b.com/b"
+-
+-func _() {
+-	b.Hello()
+-}
+--- b.com/other@v1.4.6/foo/foo.go --
+-package foo
+-
+-const Foo = 0
+-`
+-
+-	const files = `
+--- go.mod --
+-module b.com/nested
+-
+-go 1.18
+-
+-require b.com/other v1.4.6
+--- go.sum --
+-b.com/other v1.4.6 h1:pHXSzGsk6DamYXp9uRdDB9A/ZQqAN9it+JudU0sBf94=
+-b.com/other v1.4.6/go.mod h1:T0TYuGdAHw4p/l0+1P/yhhYHfZRia7PaadNVDu58OWM=
+--- nested.go --
+-package nested
+-
+-import "b.com/other/foo"
+-
+-const C = foo.Foo
+-`
+-	WithOptions(
+-		ProxyFiles(proxy),
+-	).Run(t, files, func(t *testing.T, env *Env) {
+-		env.OnceMet(
+-			InitialWorkspaceLoad,
+-			NoDiagnostics(),
+-		)
+-	})
+-}
 diff -urN a/gopls/internal/regtest/workspace/misspelling_test.go b/gopls/internal/regtest/workspace/misspelling_test.go
 --- a/gopls/internal/regtest/workspace/misspelling_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/misspelling_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/workspace/misspelling_test.go	1970-01-01 08:00:00
 @@ -1,80 +0,0 @@
 -// Copyright 2023 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -123005,9 +136744,355 @@
 -		env.AfterChange(NoDiagnostics())
 -	})
 -}
+diff -urN a/gopls/internal/regtest/workspace/quickfix_test.go b/gopls/internal/regtest/workspace/quickfix_test.go
+--- a/gopls/internal/regtest/workspace/quickfix_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/regtest/workspace/quickfix_test.go	1970-01-01 08:00:00
+@@ -1,342 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package workspace
+-
+-import (
+-	"strings"
+-	"testing"
+-
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	"golang.org/x/tools/gopls/internal/lsp/tests/compare"
+-	"golang.org/x/tools/internal/testenv"
+-
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-)
+-
+-func TestQuickFix_UseModule(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // needs go.work
+-
+-	const files = `
+--- go.work --
+-go 1.20
+-
+-use (
+-	./a
+-)
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main
+-
+-import "mod.com/a/lib"
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- a/lib/lib.go --
+-package lib
+-
+-const C = "b"
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main
+-
+-import "mod.com/b/lib"
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- b/lib/lib.go --
+-package lib
+-
+-const C = "b"
+-`
+-
+-	for _, title := range []string{
+-		"Use this module",
+-		"Use all modules",
+-	} {
+-		t.Run(title, func(t *testing.T) {
+-			Run(t, files, func(t *testing.T, env *Env) {
+-				env.OpenFile("b/main.go")
+-				var d protocol.PublishDiagnosticsParams
+-				env.AfterChange(ReadDiagnostics("b/main.go", &d))
+-				fixes := env.GetQuickFixes("b/main.go", d.Diagnostics)
+-				var toApply []protocol.CodeAction
+-				for _, fix := range fixes {
+-					if strings.Contains(fix.Title, title) {
+-						toApply = append(toApply, fix)
+-					}
+-				}
+-				if len(toApply) != 1 {
+-					t.Fatalf("codeAction: got %d quick fixes matching %q, want 1; got: %v", len(toApply), title, toApply)
+-				}
+-				env.ApplyCodeAction(toApply[0])
+-				env.AfterChange(NoDiagnostics())
+-				want := `go 1.20
+-
+-use (
+-	./a
+-	./b
+-)
+-`
+-				got := env.ReadWorkspaceFile("go.work")
+-				if diff := compare.Text(want, got); diff != "" {
+-					t.Errorf("unexpeced go.work content:\n%s", diff)
+-				}
+-			})
+-		})
+-	}
+-}
+-
+-func TestQuickFix_AddGoWork(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // needs go.work
+-
+-	const files = `
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main
+-
+-import "mod.com/a/lib"
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- a/lib/lib.go --
+-package lib
+-
+-const C = "b"
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main
+-
+-import "mod.com/b/lib"
+-
+-func main() {
+-	_ = lib.C
+-}
+-
+--- b/lib/lib.go --
+-package lib
+-
+-const C = "b"
+-`
+-
+-	tests := []struct {
+-		name  string
+-		file  string
+-		title string
+-		want  string // expected go.work content, excluding go directive line
+-	}{
+-		{
+-			"use b",
+-			"b/main.go",
+-			"Add a go.work file using this module",
+-			`
+-use ./b
+-`,
+-		},
+-		{
+-			"use a",
+-			"a/main.go",
+-			"Add a go.work file using this module",
+-			`
+-use ./a
+-`,
+-		},
+-		{
+-			"use all",
+-			"a/main.go",
+-			"Add a go.work file using all modules",
+-			`
+-use (
+-	./a
+-	./b
+-)
+-`,
+-		},
+-	}
+-
+-	for _, test := range tests {
+-		t.Run(test.name, func(t *testing.T) {
+-			Run(t, files, func(t *testing.T, env *Env) {
+-				env.OpenFile(test.file)
+-				var d protocol.PublishDiagnosticsParams
+-				env.AfterChange(ReadDiagnostics(test.file, &d))
+-				fixes := env.GetQuickFixes(test.file, d.Diagnostics)
+-				var toApply []protocol.CodeAction
+-				for _, fix := range fixes {
+-					if strings.Contains(fix.Title, test.title) {
+-						toApply = append(toApply, fix)
+-					}
+-				}
+-				if len(toApply) != 1 {
+-					t.Fatalf("codeAction: got %d quick fixes matching %q, want 1; got: %v", len(toApply), test.title, toApply)
+-				}
+-				env.ApplyCodeAction(toApply[0])
+-				env.AfterChange(
+-					NoDiagnostics(ForFile(test.file)),
+-				)
+-
+-				got := env.ReadWorkspaceFile("go.work")
+-				// Ignore the `go` directive, which we assume is on the first line of
+-				// the go.work file. This allows the test to be independent of go version.
+-				got = strings.Join(strings.Split(got, "\n")[1:], "\n")
+-				if diff := compare.Text(test.want, got); diff != "" {
+-					t.Errorf("unexpected go.work content:\n%s", diff)
+-				}
+-			})
+-		})
+-	}
+-}
+-
+-func TestQuickFix_UnsavedGoWork(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // needs go.work
+-
+-	const files = `
+--- go.work --
+-go 1.21
+-
+-use (
+-	./a
+-)
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main
+-
+-func main() {}
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main
+-
+-func main() {}
+-`
+-
+-	for _, title := range []string{
+-		"Use this module",
+-		"Use all modules",
+-	} {
+-		t.Run(title, func(t *testing.T) {
+-			Run(t, files, func(t *testing.T, env *Env) {
+-				env.OpenFile("go.work")
+-				env.OpenFile("b/main.go")
+-				env.RegexpReplace("go.work", "go 1.21", "go 1.21 // arbitrary comment")
+-				var d protocol.PublishDiagnosticsParams
+-				env.AfterChange(ReadDiagnostics("b/main.go", &d))
+-				fixes := env.GetQuickFixes("b/main.go", d.Diagnostics)
+-				var toApply []protocol.CodeAction
+-				for _, fix := range fixes {
+-					if strings.Contains(fix.Title, title) {
+-						toApply = append(toApply, fix)
+-					}
+-				}
+-				if len(toApply) != 1 {
+-					t.Fatalf("codeAction: got %d quick fixes matching %q, want 1; got: %v", len(toApply), title, toApply)
+-				}
+-				fix := toApply[0]
+-				err := env.Editor.ApplyCodeAction(env.Ctx, fix)
+-				if err == nil {
+-					t.Fatalf("codeAction(%q) succeeded unexpectedly", fix.Title)
+-				}
+-
+-				if got := err.Error(); !strings.Contains(got, "must save") {
+-					t.Errorf("codeAction(%q) returned error %q, want containing \"must save\"", fix.Title, err)
+-				}
+-			})
+-		})
+-	}
+-}
+-
+-func TestQuickFix_GOWORKOff(t *testing.T) {
+-	testenv.NeedsGo1Point(t, 18) // needs go.work
+-
+-	const files = `
+--- go.work --
+-go 1.21
+-
+-use (
+-	./a
+-)
+--- a/go.mod --
+-module mod.com/a
+-
+-go 1.18
+-
+--- a/main.go --
+-package main
+-
+-func main() {}
+--- b/go.mod --
+-module mod.com/b
+-
+-go 1.18
+-
+--- b/main.go --
+-package main
+-
+-func main() {}
+-`
+-
+-	for _, title := range []string{
+-		"Use this module",
+-		"Use all modules",
+-	} {
+-		t.Run(title, func(t *testing.T) {
+-			WithOptions(
+-				EnvVars{"GOWORK": "off"},
+-			).Run(t, files, func(t *testing.T, env *Env) {
+-				env.OpenFile("go.work")
+-				env.OpenFile("b/main.go")
+-				var d protocol.PublishDiagnosticsParams
+-				env.AfterChange(ReadDiagnostics("b/main.go", &d))
+-				fixes := env.GetQuickFixes("b/main.go", d.Diagnostics)
+-				var toApply []protocol.CodeAction
+-				for _, fix := range fixes {
+-					if strings.Contains(fix.Title, title) {
+-						toApply = append(toApply, fix)
+-					}
+-				}
+-				if len(toApply) != 1 {
+-					t.Fatalf("codeAction: got %d quick fixes matching %q, want 1; got: %v", len(toApply), title, toApply)
+-				}
+-				fix := toApply[0]
+-				err := env.Editor.ApplyCodeAction(env.Ctx, fix)
+-				if err == nil {
+-					t.Fatalf("codeAction(%q) succeeded unexpectedly", fix.Title)
+-				}
+-
+-				if got := err.Error(); !strings.Contains(got, "GOWORK=off") {
+-					t.Errorf("codeAction(%q) returned error %q, want containing \"GOWORK=off\"", fix.Title, err)
+-				}
+-			})
+-		})
+-	}
+-}
 diff -urN a/gopls/internal/regtest/workspace/standalone_test.go b/gopls/internal/regtest/workspace/standalone_test.go
 --- a/gopls/internal/regtest/workspace/standalone_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/standalone_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/regtest/workspace/standalone_test.go	1970-01-01 08:00:00
 @@ -1,206 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -123033,7 +137118,7 @@
 --- lib/lib.go --
 -package lib
 -
--const C = 0
+-const K = 0
 -
 -type I interface {
 -	M()
@@ -123048,13 +137133,13 @@
 -	"mod.test/lib"
 -)
 -
--const C = 1
+-const K = 1
 -
 -type Mer struct{}
 -func (Mer) M()
 -
 -func main() {
--	println(lib.C + C)
+-	println(lib.K + K)
 -}
 -`
 -	WithOptions(
@@ -123064,13 +137149,18 @@
 -		Modes(Default),
 -	).Run(t, files, func(t *testing.T, env *Env) {
 -		// Initially, gopls should not know about the standalone file as it hasn't
--		// been opened. Therefore, we should only find one symbol 'C'.
--		syms := env.Symbol("C")
+-		// been opened. Therefore, we should only find one symbol 'K'.
+-		//
+-		// (The choice of "K" is a little sleazy: it was originally "C" until
+-		// we started adding "unsafe" to the workspace unconditionally, which
+-		// caused a spurious match of "unsafe.Slice". But in practice every
+-		// workspace depends on unsafe.)
+-		syms := env.Symbol("K")
 -		if got, want := len(syms), 1; got != want {
--			t.Errorf("got %d symbols, want %d", got, want)
+-			t.Errorf("got %d symbols, want %d (%+v)", got, want, syms)
 -		}
 -
--		// Similarly, we should only find one reference to "C", and no
+-		// Similarly, we should only find one reference to "K", and no
 -		// implementations of I.
 -		checkLocations := func(method string, gotLocations []protocol.Location, wantFiles ...string) {
 -			var gotFiles []string
@@ -123087,14 +137177,14 @@
 -		env.OpenFile("lib/lib.go")
 -		env.AfterChange(NoDiagnostics())
 -
--		// Replacing C with D should not cause any workspace diagnostics, since we
+-		// Replacing K with D should not cause any workspace diagnostics, since we
 -		// haven't yet opened the standalone file.
--		env.RegexpReplace("lib/lib.go", "C", "D")
+-		env.RegexpReplace("lib/lib.go", "K", "D")
 -		env.AfterChange(NoDiagnostics())
--		env.RegexpReplace("lib/lib.go", "D", "C")
+-		env.RegexpReplace("lib/lib.go", "D", "K")
 -		env.AfterChange(NoDiagnostics())
 -
--		refs := env.References(env.RegexpSearch("lib/lib.go", "C"))
+-		refs := env.References(env.RegexpSearch("lib/lib.go", "K"))
 -		checkLocations("References", refs, "lib/lib.go")
 -
 -		impls := env.Implementations(env.RegexpSearch("lib/lib.go", "I"))
@@ -123106,56 +137196,56 @@
 -
 -		// Having opened the standalone file, we should find its symbols in the
 -		// workspace.
--		syms = env.Symbol("C")
+-		syms = env.Symbol("K")
 -		if got, want := len(syms), 2; got != want {
 -			t.Fatalf("got %d symbols, want %d", got, want)
 -		}
 -
--		foundMainC := false
+-		foundMainK := false
 -		var symNames []string
 -		for _, sym := range syms {
 -			symNames = append(symNames, sym.Name)
--			if sym.Name == "main.C" {
--				foundMainC = true
+-			if sym.Name == "main.K" {
+-				foundMainK = true
 -			}
 -		}
--		if !foundMainC {
--			t.Errorf("WorkspaceSymbol(\"C\") = %v, want containing main.C", symNames)
+-		if !foundMainK {
+-			t.Errorf("WorkspaceSymbol(\"K\") = %v, want containing main.K", symNames)
 -		}
 -
 -		// We should resolve workspace definitions in the standalone file.
--		fileLoc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "lib.(C)"))
+-		fileLoc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "lib.(K)"))
 -		file := env.Sandbox.Workdir.URIToPath(fileLoc.URI)
 -		if got, want := file, "lib/lib.go"; got != want {
--			t.Errorf("GoToDefinition(lib.C) = %v, want %v", got, want)
+-			t.Errorf("GoToDefinition(lib.K) = %v, want %v", got, want)
 -		}
 -
 -		// ...as well as intra-file definitions
--		loc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "\\+ (C)"))
--		wantLoc := env.RegexpSearch("lib/ignore.go", "const (C)")
+-		loc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "\\+ (K)"))
+-		wantLoc := env.RegexpSearch("lib/ignore.go", "const (K)")
 -		if loc != wantLoc {
--			t.Errorf("GoToDefinition(C) = %v, want %v", loc, wantLoc)
+-			t.Errorf("GoToDefinition(K) = %v, want %v", loc, wantLoc)
 -		}
 -
--		// Renaming "lib.C" to "lib.D" should cause a diagnostic in the standalone
+-		// Renaming "lib.K" to "lib.D" should cause a diagnostic in the standalone
 -		// file.
--		env.RegexpReplace("lib/lib.go", "C", "D")
--		env.AfterChange(Diagnostics(env.AtRegexp("lib/ignore.go", "lib.(C)")))
+-		env.RegexpReplace("lib/lib.go", "K", "D")
+-		env.AfterChange(Diagnostics(env.AtRegexp("lib/ignore.go", "lib.(K)")))
 -
 -		// Undoing the replacement should fix diagnostics
--		env.RegexpReplace("lib/lib.go", "D", "C")
+-		env.RegexpReplace("lib/lib.go", "D", "K")
 -		env.AfterChange(NoDiagnostics())
 -
 -		// Now that our workspace has no errors, we should be able to find
 -		// references and rename.
--		refs = env.References(env.RegexpSearch("lib/lib.go", "C"))
+-		refs = env.References(env.RegexpSearch("lib/lib.go", "K"))
 -		checkLocations("References", refs, "lib/lib.go", "lib/ignore.go")
 -
 -		impls = env.Implementations(env.RegexpSearch("lib/lib.go", "I"))
 -		checkLocations("Implementations", impls, "lib/ignore.go")
 -
 -		// Renaming should rename in the standalone package.
--		env.Rename(env.RegexpSearch("lib/lib.go", "C"), "D")
+-		env.Rename(env.RegexpSearch("lib/lib.go", "K"), "D")
 -		env.RegexpSearch("lib/ignore.go", "lib.D")
 -	})
 -}
@@ -123204,11 +137294,6 @@
 -			"standaloneTags": []string{"ignore"},
 -		}
 -		env.ChangeConfiguration(cfg)
--
--		// TODO(golang/go#56158): gopls does not purge previously published
--		// diagnostice when configuration changes.
--		env.RegexpReplace("ignore.go", "arbitrary", "meaningless")
--
 -		env.AfterChange(
 -			NoDiagnostics(ForFile("ignore.go")),
 -			Diagnostics(env.AtRegexp("standalone.go", "package (main)")),
@@ -123217,8 +137302,8 @@
 -}
 diff -urN a/gopls/internal/regtest/workspace/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go
 --- a/gopls/internal/regtest/workspace/workspace_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/regtest/workspace/workspace_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,1263 +0,0 @@
++++ b/gopls/internal/regtest/workspace/workspace_test.go	1970-01-01 08:00:00
+@@ -1,1258 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -123232,11 +137317,11 @@
 -	"strings"
 -	"testing"
 -
+-	"golang.org/x/tools/gopls/internal/bug"
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp"
 -	"golang.org/x/tools/gopls/internal/lsp/fake"
 -	"golang.org/x/tools/gopls/internal/lsp/protocol"
--	"golang.org/x/tools/internal/bug"
 -	"golang.org/x/tools/internal/gocommand"
 -	"golang.org/x/tools/internal/testenv"
 -
@@ -123398,35 +137483,12 @@
 -replace random.org => %s
 -`, env.ReadWorkspaceFile("pkg/go.mod"), dir)
 -		env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace)
--		env.AfterChange(
+-		env.Await(
 -			LogMatching(protocol.Info, `packages\.Load #\d+\n`, 2, false),
 -		)
 -	})
 -}
 -
--// This test checks that gopls updates the set of files it watches when a
--// replace target is added to the go.mod.
--func TestWatchReplaceTargets(t *testing.T) {
--	t.Skipf("skipping known-flaky test: see https://go.dev/issue/50748")
--
--	WithOptions(
--		ProxyFiles(workspaceProxy),
--		WorkspaceFolders("pkg"),
--	).Run(t, workspaceModule, func(t *testing.T, env *Env) {
--		// Add a replace directive and expect the files that gopls is watching
--		// to change.
--		dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename()
--		goModWithReplace := fmt.Sprintf(`%s
--replace random.org => %s
--`, env.ReadWorkspaceFile("pkg/go.mod"), dir)
--		env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace)
--		env.AfterChange(
--			UnregistrationMatching("didChangeWatchedFiles"),
--			RegistrationMatching("didChangeWatchedFiles"),
--		)
--	})
--}
--
 -const workspaceModuleProxy = `
 --- example.com@v1.2.3/go.mod --
 -module example.com
@@ -123796,10 +137858,18 @@
 -`
 -	WithOptions(
 -		ProxyFiles(workspaceModuleProxy),
+-		Settings{
+-			"subdirWatchPatterns": "on",
+-		},
 -	).Run(t, multiModule, func(t *testing.T, env *Env) {
--		// Initially, the go.work should cause only the a.com module to be
--		// loaded. Validate this by jumping to a definition in b.com and ensuring
--		// that we go to the module cache.
+-		// Initially, the go.work should cause only the a.com module to be loaded,
+-		// so we shouldn't get any file watches for modb. Further validate this by
+-		// jumping to a definition in b.com and ensuring that we go to the module
+-		// cache.
+-		env.OnceMet(
+-			InitialWorkspaceLoad,
+-			NoFileWatchMatching("modb"),
+-		)
 -		env.OpenFile("moda/a/a.go")
 -		env.Await(env.DoneWithOpen())
 -
@@ -123831,9 +137901,13 @@
 -`)
 -
 -		// As of golang/go#54069, writing go.work to the workspace triggers a
--		// workspace reload.
+-		// workspace reload, and new file watches.
 -		env.AfterChange(
 -			Diagnostics(env.AtRegexp("modb/b/b.go", "x")),
+-			// TODO(golang/go#60340): we don't get a file watch yet, because
+-			// updateWatchedDirectories runs before snapshot.load. Instead, we get it
+-			// after the next change (the didOpen below).
+-			// FileWatchMatching("modb"),
 -		)
 -
 -		// Jumping to definition should now go to b.com in the workspace.
@@ -123844,7 +137918,13 @@
 -		// Now, let's modify the go.work *overlay* (not on disk), and verify that
 -		// this change is only picked up once it is saved.
 -		env.OpenFile("go.work")
--		env.AfterChange()
+-		env.AfterChange(
+-			// TODO(golang/go#60340): delete this expectation in favor of
+-			// the commented-out expectation above, once we fix the evaluation order
+-			// of file watches. We should not have to wait for a second change to get
+-			// the correct watches.
+-			FileWatchMatching("modb"),
+-		)
 -		env.SetBufferContent("go.work", `go 1.17
 -
 -use (
@@ -123868,7 +137948,7 @@
 -		}
 -
 -		// This fails if guarded with a OnceMet(DoneWithSave(), ...), because it is
--		// debounced (and therefore not synchronous with the change).
+-		// delayed (and therefore not synchronous with the change).
 -		env.Await(NoDiagnostics(ForFile("modb/go.mod")))
 -
 -		// Test Formatting.
@@ -124280,7 +138360,7 @@
 -		// package declaration.
 -		env.AfterChange(
 -			NoDiagnostics(ForFile("main.go")),
--			Diagnostics(AtPosition("b/main.go", 0, 0)),
+-			Diagnostics(env.AtRegexp("b/main.go", "package (main)")),
 -		)
 -		env.WriteWorkspaceFile("go.work", `go 1.16
 -
@@ -124306,7 +138386,7 @@
 -
 -		env.AfterChange(
 -			NoDiagnostics(ForFile("main.go")),
--			Diagnostics(AtPosition("b/main.go", 0, 0)),
+-			Diagnostics(env.AtRegexp("b/main.go", "package (main)")),
 -		)
 -	})
 -}
@@ -124484,7 +138564,7 @@
 -}
 diff -urN a/gopls/internal/span/parse.go b/gopls/internal/span/parse.go
 --- a/gopls/internal/span/parse.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/parse.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/span/parse.go	1970-01-01 08:00:00
 @@ -1,114 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -124602,8 +138682,8 @@
 -}
 diff -urN a/gopls/internal/span/span.go b/gopls/internal/span/span.go
 --- a/gopls/internal/span/span.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/span.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,253 +0,0 @@
++++ b/gopls/internal/span/span.go	1970-01-01 08:00:00
+@@ -1,249 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -124703,10 +138783,6 @@
 -	return comparePoint(a.v.End, b.v.End)
 -}
 -
--func ComparePoint(a, b Point) int {
--	return comparePoint(a.v, b.v)
--}
--
 -func comparePoint(a, b point) int {
 -	if !a.hasPosition() {
 -		if a.Offset < b.Offset {
@@ -124859,7 +138935,7 @@
 -}
 diff -urN a/gopls/internal/span/span_test.go b/gopls/internal/span/span_test.go
 --- a/gopls/internal/span/span_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/span_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/span/span_test.go	1970-01-01 08:00:00
 @@ -1,57 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -124920,8 +138996,8 @@
 -}
 diff -urN a/gopls/internal/span/uri.go b/gopls/internal/span/uri.go
 --- a/gopls/internal/span/uri.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/uri.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,185 +0,0 @@
++++ b/gopls/internal/span/uri.go	1970-01-01 08:00:00
+@@ -1,177 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -125099,17 +139175,9 @@
 -	}
 -	return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
 -}
--
--// Dir returns the URI for the directory containing uri. Dir panics if uri is
--// not a file uri.
--//
--// TODO(rfindley): add a unit test for various edge cases.
--func Dir(uri URI) URI {
--	return URIFromPath(filepath.Dir(uri.Filename()))
--}
 diff -urN a/gopls/internal/span/uri_test.go b/gopls/internal/span/uri_test.go
 --- a/gopls/internal/span/uri_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/uri_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/span/uri_test.go	1970-01-01 08:00:00
 @@ -1,117 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -125230,7 +139298,7 @@
 -}
 diff -urN a/gopls/internal/span/uri_windows_test.go b/gopls/internal/span/uri_windows_test.go
 --- a/gopls/internal/span/uri_windows_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/span/uri_windows_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/span/uri_windows_test.go	1970-01-01 08:00:00
 @@ -1,112 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -125344,10 +139412,1135 @@
 -		}
 -	}
 -}
-diff -urN a/gopls/internal/vulncheck/command.go b/gopls/internal/vulncheck/command.go
---- a/gopls/internal/vulncheck/command.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/command.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,381 +0,0 @@
+diff -urN a/gopls/internal/telemetry/latency.go b/gopls/internal/telemetry/latency.go
+--- a/gopls/internal/telemetry/latency.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/telemetry/latency.go	1970-01-01 08:00:00
+@@ -1,102 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-package telemetry
+-
+-import (
+-	"context"
+-	"errors"
+-	"fmt"
+-	"sort"
+-	"sync"
+-	"time"
+-
+-	"golang.org/x/telemetry/counter"
+-)
+-
+-// latencyKey is used for looking up latency counters.
+-type latencyKey struct {
+-	operation, bucket string
+-	isError           bool
+-}
+-
+-var (
+-	latencyBuckets = []struct {
+-		end  time.Duration
+-		name string
+-	}{
+-		{10 * time.Millisecond, "<10ms"},
+-		{50 * time.Millisecond, "<50ms"},
+-		{100 * time.Millisecond, "<100ms"},
+-		{200 * time.Millisecond, "<200ms"},
+-		{500 * time.Millisecond, "<500ms"},
+-		{1 * time.Second, "<1s"},
+-		{5 * time.Second, "<5s"},
+-		{24 * time.Hour, "<24h"},
+-	}
+-
+-	latencyCounterMu sync.Mutex
+-	latencyCounters  = make(map[latencyKey]*counter.Counter) // lazily populated
+-)
+-
+-// ForEachLatencyCounter runs the provided function for each current latency
+-// counter measuring the given operation.
+-//
+-// Exported for testing.
+-func ForEachLatencyCounter(operation string, isError bool, f func(*counter.Counter)) {
+-	latencyCounterMu.Lock()
+-	defer latencyCounterMu.Unlock()
+-
+-	for k, v := range latencyCounters {
+-		if k.operation == operation && k.isError == isError {
+-			f(v)
+-		}
+-	}
+-}
+-
+-// getLatencyCounter returns the counter used to record latency of the given
+-// operation in the given bucket.
+-func getLatencyCounter(operation, bucket string, isError bool) *counter.Counter {
+-	latencyCounterMu.Lock()
+-	defer latencyCounterMu.Unlock()
+-
+-	key := latencyKey{operation, bucket, isError}
+-	c, ok := latencyCounters[key]
+-	if !ok {
+-		var name string
+-		if isError {
+-			name = fmt.Sprintf("gopls/%s/error-latency:%s", operation, bucket)
+-		} else {
+-			name = fmt.Sprintf("gopls/%s/latency:%s", operation, bucket)
+-		}
+-		c = counter.New(name)
+-		latencyCounters[key] = c
+-	}
+-	return c
+-}
+-
+-// StartLatencyTimer starts a timer for the gopls operation with the given
+-// name, and returns a func to stop the timer and record the latency sample.
+-//
+-// If the context provided to the the resulting func is done, no observation is
+-// recorded.
+-func StartLatencyTimer(operation string) func(context.Context, error) {
+-	start := time.Now()
+-	return func(ctx context.Context, err error) {
+-		if errors.Is(ctx.Err(), context.Canceled) {
+-			// Ignore timing where the operation is cancelled, it may be influenced
+-			// by client behavior.
+-			return
+-		}
+-		latency := time.Since(start)
+-		bucketIdx := sort.Search(len(latencyBuckets), func(i int) bool {
+-			bucket := latencyBuckets[i]
+-			return latency < bucket.end
+-		})
+-		if bucketIdx < len(latencyBuckets) { // ignore latency longer than a day :)
+-			bucketName := latencyBuckets[bucketIdx].name
+-			getLatencyCounter(operation, bucketName, err != nil).Inc()
+-		}
+-	}
+-}
+diff -urN a/gopls/internal/telemetry/telemetry.go b/gopls/internal/telemetry/telemetry.go
+--- a/gopls/internal/telemetry/telemetry.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/telemetry/telemetry.go	1970-01-01 08:00:00
+@@ -1,93 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.19
+-// +build go1.19
+-
+-package telemetry
+-
+-import (
+-	"fmt"
+-
+-	"golang.org/x/telemetry"
+-	"golang.org/x/telemetry/counter"
+-	"golang.org/x/telemetry/upload"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-)
+-
+-// Mode calls x/telemetry.Mode.
+-func Mode() string {
+-	return telemetry.Mode()
+-}
+-
+-// SetMode calls x/telemetry.SetMode.
+-func SetMode(mode string) error {
+-	return telemetry.SetMode(mode)
+-}
+-
+-// Start starts telemetry instrumentation.
+-func Start() {
+-	counter.Open()
+-	// upload only once at startup, hoping that users restart gopls often.
+-	go upload.Run(nil)
+-}
+-
+-// RecordClientInfo records gopls client info.
+-func RecordClientInfo(params *protocol.ParamInitialize) {
+-	client := "gopls/client:other"
+-	if params != nil && params.ClientInfo != nil {
+-		switch params.ClientInfo.Name {
+-		case "Visual Studio Code":
+-			client = "gopls/client:vscode"
+-		case "Visual Studio Code - Insiders":
+-			client = "gopls/client:vscode-insiders"
+-		case "VSCodium":
+-			client = "gopls/client:vscodium"
+-		case "code-server":
+-			// https://github.com/coder/code-server/blob/3cb92edc76ecc2cfa5809205897d93d4379b16a6/ci/build/build-vscode.sh#L19
+-			client = "gopls/client:code-server"
+-		case "Eglot":
+-			// https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-03/msg00954.html
+-			client = "gopls/client:eglot"
+-		case "govim":
+-			// https://github.com/govim/govim/pull/1189
+-			client = "gopls/client:govim"
+-		case "Neovim":
+-			// https://github.com/neovim/neovim/blob/42333ea98dfcd2994ee128a3467dfe68205154cd/runtime/lua/vim/lsp.lua#L1361
+-			client = "gopls/client:neovim"
+-		case "coc.nvim":
+-			// https://github.com/neoclide/coc.nvim/blob/3dc6153a85ed0f185abec1deb972a66af3fbbfb4/src/language-client/client.ts#L994
+-			client = "gopls/client:coc.nvim"
+-		case "Sublime Text LSP":
+-			// https://github.com/sublimelsp/LSP/blob/e608f878e7e9dd34aabe4ff0462540fadcd88fcc/plugin/core/sessions.py#L493
+-			client = "gopls/client:sublimetext"
+-		default:
+-			// at least accumulate the client name locally
+-			counter.New(fmt.Sprintf("gopls/client-other:%s", params.ClientInfo.Name)).Inc()
+-			// but also record client:other
+-		}
+-	}
+-	counter.Inc(client)
+-}
+-
+-// RecordViewGoVersion records the Go minor version number (1.x) used for a view.
+-func RecordViewGoVersion(x int) {
+-	if x < 0 {
+-		return
+-	}
+-	name := fmt.Sprintf("gopls/goversion:1.%d", x)
+-	counter.Inc(name)
+-}
+-
+-// AddForwardedCounters adds the given counters on behalf of clients.
+-// Names and values must have the same length.
+-func AddForwardedCounters(names []string, values []int64) {
+-	for i, n := range names {
+-		v := values[i]
+-		if n == "" || v < 0 {
+-			continue // Should we report an error? Who is the audience?
+-		}
+-		counter.Add("fwd/"+n, v)
+-	}
+-}
+diff -urN a/gopls/internal/telemetry/telemetry_go118.go b/gopls/internal/telemetry/telemetry_go118.go
+--- a/gopls/internal/telemetry/telemetry_go118.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/telemetry/telemetry_go118.go	1970-01-01 08:00:00
+@@ -1,30 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build !go1.19
+-// +build !go1.19
+-
+-package telemetry
+-
+-import "golang.org/x/tools/gopls/internal/lsp/protocol"
+-
+-func Mode() string {
+-	return "local"
+-}
+-
+-func SetMode(mode string) error {
+-	return nil
+-}
+-
+-func Start() {
+-}
+-
+-func RecordClientInfo(params *protocol.ParamInitialize) {
+-}
+-
+-func RecordViewGoVersion(x int) {
+-}
+-
+-func AddForwardedCounters(names []string, values []int64) {
+-}
+diff -urN a/gopls/internal/telemetry/telemetry_test.go b/gopls/internal/telemetry/telemetry_test.go
+--- a/gopls/internal/telemetry/telemetry_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/telemetry/telemetry_test.go	1970-01-01 08:00:00
+@@ -1,215 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.21 && !openbsd && !js && !wasip1 && !solaris && !android && !386
+-// +build go1.21,!openbsd,!js,!wasip1,!solaris,!android,!386
+-
+-package telemetry_test
+-
+-import (
+-	"context"
+-	"errors"
+-	"os"
+-	"strconv"
+-	"strings"
+-	"testing"
+-	"time"
+-
+-	"golang.org/x/telemetry/counter"
+-	"golang.org/x/telemetry/counter/countertest" // requires go1.21+
+-	"golang.org/x/tools/gopls/internal/bug"
+-	"golang.org/x/tools/gopls/internal/hooks"
+-	"golang.org/x/tools/gopls/internal/lsp/command"
+-	"golang.org/x/tools/gopls/internal/lsp/protocol"
+-	. "golang.org/x/tools/gopls/internal/lsp/regtest"
+-	"golang.org/x/tools/gopls/internal/telemetry"
+-)
+-
+-func TestMain(m *testing.M) {
+-	tmp, err := os.MkdirTemp("", "gopls-telemetry-test")
+-	if err != nil {
+-		panic(err)
+-	}
+-	countertest.Open(tmp)
+-	defer os.RemoveAll(tmp)
+-	Main(m, hooks.Options)
+-}
+-
+-func TestTelemetry(t *testing.T) {
+-	var (
+-		goversion = ""
+-		editor    = "vscode" // We set ClientName("Visual Studio Code") below.
+-	)
+-
+-	// Run gopls once to determine the Go version.
+-	WithOptions(
+-		Modes(Default),
+-	).Run(t, "", func(_ *testing.T, env *Env) {
+-		goversion = strconv.Itoa(env.GoVersion())
+-	})
+-
+-	// counters that should be incremented once per session
+-	sessionCounters := []*counter.Counter{
+-		counter.New("gopls/client:" + editor),
+-		counter.New("gopls/goversion:1." + goversion),
+-		counter.New("fwd/vscode/linter:a"),
+-	}
+-	initialCounts := make([]uint64, len(sessionCounters))
+-	for i, c := range sessionCounters {
+-		count, err := countertest.ReadCounter(c)
+-		if err != nil {
+-			t.Fatalf("ReadCounter(%s): %v", c.Name(), err)
+-		}
+-		initialCounts[i] = count
+-	}
+-
+-	// Verify that a properly configured session gets notified of a bug on the
+-	// server.
+-	WithOptions(
+-		Modes(Default), // must be in-process to receive the bug report below
+-		Settings{"showBugReports": true},
+-		ClientName("Visual Studio Code"),
+-	).Run(t, "", func(_ *testing.T, env *Env) {
+-		goversion = strconv.Itoa(env.GoVersion())
+-		addForwardedCounters(env, []string{"vscode/linter:a"}, []int64{1})
+-		const desc = "got a bug"
+-		bug.Report(desc) // want a stack counter with the trace starting from here.
+-		env.Await(ShownMessage(desc))
+-	})
+-
+-	// gopls/editor:client
+-	// gopls/goversion:1.x
+-	// fwd/vscode/linter:a
+-	for i, c := range sessionCounters {
+-		want := initialCounts[i] + 1
+-		got, err := countertest.ReadCounter(c)
+-		if err != nil || got != want {
+-			t.Errorf("ReadCounter(%q) = (%v, %v), want (%v, nil)", c.Name(), got, err, want)
+-			t.Logf("Current timestamp = %v", time.Now().UTC())
+-		}
+-	}
+-
+-	// gopls/bug
+-	bugcount := bug.BugReportCount
+-	counts, err := countertest.ReadStackCounter(bugcount)
+-	if err != nil {
+-		t.Fatalf("ReadStackCounter(bugreportcount) failed - %v", err)
+-	}
+-	if len(counts) != 1 || !hasEntry(counts, t.Name(), 1) {
+-		t.Errorf("read stackcounter(%q) = (%#v, %v), want one entry", "gopls/bug", counts, err)
+-		t.Logf("Current timestamp = %v", time.Now().UTC())
+-	}
+-}
+-
+-func addForwardedCounters(env *Env, names []string, values []int64) {
+-	args, err := command.MarshalArgs(command.AddTelemetryCountersArgs{
+-		Names: names, Values: values,
+-	})
+-	if err != nil {
+-		env.T.Fatal(err)
+-	}
+-	var res error
+-	env.ExecuteCommand(&protocol.ExecuteCommandParams{
+-		Command:   command.AddTelemetryCounters.ID(),
+-		Arguments: args,
+-	}, res)
+-	if res != nil {
+-		env.T.Errorf("%v failed - %v", command.AddTelemetryCounters.ID(), res)
+-	}
+-}
+-
+-func hasEntry(counts map[string]uint64, pattern string, want uint64) bool {
+-	for k, v := range counts {
+-		if strings.Contains(k, pattern) && v == want {
+-			return true
+-		}
+-	}
+-	return false
+-}
+-
+-func TestLatencyCounter(t *testing.T) {
+-	const operation = "TestLatencyCounter" // a unique operation name
+-
+-	stop := telemetry.StartLatencyTimer(operation)
+-	stop(context.Background(), nil)
+-
+-	for isError, want := range map[bool]uint64{false: 1, true: 0} {
+-		if got := totalLatencySamples(t, operation, isError); got != want {
+-			t.Errorf("totalLatencySamples(operation=%v, isError=%v) = %d, want %d", operation, isError, got, want)
+-		}
+-	}
+-}
+-
+-func TestLatencyCounter_Error(t *testing.T) {
+-	const operation = "TestLatencyCounter_Error" // a unique operation name
+-
+-	stop := telemetry.StartLatencyTimer(operation)
+-	stop(context.Background(), errors.New("bad"))
+-
+-	for isError, want := range map[bool]uint64{false: 0, true: 1} {
+-		if got := totalLatencySamples(t, operation, isError); got != want {
+-			t.Errorf("totalLatencySamples(operation=%v, isError=%v) = %d, want %d", operation, isError, got, want)
+-		}
+-	}
+-}
+-
+-func TestLatencyCounter_Cancellation(t *testing.T) {
+-	const operation = "TestLatencyCounter_Cancellation"
+-
+-	stop := telemetry.StartLatencyTimer(operation)
+-	ctx, cancel := context.WithCancel(context.Background())
+-	cancel()
+-	stop(ctx, nil)
+-
+-	for isError, want := range map[bool]uint64{false: 0, true: 0} {
+-		if got := totalLatencySamples(t, operation, isError); got != want {
+-			t.Errorf("totalLatencySamples(operation=%v, isError=%v) = %d, want %d", operation, isError, got, want)
+-		}
+-	}
+-}
+-
+-func totalLatencySamples(t *testing.T, operation string, isError bool) uint64 {
+-	var total uint64
+-	telemetry.ForEachLatencyCounter(operation, isError, func(c *counter.Counter) {
+-		count, err := countertest.ReadCounter(c)
+-		if err != nil {
+-			t.Errorf("ReadCounter(%s) failed: %v", c.Name(), err)
+-		} else {
+-			total += count
+-		}
+-	})
+-	return total
+-}
+-
+-func TestLatencyInstrumentation(t *testing.T) {
+-	const files = `
+--- go.mod --
+-module mod.test/a
+-go 1.18
+--- a.go --
+-package a
+-
+-func _() {
+-	x := 0
+-	_ = x
+-}
+-`
+-
+-	// Verify that a properly configured session gets notified of a bug on the
+-	// server.
+-	WithOptions(
+-		Modes(Default), // must be in-process to receive the bug report below
+-	).Run(t, files, func(_ *testing.T, env *Env) {
+-		env.OpenFile("a.go")
+-		before := totalLatencySamples(t, "completion", false)
+-		loc := env.RegexpSearch("a.go", "x")
+-		for i := 0; i < 10; i++ {
+-			env.Completion(loc)
+-		}
+-		after := totalLatencySamples(t, "completion", false)
+-		if after-before < 10 {
+-			t.Errorf("after 10 completions, completion counter went from %d to %d", before, after)
+-		}
+-	})
+-}
+diff -urN a/gopls/internal/vulncheck/copier.go b/gopls/internal/vulncheck/copier.go
+--- a/gopls/internal/vulncheck/copier.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/copier.go	1970-01-01 08:00:00
+@@ -1,142 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build ignore
+-// +build ignore
+-
+-//go:generate go run ./copier.go
+-
+-// Copier is a tool to automate copy of govulncheck's internal files.
+-//
+-//   - copy golang.org/x/vuln/internal/osv/ to osv
+-//   - copy golang.org/x/vuln/internal/govulncheck/ to govulncheck
+-package main
+-
+-import (
+-	"bytes"
+-	"encoding/json"
+-	"fmt"
+-	"go/parser"
+-	"go/token"
+-	"log"
+-	"os"
+-	"os/exec"
+-	"path/filepath"
+-	"strconv"
+-	"strings"
+-
+-	"golang.org/x/tools/internal/edit"
+-)
+-
+-func main() {
+-	log.SetPrefix("copier: ")
+-	log.SetFlags(log.Lshortfile)
+-
+-	srcMod := "golang.org/x/vuln"
+-	srcModVers := "@latest"
+-	srcDir, srcVer := downloadModule(srcMod + srcModVers)
+-
+-	cfg := rewrite{
+-		banner:        fmt.Sprintf("// Code generated by copying from %v@%v (go run copier.go); DO NOT EDIT.", srcMod, srcVer),
+-		srcImportPath: "golang.org/x/vuln/internal",
+-		dstImportPath: currentPackagePath(),
+-	}
+-
+-	copyFiles("osv", filepath.Join(srcDir, "internal", "osv"), cfg)
+-	copyFiles("govulncheck", filepath.Join(srcDir, "internal", "govulncheck"), cfg)
+-}
+-
+-type rewrite struct {
+-	// DO NOT EDIT marker to add at the beginning
+-	banner string
+-	// rewrite srcImportPath with dstImportPath
+-	srcImportPath string
+-	dstImportPath string
+-}
+-
+-func copyFiles(dst, src string, cfg rewrite) {
+-	entries, err := os.ReadDir(src)
+-	if err != nil {
+-		log.Fatalf("failed to read dir: %v", err)
+-	}
+-	if err := os.MkdirAll(dst, 0777); err != nil {
+-		log.Fatalf("failed to create dir: %v", err)
+-	}
+-
+-	for _, e := range entries {
+-		fname := e.Name()
+-		// we need only non-test go files.
+-		if e.IsDir() || !strings.HasSuffix(fname, ".go") || strings.HasSuffix(fname, "_test.go") {
+-			continue
+-		}
+-		data, err := os.ReadFile(filepath.Join(src, fname))
+-		if err != nil {
+-			log.Fatal(err)
+-		}
+-		fset := token.NewFileSet()
+-		f, err := parser.ParseFile(fset, fname, data, parser.ParseComments|parser.ImportsOnly)
+-		if err != nil {
+-			log.Fatalf("parsing source module:\n%s", err)
+-		}
+-
+-		buf := edit.NewBuffer(data)
+-		at := func(p token.Pos) int {
+-			return fset.File(p).Offset(p)
+-		}
+-
+-		// Add banner right after the copyright statement (the first comment)
+-		bannerInsert, banner := f.FileStart, cfg.banner
+-		if len(f.Comments) > 0 && strings.HasPrefix(f.Comments[0].Text(), "Copyright ") {
+-			bannerInsert = f.Comments[0].End()
+-			banner = "\n\n" + banner
+-		}
+-		buf.Replace(at(bannerInsert), at(bannerInsert), banner)
+-
+-		// Adjust imports
+-		for _, spec := range f.Imports {
+-			path, err := strconv.Unquote(spec.Path.Value)
+-			if err != nil {
+-				log.Fatal(err)
+-			}
+-			if strings.HasPrefix(path, cfg.srcImportPath) {
+-				newPath := strings.Replace(path, cfg.srcImportPath, cfg.dstImportPath, 1)
+-				buf.Replace(at(spec.Path.Pos()), at(spec.Path.End()), strconv.Quote(newPath))
+-			}
+-		}
+-		data = buf.Bytes()
+-
+-		if err := os.WriteFile(filepath.Join(dst, fname), data, 0666); err != nil {
+-			log.Fatal(err)
+-		}
+-	}
+-}
+-
+-func downloadModule(srcModVers string) (dir, ver string) {
+-	var stdout, stderr bytes.Buffer
+-	cmd := exec.Command("go", "mod", "download", "-json", srcModVers)
+-	cmd.Stdout = &stdout
+-	cmd.Stderr = &stderr
+-	if err := cmd.Run(); err != nil {
+-		log.Fatalf("go mod download -json %s: %v\n%s%s", srcModVers, err, stderr.Bytes(), stdout.Bytes())
+-	}
+-	var info struct {
+-		Dir     string
+-		Version string
+-	}
+-	if err := json.Unmarshal(stdout.Bytes(), &info); err != nil {
+-		log.Fatalf("go mod download -json %s: invalid JSON output: %v\n%s%s", srcModVers, err, stderr.Bytes(), stdout.Bytes())
+-	}
+-	return info.Dir, info.Version
+-}
+-
+-func currentPackagePath() string {
+-	var stdout, stderr bytes.Buffer
+-	cmd := exec.Command("go", "list", ".")
+-	cmd.Stdout = &stdout
+-	cmd.Stderr = &stderr
+-	if err := cmd.Run(); err != nil {
+-		log.Fatalf("go list: %v\n%s%s", err, stderr.Bytes(), stdout.Bytes())
+-	}
+-	return strings.TrimSpace(stdout.String())
+-}
+diff -urN a/gopls/internal/vulncheck/govulncheck/govulncheck.go b/gopls/internal/vulncheck/govulncheck/govulncheck.go
+--- a/gopls/internal/vulncheck/govulncheck/govulncheck.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/govulncheck/govulncheck.go	1970-01-01 08:00:00
+@@ -1,160 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Code generated by copying from golang.org/x/vuln@v1.0.1 (go run copier.go); DO NOT EDIT.
+-
+-// Package govulncheck contains the JSON output structs for govulncheck.
+-package govulncheck
+-
+-import (
+-	"time"
+-
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
+-)
+-
+-const (
+-	// ProtocolVersion is the current protocol version this file implements
+-	ProtocolVersion = "v1.0.0"
+-)
+-
+-// Message is an entry in the output stream. It will always have exactly one
+-// field filled in.
+-type Message struct {
+-	Config   *Config    `json:"config,omitempty"`
+-	Progress *Progress  `json:"progress,omitempty"`
+-	OSV      *osv.Entry `json:"osv,omitempty"`
+-	Finding  *Finding   `json:"finding,omitempty"`
+-}
+-
+-// Config must occur as the first message of a stream and informs the client
+-// about the information used to generate the findings.
+-// The only required field is the protocol version.
+-type Config struct {
+-	// ProtocolVersion specifies the version of the JSON protocol.
+-	ProtocolVersion string `json:"protocol_version"`
+-
+-	// ScannerName is the name of the tool, for example, govulncheck.
+-	//
+-	// We expect this JSON format to be used by other tools that wrap
+-	// govulncheck, which will have a different name.
+-	ScannerName string `json:"scanner_name,omitempty"`
+-
+-	// ScannerVersion is the version of the tool.
+-	ScannerVersion string `json:"scanner_version,omitempty"`
+-
+-	// DB is the database used by the tool, for example,
+-	// vuln.go.dev.
+-	DB string `json:"db,omitempty"`
+-
+-	// LastModified is the last modified time of the data source.
+-	DBLastModified *time.Time `json:"db_last_modified,omitempty"`
+-
+-	// GoVersion is the version of Go used for analyzing standard library
+-	// vulnerabilities.
+-	GoVersion string `json:"go_version,omitempty"`
+-
+-	// ScanLevel instructs govulncheck to analyze at a specific level of detail.
+-	// Valid values include module, package and symbol.
+-	ScanLevel ScanLevel `json:"scan_level,omitempty"`
+-}
+-
+-// Progress messages are informational only, intended to allow users to monitor
+-// the progress of a long running scan.
+-// A stream must remain fully valid and able to be interpreted with all progress
+-// messages removed.
+-type Progress struct {
+-	// A time stamp for the message.
+-	Timestamp *time.Time `json:"time,omitempty"`
+-
+-	// Message is the progress message.
+-	Message string `json:"message,omitempty"`
+-}
+-
+-// Vuln represents a single OSV entry.
+-type Finding struct {
+-	// OSV is the id of the detected vulnerability.
+-	OSV string `json:"osv,omitempty"`
+-
+-	// FixedVersion is the module version where the vulnerability was
+-	// fixed. This is empty if a fix is not available.
+-	//
+-	// If there are multiple fixed versions in the OSV report, this will
+-	// be the fixed version in the latest range event for the OSV report.
+-	//
+-	// For example, if the range events are
+-	// {introduced: 0, fixed: 1.0.0} and {introduced: 1.1.0}, the fixed version
+-	// will be empty.
+-	//
+-	// For the stdlib, we will show the fixed version closest to the
+-	// Go version that is used. For example, if a fix is available in 1.17.5 and
+-	// 1.18.5, and the GOVERSION is 1.17.3, 1.17.5 will be returned as the
+-	// fixed version.
+-	FixedVersion string `json:"fixed_version,omitempty"`
+-
+-	// Trace contains an entry for each frame in the trace.
+-	//
+-	// Frames are sorted starting from the imported vulnerable symbol
+-	// until the entry point. The first frame in Frames should match
+-	// Symbol.
+-	//
+-	// In binary mode, trace will contain a single-frame with no position
+-	// information.
+-	//
+-	// When a package is imported but no vulnerable symbol is called, the trace
+-	// will contain a single-frame with no symbol or position information.
+-	Trace []*Frame `json:"trace,omitempty"`
+-}
+-
+-// Frame represents an entry in a finding trace.
+-type Frame struct {
+-	// Module is the module path of the module containing this symbol.
+-	//
+-	// Importable packages in the standard library will have the path "stdlib".
+-	Module string `json:"module"`
+-
+-	// Version is the module version from the build graph.
+-	Version string `json:"version,omitempty"`
+-
+-	// Package is the import path.
+-	Package string `json:"package,omitempty"`
+-
+-	// Function is the function name.
+-	Function string `json:"function,omitempty"`
+-
+-	// Receiver is the receiver type if the called symbol is a method.
+-	//
+-	// The client can create the final symbol name by
+-	// prepending Receiver to FuncName.
+-	Receiver string `json:"receiver,omitempty"`
+-
+-	// Position describes an arbitrary source position
+-	// including the file, line, and column location.
+-	// A Position is valid if the line number is > 0.
+-	Position *Position `json:"position,omitempty"`
+-}
+-
+-// Position represents arbitrary source position.
+-type Position struct {
+-	Filename string `json:"filename,omitempty"` // filename, if any
+-	Offset   int    `json:"offset"`             // byte offset, starting at 0
+-	Line     int    `json:"line"`               // line number, starting at 1
+-	Column   int    `json:"column"`             // column number, starting at 1 (byte count)
+-}
+-
+-// ScanLevel represents the detail level at which a scan occurred.
+-// This can be necessary to correctly interpret the findings, for instance if
+-// a scan is at symbol level and a finding does not have a symbol it means the
+-// vulnerability was imported but not called. If the scan however was at
+-// "package" level, that determination cannot be made.
+-type ScanLevel string
+-
+-const (
+-	scanLevelModule  = "module"
+-	scanLevelPackage = "package"
+-	scanLevelSymbol  = "symbol"
+-)
+-
+-// WantSymbols can be used to check whether the scan level is one that is able
+-// to generate symbols called findings.
+-func (l ScanLevel) WantSymbols() bool { return l == scanLevelSymbol }
+diff -urN a/gopls/internal/vulncheck/govulncheck/handler.go b/gopls/internal/vulncheck/govulncheck/handler.go
+--- a/gopls/internal/vulncheck/govulncheck/handler.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/govulncheck/handler.go	1970-01-01 08:00:00
+@@ -1,61 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Code generated by copying from golang.org/x/vuln@v1.0.1 (go run copier.go); DO NOT EDIT.
+-
+-package govulncheck
+-
+-import (
+-	"encoding/json"
+-	"io"
+-
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
+-)
+-
+-// Handler handles messages to be presented in a vulnerability scan output
+-// stream.
+-type Handler interface {
+-	// Config communicates introductory message to the user.
+-	Config(config *Config) error
+-
+-	// Progress is called to display a progress message.
+-	Progress(progress *Progress) error
+-
+-	// OSV is invoked for each osv Entry in the stream.
+-	OSV(entry *osv.Entry) error
+-
+-	// Finding is called for each vulnerability finding in the stream.
+-	Finding(finding *Finding) error
+-}
+-
+-// HandleJSON reads the json from the supplied stream and hands the decoded
+-// output to the handler.
+-func HandleJSON(from io.Reader, to Handler) error {
+-	dec := json.NewDecoder(from)
+-	for dec.More() {
+-		msg := Message{}
+-		// decode the next message in the stream
+-		if err := dec.Decode(&msg); err != nil {
+-			return err
+-		}
+-		// dispatch the message
+-		var err error
+-		if msg.Config != nil {
+-			err = to.Config(msg.Config)
+-		}
+-		if msg.Progress != nil {
+-			err = to.Progress(msg.Progress)
+-		}
+-		if msg.OSV != nil {
+-			err = to.OSV(msg.OSV)
+-		}
+-		if msg.Finding != nil {
+-			err = to.Finding(msg.Finding)
+-		}
+-		if err != nil {
+-			return err
+-		}
+-	}
+-	return nil
+-}
+diff -urN a/gopls/internal/vulncheck/govulncheck/jsonhandler.go b/gopls/internal/vulncheck/govulncheck/jsonhandler.go
+--- a/gopls/internal/vulncheck/govulncheck/jsonhandler.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/govulncheck/jsonhandler.go	1970-01-01 08:00:00
+@@ -1,46 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Code generated by copying from golang.org/x/vuln@v1.0.1 (go run copier.go); DO NOT EDIT.
+-
+-package govulncheck
+-
+-import (
+-	"encoding/json"
+-
+-	"io"
+-
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
+-)
+-
+-type jsonHandler struct {
+-	enc *json.Encoder
+-}
+-
+-// NewJSONHandler returns a handler that writes govulncheck output as json.
+-func NewJSONHandler(w io.Writer) Handler {
+-	enc := json.NewEncoder(w)
+-	enc.SetIndent("", "  ")
+-	return &jsonHandler{enc: enc}
+-}
+-
+-// Config writes config block in JSON to the underlying writer.
+-func (h *jsonHandler) Config(config *Config) error {
+-	return h.enc.Encode(Message{Config: config})
+-}
+-
+-// Progress writes a progress message in JSON to the underlying writer.
+-func (h *jsonHandler) Progress(progress *Progress) error {
+-	return h.enc.Encode(Message{Progress: progress})
+-}
+-
+-// OSV writes an osv entry in JSON to the underlying writer.
+-func (h *jsonHandler) OSV(entry *osv.Entry) error {
+-	return h.enc.Encode(Message{OSV: entry})
+-}
+-
+-// Finding writes a finding in JSON to the underlying writer.
+-func (h *jsonHandler) Finding(finding *Finding) error {
+-	return h.enc.Encode(Message{Finding: finding})
+-}
+diff -urN a/gopls/internal/vulncheck/osv/osv.go b/gopls/internal/vulncheck/osv/osv.go
+--- a/gopls/internal/vulncheck/osv/osv.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/osv/osv.go	1970-01-01 08:00:00
+@@ -1,240 +0,0 @@
+-// Copyright 2023 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// Code generated by copying from golang.org/x/vuln@v1.0.1 (go run copier.go); DO NOT EDIT.
+-
+-// Package osv implements the Go OSV vulnerability format
+-// (https://go.dev/security/vuln/database#schema), which is a subset of
+-// the OSV shared vulnerability format
+-// (https://ossf.github.io/osv-schema), with database and
+-// ecosystem-specific meanings and fields.
+-//
+-// As this package is intended for use with the Go vulnerability
+-// database, only the subset of features which are used by that
+-// database are implemented (for instance, only the SEMVER affected
+-// range type is implemented).
+-package osv
+-
+-import "time"
+-
+-// RangeType specifies the type of version range being recorded and
+-// defines the interpretation of the RangeEvent object's Introduced
+-// and Fixed fields.
+-//
+-// In this implementation, only the "SEMVER" type is supported.
+-//
+-// See https://ossf.github.io/osv-schema/#affectedrangestype-field.
+-type RangeType string
+-
+-// RangeTypeSemver indicates a semantic version as defined by
+-// SemVer 2.0.0, with no leading "v" prefix.
+-const RangeTypeSemver RangeType = "SEMVER"
+-
+-// Ecosystem identifies the overall library ecosystem.
+-// In this implementation, only the "Go" ecosystem is supported.
+-type Ecosystem string
+-
+-// GoEcosystem indicates the Go ecosystem.
+-const GoEcosystem Ecosystem = "Go"
+-
+-// Pseudo-module paths used to describe vulnerabilities
+-// in the Go standard library and toolchain.
+-const (
+-	// GoStdModulePath is the pseudo-module path string used
+-	// to describe vulnerabilities in the Go standard library.
+-	GoStdModulePath = "stdlib"
+-	// GoCmdModulePath is the pseudo-module path string used
+-	// to describe vulnerabilities in the go command.
+-	GoCmdModulePath = "toolchain"
+-)
+-
+-// Module identifies the Go module containing the vulnerability.
+-// Note that this field is called "package" in the OSV specification.
+-//
+-// See https://ossf.github.io/osv-schema/#affectedpackage-field.
+-type Module struct {
+-	// The Go module path. Required.
+-	// For the Go standard library, this is "stdlib".
+-	// For the Go toolchain, this is "toolchain."
+-	Path string `json:"name"`
+-	// The ecosystem containing the module. Required.
+-	// This should always be "Go".
+-	Ecosystem Ecosystem `json:"ecosystem"`
+-}
+-
+-// RangeEvent describes a single module version that either
+-// introduces or fixes a vulnerability.
+-//
+-// Exactly one of Introduced and Fixed must be present. Other range
+-// event types (e.g, "last_affected" and "limit") are not supported in
+-// this implementation.
+-//
+-// See https://ossf.github.io/osv-schema/#affectedrangesevents-fields.
+-type RangeEvent struct {
+-	// Introduced is a version that introduces the vulnerability.
+-	// A special value, "0", represents a version that sorts before
+-	// any other version, and should be used to indicate that the
+-	// vulnerability exists from the "beginning of time".
+-	Introduced string `json:"introduced,omitempty"`
+-	// Fixed is a version that fixes the vulnerability.
+-	Fixed string `json:"fixed,omitempty"`
+-}
+-
+-// Range describes the affected versions of the vulnerable module.
+-//
+-// See https://ossf.github.io/osv-schema/#affectedranges-field.
+-type Range struct {
+-	// Type is the version type that should be used to interpret the
+-	// versions in Events. Required.
+-	// In this implementation, only the "SEMVER" type is supported.
+-	Type RangeType `json:"type"`
+-	// Events is a list of versions representing the ranges in which
+-	// the module is vulnerable. Required.
+-	// The events should be sorted, and MUST represent non-overlapping
+-	// ranges.
+-	// There must be at least one RangeEvent containing a value for
+-	// Introduced.
+-	// See https://ossf.github.io/osv-schema/#examples for examples.
+-	Events []RangeEvent `json:"events"`
+-}
+-
+-// Reference type is a reference (link) type.
+-type ReferenceType string
+-
+-const (
+-	// ReferenceTypeAdvisory is a published security advisory for
+-	// the vulnerability.
+-	ReferenceTypeAdvisory = ReferenceType("ADVISORY")
+-	// ReferenceTypeArticle is an article or blog post describing the vulnerability.
+-	ReferenceTypeArticle = ReferenceType("ARTICLE")
+-	// ReferenceTypeReport is a report, typically on a bug or issue tracker, of
+-	// the vulnerability.
+-	ReferenceTypeReport = ReferenceType("REPORT")
+-	// ReferenceTypeFix is a source code browser link to the fix (e.g., a GitHub commit).
+-	ReferenceTypeFix = ReferenceType("FIX")
+-	// ReferenceTypePackage is a home web page for the package.
+-	ReferenceTypePackage = ReferenceType("PACKAGE")
+-	// ReferenceTypeEvidence is a demonstration of the validity of a vulnerability claim.
+-	ReferenceTypeEvidence = ReferenceType("EVIDENCE")
+-	// ReferenceTypeWeb is a web page of some unspecified kind.
+-	ReferenceTypeWeb = ReferenceType("WEB")
+-)
+-
+-// Reference is a reference URL containing additional information,
+-// advisories, issue tracker entries, etc., about the vulnerability.
+-//
+-// See https://ossf.github.io/osv-schema/#references-field.
+-type Reference struct {
+-	// The type of reference. Required.
+-	Type ReferenceType `json:"type"`
+-	// The fully-qualified URL of the reference. Required.
+-	URL string `json:"url"`
+-}
+-
+-// Affected gives details about a module affected by the vulnerability.
+-//
+-// See https://ossf.github.io/osv-schema/#affected-fields.
+-type Affected struct {
+-	// The affected Go module. Required.
+-	// Note that this field is called "package" in the OSV specification.
+-	Module Module `json:"package"`
+-	// The module version ranges affected by the vulnerability.
+-	Ranges []Range `json:"ranges,omitempty"`
+-	// Details on the affected packages and symbols within the module.
+-	EcosystemSpecific EcosystemSpecific `json:"ecosystem_specific"`
+-}
+-
+-// Package contains additional information about an affected package.
+-// This is an ecosystem-specific field for the Go ecosystem.
+-type Package struct {
+-	// Path is the package import path. Required.
+-	Path string `json:"path,omitempty"`
+-	// GOOS is the execution operating system where the symbols appear, if
+-	// known.
+-	GOOS []string `json:"goos,omitempty"`
+-	// GOARCH specifies the execution architecture where the symbols appear, if
+-	// known.
+-	GOARCH []string `json:"goarch,omitempty"`
+-	// Symbols is a list of function and method names affected by
+-	// this vulnerability. Methods are listed as <recv>.<method>.
+-	//
+-	// If included, only programs which use these symbols will be marked as
+-	// vulnerable by `govulncheck`. If omitted, any program which imports this
+-	// package will be marked vulnerable.
+-	Symbols []string `json:"symbols,omitempty"`
+-}
+-
+-// EcosystemSpecific contains additional information about the vulnerable
+-// module for the Go ecosystem.
+-//
+-// See https://go.dev/security/vuln/database#schema.
+-type EcosystemSpecific struct {
+-	// Packages is the list of affected packages within the module.
+-	Packages []Package `json:"imports,omitempty"`
+-}
+-
+-// Entry represents a vulnerability in the Go OSV format, documented
+-// in https://go.dev/security/vuln/database#schema.
+-// It is a subset of the OSV schema (https://ossf.github.io/osv-schema).
+-// Only fields that are published in the Go Vulnerability Database
+-// are supported.
+-type Entry struct {
+-	// SchemaVersion is the OSV schema version used to encode this
+-	// vulnerability.
+-	SchemaVersion string `json:"schema_version,omitempty"`
+-	// ID is a unique identifier for the vulnerability. Required.
+-	// The Go vulnerability database issues IDs of the form
+-	// GO-<YEAR>-<ENTRYID>.
+-	ID string `json:"id"`
+-	// Modified is the time the entry was last modified. Required.
+-	Modified time.Time `json:"modified,omitempty"`
+-	// Published is the time the entry should be considered to have
+-	// been published.
+-	Published time.Time `json:"published,omitempty"`
+-	// Withdrawn is the time the entry should be considered to have
+-	// been withdrawn. If the field is missing, then the entry has
+-	// not been withdrawn.
+-	Withdrawn *time.Time `json:"withdrawn,omitempty"`
+-	// Aliases is a list of IDs for the same vulnerability in other
+-	// databases.
+-	Aliases []string `json:"aliases,omitempty"`
+-	// Summary gives a one-line, English textual summary of the vulnerability.
+-	// It is recommended that this field be kept short, on the order of no more
+-	// than 120 characters.
+-	Summary string `json:"summary,omitempty"`
+-	// Details contains additional English textual details about the vulnerability.
+-	Details string `json:"details"`
+-	// Affected contains information on the modules and versions
+-	// affected by the vulnerability.
+-	Affected []Affected `json:"affected"`
+-	// References contains links to more information about the
+-	// vulnerability.
+-	References []Reference `json:"references,omitempty"`
+-	// Credits contains credits to entities that helped find or fix the
+-	// vulnerability.
+-	Credits []Credit `json:"credits,omitempty"`
+-	// DatabaseSpecific contains additional information about the
+-	// vulnerability, specific to the Go vulnerability database.
+-	DatabaseSpecific *DatabaseSpecific `json:"database_specific,omitempty"`
+-}
+-
+-// Credit represents a credit for the discovery, confirmation, patch, or
+-// other event in the life cycle of a vulnerability.
+-//
+-// See https://ossf.github.io/osv-schema/#credits-fields.
+-type Credit struct {
+-	// Name is the name, label, or other identifier of the individual or
+-	// entity being credited. Required.
+-	Name string `json:"name"`
+-}
+-
+-// DatabaseSpecific contains additional information about the
+-// vulnerability, specific to the Go vulnerability database.
+-//
+-// See https://go.dev/security/vuln/database#schema.
+-type DatabaseSpecific struct {
+-	// The URL of the Go advisory for this vulnerability, of the form
+-	// "https://pkg.go.dev/GO-YYYY-XXXX".
+-	URL string `json:"url,omitempty"`
+-}
+diff -urN a/gopls/internal/vulncheck/scan/command.go b/gopls/internal/vulncheck/scan/command.go
+--- a/gopls/internal/vulncheck/scan/command.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/scan/command.go	1970-01-01 08:00:00
+@@ -1,476 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -125355,143 +140548,182 @@
 -//go:build go1.18
 -// +build go1.18
 -
--package vulncheck
+-package scan
 -
 -import (
+-	"bytes"
 -	"context"
--	"encoding/json"
--	"errors"
 -	"fmt"
--	"log"
+-	"io"
 -	"os"
--	"regexp"
+-	"os/exec"
 -	"sort"
 -	"strings"
 -	"sync"
+-	"time"
 -
 -	"golang.org/x/mod/semver"
 -	"golang.org/x/sync/errgroup"
 -	"golang.org/x/tools/go/packages"
--	"golang.org/x/tools/gopls/internal/govulncheck"
 -	"golang.org/x/tools/gopls/internal/lsp/source"
--	"golang.org/x/vuln/client"
--	gvcapi "golang.org/x/vuln/exp/govulncheck"
--	"golang.org/x/vuln/osv"
--	"golang.org/x/vuln/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/govulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
+-	isem "golang.org/x/tools/gopls/internal/vulncheck/semver"
+-	"golang.org/x/vuln/scan"
 -)
 -
--func init() {
--	VulnerablePackages = vulnerablePackages
--}
--
--func findGOVULNDB(env []string) []string {
--	for _, kv := range env {
--		if strings.HasPrefix(kv, "GOVULNDB=") {
--			return strings.Split(kv[len("GOVULNDB="):], ",")
--		}
--	}
--	if GOVULNDB := os.Getenv("GOVULNDB"); GOVULNDB != "" {
--		return strings.Split(GOVULNDB, ",")
--	}
--	return []string{"https://vuln.go.dev"}
--}
--
 -// GoVersionForVulnTest is an internal environment variable used in gopls
 -// testing to examine govulncheck behavior with a go version different
 -// than what `go version` returns in the system.
 -const GoVersionForVulnTest = "_GOPLS_TEST_VULNCHECK_GOVERSION"
 -
--func init() {
--	Main = func(cfg packages.Config, patterns ...string) error {
--		// Set the mode that Source needs.
--		cfg.Mode = packages.NeedName | packages.NeedImports | packages.NeedTypes |
--			packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps |
--			packages.NeedModule
--		logf := log.New(os.Stderr, "", log.Ltime).Printf
--		logf("Loading packages...")
--		pkgs, err := packages.Load(&cfg, patterns...)
--		if err != nil {
--			logf("Failed to load packages: %v", err)
--			return err
--		}
--		if n := packages.PrintErrors(pkgs); n > 0 {
--			err := errors.New("failed to load packages due to errors")
--			logf("%v", err)
--			return err
--		}
--		logf("Loaded %d packages and their dependencies", len(pkgs))
--		cache, err := govulncheck.DefaultCache()
--		if err != nil {
--			return err
--		}
--		cli, err := client.NewClient(findGOVULNDB(cfg.Env), client.Options{
--			HTTPCache: cache,
--		})
--		if err != nil {
--			return err
--		}
--		res, err := gvcapi.Source(context.Background(), &gvcapi.Config{
--			Client:    cli,
--			GoVersion: os.Getenv(GoVersionForVulnTest),
--		}, vulncheck.Convert(pkgs))
--		if err != nil {
--			return err
--		}
--		affecting := 0
--		for _, v := range res.Vulns {
--			if v.IsCalled() {
--				affecting++
--			}
--		}
--		logf("Found %d affecting vulns and %d unaffecting vulns in imported packages", affecting, len(res.Vulns)-affecting)
--		if err := json.NewEncoder(os.Stdout).Encode(res); err != nil {
--			return err
--		}
--		return nil
+-// Main implements gopls vulncheck.
+-func Main(ctx context.Context, args ...string) error {
+-	// wrapping govulncheck.
+-	cmd := scan.Command(ctx, args...)
+-	if err := cmd.Start(); err != nil {
+-		return err
 -	}
+-	return cmd.Wait()
 -}
 -
--var (
--	// Regexp for matching go tags. The groups are:
--	// 1  the major.minor version
--	// 2  the patch version, or empty if none
--	// 3  the entire prerelease, if present
--	// 4  the prerelease type ("beta" or "rc")
--	// 5  the prerelease number
--	tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc|-pre)(\d+))?$`)
--)
+-// RunGovulncheck implements the codelens "Run Govulncheck"
+-// that runs 'gopls vulncheck' and converts the output to gopls's internal data
+-// used for diagnostics and hover message construction.
+-func RunGovulncheck(ctx context.Context, pattern string, snapshot source.Snapshot, dir string, log io.Writer) (*vulncheck.Result, error) {
+-	vulncheckargs := []string{
+-		"vulncheck", "--",
+-		"-json",
+-		"-mode", "source",
+-		"-scan", "symbol",
+-	}
+-	if dir != "" {
+-		vulncheckargs = append(vulncheckargs, "-C", dir)
+-	}
+-	if db := getEnv(snapshot, "GOVULNDB"); db != "" {
+-		vulncheckargs = append(vulncheckargs, "-db", db)
+-	}
+-	vulncheckargs = append(vulncheckargs, pattern)
+-	// TODO: support -tags. need to compute tags args from opts.BuildFlags.
+-	// TODO: support -test.
 -
--// This is a modified copy of pkgsite/internal/stdlib:VersionForTag.
--func GoTagToSemver(tag string) string {
--	if tag == "" {
--		return ""
--	}
+-	ir, iw := io.Pipe()
+-	handler := &govulncheckHandler{logger: log, osvs: map[string]*osv.Entry{}}
 -
--	tag = strings.Fields(tag)[0]
--	// Special cases for go1.
--	if tag == "go1" {
--		return "v1.0.0"
--	}
--	if tag == "go1.0" {
--		return ""
--	}
--	m := tagRegexp.FindStringSubmatch(tag)
--	if m == nil {
--		return ""
--	}
--	version := "v" + m[1]
--	if m[2] != "" {
--		version += m[2]
--	} else {
--		version += ".0"
--	}
--	if m[3] != "" {
--		if !strings.HasPrefix(m[4], "-") {
--			version += "-"
+-	stderr := new(bytes.Buffer)
+-	var g errgroup.Group
+-	// We run the govulncheck's analysis in a separate process as it can
+-	// consume a lot of CPUs and memory, and terminates: a separate process
+-	// is a perfect garbage collector and affords us ways to limit its resource usage.
+-	g.Go(func() error {
+-		defer iw.Close()
+-
+-		cmd := exec.CommandContext(ctx, os.Args[0], vulncheckargs...)
+-		cmd.Env = getEnvSlices(snapshot)
+-		if goversion := getEnv(snapshot, GoVersionForVulnTest); goversion != "" {
+-			// Let govulncheck API use a different Go version using the (undocumented) hook
+-			// in https://go.googlesource.com/vuln/+/v1.0.1/internal/scan/run.go#76
+-			cmd.Env = append(cmd.Env, "GOVERSION="+goversion)
 -		}
--		version += m[4] + "." + m[5]
+-		cmd.Stderr = stderr // stream vulncheck's STDERR as progress reports
+-		cmd.Stdout = iw     // let the other goroutine parses the result.
+-
+-		if err := cmd.Start(); err != nil {
+-			return fmt.Errorf("failed to start govulncheck: %v", err)
+-		}
+-		if err := cmd.Wait(); err != nil {
+-			return fmt.Errorf("failed to run govulncheck: %v", err)
+-		}
+-		return nil
+-	})
+-	g.Go(func() error {
+-		return govulncheck.HandleJSON(ir, handler)
+-	})
+-	if err := g.Wait(); err != nil {
+-		if stderr.Len() > 0 {
+-			log.Write(stderr.Bytes())
+-		}
+-		return nil, fmt.Errorf("failed to read govulncheck output: %v", err)
 -	}
--	return version
+-
+-	findings := handler.findings // sort so the findings in the result is deterministic.
+-	sort.Slice(findings, func(i, j int) bool {
+-		x, y := findings[i], findings[j]
+-		if x.OSV != y.OSV {
+-			return x.OSV < y.OSV
+-		}
+-		return x.Trace[0].Package < y.Trace[0].Package
+-	})
+-	result := &vulncheck.Result{
+-		Mode:     vulncheck.ModeGovulncheck,
+-		AsOf:     time.Now(),
+-		Entries:  handler.osvs,
+-		Findings: findings,
+-	}
+-	return result, nil
+-}
+-
+-type govulncheckHandler struct {
+-	logger io.Writer // forward progress reports to logger.
+-	err    error
+-
+-	osvs     map[string]*osv.Entry
+-	findings []*govulncheck.Finding
+-}
+-
+-// Config implements vulncheck.Handler.
+-func (h *govulncheckHandler) Config(config *govulncheck.Config) error {
+-	if config.GoVersion != "" {
+-		fmt.Fprintf(h.logger, "Go: %v\n", config.GoVersion)
+-	}
+-	if config.ScannerName != "" {
+-		scannerName := fmt.Sprintf("Scanner: %v", config.ScannerName)
+-		if config.ScannerVersion != "" {
+-			scannerName += "@" + config.ScannerVersion
+-		}
+-		fmt.Fprintln(h.logger, scannerName)
+-	}
+-	if config.DB != "" {
+-		dbInfo := fmt.Sprintf("DB: %v", config.DB)
+-		if config.DBLastModified != nil {
+-			dbInfo += fmt.Sprintf(" (DB updated: %v)", config.DBLastModified.String())
+-		}
+-		fmt.Fprintln(h.logger, dbInfo)
+-	}
+-	return nil
+-}
+-
+-// Finding implements vulncheck.Handler.
+-func (h *govulncheckHandler) Finding(finding *govulncheck.Finding) error {
+-	h.findings = append(h.findings, finding)
+-	return nil
+-}
+-
+-// OSV implements vulncheck.Handler.
+-func (h *govulncheckHandler) OSV(entry *osv.Entry) error {
+-	h.osvs[entry.ID] = entry
+-	return nil
+-}
+-
+-// Progress implements vulncheck.Handler.
+-func (h *govulncheckHandler) Progress(progress *govulncheck.Progress) error {
+-	if progress.Message != "" {
+-		fmt.Fprintf(h.logger, "%v\n", progress.Message)
+-	}
+-	return nil
+-}
+-
+-func getEnv(snapshot source.Snapshot, key string) string {
+-	val, ok := snapshot.Options().Env[key]
+-	if ok {
+-		return val
+-	}
+-	return os.Getenv(key)
+-}
+-
+-func getEnvSlices(snapshot source.Snapshot) []string {
+-	return append(os.Environ(), snapshot.Options().EnvSlice()...)
 -}
 -
 -// semverToGoTag returns the Go standard library repository tag corresponding
@@ -125550,10 +140782,14 @@
 -	return i + 1
 -}
 -
--// vulnerablePackages queries the vulndb and reports which vulnerabilities
+-// VulnerablePackages queries the vulndb and reports which vulnerabilities
 -// apply to this snapshot. The result contains a set of packages,
--// grouped by vuln ID and by module.
--func vulnerablePackages(ctx context.Context, snapshot source.Snapshot, modfile source.FileHandle) (*govulncheck.Result, error) {
+-// grouped by vuln ID and by module. This implements the "import-based"
+-// vulnerability report on go.mod files.
+-func VulnerablePackages(ctx context.Context, snapshot source.Snapshot) (*vulncheck.Result, error) {
+-	// TODO(hyangah): can we let 'govulncheck' take a package list
+-	// used in the workspace and implement this function?
+-
 -	// We want to report the intersection of vulnerable packages in the vulndb
 -	// and packages transitively imported by this module ('go list -deps all').
 -	// We use snapshot.AllMetadata to retrieve the list of packages
@@ -125577,43 +140813,37 @@
 -	// Group packages by modules since vuln db is keyed by module.
 -	metadataByModule := map[source.PackagePath][]*source.Metadata{}
 -	for _, md := range metadata {
--		mi := md.Module
--		modulePath := source.PackagePath("stdlib")
--		if mi != nil {
+-		modulePath := source.PackagePath(osv.GoStdModulePath)
+-		if mi := md.Module; mi != nil {
 -			modulePath = source.PackagePath(mi.Path)
 -		}
 -		metadataByModule[modulePath] = append(metadataByModule[modulePath], md)
 -	}
 -
--	// Request vuln entries from remote service.
--	fsCache, err := govulncheck.DefaultCache()
--	if err != nil {
--		return nil, err
--	}
--	cli, err := client.NewClient(
--		findGOVULNDB(snapshot.View().Options().EnvSlice()),
--		client.Options{HTTPCache: govulncheck.NewInMemoryCache(fsCache)})
--	if err != nil {
--		return nil, err
--	}
--	// Keys are osv.Entry.IDs
--	vulnsResult := map[string]*govulncheck.Vuln{}
 -	var (
--		group errgroup.Group
--		mu    sync.Mutex
+-		mu sync.Mutex
+-		// Keys are osv.Entry.ID
+-		osvs     = map[string]*osv.Entry{}
+-		findings []*govulncheck.Finding
 -	)
 -
--	goVersion := snapshot.View().Options().Env[GoVersionForVulnTest]
+-	goVersion := snapshot.Options().Env[GoVersionForVulnTest]
 -	if goVersion == "" {
 -		goVersion = snapshot.View().GoVersionString()
 -	}
--	group.SetLimit(10)
+-
 -	stdlibModule := &packages.Module{
--		Path:    "stdlib",
+-		Path:    osv.GoStdModulePath,
 -		Version: goVersion,
 -	}
--	for path, mds := range metadataByModule {
--		path, mds := path, mds
+-
+-	// GOVULNDB may point the test db URI.
+-	db := getEnv(snapshot, "GOVULNDB")
+-
+-	var group errgroup.Group
+-	group.SetLimit(10) // limit govulncheck api runs
+-	for _, mds := range metadataByModule {
+-		mds := mds
 -		group.Go(func() error {
 -			effectiveModule := stdlibModule
 -			if m := mds[0].Module; m != nil {
@@ -125623,9 +140853,13 @@
 -				effectiveModule = effectiveModule.Replace
 -			}
 -			ver := effectiveModule.Version
+-			if ver == "" || !isem.Valid(ver) {
+-				// skip invalid version strings. the underlying scan api is strict.
+-				return nil
+-			}
 -
--			// TODO(go.dev/issues/56312): batch these requests for efficiency.
--			vulns, err := cli.GetByModule(ctx, effectiveModule.Path)
+-			// TODO(hyangah): batch these requests and add in-memory cache for efficiency.
+-			vulns, err := osvsByModule(ctx, db, effectiveModule.Path+"@"+ver)
 -			if err != nil {
 -				return err
 -			}
@@ -125639,22 +140873,28 @@
 -
 -			// Report vulnerabilities that affect packages of this module.
 -			for _, entry := range vulns {
--				var vulnerablePkgs []*govulncheck.Package
+-				var vulnerablePkgs []*govulncheck.Finding
+-				fixed := fixedVersion(effectiveModule.Path, entry.Affected)
 -
 -				for _, a := range entry.Affected {
--					if a.Package.Ecosystem != osv.GoEcosystem || a.Package.Name != effectiveModule.Path {
+-					if a.Module.Ecosystem != osv.GoEcosystem || a.Module.Path != effectiveModule.Path {
 -						continue
 -					}
--					if !a.Ranges.AffectsSemver(ver) {
--						continue
--					}
--					for _, imp := range a.EcosystemSpecific.Imports {
+-					for _, imp := range a.EcosystemSpecific.Packages {
 -						if knownPkgs == nil {
 -							knownPkgs = toPackagePathSet(mds)
 -						}
 -						if knownPkgs[source.PackagePath(imp.Path)] {
--							vulnerablePkgs = append(vulnerablePkgs, &govulncheck.Package{
--								Path: imp.Path,
+-							vulnerablePkgs = append(vulnerablePkgs, &govulncheck.Finding{
+-								OSV:          entry.ID,
+-								FixedVersion: fixed,
+-								Trace: []*govulncheck.Frame{
+-									{
+-										Module:  effectiveModule.Path,
+-										Version: effectiveModule.Version,
+-										Package: imp.Path,
+-									},
+-								},
 -							})
 -						}
 -					}
@@ -125663,17 +140903,8 @@
 -					continue
 -				}
 -				mu.Lock()
--				vuln, ok := vulnsResult[entry.ID]
--				if !ok {
--					vuln = &govulncheck.Vuln{OSV: entry}
--					vulnsResult[entry.ID] = vuln
--				}
--				vuln.Modules = append(vuln.Modules, &govulncheck.Module{
--					Path:         string(path),
--					FoundVersion: ver,
--					FixedVersion: fixedVersion(effectiveModule.Path, entry.Affected),
--					Packages:     vulnerablePkgs,
--				})
+-				osvs[entry.ID] = entry
+-				findings = append(findings, vulnerablePkgs...)
 -				mu.Unlock()
 -			}
 -			return nil
@@ -125683,17 +140914,18 @@
 -		return nil, err
 -	}
 -
--	vulns := make([]*govulncheck.Vuln, 0, len(vulnsResult))
--	for _, v := range vulnsResult {
--		vulns = append(vulns, v)
--	}
 -	// Sort so the results are deterministic.
--	sort.Slice(vulns, func(i, j int) bool {
--		return vulns[i].OSV.ID < vulns[j].OSV.ID
+-	sort.Slice(findings, func(i, j int) bool {
+-		x, y := findings[i], findings[j]
+-		if x.OSV != y.OSV {
+-			return x.OSV < y.OSV
+-		}
+-		return x.Trace[0].Package < y.Trace[0].Package
 -	})
--	ret := &govulncheck.Result{
--		Vulns: vulns,
--		Mode:  govulncheck.ModeImports,
+-	ret := &vulncheck.Result{
+-		Entries:  osvs,
+-		Findings: findings,
+-		Mode:     vulncheck.ModeImports,
 -	}
 -	return ret, nil
 -}
@@ -125708,7 +140940,7 @@
 -}
 -
 -func fixedVersion(modulePath string, affected []osv.Affected) string {
--	fixed := govulncheck.LatestFixed(modulePath, affected)
+-	fixed := LatestFixed(modulePath, affected)
 -	if fixed != "" {
 -		fixed = versionString(modulePath, fixed)
 -	}
@@ -125729,39 +140961,252 @@
 -	}
 -	return v
 -}
-diff -urN a/gopls/internal/vulncheck/vulncheck.go b/gopls/internal/vulncheck/vulncheck.go
---- a/gopls/internal/vulncheck/vulncheck.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulncheck.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,25 +0,0 @@
+-
+-// osvsByModule runs a govulncheck database query.
+-func osvsByModule(ctx context.Context, db, moduleVersion string) ([]*osv.Entry, error) {
+-	var args []string
+-	args = append(args, "-mode=query", "-json")
+-	if db != "" {
+-		args = append(args, "-db="+db)
+-	}
+-	args = append(args, moduleVersion)
+-
+-	ir, iw := io.Pipe()
+-	handler := &osvReader{}
+-
+-	var g errgroup.Group
+-	g.Go(func() error {
+-		defer iw.Close() // scan API doesn't close cmd.Stderr/cmd.Stdout.
+-		cmd := scan.Command(ctx, args...)
+-		cmd.Stdout = iw
+-		// TODO(hakim): Do we need to set cmd.Env = getEnvSlices(),
+-		// or is the process environment good enough?
+-		if err := cmd.Start(); err != nil {
+-			return err
+-		}
+-		return cmd.Wait()
+-	})
+-	g.Go(func() error {
+-		return govulncheck.HandleJSON(ir, handler)
+-	})
+-
+-	if err := g.Wait(); err != nil {
+-		return nil, err
+-	}
+-	return handler.entry, nil
+-}
+-
+-// osvReader implements govulncheck.Handler.
+-type osvReader struct {
+-	entry []*osv.Entry
+-}
+-
+-func (h *osvReader) OSV(entry *osv.Entry) error {
+-	h.entry = append(h.entry, entry)
+-	return nil
+-}
+-
+-func (h *osvReader) Config(config *govulncheck.Config) error {
+-	return nil
+-}
+-
+-func (h *osvReader) Finding(finding *govulncheck.Finding) error {
+-	return nil
+-}
+-
+-func (h *osvReader) Progress(progress *govulncheck.Progress) error {
+-	return nil
+-}
+diff -urN a/gopls/internal/vulncheck/scan/util.go b/gopls/internal/vulncheck/scan/util.go
+--- a/gopls/internal/vulncheck/scan/util.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/scan/util.go	1970-01-01 08:00:00
+@@ -1,36 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
--// Package vulncheck provides an analysis command
--// that runs vulnerability analysis using data from
--// golang.org/x/vuln/vulncheck.
--// This package requires go1.18 or newer.
+-//go:build go1.18
+-// +build go1.18
+-
+-package scan
+-
+-import (
+-	"golang.org/x/mod/semver"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
+-	isem "golang.org/x/tools/gopls/internal/vulncheck/semver"
+-)
+-
+-// LatestFixed returns the latest fixed version in the list of affected ranges,
+-// or the empty string if there are no fixed versions.
+-func LatestFixed(modulePath string, as []osv.Affected) string {
+-	v := ""
+-	for _, a := range as {
+-		if a.Module.Path != modulePath {
+-			continue
+-		}
+-		for _, r := range a.Ranges {
+-			if r.Type == osv.RangeTypeSemver {
+-				for _, e := range r.Events {
+-					if e.Fixed != "" && (v == "" ||
+-						semver.Compare(isem.CanonicalizeSemverPrefix(e.Fixed), isem.CanonicalizeSemverPrefix(v)) > 0) {
+-						v = e.Fixed
+-					}
+-				}
+-			}
+-		}
+-	}
+-	return v
+-}
+diff -urN a/gopls/internal/vulncheck/semver/semver.go b/gopls/internal/vulncheck/semver/semver.go
+--- a/gopls/internal/vulncheck/semver/semver.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/semver/semver.go	1970-01-01 08:00:00
+@@ -1,59 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.18
+-// +build go1.18
+-
+-// Package semver provides shared utilities for manipulating
+-// Go semantic versions.
+-package semver
+-
+-import (
+-	"regexp"
+-	"strings"
+-
+-	"golang.org/x/mod/semver"
+-)
+-
+-// addSemverPrefix adds a 'v' prefix to s if it isn't already prefixed
+-// with 'v' or 'go'. This allows us to easily test go-style SEMVER
+-// strings against normal SEMVER strings.
+-func addSemverPrefix(s string) string {
+-	if !strings.HasPrefix(s, "v") && !strings.HasPrefix(s, "go") {
+-		return "v" + s
+-	}
+-	return s
+-}
+-
+-// removeSemverPrefix removes the 'v' or 'go' prefixes from go-style
+-// SEMVER strings, for usage in the public vulnerability format.
+-func removeSemverPrefix(s string) string {
+-	s = strings.TrimPrefix(s, "v")
+-	s = strings.TrimPrefix(s, "go")
+-	return s
+-}
+-
+-// CanonicalizeSemverPrefix turns a SEMVER string into the canonical
+-// representation using the 'v' prefix, as used by the OSV format.
+-// Input may be a bare SEMVER ("1.2.3"), Go prefixed SEMVER ("go1.2.3"),
+-// or already canonical SEMVER ("v1.2.3").
+-func CanonicalizeSemverPrefix(s string) string {
+-	return addSemverPrefix(removeSemverPrefix(s))
+-}
+-
+-// Valid returns whether v is valid semver, allowing
+-// either a "v", "go" or no prefix.
+-func Valid(v string) bool {
+-	return semver.IsValid(CanonicalizeSemverPrefix(v))
+-}
+-
+-var (
+-	// Regexp for matching go tags. The groups are:
+-	// 1  the major.minor version
+-	// 2  the patch version, or empty if none
+-	// 3  the entire prerelease, if present
+-	// 4  the prerelease type ("beta" or "rc")
+-	// 5  the prerelease number
+-	tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc|-pre)(\d+))?$`)
+-)
+diff -urN a/gopls/internal/vulncheck/semver/semver_test.go b/gopls/internal/vulncheck/semver/semver_test.go
+--- a/gopls/internal/vulncheck/semver/semver_test.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/semver/semver_test.go	1970-01-01 08:00:00
+@@ -1,28 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-//go:build go1.18
+-// +build go1.18
+-
+-package semver
+-
+-import (
+-	"testing"
+-)
+-
+-func TestCanonicalize(t *testing.T) {
+-	for _, test := range []struct {
+-		v    string
+-		want string
+-	}{
+-		{"v1.2.3", "v1.2.3"},
+-		{"1.2.3", "v1.2.3"},
+-		{"go1.2.3", "v1.2.3"},
+-	} {
+-		got := CanonicalizeSemverPrefix(test.v)
+-		if got != test.want {
+-			t.Errorf("want %s; got %s", test.want, got)
+-		}
+-	}
+-}
+diff -urN a/gopls/internal/vulncheck/types.go b/gopls/internal/vulncheck/types.go
+--- a/gopls/internal/vulncheck/types.go	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/types.go	1970-01-01 08:00:00
+@@ -1,47 +0,0 @@
+-// Copyright 2022 The Go Authors. All rights reserved.
+-// Use of this source code is governed by a BSD-style
+-// license that can be found in the LICENSE file.
+-
+-// go:generate go run copier.go
+-
 -package vulncheck
 -
 -import (
--	"context"
+-	"time"
 -
--	"golang.org/x/tools/go/packages"
--	"golang.org/x/tools/gopls/internal/govulncheck"
--	"golang.org/x/tools/gopls/internal/lsp/source"
+-	gvc "golang.org/x/tools/gopls/internal/vulncheck/govulncheck"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
 -)
 -
--// With go1.18+, this is swapped with the real implementation.
--var Main func(cfg packages.Config, patterns ...string) error = nil
+-// Result is the result of vulnerability scanning.
+-type Result struct {
+-	// Entries contains all vulnerabilities that are called or imported by
+-	// the analyzed module. Keys are Entry.IDs.
+-	Entries map[string]*osv.Entry
+-	// Findings are vulnerabilities found by vulncheck or import-based analysis.
+-	// Ordered by the OSV IDs and the package names.
+-	Findings []*gvc.Finding
 -
--// VulnerablePackages queries the vulndb and reports which vulnerabilities
--// apply to this snapshot. The result contains a set of packages,
--// grouped by vuln ID and by module.
--var VulnerablePackages func(ctx context.Context, snapshot source.Snapshot, modfile source.FileHandle) (*govulncheck.Result, error) = nil
+-	// Mode contains the source of the vulnerability info.
+-	// Clients of the gopls.fetch_vulncheck_result command may need
+-	// to interpret the vulnerabilities differently based on the
+-	// analysis mode. For example, Vuln without callstack traces
+-	// indicate a vulnerability that is not used if the result was
+-	// from 'govulncheck' analysis mode. On the other hand, Vuln
+-	// without callstack traces just implies the package with the
+-	// vulnerability is known to the workspace and we do not know
+-	// whether the vulnerable symbols are actually used or not.
+-	Mode AnalysisMode `json:",omitempty"`
+-
+-	// AsOf describes when this Result was computed using govulncheck.
+-	// It is valid only with the govulncheck analysis mode.
+-	AsOf time.Time `json:",omitempty"`
+-}
+-
+-type AnalysisMode string
+-
+-const (
+-	ModeInvalid     AnalysisMode = "" // zero value
+-	ModeGovulncheck AnalysisMode = "govulncheck"
+-	ModeImports     AnalysisMode = "imports"
+-)
 diff -urN a/gopls/internal/vulncheck/vulntest/db.go b/gopls/internal/vulncheck/vulntest/db.go
 --- a/gopls/internal/vulncheck/vulntest/db.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/db.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,303 +0,0 @@
++++ b/gopls/internal/vulncheck/vulntest/db.go	1970-01-01 08:00:00
+@@ -1,243 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -125777,7 +141222,6 @@
 -	"context"
 -	"encoding/json"
 -	"fmt"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"sort"
@@ -125785,9 +141229,8 @@
 -	"time"
 -
 -	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
 -	"golang.org/x/tools/txtar"
--	"golang.org/x/vuln/client"
--	"golang.org/x/vuln/osv"
 -)
 -
 -// NewDatabase returns a read-only DB containing the provided
@@ -125806,7 +141249,7 @@
 -// The returned DB's Clean method must be called to clean up the
 -// generated database.
 -func NewDatabase(ctx context.Context, txtarReports []byte) (*DB, error) {
--	disk, err := ioutil.TempDir("", "vulndb-test")
+-	disk, err := os.MkdirTemp("", "vulndb-test")
 -	if err != nil {
 -		return nil, err
 -	}
@@ -125828,7 +141271,7 @@
 -// URI returns the file URI that can be used for VULNDB environment
 -// variable.
 -func (db *DB) URI() string {
--	u := span.URIFromPath(db.disk)
+-	u := span.URIFromPath(filepath.Join(db.disk, "ID"))
 -	return string(u)
 -}
 -
@@ -125837,11 +141280,6 @@
 -	return os.RemoveAll(db.disk)
 -}
 -
--// NewClient returns a vuln DB client that works with the given DB.
--func NewClient(db *DB) (client.Client, error) {
--	return client.NewClient([]string{db.URI()}, client.Options{})
--}
--
 -//
 -// The following was selectively copied from golang.org/x/vulndb/internal/database
 -//
@@ -125853,14 +141291,6 @@
 -	// listed by their IDs.
 -	idDirectory = "ID"
 -
--	// stdFileName is the name of the .json file in the vulndb repo
--	// that will contain info on standard library vulnerabilities.
--	stdFileName = "stdlib"
--
--	// toolchainFileName is the name of the .json file in the vulndb repo
--	// that will contain info on toolchain (cmd/...) vulnerabilities.
--	toolchainFileName = "toolchain"
--
 -	// cmdModule is the name of the module containing Go toolchain
 -	// binaries.
 -	cmdModule = "cmd"
@@ -125873,38 +141303,15 @@
 -func generateDB(ctx context.Context, txtarData []byte, jsonDir string, indent bool) error {
 -	archive := txtar.Parse(txtarData)
 -
--	jsonVulns, entries, err := generateEntries(ctx, archive)
+-	entries, err := generateEntries(ctx, archive)
 -	if err != nil {
 -		return err
 -	}
--
--	index := make(client.DBIndex, len(jsonVulns))
--	for modulePath, vulns := range jsonVulns {
--		epath, err := client.EscapeModulePath(modulePath)
--		if err != nil {
--			return err
--		}
--		if err := writeVulns(filepath.Join(jsonDir, epath), vulns, indent); err != nil {
--			return err
--		}
--		for _, v := range vulns {
--			if v.Modified.After(index[modulePath]) {
--				index[modulePath] = v.Modified
--			}
--		}
--	}
--	if err := writeJSON(filepath.Join(jsonDir, "index.json"), index, indent); err != nil {
--		return err
--	}
--	if err := writeAliasIndex(jsonDir, entries, indent); err != nil {
--		return err
--	}
 -	return writeEntriesByID(filepath.Join(jsonDir, idDirectory), entries, indent)
 -}
 -
--func generateEntries(_ context.Context, archive *txtar.Archive) (map[string][]osv.Entry, []osv.Entry, error) {
+-func generateEntries(_ context.Context, archive *txtar.Archive) ([]osv.Entry, error) {
 -	now := time.Now()
--	jsonVulns := map[string][]osv.Entry{}
 -	var entries []osv.Entry
 -	for _, f := range archive.Files {
 -		if !strings.HasSuffix(f.Name, ".yaml") {
@@ -125912,17 +141319,14 @@
 -		}
 -		r, err := readReport(bytes.NewReader(f.Data))
 -		if err != nil {
--			return nil, nil, err
+-			return nil, err
 -		}
 -		name := strings.TrimSuffix(filepath.Base(f.Name), filepath.Ext(f.Name))
 -		linkName := fmt.Sprintf("%s%s", dbURL, name)
--		entry, modulePaths := generateOSVEntry(name, linkName, now, *r)
--		for _, modulePath := range modulePaths {
--			jsonVulns[modulePath] = append(jsonVulns[modulePath], entry)
--		}
+-		entry := generateOSVEntry(name, linkName, now, *r)
 -		entries = append(entries, entry)
 -	}
--	return jsonVulns, entries, nil
+-	return entries, nil
 -}
 -
 -func writeVulns(outPath string, vulns []osv.Entry, indent bool) error {
@@ -125937,27 +141341,13 @@
 -	if err := os.MkdirAll(idDir, 0755); err != nil {
 -		return fmt.Errorf("failed to create directory %q: %v", idDir, err)
 -	}
--	var idIndex []string
 -	for _, e := range entries {
 -		outPath := filepath.Join(idDir, e.ID+".json")
 -		if err := writeJSON(outPath, e, indent); err != nil {
 -			return err
 -		}
--		idIndex = append(idIndex, e.ID)
 -	}
--	// Write an index.json in the ID directory with a list of all the IDs.
--	return writeJSON(filepath.Join(idDir, "index.json"), idIndex, indent)
--}
--
--// Write a JSON file containing a map from alias to GO IDs.
--func writeAliasIndex(dir string, entries []osv.Entry, indent bool) error {
--	aliasToGoIDs := map[string][]string{}
--	for _, e := range entries {
--		for _, a := range e.Aliases {
--			aliasToGoIDs[a] = append(aliasToGoIDs[a], e.ID)
--		}
--	}
--	return writeJSON(filepath.Join(dir, "aliases.json"), aliasToGoIDs, indent)
+-	return nil
 -}
 -
 -func writeJSON(filename string, value any, indent bool) (err error) {
@@ -125978,45 +141368,40 @@
 -// generateOSVEntry create an osv.Entry for a report. In addition to the report, it
 -// takes the ID for the vuln and a URL that will point to the entry in the vuln DB.
 -// It returns the osv.Entry and a list of module paths that the vuln affects.
--func generateOSVEntry(id, url string, lastModified time.Time, r Report) (osv.Entry, []string) {
+-func generateOSVEntry(id, url string, lastModified time.Time, r Report) osv.Entry {
 -	entry := osv.Entry{
--		ID:        id,
--		Published: r.Published,
--		Modified:  lastModified,
--		Withdrawn: r.Withdrawn,
--		Details:   r.Description,
+-		ID:               id,
+-		Published:        r.Published,
+-		Modified:         lastModified,
+-		Withdrawn:        r.Withdrawn,
+-		Summary:          r.Summary,
+-		Details:          r.Description,
+-		DatabaseSpecific: &osv.DatabaseSpecific{URL: url},
 -	}
 -
 -	moduleMap := make(map[string]bool)
 -	for _, m := range r.Modules {
 -		switch m.Module {
 -		case stdModule:
--			moduleMap[stdFileName] = true
+-			moduleMap[osv.GoStdModulePath] = true
 -		case cmdModule:
--			moduleMap[toolchainFileName] = true
+-			moduleMap[osv.GoCmdModulePath] = true
 -		default:
 -			moduleMap[m.Module] = true
 -		}
--		entry.Affected = append(entry.Affected, generateAffected(m, url))
+-		entry.Affected = append(entry.Affected, toAffected(m))
 -	}
 -	for _, ref := range r.References {
 -		entry.References = append(entry.References, osv.Reference{
--			Type: string(ref.Type),
+-			Type: ref.Type,
 -			URL:  ref.URL,
 -		})
 -	}
--
--	var modulePaths []string
--	for module := range moduleMap {
--		modulePaths = append(modulePaths, module)
--	}
--	// TODO: handle missing fields - Aliases
--
--	return entry, modulePaths
+-	return entry
 -}
 -
--func generateAffectedRanges(versions []VersionRange) osv.Affects {
--	a := osv.AffectsRange{Type: osv.TypeSemver}
+-func AffectedRanges(versions []VersionRange) []osv.Range {
+-	a := osv.Range{Type: osv.RangeTypeSemver}
 -	if len(versions) == 0 || versions[0].Introduced == "" {
 -		a.Events = append(a.Events, osv.RangeEvent{Introduced: "0"})
 -	}
@@ -126028,15 +141413,15 @@
 -			a.Events = append(a.Events, osv.RangeEvent{Fixed: v.Fixed.Canonical()})
 -		}
 -	}
--	return osv.Affects{a}
+-	return []osv.Range{a}
 -}
 -
--func generateImports(m *Module) (imps []osv.EcosystemSpecificImport) {
--	for _, p := range m.Packages {
+-func toOSVPackages(pkgs []*Package) (imps []osv.Package) {
+-	for _, p := range pkgs {
 -		syms := append([]string{}, p.Symbols...)
 -		syms = append(syms, p.DerivedSymbols...)
 -		sort.Strings(syms)
--		imps = append(imps, osv.EcosystemSpecificImport{
+-		imps = append(imps, osv.Package{
 -			Path:    p.Package,
 -			GOOS:    p.GOOS,
 -			GOARCH:  p.GOARCH,
@@ -126045,30 +141430,30 @@
 -	}
 -	return imps
 -}
--func generateAffected(m *Module, url string) osv.Affected {
+-
+-func toAffected(m *Module) osv.Affected {
 -	name := m.Module
 -	switch name {
 -	case stdModule:
--		name = "stdlib"
+-		name = osv.GoStdModulePath
 -	case cmdModule:
--		name = "toolchain"
+-		name = osv.GoCmdModulePath
 -	}
 -	return osv.Affected{
--		Package: osv.Package{
--			Name:      name,
+-		Module: osv.Module{
+-			Path:      name,
 -			Ecosystem: osv.GoEcosystem,
 -		},
--		Ranges:           generateAffectedRanges(m.Versions),
--		DatabaseSpecific: osv.DatabaseSpecific{URL: url},
+-		Ranges: AffectedRanges(m.Versions),
 -		EcosystemSpecific: osv.EcosystemSpecific{
--			Imports: generateImports(m),
+-			Packages: toOSVPackages(m.Packages),
 -		},
 -	}
 -}
 diff -urN a/gopls/internal/vulncheck/vulntest/db_test.go b/gopls/internal/vulncheck/vulntest/db_test.go
 --- a/gopls/internal/vulncheck/vulntest/db_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/db_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,61 +0,0 @@
++++ b/gopls/internal/vulncheck/vulntest/db_test.go	1970-01-01 08:00:00
+@@ -1,79 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -126081,59 +141466,77 @@
 -import (
 -	"context"
 -	"encoding/json"
+-	"flag"
+-	"os"
+-	"path/filepath"
 -	"testing"
+-	"time"
+-
+-	"github.com/google/go-cmp/cmp"
+-	"golang.org/x/tools/gopls/internal/span"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
 -)
 -
+-var update = flag.Bool("update", false, "update golden files in testdata/")
+-
 -func TestNewDatabase(t *testing.T) {
 -	ctx := context.Background()
--	in := []byte(`
---- GO-2020-0001.yaml --
--modules:
--  - module: github.com/gin-gonic/gin
--    versions:
--      - fixed: 1.6.0
--    packages:
--      - package: github.com/gin-gonic/gin
--        symbols:
--          - defaultLogFormatter
--description: |
--    Something.
--published: 2021-04-14T20:04:52Z
--references:
--  - fix: https://github.com/gin-gonic/gin/pull/2237
--`)
+-
+-	in, err := os.ReadFile("testdata/report.yaml")
+-	if err != nil {
+-		t.Fatal(err)
+-	}
+-	in = append([]byte("-- GO-2020-0001.yaml --\n"), in...)
 -
 -	db, err := NewDatabase(ctx, in)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
 -	defer db.Clean()
+-	dbpath := span.URIFromURI(db.URI()).Filename()
 -
--	cli, err := NewClient(db)
+-	// The generated JSON file will be in DB/GO-2022-0001.json.
+-	got := readOSVEntry(t, filepath.Join(dbpath, "GO-2020-0001.json"))
+-	got.Modified = time.Time{}
+-
+-	if *update {
+-		updateTestData(t, got, "testdata/GO-2020-0001.json")
+-	}
+-
+-	want := readOSVEntry(t, "testdata/GO-2020-0001.json")
+-	want.Modified = time.Time{}
+-	if diff := cmp.Diff(want, got); diff != "" {
+-		t.Errorf("mismatch (-want +got):\n%s", diff)
+-	}
+-}
+-
+-func updateTestData(t *testing.T, got *osv.Entry, fname string) {
+-	content, err := json.MarshalIndent(got, "", "\t")
 -	if err != nil {
 -		t.Fatal(err)
 -	}
--	got, err := cli.GetByID(ctx, "GO-2020-0001")
+-	if err := os.WriteFile(fname, content, 0666); err != nil {
+-		t.Fatal(err)
+-	}
+-	t.Logf("updated %v", fname)
+-}
+-
+-func readOSVEntry(t *testing.T, filename string) *osv.Entry {
+-	t.Helper()
+-	content, err := os.ReadFile(filename)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
--	if got.ID != "GO-2020-0001" {
--		m, _ := json.Marshal(got)
--		t.Errorf("got %s\nwant GO-2020-0001 entry", m)
--	}
--	gotAll, err := cli.GetByModule(ctx, "github.com/gin-gonic/gin")
--	if err != nil {
+-	var entry osv.Entry
+-	if err := json.Unmarshal(content, &entry); err != nil {
 -		t.Fatal(err)
 -	}
--	if len(gotAll) != 1 || gotAll[0].ID != "GO-2020-0001" {
--		m, _ := json.Marshal(got)
--		t.Errorf("got %s\nwant GO-2020-0001 entry", m)
--	}
+-	return &entry
 -}
 diff -urN a/gopls/internal/vulncheck/vulntest/report.go b/gopls/internal/vulncheck/vulntest/report.go
 --- a/gopls/internal/vulncheck/vulntest/report.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/report.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,176 +0,0 @@
++++ b/gopls/internal/vulncheck/vulntest/report.go	1970-01-01 08:00:00
+@@ -1,179 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -126151,6 +141554,7 @@
 -	"time"
 -
 -	"golang.org/x/mod/semver"
+-	"golang.org/x/tools/gopls/internal/vulncheck/osv"
 -	"gopkg.in/yaml.v3"
 -)
 -
@@ -126172,10 +141576,15 @@
 -}
 -
 -// Report represents a vulnerability report in the vulndb.
--// Remember to update doc/format.md when this structure changes.
+-// See https://go.googlesource.com/vulndb/+/refs/heads/master/doc/format.md
 -type Report struct {
+-	ID string `yaml:",omitempty"`
+-
 -	Modules []*Module `yaml:",omitempty"`
 -
+-	// Summary is a short phrase describing the vulnerability.
+-	Summary string `yaml:",omitempty"`
+-
 -	// Description is the CVE description from an existing CVE. If we are
 -	// assigning a CVE ID ourselves, use CVEMetadata.Description instead.
 -	Description string     `yaml:",omitempty"`
@@ -126289,10 +141698,7 @@
 -//
 -// For ease of typing, References are represented in the YAML as a
 -// single-element mapping of type to URL.
--type Reference struct {
--	Type ReferenceType `json:"type,omitempty"`
--	URL  string        `json:"url,omitempty"`
--}
+-type Reference osv.Reference
 -
 -func (r *Reference) MarshalYAML() (interface{}, error) {
 -	return map[string]string{
@@ -126306,14 +141712,14 @@
 -			fmt.Sprintf("line %d: report.Reference must contain a mapping with one value", n.Line),
 -		}}
 -	}
--	r.Type = ReferenceType(strings.ToUpper(n.Content[0].Value))
+-	r.Type = osv.ReferenceType(strings.ToUpper(n.Content[0].Value))
 -	r.URL = n.Content[1].Value
 -	return nil
 -}
 diff -urN a/gopls/internal/vulncheck/vulntest/report_test.go b/gopls/internal/vulncheck/vulntest/report_test.go
 --- a/gopls/internal/vulncheck/vulntest/report_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/report_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,52 +0,0 @@
++++ b/gopls/internal/vulncheck/vulntest/report_test.go	1970-01-01 08:00:00
+@@ -1,51 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -126326,7 +141732,6 @@
 -import (
 -	"bytes"
 -	"io"
--	"io/ioutil"
 -	"os"
 -	"path/filepath"
 -	"testing"
@@ -126335,7 +141740,7 @@
 -)
 -
 -func readAll(t *testing.T, filename string) io.Reader {
--	d, err := ioutil.ReadFile(filename)
+-	d, err := os.ReadFile(filename)
 -	if err != nil {
 -		t.Fatal(err)
 -	}
@@ -126368,7 +141773,7 @@
 -}
 diff -urN a/gopls/internal/vulncheck/vulntest/stdlib.go b/gopls/internal/vulncheck/vulntest/stdlib.go
 --- a/gopls/internal/vulncheck/vulntest/stdlib.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/stdlib.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/vulncheck/vulntest/stdlib.go	1970-01-01 08:00:00
 @@ -1,26 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -126398,7 +141803,7 @@
 -}
 diff -urN a/gopls/internal/vulncheck/vulntest/stdlib_test.go b/gopls/internal/vulncheck/vulntest/stdlib_test.go
 --- a/gopls/internal/vulncheck/vulntest/stdlib_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/stdlib_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/vulncheck/vulntest/stdlib_test.go	1970-01-01 08:00:00
 @@ -1,27 +0,0 @@
 -// Copyright 2022 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
@@ -126427,9 +141832,64 @@
 -		}
 -	}
 -}
+diff -urN a/gopls/internal/vulncheck/vulntest/testdata/GO-2020-0001.json b/gopls/internal/vulncheck/vulntest/testdata/GO-2020-0001.json
+--- a/gopls/internal/vulncheck/vulntest/testdata/GO-2020-0001.json	2000-01-01 00:00:00.000000000 -0000
++++ b/gopls/internal/vulncheck/vulntest/testdata/GO-2020-0001.json	1970-01-01 08:00:00
+@@ -1,50 +0,0 @@
+-{
+-	"id": "GO-2020-0001",
+-	"modified": "0001-01-01T00:00:00Z",
+-	"published": "0001-01-01T00:00:00Z",
+-	"details": "The default Formatter for the Logger middleware (LoggerConfig.Formatter),\nwhich is included in the Default engine, allows attackers to inject arbitrary\nlog entries by manipulating the request path.\n",
+-	"affected": [
+-		{
+-			"package": {
+-				"name": "github.com/gin-gonic/gin",
+-				"ecosystem": "Go"
+-			},
+-			"ranges": [
+-				{
+-					"type": "SEMVER",
+-					"events": [
+-						{
+-							"introduced": "0"
+-						},
+-						{
+-							"fixed": "1.6.0"
+-						}
+-					]
+-				}
+-			],
+-			"ecosystem_specific": {
+-				"imports": [
+-					{
+-						"path": "github.com/gin-gonic/gin",
+-						"symbols": [
+-							"defaultLogFormatter"
+-						]
+-					}
+-				]
+-			}
+-		}
+-	],
+-	"references": [
+-		{
+-			"type": "FIX",
+-			"url": "https://github.com/gin-gonic/gin/pull/1234"
+-		},
+-		{
+-			"type": "FIX",
+-			"url": "https://github.com/gin-gonic/gin/commit/abcdefg"
+-		}
+-	],
+-	"database_specific": {
+-		"url": "https://pkg.go.dev/vuln/GO-2020-0001"
+-	}
+-}
+\ No newline at end of file
 diff -urN a/gopls/internal/vulncheck/vulntest/testdata/report.yaml b/gopls/internal/vulncheck/vulntest/testdata/report.yaml
 --- a/gopls/internal/vulncheck/vulntest/testdata/report.yaml	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/internal/vulncheck/vulntest/testdata/report.yaml	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/internal/vulncheck/vulntest/testdata/report.yaml	1970-01-01 08:00:00
 @@ -1,15 +0,0 @@
 -modules:
 -    - module: github.com/gin-gonic/gin
@@ -126448,8 +141908,8 @@
 -    - fix: https://github.com/gin-gonic/gin/commit/abcdefg
 diff -urN a/gopls/main.go b/gopls/main.go
 --- a/gopls/main.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/main.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,33 +0,0 @@
++++ b/gopls/main.go	1970-01-01 08:00:00
+@@ -1,30 +0,0 @@
 -// Copyright 2019 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -126467,161 +141927,23 @@
 -
 -import (
 -	"context"
--	"golang.org/x/tools/internal/analysisinternal"
 -	"os"
 -
 -	"golang.org/x/tools/gopls/internal/hooks"
 -	"golang.org/x/tools/gopls/internal/lsp/cmd"
+-	"golang.org/x/tools/gopls/internal/telemetry"
 -	"golang.org/x/tools/internal/tool"
 -)
 -
 -func main() {
--	// In 1.18, diagnostics for Fuzz tests must not be used by cmd/vet.
--	// So the code for Fuzz tests diagnostics is guarded behind flag analysisinternal.DiagnoseFuzzTests
--	// Turn on analysisinternal.DiagnoseFuzzTests for gopls
--	analysisinternal.DiagnoseFuzzTests = true
+-	telemetry.Start()
 -	ctx := context.Background()
 -	tool.Main(ctx, cmd.New("gopls", "", nil, hooks.Options), os.Args[1:])
 -}
-diff -urN a/gopls/README.md b/gopls/README.md
---- a/gopls/README.md	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/README.md	1970-01-01 00:00:00.000000000 +0000
-@@ -1,131 +0,0 @@
--# `gopls`, the Go language server
--
--[![PkgGoDev](https://pkg.go.dev/badge/golang.org/x/tools/gopls)](https://pkg.go.dev/golang.org/x/tools/gopls)
--
--`gopls` (pronounced "Go please") is the official Go [language server] developed
--by the Go team. It provides IDE features to any [LSP]-compatible editor.
--
--<!--TODO(rfindley): Add gifs here.-->
--
--You should not need to interact with `gopls` directly--it will be automatically
--integrated into your editor. The specific features and settings vary slightly
--by editor, so we recommend that you proceed to the
--[documentation for your editor](#editors) below.
--
--## Editors
--
--To get started with `gopls`, install an LSP plugin in your editor of choice.
--
--* [VS Code](https://github.com/golang/vscode-go/blob/master/README.md)
--* [Vim / Neovim](doc/vim.md)
--* [Emacs](doc/emacs.md)
--* [Atom](https://github.com/MordFustang21/ide-gopls)
--* [Sublime Text](doc/subl.md)
--* [Acme](https://github.com/fhs/acme-lsp)
--* [Lapce](https://github.com/lapce-community/lapce-go)
--
--If you use `gopls` with an editor that is not on this list, please send us a CL
--[updating this documentation](doc/contributing.md).
--
--## Installation
--
--For the most part, you should not need to install or update `gopls`. Your
--editor should handle that step for you.
--
--If you do want to get the latest stable version of `gopls`, run the following
--command:
--
--```sh
--go install golang.org/x/tools/gopls@latest
--```
--
--Learn more in the
--[advanced installation instructions](doc/advanced.md#installing-unreleased-versions).
--
--Learn more about gopls releases in the [release policy](doc/releases.md).
--
--## Setting up your workspace
--
--`gopls` supports both Go module, multi-module and GOPATH modes. See the
--[workspace documentation](doc/workspace.md) for information on supported
--workspace layouts.
--
--## Configuration
--
--You can configure `gopls` to change your editor experience or view additional
--debugging information. Configuration options will be made available by your
--editor, so see your [editor's instructions](#editors) for specific details. A
--full list of `gopls` settings can be found in the [settings documentation](doc/settings.md).
--
--### Environment variables
--
--`gopls` inherits your editor's environment, so be aware of any environment
--variables you configure. Some editors, such as VS Code, allow users to
--selectively override the values of some environment variables.
--
--## Support Policy
--
--Gopls is maintained by engineers on the
--[Go tools team](https://github.com/orgs/golang/teams/tools-team/members),
--who actively monitor the
--[Go](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls)
--and
--[VS Code Go](https://github.com/golang/vscode-go/issues) issue trackers.
--
--### Supported Go versions
--
--`gopls` follows the
--[Go Release Policy](https://golang.org/doc/devel/release.html#policy),
--meaning that it officially supports the last 2 major Go releases. Per
--[issue #39146](https://go.dev/issues/39146), we attempt to maintain best-effort
--support for the last 4 major Go releases, but this support extends only to not
--breaking the build and avoiding easily fixable regressions.
--
--In the context of this discussion, gopls "supports" a Go version if it supports
--being built with that Go version as well as integrating with the `go` command
--of that Go version.
--
--The following table shows the final gopls version that supports a given Go
--version. Go releases more recent than any in the table can be used with any
--version of gopls.
--
--| Go Version  | Final gopls version with support (without warnings) |
--| ----------- | --------------------------------------------------- |
--| Go 1.12     | [gopls@v0.7.5](https://github.com/golang/tools/releases/tag/gopls%2Fv0.7.5) |
--| Go 1.15     | [gopls@v0.9.5](https://github.com/golang/tools/releases/tag/gopls%2Fv0.9.5) |
--
--Our extended support is enforced via [continuous integration with older Go
--versions](doc/contributing.md#ci). This legacy Go CI may not block releases:
--test failures may be skipped rather than fixed. Furthermore, if a regression in
--an older Go version causes irreconcilable CI failures, we may drop support for
--that Go version in CI if it is 3 or 4 Go versions old.
--
--### Supported build systems
--
--`gopls` currently only supports the `go` command, so if you are using
--a different build system, `gopls` will not work well. Bazel is not officially
--supported, but may be made to work with an appropriately configured
--`go/packages` driver. See
--[bazelbuild/rules_go#512](https://github.com/bazelbuild/rules_go/issues/512)
--for more information.
--You can follow [these instructions](https://github.com/bazelbuild/rules_go/wiki/Editor-setup)
--to configure your `gopls` to work with Bazel.
--
--### Troubleshooting
--
--If you are having issues with `gopls`, please follow the steps described in the
--[troubleshooting guide](doc/troubleshooting.md).
--
--## Additional information
--
--* [Features](doc/features.md)
--* [Command-line interface](doc/command-line.md)
--* [Advanced topics](doc/advanced.md)
--* [Contributing to `gopls`](doc/contributing.md)
--* [Integrating `gopls` with an editor](doc/design/integrating.md)
--* [Design requirements and decisions](doc/design/design.md)
--* [Implementation details](doc/design/implementation.md)
--* [Open issues](https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+label%3Agopls)
--
--[language server]: https://langserver.org
--[LSP]: https://microsoft.github.io/language-server-protocol/
 diff -urN a/gopls/release/release.go b/gopls/release/release.go
 --- a/gopls/release/release.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/release/release.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,156 +0,0 @@
++++ b/gopls/release/release.go	1970-01-01 08:00:00
+@@ -1,155 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
@@ -126639,7 +141961,6 @@
 -	"flag"
 -	"fmt"
 -	"go/types"
--	"io/ioutil"
 -	"log"
 -	"os"
 -	"path/filepath"
@@ -126733,7 +142054,7 @@
 -
 -func validateGoModFile(goplsDir string) error {
 -	filename := filepath.Join(goplsDir, "go.mod")
--	data, err := ioutil.ReadFile(filename)
+-	data, err := os.ReadFile(filename)
 -	if err != nil {
 -		return err
 -	}
@@ -126780,15 +142101,15 @@
 -}
 diff -urN a/gopls/test/debug/debug_test.go b/gopls/test/debug/debug_test.go
 --- a/gopls/test/debug/debug_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/test/debug/debug_test.go	1970-01-01 00:00:00.000000000 +0000
-@@ -1,141 +0,0 @@
++++ b/gopls/test/debug/debug_test.go	1970-01-01 08:00:00
+@@ -1,153 +0,0 @@
 -// Copyright 2020 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
 -// license that can be found in the LICENSE file.
 -
 -package debug_test
 -
--// Provide 'static type checking' of the templates. This guards against changes is various
+-// Provide 'static type checking' of the templates. This guards against changes in various
 -// gopls datastructures causing template execution to fail. The checking is done by
 -// the github.com/jba/templatecheck package. Before that is run, the test checks that
 -// its list of templates and their arguments corresponds to the arguments in
@@ -126797,6 +142118,7 @@
 -import (
 -	"go/ast"
 -	"html/template"
+-	"os"
 -	"runtime"
 -	"sort"
 -	"strings"
@@ -126806,33 +142128,42 @@
 -	"golang.org/x/tools/go/packages"
 -	"golang.org/x/tools/gopls/internal/lsp/cache"
 -	"golang.org/x/tools/gopls/internal/lsp/debug"
+-	"golang.org/x/tools/internal/testenv"
 -)
 -
 -var templates = map[string]struct {
 -	tmpl *template.Template
 -	data interface{} // a value of the needed type
 -}{
--	"MainTmpl":    {debug.MainTmpl, &debug.Instance{}},
--	"DebugTmpl":   {debug.DebugTmpl, nil},
--	"RPCTmpl":     {debug.RPCTmpl, &debug.Rpcs{}},
--	"TraceTmpl":   {debug.TraceTmpl, debug.TraceResults{}},
--	"CacheTmpl":   {debug.CacheTmpl, &cache.Cache{}},
--	"SessionTmpl": {debug.SessionTmpl, &cache.Session{}},
--	"ViewTmpl":    {debug.ViewTmpl, &cache.View{}},
--	"ClientTmpl":  {debug.ClientTmpl, &debug.Client{}},
--	"ServerTmpl":  {debug.ServerTmpl, &debug.Server{}},
--	"FileTmpl":    {debug.FileTmpl, &cache.Overlay{}},
--	"InfoTmpl":    {debug.InfoTmpl, "something"},
--	"MemoryTmpl":  {debug.MemoryTmpl, runtime.MemStats{}},
+-	"MainTmpl":     {debug.MainTmpl, &debug.Instance{}},
+-	"DebugTmpl":    {debug.DebugTmpl, nil},
+-	"RPCTmpl":      {debug.RPCTmpl, &debug.Rpcs{}},
+-	"TraceTmpl":    {debug.TraceTmpl, debug.TraceResults{}},
+-	"CacheTmpl":    {debug.CacheTmpl, &cache.Cache{}},
+-	"SessionTmpl":  {debug.SessionTmpl, &cache.Session{}},
+-	"ViewTmpl":     {debug.ViewTmpl, &cache.View{}},
+-	"ClientTmpl":   {debug.ClientTmpl, &debug.Client{}},
+-	"ServerTmpl":   {debug.ServerTmpl, &debug.Server{}},
+-	"FileTmpl":     {debug.FileTmpl, &cache.Overlay{}},
+-	"InfoTmpl":     {debug.InfoTmpl, "something"},
+-	"MemoryTmpl":   {debug.MemoryTmpl, runtime.MemStats{}},
+-	"AnalysisTmpl": {debug.AnalysisTmpl, new(debug.State).Analysis()},
 -}
 -
 -func TestTemplates(t *testing.T) {
--	if runtime.GOOS == "android" {
--		t.Skip("this test is not supported for Android")
--	}
+-	testenv.NeedsGoPackages(t)
+-	testenv.NeedsLocalXTools(t)
+-
 -	cfg := &packages.Config{
--		Mode: packages.NeedTypesInfo | packages.LoadAllSyntax, // figure out what's necessary PJW
+-		Mode: packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo,
 -	}
+-	cfg.Env = os.Environ()
+-	cfg.Env = append(cfg.Env,
+-		"GOPACKAGESDRIVER=off",
+-		"GOWORK=off", // necessary for -mod=mod below
+-		"GOFLAGS=-mod=mod",
+-	)
+-
 -	pkgs, err := packages.Load(cfg, "golang.org/x/tools/gopls/internal/lsp/debug")
 -	if err != nil {
 -		t.Fatal(err)
@@ -126891,7 +142222,9 @@
 -		// the FuncMap is an annoyance; should not be necessary
 -		if err := templatecheck.CheckHTML(v.tmpl, v.data); err != nil {
 -			t.Errorf("%s: %v", k, err)
+-			continue
 -		}
+-		t.Logf("%s ok", k)
 -	}
 -}
 -
@@ -126925,7 +142258,7 @@
 -}
 diff -urN a/gopls/test/json_test.go b/gopls/test/json_test.go
 --- a/gopls/test/json_test.go	2000-01-01 00:00:00.000000000 -0000
-+++ b/gopls/test/json_test.go	1970-01-01 00:00:00.000000000 +0000
++++ b/gopls/test/json_test.go	1970-01-01 08:00:00
 @@ -1,140 +0,0 @@
 -// Copyright 2021 The Go Authors. All rights reserved.
 -// Use of this source code is governed by a BSD-style
diff --git a/third_party/org_golang_x_tools-gazelle.patch b/third_party/org_golang_x_tools-gazelle.patch
index f3a1f23..33d7c10 100644
--- a/third_party/org_golang_x_tools-gazelle.patch
+++ b/third_party/org_golang_x_tools-gazelle.patch
@@ -1,5 +1,5 @@
 diff -urN b/benchmark/parse/BUILD.bazel c/benchmark/parse/BUILD.bazel
---- b/benchmark/parse/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/benchmark/parse/BUILD.bazel	1970-01-01 08:00:00
 +++ c/benchmark/parse/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -22,26 +22,8 @@
 +    srcs = ["parse_test.go"],
 +    embed = [":parse"],
 +)
-diff -urN b/blog/atom/BUILD.bazel c/blog/atom/BUILD.bazel
---- b/blog/atom/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/blog/atom/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
-+
-+go_library(
-+    name = "atom",
-+    srcs = ["atom.go"],
-+    importpath = "golang.org/x/tools/blog/atom",
-+    visibility = ["//visibility:public"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":atom",
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/blog/BUILD.bazel c/blog/BUILD.bazel
---- b/blog/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/blog/BUILD.bazel	1970-01-01 08:00:00
 +++ c/blog/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -68,8 +50,26 @@
 +    srcs = ["blog_test.go"],
 +    embed = [":blog"],
 +)
+diff -urN b/blog/atom/BUILD.bazel c/blog/atom/BUILD.bazel
+--- b/blog/atom/BUILD.bazel	1970-01-01 08:00:00
++++ c/blog/atom/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "atom",
++    srcs = ["atom.go"],
++    importpath = "golang.org/x/tools/blog/atom",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":atom",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/cmd/auth/authtest/BUILD.bazel c/cmd/auth/authtest/BUILD.bazel
---- b/cmd/auth/authtest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/auth/authtest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/auth/authtest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -88,7 +88,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/auth/cookieauth/BUILD.bazel c/cmd/auth/cookieauth/BUILD.bazel
---- b/cmd/auth/cookieauth/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/auth/cookieauth/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/auth/cookieauth/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -106,7 +106,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/auth/gitauth/BUILD.bazel c/cmd/auth/gitauth/BUILD.bazel
---- b/cmd/auth/gitauth/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/auth/gitauth/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/auth/gitauth/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -125,7 +125,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/auth/netrcauth/BUILD.bazel c/cmd/auth/netrcauth/BUILD.bazel
---- b/cmd/auth/netrcauth/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/auth/netrcauth/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/auth/netrcauth/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -143,7 +143,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/benchcmp/BUILD.bazel c/cmd/benchcmp/BUILD.bazel
---- b/cmd/benchcmp/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/benchcmp/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/benchcmp/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -175,10 +175,47 @@
 +    embed = [":benchcmp_lib"],
 +    deps = ["//benchmark/parse"],
 +)
+diff -urN b/cmd/bisect/BUILD.bazel c/cmd/bisect/BUILD.bazel
+--- b/cmd/bisect/BUILD.bazel	1970-01-01 08:00:00
++++ c/cmd/bisect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,33 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
++
++go_library(
++    name = "bisect_lib",
++    srcs = [
++        "go119.go",
++        "go120.go",
++        "main.go",
++        "rand.go",
++    ],
++    importpath = "golang.org/x/tools/cmd/bisect",
++    visibility = ["//visibility:private"],
++    deps = ["//internal/bisect"],
++)
++
++go_binary(
++    name = "bisect",
++    embed = [":bisect_lib"],
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "bisect_test",
++    srcs = ["main_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    embed = [":bisect_lib"],
++    deps = [
++        "//internal/bisect",
++        "//internal/compat",
++        "//internal/diffp",
++        "//txtar",
++    ],
++)
 diff -urN b/cmd/bundle/BUILD.bazel c/cmd/bundle/BUILD.bazel
---- b/cmd/bundle/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/bundle/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/bundle/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,22 @@
+@@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 +
 +go_library(
@@ -198,11 +235,12 @@
 +go_test(
 +    name = "bundle_test",
 +    srcs = ["main_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":bundle_lib"],
 +    deps = ["//go/packages/packagestest"],
 +)
 diff -urN b/cmd/bundle/testdata/src/domain.name/importdecl/BUILD.bazel c/cmd/bundle/testdata/src/domain.name/importdecl/BUILD.bazel
---- b/cmd/bundle/testdata/src/domain.name/importdecl/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/bundle/testdata/src/domain.name/importdecl/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/bundle/testdata/src/domain.name/importdecl/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -220,7 +258,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/bundle/testdata/src/initial/BUILD.bazel c/cmd/bundle/testdata/src/initial/BUILD.bazel
---- b/cmd/bundle/testdata/src/initial/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/bundle/testdata/src/initial/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/bundle/testdata/src/initial/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -242,7 +280,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/callgraph/BUILD.bazel c/cmd/callgraph/BUILD.bazel
---- b/cmd/callgraph/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/callgraph/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/callgraph/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,74 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -260,7 +298,6 @@
 +        "//go/callgraph/static",
 +        "//go/callgraph/vta",
 +        "//go/packages",
-+        "//go/pointer",
 +        "//go/ssa",
 +        "//go/ssa/ssautil",
 +    ],
@@ -275,6 +312,7 @@
 +go_test(
 +    name = "callgraph_test",
 +    srcs = ["main_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":callgraph_lib"],
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:aix": [
@@ -320,7 +358,7 @@
 +    }),
 +)
 diff -urN b/cmd/callgraph/testdata/src/pkg/BUILD.bazel c/cmd/callgraph/testdata/src/pkg/BUILD.bazel
---- b/cmd/callgraph/testdata/src/pkg/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/callgraph/testdata/src/pkg/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/callgraph/testdata/src/pkg/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -344,7 +382,7 @@
 +    embed = [":pkg_lib"],
 +)
 diff -urN b/cmd/compilebench/BUILD.bazel c/cmd/compilebench/BUILD.bazel
---- b/cmd/compilebench/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/compilebench/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/compilebench/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -363,14 +401,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/digraph/BUILD.bazel c/cmd/digraph/BUILD.bazel
---- b/cmd/digraph/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/digraph/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/digraph/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 +
 +go_library(
 +    name = "digraph_lib",
-+    srcs = ["digraph.go"],
++    srcs = [
++        "digraph.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/cmd/digraph",
 +    visibility = ["//visibility:private"],
 +)
@@ -387,7 +429,7 @@
 +    embed = [":digraph_lib"],
 +)
 diff -urN b/cmd/eg/BUILD.bazel c/cmd/eg/BUILD.bazel
---- b/cmd/eg/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/eg/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/eg/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,19 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -410,9 +452,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/file2fuzz/BUILD.bazel c/cmd/file2fuzz/BUILD.bazel
---- b/cmd/file2fuzz/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/file2fuzz/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/file2fuzz/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 +
 +go_library(
@@ -432,11 +474,12 @@
 +    name = "file2fuzz_test",
 +    srcs = ["main_test.go"],
 +    embed = [":file2fuzz_lib"],
++    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/fiximports/BUILD.bazel c/cmd/fiximports/BUILD.bazel
---- b/cmd/fiximports/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,63 @@
+@@ -0,0 +1,64 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 +
 +go_library(
@@ -456,6 +499,7 @@
 +go_test(
 +    name = "fiximports_test",
 +    srcs = ["main_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":fiximports_lib"],
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:aix": [
@@ -501,7 +545,7 @@
 +    }),
 +)
 diff -urN b/cmd/fiximports/testdata/src/fruit.io/banana/BUILD.bazel c/cmd/fiximports/testdata/src/fruit.io/banana/BUILD.bazel
---- b/cmd/fiximports/testdata/src/fruit.io/banana/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/fruit.io/banana/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/fruit.io/banana/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -519,7 +563,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/fruit.io/orange/BUILD.bazel c/cmd/fiximports/testdata/src/fruit.io/orange/BUILD.bazel
---- b/cmd/fiximports/testdata/src/fruit.io/orange/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/fruit.io/orange/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/fruit.io/orange/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -537,7 +581,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/fruit.io/pear/BUILD.bazel c/cmd/fiximports/testdata/src/fruit.io/pear/BUILD.bazel
---- b/cmd/fiximports/testdata/src/fruit.io/pear/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/fruit.io/pear/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/fruit.io/pear/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -555,7 +599,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/new.com/one/BUILD.bazel c/cmd/fiximports/testdata/src/new.com/one/BUILD.bazel
---- b/cmd/fiximports/testdata/src/new.com/one/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/new.com/one/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/new.com/one/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -573,7 +617,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/old.com/bad/BUILD.bazel c/cmd/fiximports/testdata/src/old.com/bad/BUILD.bazel
---- b/cmd/fiximports/testdata/src/old.com/bad/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/old.com/bad/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/old.com/bad/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -591,7 +635,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/old.com/one/BUILD.bazel c/cmd/fiximports/testdata/src/old.com/one/BUILD.bazel
---- b/cmd/fiximports/testdata/src/old.com/one/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/old.com/one/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/old.com/one/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -609,7 +653,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/titanic.biz/bar/BUILD.bazel c/cmd/fiximports/testdata/src/titanic.biz/bar/BUILD.bazel
---- b/cmd/fiximports/testdata/src/titanic.biz/bar/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/titanic.biz/bar/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/titanic.biz/bar/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -627,7 +671,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/fiximports/testdata/src/titanic.biz/foo/BUILD.bazel c/cmd/fiximports/testdata/src/titanic.biz/foo/BUILD.bazel
---- b/cmd/fiximports/testdata/src/titanic.biz/foo/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/fiximports/testdata/src/titanic.biz/foo/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/fiximports/testdata/src/titanic.biz/foo/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -645,7 +689,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/getgo/BUILD.bazel c/cmd/getgo/BUILD.bazel
---- b/cmd/getgo/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/getgo/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/getgo/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,74 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -723,7 +767,7 @@
 +    embed = [":getgo_lib"],
 +)
 diff -urN b/cmd/getgo/server/BUILD.bazel c/cmd/getgo/server/BUILD.bazel
---- b/cmd/getgo/server/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/getgo/server/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/getgo/server/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -741,7 +785,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/go-contrib-init/BUILD.bazel c/cmd/go-contrib-init/BUILD.bazel
---- b/cmd/go-contrib-init/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/go-contrib-init/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/go-contrib-init/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -766,7 +810,7 @@
 +    embed = [":go-contrib-init_lib"],
 +)
 diff -urN b/cmd/godex/BUILD.bazel c/cmd/godex/BUILD.bazel
---- b/cmd/godex/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/godex/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/godex/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -794,7 +838,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/godoc/BUILD.bazel c/cmd/godoc/BUILD.bazel
---- b/cmd/godoc/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/godoc/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/godoc/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,41 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -839,7 +883,7 @@
 +    ],
 +)
 diff -urN b/cmd/goimports/BUILD.bazel c/cmd/goimports/BUILD.bazel
---- b/cmd/goimports/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/goimports/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/goimports/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -866,7 +910,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/gomvpkg/BUILD.bazel c/cmd/gomvpkg/BUILD.bazel
---- b/cmd/gomvpkg/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/gomvpkg/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/gomvpkg/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -887,8 +931,42 @@
 +    embed = [":gomvpkg_lib"],
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/cmd/gonew/BUILD.bazel c/cmd/gonew/BUILD.bazel
+--- b/cmd/gonew/BUILD.bazel	1970-01-01 08:00:00
++++ c/cmd/gonew/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,30 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
++
++go_library(
++    name = "gonew_lib",
++    srcs = ["main.go"],
++    importpath = "golang.org/x/tools/cmd/gonew",
++    visibility = ["//visibility:private"],
++    deps = [
++        "//internal/edit",
++        "@org_golang_x_mod//modfile:go_default_library",
++        "@org_golang_x_mod//module:go_default_library",
++    ],
++)
++
++go_binary(
++    name = "gonew",
++    embed = [":gonew_lib"],
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "gonew_test",
++    srcs = ["main_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    embed = [":gonew_lib"],
++    deps = [
++        "//internal/diffp",
++        "//txtar",
++    ],
++)
 diff -urN b/cmd/gorename/BUILD.bazel c/cmd/gorename/BUILD.bazel
---- b/cmd/gorename/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/gorename/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/gorename/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -916,7 +994,7 @@
 +    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/gotype/BUILD.bazel c/cmd/gotype/BUILD.bazel
---- b/cmd/gotype/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/gotype/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/gotype/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -938,7 +1016,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/goyacc/BUILD.bazel c/cmd/goyacc/BUILD.bazel
---- b/cmd/goyacc/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/goyacc/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/goyacc/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -959,7 +1037,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/goyacc/testdata/expr/BUILD.bazel c/cmd/goyacc/testdata/expr/BUILD.bazel
---- b/cmd/goyacc/testdata/expr/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/goyacc/testdata/expr/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/goyacc/testdata/expr/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -977,17 +1055,14 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/BUILD.bazel c/cmd/guru/BUILD.bazel
---- b/cmd/guru/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,46 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
 +
 +go_library(
 +    name = "guru_lib",
 +    srcs = [
-+        "callees.go",
-+        "callers.go",
-+        "callstack.go",
 +        "definition.go",
 +        "describe.go",
 +        "freevars.go",
@@ -996,12 +1071,9 @@
 +        "isAlias18.go",
 +        "isAlias19.go",
 +        "main.go",
-+        "peers.go",
-+        "pointsto.go",
 +        "pos.go",
 +        "referrers.go",
 +        "what.go",
-+        "whicherrs.go",
 +    ],
 +    importpath = "golang.org/x/tools/cmd/guru",
 +    visibility = ["//visibility:private"],
@@ -1009,12 +1081,7 @@
 +        "//cmd/guru/serial",
 +        "//go/ast/astutil",
 +        "//go/buildutil",
-+        "//go/callgraph",
-+        "//go/callgraph/static",
 +        "//go/loader",
-+        "//go/pointer",
-+        "//go/ssa",
-+        "//go/ssa/ssautil",
 +        "//go/types/typeutil",
 +        "//imports",
 +        "//refactor/importgraph",
@@ -1033,11 +1100,12 @@
 +        "guru_test.go",
 +        "unit_test.go",
 +    ],
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":guru_lib"],
 +    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/guru/serial/BUILD.bazel c/cmd/guru/serial/BUILD.bazel
---- b/cmd/guru/serial/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/serial/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/serial/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1055,7 +1123,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/alias/BUILD.bazel c/cmd/guru/testdata/src/alias/BUILD.bazel
---- b/cmd/guru/testdata/src/alias/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/alias/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/alias/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1072,44 +1140,8 @@
 +    actual = ":alias",
 +    visibility = ["//visibility:public"],
 +)
-diff -urN b/cmd/guru/testdata/src/calls/BUILD.bazel c/cmd/guru/testdata/src/calls/BUILD.bazel
---- b/cmd/guru/testdata/src/calls/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/calls/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "calls_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/calls",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "calls",
-+    embed = [":calls_lib"],
-+    visibility = ["//visibility:public"],
-+)
-diff -urN b/cmd/guru/testdata/src/calls-json/BUILD.bazel c/cmd/guru/testdata/src/calls-json/BUILD.bazel
---- b/cmd/guru/testdata/src/calls-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/calls-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "calls-json_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/calls-json",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "calls-json",
-+    embed = [":calls-json_lib"],
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/cmd/guru/testdata/src/definition-json/BUILD.bazel c/cmd/guru/testdata/src/definition-json/BUILD.bazel
---- b/cmd/guru/testdata/src/definition-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/definition-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/definition-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1130,7 +1162,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/describe/BUILD.bazel c/cmd/guru/testdata/src/describe/BUILD.bazel
---- b/cmd/guru/testdata/src/describe/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/describe/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/describe/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1148,7 +1180,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/describe-json/BUILD.bazel c/cmd/guru/testdata/src/describe-json/BUILD.bazel
---- b/cmd/guru/testdata/src/describe-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/describe-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/describe-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1166,7 +1198,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/freevars/BUILD.bazel c/cmd/guru/testdata/src/freevars/BUILD.bazel
---- b/cmd/guru/testdata/src/freevars/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/freevars/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/freevars/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1184,7 +1216,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/implements/BUILD.bazel c/cmd/guru/testdata/src/implements/BUILD.bazel
---- b/cmd/guru/testdata/src/implements/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/implements/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/implements/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1202,7 +1234,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/implements-json/BUILD.bazel c/cmd/guru/testdata/src/implements-json/BUILD.bazel
---- b/cmd/guru/testdata/src/implements-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/implements-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/implements-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1220,7 +1252,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/implements-methods/BUILD.bazel c/cmd/guru/testdata/src/implements-methods/BUILD.bazel
---- b/cmd/guru/testdata/src/implements-methods/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/implements-methods/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/implements-methods/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1238,7 +1270,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/implements-methods-json/BUILD.bazel c/cmd/guru/testdata/src/implements-methods-json/BUILD.bazel
---- b/cmd/guru/testdata/src/implements-methods-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/implements-methods-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/implements-methods-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1256,7 +1288,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/imports/BUILD.bazel c/cmd/guru/testdata/src/imports/BUILD.bazel
---- b/cmd/guru/testdata/src/imports/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/imports/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/imports/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1274,7 +1306,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/lib/BUILD.bazel c/cmd/guru/testdata/src/lib/BUILD.bazel
---- b/cmd/guru/testdata/src/lib/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/lib/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/lib/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1292,7 +1324,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/lib/sublib/BUILD.bazel c/cmd/guru/testdata/src/lib/sublib/BUILD.bazel
---- b/cmd/guru/testdata/src/lib/sublib/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/lib/sublib/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/lib/sublib/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -1310,7 +1342,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/main/BUILD.bazel c/cmd/guru/testdata/src/main/BUILD.bazel
---- b/cmd/guru/testdata/src/main/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/main/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/main/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1327,80 +1359,8 @@
 +    embed = [":main_lib"],
 +    visibility = ["//visibility:public"],
 +)
-diff -urN b/cmd/guru/testdata/src/peers/BUILD.bazel c/cmd/guru/testdata/src/peers/BUILD.bazel
---- b/cmd/guru/testdata/src/peers/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/peers/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "peers_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/peers",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "peers",
-+    embed = [":peers_lib"],
-+    visibility = ["//visibility:public"],
-+)
-diff -urN b/cmd/guru/testdata/src/peers-json/BUILD.bazel c/cmd/guru/testdata/src/peers-json/BUILD.bazel
---- b/cmd/guru/testdata/src/peers-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/peers-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "peers-json_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/peers-json",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "peers-json",
-+    embed = [":peers-json_lib"],
-+    visibility = ["//visibility:public"],
-+)
-diff -urN b/cmd/guru/testdata/src/pointsto/BUILD.bazel c/cmd/guru/testdata/src/pointsto/BUILD.bazel
---- b/cmd/guru/testdata/src/pointsto/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/pointsto/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "pointsto_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/pointsto",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "pointsto",
-+    embed = [":pointsto_lib"],
-+    visibility = ["//visibility:public"],
-+)
-diff -urN b/cmd/guru/testdata/src/pointsto-json/BUILD.bazel c/cmd/guru/testdata/src/pointsto-json/BUILD.bazel
---- b/cmd/guru/testdata/src/pointsto-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/pointsto-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "pointsto-json_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/pointsto-json",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "pointsto-json",
-+    embed = [":pointsto-json_lib"],
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/cmd/guru/testdata/src/referrers/BUILD.bazel c/cmd/guru/testdata/src/referrers/BUILD.bazel
---- b/cmd/guru/testdata/src/referrers/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/referrers/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/referrers/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -1427,7 +1387,7 @@
 +    embed = [":referrers_lib"],
 +)
 diff -urN b/cmd/guru/testdata/src/referrers-json/BUILD.bazel c/cmd/guru/testdata/src/referrers-json/BUILD.bazel
---- b/cmd/guru/testdata/src/referrers-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/referrers-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/referrers-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1444,44 +1404,8 @@
 +    embed = [":referrers-json_lib"],
 +    visibility = ["//visibility:public"],
 +)
-diff -urN b/cmd/guru/testdata/src/reflection/BUILD.bazel c/cmd/guru/testdata/src/reflection/BUILD.bazel
---- b/cmd/guru/testdata/src/reflection/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/reflection/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "reflection_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/reflection",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "reflection",
-+    embed = [":reflection_lib"],
-+    visibility = ["//visibility:public"],
-+)
-diff -urN b/cmd/guru/testdata/src/softerrs/BUILD.bazel c/cmd/guru/testdata/src/softerrs/BUILD.bazel
---- b/cmd/guru/testdata/src/softerrs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/softerrs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "softerrs_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/softerrs",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "softerrs",
-+    embed = [":softerrs_lib"],
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/cmd/guru/testdata/src/what/BUILD.bazel c/cmd/guru/testdata/src/what/BUILD.bazel
---- b/cmd/guru/testdata/src/what/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/what/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/what/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1499,7 +1423,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/guru/testdata/src/what-json/BUILD.bazel c/cmd/guru/testdata/src/what-json/BUILD.bazel
---- b/cmd/guru/testdata/src/what-json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/guru/testdata/src/what-json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/guru/testdata/src/what-json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1516,26 +1440,8 @@
 +    embed = [":what-json_lib"],
 +    visibility = ["//visibility:public"],
 +)
-diff -urN b/cmd/guru/testdata/src/whicherrs/BUILD.bazel c/cmd/guru/testdata/src/whicherrs/BUILD.bazel
---- b/cmd/guru/testdata/src/whicherrs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/cmd/guru/testdata/src/whicherrs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "whicherrs_lib",
-+    srcs = ["main.go"],
-+    importpath = "golang.org/x/tools/cmd/guru/testdata/src/whicherrs",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "whicherrs",
-+    embed = [":whicherrs_lib"],
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/cmd/html2article/BUILD.bazel c/cmd/html2article/BUILD.bazel
---- b/cmd/html2article/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/html2article/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/html2article/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1557,9 +1463,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/present/BUILD.bazel c/cmd/present/BUILD.bazel
---- b/cmd/present/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/present/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/present/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,40 @@
+@@ -0,0 +1,42 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 +
 +go_library(
@@ -1576,8 +1482,11 @@
 +        "static/dir.js",
 +        "static/favicon.ico",
 +        "static/jquery-ui.js",
++        "static/jquery.js",
 +        "static/notes.css",
 +        "static/notes.js",
++        "static/play.js",
++        "static/playground.js",
 +        "static/slides.js",
 +        "static/styles.css",
 +        "templates/action.tmpl",
@@ -1588,7 +1497,6 @@
 +    importpath = "golang.org/x/tools/cmd/present",
 +    visibility = ["//visibility:private"],
 +    deps = [
-+        "//godoc/static",
 +        "//playground",
 +        "//playground/socket",
 +        "//present",
@@ -1601,7 +1509,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/present2md/BUILD.bazel c/cmd/present2md/BUILD.bazel
---- b/cmd/present2md/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/present2md/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/present2md/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1620,7 +1528,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/signature-fuzzer/fuzz-driver/BUILD.bazel c/cmd/signature-fuzzer/fuzz-driver/BUILD.bazel
---- b/cmd/signature-fuzzer/fuzz-driver/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/signature-fuzzer/fuzz-driver/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/signature-fuzzer/fuzz-driver/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -1646,7 +1554,7 @@
 +    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/signature-fuzzer/fuzz-runner/BUILD.bazel c/cmd/signature-fuzzer/fuzz-runner/BUILD.bazel
---- b/cmd/signature-fuzzer/fuzz-runner/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/signature-fuzzer/fuzz-runner/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/signature-fuzzer/fuzz-runner/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -1672,7 +1580,7 @@
 +    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/signature-fuzzer/fuzz-runner/testdata/BUILD.bazel c/cmd/signature-fuzzer/fuzz-runner/testdata/BUILD.bazel
---- b/cmd/signature-fuzzer/fuzz-runner/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/signature-fuzzer/fuzz-runner/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/signature-fuzzer/fuzz-runner/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1690,7 +1598,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/signature-fuzzer/internal/fuzz-generator/BUILD.bazel c/cmd/signature-fuzzer/internal/fuzz-generator/BUILD.bazel
---- b/cmd/signature-fuzzer/internal/fuzz-generator/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/signature-fuzzer/internal/fuzz-generator/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/signature-fuzzer/internal/fuzz-generator/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -1726,9 +1634,9 @@
 +    deps = ["//internal/testenv"],
 +)
 diff -urN b/cmd/splitdwarf/BUILD.bazel c/cmd/splitdwarf/BUILD.bazel
---- b/cmd/splitdwarf/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/splitdwarf/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/splitdwarf/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,47 @@
+@@ -0,0 +1,44 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 +
 +go_library(
@@ -1752,9 +1660,6 @@
 +        "@io_bazel_rules_go//go/platform:freebsd": [
 +            "//cmd/splitdwarf/internal/macho",
 +        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            "//cmd/splitdwarf/internal/macho",
-+        ],
 +        "@io_bazel_rules_go//go/platform:ios": [
 +            "//cmd/splitdwarf/internal/macho",
 +        ],
@@ -1777,7 +1682,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/splitdwarf/internal/macho/BUILD.bazel c/cmd/splitdwarf/internal/macho/BUILD.bazel
---- b/cmd/splitdwarf/internal/macho/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/splitdwarf/internal/macho/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/splitdwarf/internal/macho/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,27 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -1804,11 +1709,11 @@
 +go_test(
 +    name = "macho_test",
 +    srcs = ["file_test.go"],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":macho"],
 +)
 diff -urN b/cmd/ssadump/BUILD.bazel c/cmd/ssadump/BUILD.bazel
---- b/cmd/ssadump/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/ssadump/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/ssadump/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1833,9 +1738,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/stress/BUILD.bazel c/cmd/stress/BUILD.bazel
---- b/cmd/stress/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/stress/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/stress/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,50 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 +
 +go_library(
@@ -1859,15 +1764,9 @@
 +        "@io_bazel_rules_go//go/platform:freebsd": [
 +            "@org_golang_x_sys//execabs:go_default_library",
 +        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            "@org_golang_x_sys//execabs:go_default_library",
-+        ],
 +        "@io_bazel_rules_go//go/platform:ios": [
 +            "@org_golang_x_sys//execabs:go_default_library",
 +        ],
-+        "@io_bazel_rules_go//go/platform:js": [
-+            "@org_golang_x_sys//execabs:go_default_library",
-+        ],
 +        "@io_bazel_rules_go//go/platform:linux": [
 +            "@org_golang_x_sys//execabs:go_default_library",
 +        ],
@@ -1893,7 +1792,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/stringer/BUILD.bazel c/cmd/stringer/BUILD.bazel
---- b/cmd/stringer/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/stringer/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/stringer/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,69 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
@@ -1966,7 +1865,7 @@
 +    }),
 +)
 diff -urN b/cmd/stringer/testdata/BUILD.bazel c/cmd/stringer/testdata/BUILD.bazel
---- b/cmd/stringer/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/stringer/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/stringer/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,27 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -1997,7 +1896,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/stringer/testdata/typeparams/BUILD.bazel c/cmd/stringer/testdata/typeparams/BUILD.bazel
---- b/cmd/stringer/testdata/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/stringer/testdata/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/stringer/testdata/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -2018,7 +1917,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/cmd/toolstash/BUILD.bazel c/cmd/toolstash/BUILD.bazel
---- b/cmd/toolstash/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cmd/toolstash/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cmd/toolstash/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -2040,7 +1939,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/container/intsets/BUILD.bazel c/container/intsets/BUILD.bazel
---- b/container/intsets/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/container/intsets/BUILD.bazel	1970-01-01 08:00:00
 +++ c/container/intsets/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2067,7 +1966,7 @@
 +    embed = [":intsets"],
 +)
 diff -urN b/copyright/BUILD.bazel c/copyright/BUILD.bazel
---- b/copyright/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/copyright/BUILD.bazel	1970-01-01 08:00:00
 +++ c/copyright/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2091,7 +1990,7 @@
 +    embed = [":copyright"],
 +)
 diff -urN b/cover/BUILD.bazel c/cover/BUILD.bazel
---- b/cover/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/cover/BUILD.bazel	1970-01-01 08:00:00
 +++ c/cover/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2114,8 +2013,37 @@
 +    srcs = ["profile_test.go"],
 +    embed = [":cover"],
 +)
+diff -urN b/go/analysis/BUILD.bazel c/go/analysis/BUILD.bazel
+--- b/go/analysis/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,25 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "analysis",
++    srcs = [
++        "analysis.go",
++        "diagnostic.go",
++        "doc.go",
++        "validate.go",
++    ],
++    importpath = "golang.org/x/tools/go/analysis",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":analysis",
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "analysis_test",
++    srcs = ["validate_test.go"],
++    embed = [":analysis"],
++)
 diff -urN b/go/analysis/analysistest/BUILD.bazel c/go/analysis/analysistest/BUILD.bazel
---- b/go/analysis/analysistest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/analysistest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/analysistest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2150,39 +2078,10 @@
 +        "//internal/testenv",
 +    ],
 +)
-diff -urN b/go/analysis/BUILD.bazel c/go/analysis/BUILD.bazel
---- b/go/analysis/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/analysis/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,25 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-+
-+go_library(
-+    name = "analysis",
-+    srcs = [
-+        "analysis.go",
-+        "diagnostic.go",
-+        "doc.go",
-+        "validate.go",
-+    ],
-+    importpath = "golang.org/x/tools/go/analysis",
-+    visibility = ["//visibility:public"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":analysis",
-+    visibility = ["//visibility:public"],
-+)
-+
-+go_test(
-+    name = "analysis_test",
-+    srcs = ["validate_test.go"],
-+    embed = [":analysis"],
-+)
 diff -urN b/go/analysis/internal/analysisflags/BUILD.bazel c/go/analysis/internal/analysisflags/BUILD.bazel
---- b/go/analysis/internal/analysisflags/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/internal/analysisflags/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/internal/analysisflags/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,27 @@
+@@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2190,6 +2089,7 @@
 +    srcs = [
 +        "flags.go",
 +        "help.go",
++        "url.go",
 +    ],
 +    importpath = "golang.org/x/tools/go/analysis/internal/analysisflags",
 +    visibility = ["//go/analysis:__subpackages__"],
@@ -2204,14 +2104,17 @@
 +
 +go_test(
 +    name = "analysisflags_test",
-+    srcs = ["flags_test.go"],
++    srcs = [
++        "flags_test.go",
++        "url_test.go",
++    ],
 +    deps = [
 +        ":analysisflags",
 +        "//go/analysis",
 +    ],
 +)
 diff -urN b/go/analysis/internal/checker/BUILD.bazel c/go/analysis/internal/checker/BUILD.bazel
---- b/go/analysis/internal/checker/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/internal/checker/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/internal/checker/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,38 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2252,8 +2155,25 @@
 +        "//internal/testenv",
 +    ],
 +)
+diff -urN b/go/analysis/internal/versiontest/BUILD.bazel c/go/analysis/internal/versiontest/BUILD.bazel
+--- b/go/analysis/internal/versiontest/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/internal/versiontest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,13 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_test")
++
++go_test(
++    name = "versiontest_test",
++    srcs = ["version_test.go"],
++    deps = [
++        "//go/analysis",
++        "//go/analysis/analysistest",
++        "//go/analysis/multichecker",
++        "//go/analysis/singlechecker",
++        "//internal/testenv",
++    ],
++)
 diff -urN b/go/analysis/multichecker/BUILD.bazel c/go/analysis/multichecker/BUILD.bazel
---- b/go/analysis/multichecker/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/multichecker/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/multichecker/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2287,10 +2207,84 @@
 +        "//internal/testenv",
 +    ],
 +)
+diff -urN b/go/analysis/passes/appends/BUILD.bazel c/go/analysis/passes/appends/BUILD.bazel
+--- b/go/analysis/passes/appends/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/appends/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,34 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "appends",
++    srcs = [
++        "appends.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/appends",
++    visibility = ["//visibility:public"],
++    deps = [
++        "//go/analysis",
++        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
++        "//go/ast/inspector",
++    ],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":appends",
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "appends_test",
++    srcs = ["appends_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    deps = [
++        ":appends",
++        "//go/analysis/analysistest",
++    ],
++)
+diff -urN b/go/analysis/passes/appends/testdata/src/a/BUILD.bazel c/go/analysis/passes/appends/testdata/src/a/BUILD.bazel
+--- b/go/analysis/passes/appends/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/appends/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "a",
++    srcs = ["a.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/appends/testdata/src/a",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":a",
++    visibility = ["//visibility:public"],
++)
+diff -urN b/go/analysis/passes/appends/testdata/src/b/BUILD.bazel c/go/analysis/passes/appends/testdata/src/b/BUILD.bazel
+--- b/go/analysis/passes/appends/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/appends/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "b",
++    srcs = ["b.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/appends/testdata/src/b",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":b",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/analysis/passes/asmdecl/BUILD.bazel c/go/analysis/passes/asmdecl/BUILD.bazel
---- b/go/analysis/passes/asmdecl/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/asmdecl/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/asmdecl/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2317,13 +2311,14 @@
 +go_test(
 +    name = "asmdecl_test",
 +    srcs = ["asmdecl_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":asmdecl",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/asmdecl/testdata/src/a/BUILD.bazel c/go/analysis/passes/asmdecl/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/asmdecl/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/asmdecl/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/asmdecl/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,26 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2353,14 +2348,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/assign/BUILD.bazel c/go/analysis/passes/assign/BUILD.bazel
---- b/go/analysis/passes/assign/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/assign/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/assign/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "assign",
-+    srcs = ["assign.go"],
++    srcs = [
++        "assign.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/assign",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -2387,7 +2386,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/assign/testdata/src/a/BUILD.bazel c/go/analysis/passes/assign/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/assign/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/assign/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/assign/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2405,7 +2404,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/assign/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/assign/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/assign/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/assign/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/assign/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2423,14 +2422,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/atomic/BUILD.bazel c/go/analysis/passes/atomic/BUILD.bazel
---- b/go/analysis/passes/atomic/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomic/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomic/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "atomic",
-+    srcs = ["atomic.go"],
++    srcs = [
++        "atomic.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/atomic",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -2450,6 +2453,7 @@
 +go_test(
 +    name = "atomic_test",
 +    srcs = ["atomic_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":atomic",
 +        "//go/analysis/analysistest",
@@ -2457,7 +2461,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/atomic/testdata/src/a/BUILD.bazel c/go/analysis/passes/atomic/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/atomic/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomic/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomic/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2475,7 +2479,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/atomic/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/atomic/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/atomic/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomic/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomic/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2493,9 +2497,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/atomicalign/BUILD.bazel c/go/analysis/passes/atomicalign/BUILD.bazel
---- b/go/analysis/passes/atomicalign/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomicalign/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomicalign/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,30 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2520,13 +2524,14 @@
 +go_test(
 +    name = "atomicalign_test",
 +    srcs = ["atomicalign_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":atomicalign",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/atomicalign/testdata/src/a/BUILD.bazel c/go/analysis/passes/atomicalign/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/atomicalign/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomicalign/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomicalign/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2547,7 +2552,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/atomicalign/testdata/src/b/BUILD.bazel c/go/analysis/passes/atomicalign/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/atomicalign/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/atomicalign/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/atomicalign/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2568,9 +2573,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/bools/BUILD.bazel c/go/analysis/passes/bools/BUILD.bazel
---- b/go/analysis/passes/bools/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/bools/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/bools/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2595,6 +2600,7 @@
 +go_test(
 +    name = "bools_test",
 +    srcs = ["bools_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":bools",
 +        "//go/analysis/analysistest",
@@ -2602,7 +2608,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/bools/testdata/src/a/BUILD.bazel c/go/analysis/passes/bools/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/bools/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/bools/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/bools/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2620,7 +2626,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/bools/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/bools/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/bools/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/bools/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/bools/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2638,9 +2644,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/buildssa/BUILD.bazel c/go/analysis/passes/buildssa/BUILD.bazel
---- b/go/analysis/passes/buildssa/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildssa/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildssa/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2663,6 +2669,7 @@
 +go_test(
 +    name = "buildssa_test",
 +    srcs = ["buildssa_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":buildssa",
 +        "//go/analysis/analysistest",
@@ -2670,7 +2677,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/buildssa/testdata/src/a/BUILD.bazel c/go/analysis/passes/buildssa/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/buildssa/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildssa/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildssa/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2688,7 +2695,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/buildssa/testdata/src/b/BUILD.bazel c/go/analysis/passes/buildssa/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/buildssa/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildssa/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildssa/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2706,7 +2713,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/buildssa/testdata/src/c/BUILD.bazel c/go/analysis/passes/buildssa/testdata/src/c/BUILD.bazel
---- b/go/analysis/passes/buildssa/testdata/src/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildssa/testdata/src/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildssa/testdata/src/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2724,9 +2731,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/buildtag/BUILD.bazel c/go/analysis/passes/buildtag/BUILD.bazel
---- b/go/analysis/passes/buildtag/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildtag/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildtag/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2752,6 +2759,7 @@
 +go_test(
 +    name = "buildtag_test",
 +    srcs = ["buildtag_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":buildtag",
 +        "//go/analysis",
@@ -2759,7 +2767,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/buildtag/testdata/src/a/BUILD.bazel c/go/analysis/passes/buildtag/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/buildtag/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/buildtag/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/buildtag/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2781,14 +2789,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/cgocall/BUILD.bazel c/go/analysis/passes/cgocall/BUILD.bazel
---- b/go/analysis/passes/cgocall/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/cgocall/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/cgocall/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,33 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "cgocall",
-+    srcs = ["cgocall.go"],
++    srcs = [
++        "cgocall.go",
++        "cgocall_go120.go",
++        "cgocall_go121.go",
++    ],
 +    importpath = "golang.org/x/tools/go/analysis/passes/cgocall",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -2806,6 +2818,7 @@
 +go_test(
 +    name = "cgocall_test",
 +    srcs = ["cgocall_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":cgocall",
 +        "//go/analysis/analysistest",
@@ -2813,7 +2826,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/cgocall/testdata/src/a/BUILD.bazel c/go/analysis/passes/cgocall/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/cgocall/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/cgocall/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/cgocall/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2835,7 +2848,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/cgocall/testdata/src/b/BUILD.bazel c/go/analysis/passes/cgocall/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/cgocall/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/cgocall/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/cgocall/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2853,7 +2866,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/cgocall/testdata/src/c/BUILD.bazel c/go/analysis/passes/cgocall/testdata/src/c/BUILD.bazel
---- b/go/analysis/passes/cgocall/testdata/src/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/cgocall/testdata/src/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/cgocall/testdata/src/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2871,7 +2884,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/cgocall/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/cgocall/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/cgocall/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/cgocall/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/cgocall/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2890,9 +2903,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/composite/BUILD.bazel c/go/analysis/passes/composite/BUILD.bazel
---- b/go/analysis/passes/composite/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/composite/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/composite/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,33 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -2920,6 +2933,7 @@
 +go_test(
 +    name = "composite_test",
 +    srcs = ["composite_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":composite",
 +        "//go/analysis/analysistest",
@@ -2927,7 +2941,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/composite/testdata/src/a/BUILD.bazel c/go/analysis/passes/composite/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/composite/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/composite/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/composite/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -2951,7 +2965,7 @@
 +    embed = [":a"],
 +)
 diff -urN b/go/analysis/passes/composite/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/composite/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/composite/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/composite/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/composite/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2969,7 +2983,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/composite/testdata/src/typeparams/lib/BUILD.bazel c/go/analysis/passes/composite/testdata/src/typeparams/lib/BUILD.bazel
---- b/go/analysis/passes/composite/testdata/src/typeparams/lib/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/composite/testdata/src/typeparams/lib/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/composite/testdata/src/typeparams/lib/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -2987,9 +3001,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/copylock/BUILD.bazel c/go/analysis/passes/copylock/BUILD.bazel
---- b/go/analysis/passes/copylock/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/copylock/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/copylock/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3015,6 +3029,7 @@
 +go_test(
 +    name = "copylock_test",
 +    srcs = ["copylock_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":copylock",
 +        "//go/analysis/analysistest",
@@ -3022,9 +3037,9 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/copylock/testdata/src/a/BUILD.bazel c/go/analysis/passes/copylock/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/copylock/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/copylock/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/copylock/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,19 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
 +
 +go_library(
@@ -3033,6 +3048,7 @@
 +        "copylock.go",
 +        "copylock_func.go",
 +        "copylock_range.go",
++        "issue61678.go",
 +    ],
 +    importpath = "golang.org/x/tools/go/analysis/passes/copylock/testdata/src/a",
 +    visibility = ["//visibility:public"],
@@ -3044,7 +3060,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/copylock/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/copylock/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/copylock/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/copylock/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/copylock/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3062,9 +3078,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ctrlflow/BUILD.bazel c/go/analysis/passes/ctrlflow/BUILD.bazel
---- b/go/analysis/passes/ctrlflow/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ctrlflow/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ctrlflow/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3090,6 +3106,7 @@
 +go_test(
 +    name = "ctrlflow_test",
 +    srcs = ["ctrlflow_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":ctrlflow",
 +        "//go/analysis/analysistest",
@@ -3097,7 +3114,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/ctrlflow/testdata/src/a/BUILD.bazel c/go/analysis/passes/ctrlflow/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/ctrlflow/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ctrlflow/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ctrlflow/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3115,7 +3132,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ctrlflow/testdata/src/lib/BUILD.bazel c/go/analysis/passes/ctrlflow/testdata/src/lib/BUILD.bazel
---- b/go/analysis/passes/ctrlflow/testdata/src/lib/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ctrlflow/testdata/src/lib/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ctrlflow/testdata/src/lib/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3133,7 +3150,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ctrlflow/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/ctrlflow/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/ctrlflow/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ctrlflow/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ctrlflow/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3151,9 +3168,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/deepequalerrors/BUILD.bazel c/go/analysis/passes/deepequalerrors/BUILD.bazel
---- b/go/analysis/passes/deepequalerrors/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/deepequalerrors/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/deepequalerrors/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3164,6 +3181,7 @@
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -3178,6 +3196,7 @@
 +go_test(
 +    name = "deepequalerrors_test",
 +    srcs = ["deepequalerrors_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":deepequalerrors",
 +        "//go/analysis/analysistest",
@@ -3185,7 +3204,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/deepequalerrors/testdata/src/a/BUILD.bazel c/go/analysis/passes/deepequalerrors/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/deepequalerrors/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/deepequalerrors/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/deepequalerrors/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3203,7 +3222,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/deepequalerrors/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/deepequalerrors/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/deepequalerrors/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/deepequalerrors/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/deepequalerrors/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3220,10 +3239,89 @@
 +    actual = ":typeparams",
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/analysis/passes/defers/BUILD.bazel c/go/analysis/passes/defers/BUILD.bazel
+--- b/go/analysis/passes/defers/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/defers/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,35 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "defers",
++    srcs = [
++        "defers.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/defers",
++    visibility = ["//visibility:public"],
++    deps = [
++        "//go/analysis",
++        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
++        "//go/ast/inspector",
++        "//go/types/typeutil",
++    ],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":defers",
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "defers_test",
++    srcs = ["defers_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    deps = [
++        ":defers",
++        "//go/analysis/analysistest",
++    ],
++)
+diff -urN b/go/analysis/passes/defers/cmd/defers/BUILD.bazel c/go/analysis/passes/defers/cmd/defers/BUILD.bazel
+--- b/go/analysis/passes/defers/cmd/defers/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/defers/cmd/defers/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,18 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
++
++go_library(
++    name = "defers_lib",
++    srcs = ["main.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/defers/cmd/defers",
++    visibility = ["//visibility:private"],
++    deps = [
++        "//go/analysis/passes/defers",
++        "//go/analysis/singlechecker",
++    ],
++)
++
++go_binary(
++    name = "defers",
++    embed = [":defers_lib"],
++    visibility = ["//visibility:public"],
++)
+diff -urN b/go/analysis/passes/defers/testdata/src/a/BUILD.bazel c/go/analysis/passes/defers/testdata/src/a/BUILD.bazel
+--- b/go/analysis/passes/defers/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/defers/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "a",
++    srcs = ["a.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/defers/testdata/src/a",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":a",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/analysis/passes/directive/BUILD.bazel c/go/analysis/passes/directive/BUILD.bazel
---- b/go/analysis/passes/directive/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/directive/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/directive/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3246,6 +3344,7 @@
 +go_test(
 +    name = "directive_test",
 +    srcs = ["directive_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":directive",
 +        "//go/analysis",
@@ -3253,7 +3352,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/directive/testdata/src/a/BUILD.bazel c/go/analysis/passes/directive/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/directive/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/directive/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/directive/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -3279,9 +3378,9 @@
 +    srcs = ["misplaced_test.go"],
 +)
 diff -urN b/go/analysis/passes/errorsas/BUILD.bazel c/go/analysis/passes/errorsas/BUILD.bazel
---- b/go/analysis/passes/errorsas/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/errorsas/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/errorsas/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3292,6 +3391,7 @@
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -3313,7 +3413,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/errorsas/testdata/src/a/BUILD.bazel c/go/analysis/passes/errorsas/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/errorsas/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/errorsas/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/errorsas/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3331,7 +3431,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/errorsas/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/errorsas/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/errorsas/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/errorsas/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/errorsas/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3349,9 +3449,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/fieldalignment/BUILD.bazel c/go/analysis/passes/fieldalignment/BUILD.bazel
---- b/go/analysis/passes/fieldalignment/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/fieldalignment/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/fieldalignment/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3375,13 +3475,14 @@
 +go_test(
 +    name = "fieldalignment_test",
 +    srcs = ["fieldalignment_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":fieldalignment",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/fieldalignment/cmd/fieldalignment/BUILD.bazel c/go/analysis/passes/fieldalignment/cmd/fieldalignment/BUILD.bazel
---- b/go/analysis/passes/fieldalignment/cmd/fieldalignment/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/fieldalignment/cmd/fieldalignment/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/fieldalignment/cmd/fieldalignment/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3403,7 +3504,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/fieldalignment/testdata/src/a/BUILD.bazel c/go/analysis/passes/fieldalignment/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/fieldalignment/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/fieldalignment/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/fieldalignment/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3425,9 +3526,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/findcall/BUILD.bazel c/go/analysis/passes/findcall/BUILD.bazel
---- b/go/analysis/passes/findcall/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/findcall/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/findcall/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,24 @@
+@@ -0,0 +1,25 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3447,13 +3548,14 @@
 +go_test(
 +    name = "findcall_test",
 +    srcs = ["findcall_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":findcall",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/findcall/cmd/findcall/BUILD.bazel c/go/analysis/passes/findcall/cmd/findcall/BUILD.bazel
---- b/go/analysis/passes/findcall/cmd/findcall/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/findcall/cmd/findcall/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/findcall/cmd/findcall/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3475,7 +3577,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/findcall/testdata/src/a/BUILD.bazel c/go/analysis/passes/findcall/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/findcall/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/findcall/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/findcall/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3493,9 +3595,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/framepointer/BUILD.bazel c/go/analysis/passes/framepointer/BUILD.bazel
---- b/go/analysis/passes/framepointer/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/framepointer/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/framepointer/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,27 @@
+@@ -0,0 +1,28 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3518,13 +3620,14 @@
 +go_test(
 +    name = "framepointer_test",
 +    srcs = ["framepointer_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":framepointer",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/framepointer/testdata/src/a/BUILD.bazel c/go/analysis/passes/framepointer/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/framepointer/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/framepointer/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/framepointer/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3548,9 +3651,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/httpresponse/BUILD.bazel c/go/analysis/passes/httpresponse/BUILD.bazel
---- b/go/analysis/passes/httpresponse/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/httpresponse/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/httpresponse/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -3575,6 +3678,7 @@
 +go_test(
 +    name = "httpresponse_test",
 +    srcs = ["httpresponse_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":httpresponse",
 +        "//go/analysis/analysistest",
@@ -3582,7 +3686,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/httpresponse/testdata/src/a/BUILD.bazel c/go/analysis/passes/httpresponse/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/httpresponse/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/httpresponse/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/httpresponse/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3600,7 +3704,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/httpresponse/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/httpresponse/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/httpresponse/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/httpresponse/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/httpresponse/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3618,22 +3722,25 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ifaceassert/BUILD.bazel c/go/analysis/passes/ifaceassert/BUILD.bazel
---- b/go/analysis/passes/ifaceassert/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ifaceassert/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ifaceassert/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,33 @@
+@@ -0,0 +1,37 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "ifaceassert",
 +    srcs = [
++        "doc.go",
 +        "ifaceassert.go",
 +        "parameterized.go",
 +    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/ifaceassert",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//internal/typeparams",
 +    ],
@@ -3648,6 +3755,7 @@
 +go_test(
 +    name = "ifaceassert_test",
 +    srcs = ["ifaceassert_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":ifaceassert",
 +        "//go/analysis/analysistest",
@@ -3655,7 +3763,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/ifaceassert/cmd/ifaceassert/BUILD.bazel c/go/analysis/passes/ifaceassert/cmd/ifaceassert/BUILD.bazel
---- b/go/analysis/passes/ifaceassert/cmd/ifaceassert/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ifaceassert/cmd/ifaceassert/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ifaceassert/cmd/ifaceassert/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3677,7 +3785,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ifaceassert/testdata/src/a/BUILD.bazel c/go/analysis/passes/ifaceassert/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/ifaceassert/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ifaceassert/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ifaceassert/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3695,7 +3803,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/ifaceassert/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/ifaceassert/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/ifaceassert/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/ifaceassert/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/ifaceassert/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3713,7 +3821,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/inspect/BUILD.bazel c/go/analysis/passes/inspect/BUILD.bazel
---- b/go/analysis/passes/inspect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/inspect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/inspect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3735,14 +3843,17 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/internal/analysisutil/BUILD.bazel c/go/analysis/passes/internal/analysisutil/BUILD.bazel
---- b/go/analysis/passes/internal/analysisutil/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/internal/analysisutil/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/internal/analysisutil/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,23 @@
+@@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "analysisutil",
-+    srcs = ["util.go"],
++    srcs = [
++        "extractdoc.go",
++        "util.go",
++    ],
 +    importpath = "golang.org/x/tools/go/analysis/passes/internal/analysisutil",
 +    visibility = ["//go/analysis/passes:__subpackages__"],
 +)
@@ -3755,26 +3866,34 @@
 +
 +go_test(
 +    name = "analysisutil_test",
-+    srcs = ["util_test.go"],
++    srcs = [
++        "extractdoc_test.go",
++        "util_test.go",
++    ],
 +    deps = [
 +        ":analysisutil",
 +        "//internal/typeparams",
 +    ],
 +)
 diff -urN b/go/analysis/passes/loopclosure/BUILD.bazel c/go/analysis/passes/loopclosure/BUILD.bazel
---- b/go/analysis/passes/loopclosure/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/loopclosure/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/loopclosure/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "loopclosure",
-+    srcs = ["loopclosure.go"],
++    srcs = [
++        "doc.go",
++        "loopclosure.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/loopclosure",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -3789,6 +3908,7 @@
 +go_test(
 +    name = "loopclosure_test",
 +    srcs = ["loopclosure_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":loopclosure",
 +        "//go/analysis/analysistest",
@@ -3796,7 +3916,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/loopclosure/testdata/src/a/BUILD.bazel c/go/analysis/passes/loopclosure/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/loopclosure/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/loopclosure/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/loopclosure/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3818,7 +3938,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/loopclosure/testdata/src/golang.org/x/sync/errgroup/BUILD.bazel c/go/analysis/passes/loopclosure/testdata/src/golang.org/x/sync/errgroup/BUILD.bazel
---- b/go/analysis/passes/loopclosure/testdata/src/golang.org/x/sync/errgroup/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/loopclosure/testdata/src/golang.org/x/sync/errgroup/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/loopclosure/testdata/src/golang.org/x/sync/errgroup/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3836,7 +3956,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/loopclosure/testdata/src/subtests/BUILD.bazel c/go/analysis/passes/loopclosure/testdata/src/subtests/BUILD.bazel
---- b/go/analysis/passes/loopclosure/testdata/src/subtests/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/loopclosure/testdata/src/subtests/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/loopclosure/testdata/src/subtests/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3854,7 +3974,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/loopclosure/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/loopclosure/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/loopclosure/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/loopclosure/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/loopclosure/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3873,20 +3993,25 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/lostcancel/BUILD.bazel c/go/analysis/passes/lostcancel/BUILD.bazel
---- b/go/analysis/passes/lostcancel/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/lostcancel/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/lostcancel/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,37 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "lostcancel",
-+    srcs = ["lostcancel.go"],
++    srcs = [
++        "doc.go",
++        "lostcancel.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/lostcancel",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/ctrlflow",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/cfg",
 +    ],
@@ -3901,6 +4026,7 @@
 +go_test(
 +    name = "lostcancel_test",
 +    srcs = ["lostcancel_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":lostcancel",
 +        "//go/analysis/analysistest",
@@ -3908,7 +4034,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/lostcancel/cmd/lostcancel/BUILD.bazel c/go/analysis/passes/lostcancel/cmd/lostcancel/BUILD.bazel
---- b/go/analysis/passes/lostcancel/cmd/lostcancel/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/lostcancel/cmd/lostcancel/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/lostcancel/cmd/lostcancel/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3930,7 +4056,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/lostcancel/testdata/src/a/BUILD.bazel c/go/analysis/passes/lostcancel/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/lostcancel/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/lostcancel/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/lostcancel/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3948,7 +4074,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/lostcancel/testdata/src/b/BUILD.bazel c/go/analysis/passes/lostcancel/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/lostcancel/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/lostcancel/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/lostcancel/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -3966,7 +4092,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/lostcancel/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/lostcancel/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/lostcancel/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/lostcancel/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/lostcancel/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -3984,19 +4110,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilfunc/BUILD.bazel c/go/analysis/passes/nilfunc/BUILD.bazel
---- b/go/analysis/passes/nilfunc/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilfunc/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilfunc/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "nilfunc",
-+    srcs = ["nilfunc.go"],
++    srcs = [
++        "doc.go",
++        "nilfunc.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/nilfunc",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//internal/typeparams",
 +    ],
@@ -4018,7 +4149,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/nilfunc/testdata/src/a/BUILD.bazel c/go/analysis/passes/nilfunc/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/nilfunc/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilfunc/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilfunc/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4036,7 +4167,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilfunc/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/nilfunc/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/nilfunc/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilfunc/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilfunc/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4054,19 +4185,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilness/BUILD.bazel c/go/analysis/passes/nilness/BUILD.bazel
---- b/go/analysis/passes/nilness/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,33 @@
+@@ -0,0 +1,38 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "nilness",
-+    srcs = ["nilness.go"],
++    srcs = [
++        "doc.go",
++        "nilness.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/nilness",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/buildssa",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ssa",
 +        "//internal/typeparams",
 +    ],
@@ -4091,7 +4227,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/nilness/cmd/nilness/BUILD.bazel c/go/analysis/passes/nilness/cmd/nilness/BUILD.bazel
---- b/go/analysis/passes/nilness/cmd/nilness/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/cmd/nilness/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/cmd/nilness/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -4113,7 +4249,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilness/testdata/src/a/BUILD.bazel c/go/analysis/passes/nilness/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/nilness/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4131,7 +4267,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilness/testdata/src/b/BUILD.bazel c/go/analysis/passes/nilness/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/nilness/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4149,7 +4285,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilness/testdata/src/c/BUILD.bazel c/go/analysis/passes/nilness/testdata/src/c/BUILD.bazel
---- b/go/analysis/passes/nilness/testdata/src/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/testdata/src/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/testdata/src/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4167,7 +4303,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/nilness/testdata/src/d/BUILD.bazel c/go/analysis/passes/nilness/testdata/src/d/BUILD.bazel
---- b/go/analysis/passes/nilness/testdata/src/d/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/nilness/testdata/src/d/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/nilness/testdata/src/d/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4185,7 +4321,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/pkgfact/BUILD.bazel c/go/analysis/passes/pkgfact/BUILD.bazel
---- b/go/analysis/passes/pkgfact/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/pkgfact/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/pkgfact/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -4213,7 +4349,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/pkgfact/testdata/src/a/BUILD.bazel c/go/analysis/passes/pkgfact/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/pkgfact/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/pkgfact/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/pkgfact/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4231,7 +4367,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/pkgfact/testdata/src/b/BUILD.bazel c/go/analysis/passes/pkgfact/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/pkgfact/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/pkgfact/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/pkgfact/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4249,7 +4385,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/pkgfact/testdata/src/c/BUILD.bazel c/go/analysis/passes/pkgfact/testdata/src/c/BUILD.bazel
---- b/go/analysis/passes/pkgfact/testdata/src/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/pkgfact/testdata/src/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/pkgfact/testdata/src/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4267,17 +4403,19 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/printf/BUILD.bazel c/go/analysis/passes/printf/BUILD.bazel
---- b/go/analysis/passes/printf/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/printf/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/printf/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,38 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "printf",
 +    srcs = [
++        "doc.go",
 +        "printf.go",
 +        "types.go",
 +    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/printf",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -4302,11 +4440,12 @@
 +    deps = [
 +        ":printf",
 +        "//go/analysis/analysistest",
++        "//internal/testenv",
 +        "//internal/typeparams",
 +    ],
 +)
 diff -urN b/go/analysis/passes/printf/testdata/src/a/BUILD.bazel c/go/analysis/passes/printf/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/printf/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/printf/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/printf/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4324,7 +4463,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/printf/testdata/src/b/BUILD.bazel c/go/analysis/passes/printf/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/printf/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/printf/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/printf/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4342,7 +4481,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/printf/testdata/src/nofmt/BUILD.bazel c/go/analysis/passes/printf/testdata/src/nofmt/BUILD.bazel
---- b/go/analysis/passes/printf/testdata/src/nofmt/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/printf/testdata/src/nofmt/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/printf/testdata/src/nofmt/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4360,7 +4499,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/printf/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/printf/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/printf/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/printf/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/printf/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4381,19 +4520,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/reflectvaluecompare/BUILD.bazel c/go/analysis/passes/reflectvaluecompare/BUILD.bazel
---- b/go/analysis/passes/reflectvaluecompare/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/reflectvaluecompare/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/reflectvaluecompare/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "reflectvaluecompare",
-+    srcs = ["reflectvaluecompare.go"],
++    srcs = [
++        "doc.go",
++        "reflectvaluecompare.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/reflectvaluecompare",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -4414,7 +4558,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/reflectvaluecompare/testdata/src/a/BUILD.bazel c/go/analysis/passes/reflectvaluecompare/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/reflectvaluecompare/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/reflectvaluecompare/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/reflectvaluecompare/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4432,19 +4576,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/shadow/BUILD.bazel c/go/analysis/passes/shadow/BUILD.bazel
---- b/go/analysis/passes/shadow/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shadow/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shadow/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,33 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "shadow",
-+    srcs = ["shadow.go"],
++    srcs = [
++        "doc.go",
++        "shadow.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/shadow",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +    ],
 +)
@@ -4464,7 +4613,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/shadow/cmd/shadow/BUILD.bazel c/go/analysis/passes/shadow/cmd/shadow/BUILD.bazel
---- b/go/analysis/passes/shadow/cmd/shadow/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shadow/cmd/shadow/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shadow/cmd/shadow/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -4486,7 +4635,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/shadow/testdata/src/a/BUILD.bazel c/go/analysis/passes/shadow/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/shadow/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shadow/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shadow/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4504,7 +4653,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/shift/BUILD.bazel c/go/analysis/passes/shift/BUILD.bazel
---- b/go/analysis/passes/shift/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shift/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shift/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -4542,7 +4691,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/shift/testdata/src/a/BUILD.bazel c/go/analysis/passes/shift/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/shift/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shift/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shift/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4560,7 +4709,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/shift/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/shift/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/shift/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/shift/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/shift/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4578,19 +4727,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/sigchanyzer/BUILD.bazel c/go/analysis/passes/sigchanyzer/BUILD.bazel
---- b/go/analysis/passes/sigchanyzer/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/sigchanyzer/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/sigchanyzer/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,33 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "sigchanyzer",
-+    srcs = ["sigchanyzer.go"],
++    srcs = [
++        "doc.go",
++        "sigchanyzer.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/sigchanyzer",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +    ],
 +)
@@ -4610,7 +4764,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/sigchanyzer/testdata/src/a/BUILD.bazel c/go/analysis/passes/sigchanyzer/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/sigchanyzer/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/sigchanyzer/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/sigchanyzer/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4627,10 +4781,85 @@
 +    actual = ":a",
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/analysis/passes/slog/BUILD.bazel c/go/analysis/passes/slog/BUILD.bazel
+--- b/go/analysis/passes/slog/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/slog/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,35 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "slog",
++    srcs = [
++        "doc.go",
++        "slog.go",
++    ],
++    embedsrcs = ["doc.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/slog",
++    visibility = ["//visibility:public"],
++    deps = [
++        "//go/analysis",
++        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
++        "//go/ast/inspector",
++        "//go/types/typeutil",
++    ],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":slog",
++    visibility = ["//visibility:public"],
++)
++
++go_test(
++    name = "slog_test",
++    srcs = ["slog_test.go"],
++    embed = [":slog"],
++    deps = [
++        "//go/analysis/analysistest",
++        "//internal/testenv",
++    ],
++)
+diff -urN b/go/analysis/passes/slog/testdata/src/a/BUILD.bazel c/go/analysis/passes/slog/testdata/src/a/BUILD.bazel
+--- b/go/analysis/passes/slog/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/slog/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "a",
++    srcs = ["a.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/slog/testdata/src/a",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":a",
++    visibility = ["//visibility:public"],
++)
+diff -urN b/go/analysis/passes/slog/testdata/src/b/BUILD.bazel c/go/analysis/passes/slog/testdata/src/b/BUILD.bazel
+--- b/go/analysis/passes/slog/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/slog/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "b",
++    srcs = ["b.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/slog/testdata/src/b",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":b",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/analysis/passes/sortslice/BUILD.bazel c/go/analysis/passes/sortslice/BUILD.bazel
---- b/go/analysis/passes/sortslice/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/sortslice/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/sortslice/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,30 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -4641,6 +4870,7 @@
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -4661,7 +4891,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/sortslice/testdata/src/a/BUILD.bazel c/go/analysis/passes/sortslice/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/sortslice/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/sortslice/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/sortslice/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4679,19 +4909,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/stdmethods/BUILD.bazel c/go/analysis/passes/stdmethods/BUILD.bazel
---- b/go/analysis/passes/stdmethods/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stdmethods/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stdmethods/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "stdmethods",
-+    srcs = ["stdmethods.go"],
++    srcs = [
++        "doc.go",
++        "stdmethods.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/stdmethods",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +    ],
 +)
@@ -4705,6 +4940,7 @@
 +go_test(
 +    name = "stdmethods_test",
 +    srcs = ["stdmethods_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":stdmethods",
 +        "//go/analysis/analysistest",
@@ -4712,7 +4948,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/stdmethods/testdata/src/a/BUILD.bazel c/go/analysis/passes/stdmethods/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/stdmethods/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stdmethods/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stdmethods/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4733,7 +4969,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/stdmethods/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/stdmethods/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/stdmethods/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stdmethods/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stdmethods/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4751,19 +4987,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/stringintconv/BUILD.bazel c/go/analysis/passes/stringintconv/BUILD.bazel
---- b/go/analysis/passes/stringintconv/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stringintconv/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stringintconv/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "stringintconv",
-+    srcs = ["string.go"],
++    srcs = [
++        "doc.go",
++        "string.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/stringintconv",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//internal/typeparams",
 +    ],
@@ -4778,6 +5019,7 @@
 +go_test(
 +    name = "stringintconv_test",
 +    srcs = ["string_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":stringintconv",
 +        "//go/analysis/analysistest",
@@ -4785,7 +5027,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/stringintconv/cmd/stringintconv/BUILD.bazel c/go/analysis/passes/stringintconv/cmd/stringintconv/BUILD.bazel
---- b/go/analysis/passes/stringintconv/cmd/stringintconv/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stringintconv/cmd/stringintconv/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stringintconv/cmd/stringintconv/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -4807,7 +5049,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/stringintconv/testdata/src/a/BUILD.bazel c/go/analysis/passes/stringintconv/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/stringintconv/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stringintconv/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stringintconv/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4825,7 +5067,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/stringintconv/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/stringintconv/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/stringintconv/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/stringintconv/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/stringintconv/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4843,9 +5085,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/structtag/BUILD.bazel c/go/analysis/passes/structtag/BUILD.bazel
---- b/go/analysis/passes/structtag/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/structtag/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/structtag/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -4869,31 +5111,14 @@
 +go_test(
 +    name = "structtag_test",
 +    srcs = ["structtag_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":structtag",
 +        "//go/analysis/analysistest",
 +    ],
 +)
-diff -urN b/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel c/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel
---- b/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
-+
-+go_library(
-+    name = "b",
-+    srcs = ["b.go"],
-+    importpath = "golang.org/x/tools/go/analysis/passes/structtag/testdata/src/a/b",
-+    visibility = ["//visibility:public"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":b",
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/go/analysis/passes/structtag/testdata/src/a/BUILD.bazel c/go/analysis/passes/structtag/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/structtag/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/structtag/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/structtag/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4910,15 +5135,37 @@
 +    actual = ":a",
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel c/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel
+--- b/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/structtag/testdata/src/a/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "b",
++    srcs = ["b.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/structtag/testdata/src/a/b",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":b",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/analysis/passes/testinggoroutine/BUILD.bazel c/go/analysis/passes/testinggoroutine/BUILD.bazel
---- b/go/analysis/passes/testinggoroutine/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/testinggoroutine/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/testinggoroutine/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "testinggoroutine",
-+    srcs = ["testinggoroutine.go"],
++    srcs = [
++        "doc.go",
++        "testinggoroutine.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/testinggoroutine",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -4939,6 +5186,7 @@
 +go_test(
 +    name = "testinggoroutine_test",
 +    srcs = ["testinggoroutine_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":testinggoroutine",
 +        "//go/analysis/analysistest",
@@ -4946,7 +5194,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/testinggoroutine/testdata/src/a/BUILD.bazel c/go/analysis/passes/testinggoroutine/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/testinggoroutine/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/testinggoroutine/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/testinggoroutine/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4967,7 +5215,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/testinggoroutine/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/testinggoroutine/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/testinggoroutine/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/testinggoroutine/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/testinggoroutine/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -4985,19 +5233,23 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/tests/BUILD.bazel c/go/analysis/passes/tests/BUILD.bazel
---- b/go/analysis/passes/tests/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "tests",
-+    srcs = ["tests.go"],
++    srcs = [
++        "doc.go",
++        "tests.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/tests",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
-+        "//internal/analysisinternal",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//internal/typeparams",
 +    ],
 +)
@@ -5011,15 +5263,15 @@
 +go_test(
 +    name = "tests_test",
 +    srcs = ["tests_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":tests",
 +        "//go/analysis/analysistest",
-+        "//internal/analysisinternal",
 +        "//internal/typeparams",
 +    ],
 +)
 diff -urN b/go/analysis/passes/tests/testdata/src/a/BUILD.bazel c/go/analysis/passes/tests/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/tests/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5047,7 +5299,7 @@
 +    embed = [":a"],
 +)
 diff -urN b/go/analysis/passes/tests/testdata/src/b/BUILD.bazel c/go/analysis/passes/tests/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/tests/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5065,7 +5317,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/tests/testdata/src/b_x_test/BUILD.bazel c/go/analysis/passes/tests/testdata/src/b_x_test/BUILD.bazel
---- b/go/analysis/passes/tests/testdata/src/b_x_test/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/testdata/src/b_x_test/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/testdata/src/b_x_test/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,6 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_test")
@@ -5075,7 +5327,7 @@
 +    srcs = ["b_test.go"],
 +)
 diff -urN b/go/analysis/passes/tests/testdata/src/divergent/BUILD.bazel c/go/analysis/passes/tests/testdata/src/divergent/BUILD.bazel
---- b/go/analysis/passes/tests/testdata/src/divergent/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/testdata/src/divergent/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/testdata/src/divergent/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5099,7 +5351,7 @@
 +    embed = [":divergent"],
 +)
 diff -urN b/go/analysis/passes/tests/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/tests/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/tests/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/tests/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/tests/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5123,19 +5375,24 @@
 +    embed = [":typeparams"],
 +)
 diff -urN b/go/analysis/passes/timeformat/BUILD.bazel c/go/analysis/passes/timeformat/BUILD.bazel
---- b/go/analysis/passes/timeformat/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/timeformat/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/timeformat/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "timeformat",
-+    srcs = ["timeformat.go"],
++    srcs = [
++        "doc.go",
++        "timeformat.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/timeformat",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +    ],
@@ -5150,13 +5407,14 @@
 +go_test(
 +    name = "timeformat_test",
 +    srcs = ["timeformat_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":timeformat",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/timeformat/testdata/src/a/BUILD.bazel c/go/analysis/passes/timeformat/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/timeformat/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/timeformat/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/timeformat/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5174,7 +5432,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/timeformat/testdata/src/b/BUILD.bazel c/go/analysis/passes/timeformat/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/timeformat/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/timeformat/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/timeformat/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5192,19 +5450,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unmarshal/BUILD.bazel c/go/analysis/passes/unmarshal/BUILD.bazel
---- b/go/analysis/passes/unmarshal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unmarshal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unmarshal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,37 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unmarshal",
-+    srcs = ["unmarshal.go"],
++    srcs = [
++        "doc.go",
++        "unmarshal.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/unmarshal",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//go/types/typeutil",
 +        "//internal/typeparams",
@@ -5220,6 +5483,7 @@
 +go_test(
 +    name = "unmarshal_test",
 +    srcs = ["unmarshal_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":unmarshal",
 +        "//go/analysis/analysistest",
@@ -5227,7 +5491,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/unmarshal/cmd/unmarshal/BUILD.bazel c/go/analysis/passes/unmarshal/cmd/unmarshal/BUILD.bazel
---- b/go/analysis/passes/unmarshal/cmd/unmarshal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unmarshal/cmd/unmarshal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unmarshal/cmd/unmarshal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -5249,7 +5513,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unmarshal/testdata/src/a/BUILD.bazel c/go/analysis/passes/unmarshal/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/unmarshal/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unmarshal/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unmarshal/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5267,7 +5531,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unmarshal/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/unmarshal/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/unmarshal/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unmarshal/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unmarshal/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5285,19 +5549,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unreachable/BUILD.bazel c/go/analysis/passes/unreachable/BUILD.bazel
---- b/go/analysis/passes/unreachable/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unreachable/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unreachable/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unreachable",
-+    srcs = ["unreachable.go"],
++    srcs = [
++        "doc.go",
++        "unreachable.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/unreachable",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +    ],
 +)
@@ -5311,13 +5580,14 @@
 +go_test(
 +    name = "unreachable_test",
 +    srcs = ["unreachable_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":unreachable",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/unreachable/testdata/src/a/BUILD.bazel c/go/analysis/passes/unreachable/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/unreachable/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unreachable/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unreachable/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5335,14 +5605,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unsafeptr/BUILD.bazel c/go/analysis/passes/unsafeptr/BUILD.bazel
---- b/go/analysis/passes/unsafeptr/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unsafeptr/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unsafeptr/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unsafeptr",
-+    srcs = ["unsafeptr.go"],
++    srcs = [
++        "doc.go",
++        "unsafeptr.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/unsafeptr",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -5362,6 +5636,7 @@
 +go_test(
 +    name = "unsafeptr_test",
 +    srcs = ["unsafeptr_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":unsafeptr",
 +        "//go/analysis/analysistest",
@@ -5369,7 +5644,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/unsafeptr/testdata/src/a/BUILD.bazel c/go/analysis/passes/unsafeptr/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/unsafeptr/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unsafeptr/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unsafeptr/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5390,7 +5665,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unsafeptr/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/unsafeptr/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/unsafeptr/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unsafeptr/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unsafeptr/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5408,14 +5683,18 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unusedresult/BUILD.bazel c/go/analysis/passes/unusedresult/BUILD.bazel
---- b/go/analysis/passes/unusedresult/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedresult/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedresult/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,31 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unusedresult",
-+    srcs = ["unusedresult.go"],
++    srcs = [
++        "doc.go",
++        "unusedresult.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/unusedresult",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -5423,7 +5702,7 @@
 +        "//go/analysis/passes/inspect",
 +        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
-+        "//internal/typeparams",
++        "//go/types/typeutil",
 +    ],
 +)
 +
@@ -5436,14 +5715,37 @@
 +go_test(
 +    name = "unusedresult_test",
 +    srcs = ["unusedresult_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":unusedresult",
 +        "//go/analysis/analysistest",
 +        "//internal/typeparams",
 +    ],
 +)
+diff -urN b/go/analysis/passes/unusedresult/cmd/unusedresult/BUILD.bazel c/go/analysis/passes/unusedresult/cmd/unusedresult/BUILD.bazel
+--- b/go/analysis/passes/unusedresult/cmd/unusedresult/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/analysis/passes/unusedresult/cmd/unusedresult/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,18 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
++
++go_library(
++    name = "unusedresult_lib",
++    srcs = ["main.go"],
++    importpath = "golang.org/x/tools/go/analysis/passes/unusedresult/cmd/unusedresult",
++    visibility = ["//visibility:private"],
++    deps = [
++        "//go/analysis/passes/unusedresult",
++        "//go/analysis/singlechecker",
++    ],
++)
++
++go_binary(
++    name = "unusedresult",
++    embed = [":unusedresult_lib"],
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/analysis/passes/unusedresult/testdata/src/a/BUILD.bazel c/go/analysis/passes/unusedresult/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/unusedresult/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedresult/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedresult/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5461,7 +5763,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unusedresult/testdata/src/typeparams/BUILD.bazel c/go/analysis/passes/unusedresult/testdata/src/typeparams/BUILD.bazel
---- b/go/analysis/passes/unusedresult/testdata/src/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedresult/testdata/src/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedresult/testdata/src/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5479,7 +5781,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unusedresult/testdata/src/typeparams/userdefs/BUILD.bazel c/go/analysis/passes/unusedresult/testdata/src/typeparams/userdefs/BUILD.bazel
---- b/go/analysis/passes/unusedresult/testdata/src/typeparams/userdefs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedresult/testdata/src/typeparams/userdefs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedresult/testdata/src/typeparams/userdefs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5497,19 +5799,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/unusedwrite/BUILD.bazel c/go/analysis/passes/unusedwrite/BUILD.bazel
---- b/go/analysis/passes/unusedwrite/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedwrite/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedwrite/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unusedwrite",
-+    srcs = ["unusedwrite.go"],
++    srcs = [
++        "doc.go",
++        "unusedwrite.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/unusedwrite",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/buildssa",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ssa",
 +    ],
 +)
@@ -5523,13 +5830,14 @@
 +go_test(
 +    name = "unusedwrite_test",
 +    srcs = ["unusedwrite_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":unusedwrite",
 +        "//go/analysis/analysistest",
 +    ],
 +)
 diff -urN b/go/analysis/passes/unusedwrite/testdata/src/a/BUILD.bazel c/go/analysis/passes/unusedwrite/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/unusedwrite/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/unusedwrite/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/unusedwrite/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5547,19 +5855,24 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/usesgenerics/BUILD.bazel c/go/analysis/passes/usesgenerics/BUILD.bazel
---- b/go/analysis/passes/usesgenerics/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/usesgenerics/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/usesgenerics/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,30 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "usesgenerics",
-+    srcs = ["usesgenerics.go"],
++    srcs = [
++        "doc.go",
++        "usesgenerics.go",
++    ],
++    embedsrcs = ["doc.go"],
 +    importpath = "golang.org/x/tools/go/analysis/passes/usesgenerics",
 +    visibility = ["//visibility:public"],
 +    deps = [
 +        "//go/analysis",
 +        "//go/analysis/passes/inspect",
++        "//go/analysis/passes/internal/analysisutil",
 +        "//go/ast/inspector",
 +        "//internal/typeparams/genericfeatures",
 +    ],
@@ -5574,6 +5887,7 @@
 +go_test(
 +    name = "usesgenerics_test",
 +    srcs = ["usesgenerics_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":usesgenerics",
 +        "//go/analysis/analysistest",
@@ -5581,7 +5895,7 @@
 +    ],
 +)
 diff -urN b/go/analysis/passes/usesgenerics/testdata/src/a/BUILD.bazel c/go/analysis/passes/usesgenerics/testdata/src/a/BUILD.bazel
---- b/go/analysis/passes/usesgenerics/testdata/src/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/usesgenerics/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/usesgenerics/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5599,7 +5913,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/usesgenerics/testdata/src/b/BUILD.bazel c/go/analysis/passes/usesgenerics/testdata/src/b/BUILD.bazel
---- b/go/analysis/passes/usesgenerics/testdata/src/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/usesgenerics/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/usesgenerics/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5617,7 +5931,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/usesgenerics/testdata/src/c/BUILD.bazel c/go/analysis/passes/usesgenerics/testdata/src/c/BUILD.bazel
---- b/go/analysis/passes/usesgenerics/testdata/src/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/usesgenerics/testdata/src/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/usesgenerics/testdata/src/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5635,7 +5949,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/passes/usesgenerics/testdata/src/d/BUILD.bazel c/go/analysis/passes/usesgenerics/testdata/src/d/BUILD.bazel
---- b/go/analysis/passes/usesgenerics/testdata/src/d/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/passes/usesgenerics/testdata/src/d/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/passes/usesgenerics/testdata/src/d/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5653,7 +5967,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/singlechecker/BUILD.bazel c/go/analysis/singlechecker/BUILD.bazel
---- b/go/analysis/singlechecker/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/singlechecker/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/singlechecker/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -5677,17 +5991,14 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/analysis/unitchecker/BUILD.bazel c/go/analysis/unitchecker/BUILD.bazel
---- b/go/analysis/unitchecker/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/analysis/unitchecker/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/analysis/unitchecker/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,69 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "unitchecker",
-+    srcs = [
-+        "unitchecker.go",
-+        "unitchecker112.go",
-+    ],
++    srcs = ["unitchecker.go"],
 +    importpath = "golang.org/x/tools/go/analysis/unitchecker",
 +    visibility = ["//visibility:public"],
 +    deps = [
@@ -5706,17 +6017,54 @@
 +
 +go_test(
 +    name = "unitchecker_test",
-+    srcs = ["unitchecker_test.go"],
++    srcs = [
++        "export_test.go",
++        "separate_test.go",
++        "unitchecker_test.go",
++        "vet_std_test.go",
++    ],
++    embed = [":unitchecker"],
 +    deps = [
-+        ":unitchecker",
++        "//go/analysis/passes/appends",
++        "//go/analysis/passes/asmdecl",
 +        "//go/analysis/passes/assign",
++        "//go/analysis/passes/atomic",
++        "//go/analysis/passes/bools",
++        "//go/analysis/passes/buildtag",
++        "//go/analysis/passes/cgocall",
++        "//go/analysis/passes/composite",
++        "//go/analysis/passes/copylock",
++        "//go/analysis/passes/defers",
++        "//go/analysis/passes/directive",
++        "//go/analysis/passes/errorsas",
 +        "//go/analysis/passes/findcall",
++        "//go/analysis/passes/framepointer",
++        "//go/analysis/passes/httpresponse",
++        "//go/analysis/passes/ifaceassert",
++        "//go/analysis/passes/loopclosure",
++        "//go/analysis/passes/lostcancel",
++        "//go/analysis/passes/nilfunc",
 +        "//go/analysis/passes/printf",
++        "//go/analysis/passes/shift",
++        "//go/analysis/passes/sigchanyzer",
++        "//go/analysis/passes/stdmethods",
++        "//go/analysis/passes/stringintconv",
++        "//go/analysis/passes/structtag",
++        "//go/analysis/passes/testinggoroutine",
++        "//go/analysis/passes/tests",
++        "//go/analysis/passes/timeformat",
++        "//go/analysis/passes/unmarshal",
++        "//go/analysis/passes/unreachable",
++        "//go/analysis/passes/unusedresult",
++        "//go/gcexportdata",
++        "//go/packages",
 +        "//go/packages/packagestest",
++        "//internal/testenv",
++        "//txtar",
 +    ],
 +)
 diff -urN b/go/ast/astutil/BUILD.bazel c/go/ast/astutil/BUILD.bazel
---- b/go/ast/astutil/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ast/astutil/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ast/astutil/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,31 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5751,7 +6099,7 @@
 +    deps = ["//internal/typeparams"],
 +)
 diff -urN b/go/ast/inspector/BUILD.bazel c/go/ast/inspector/BUILD.bazel
---- b/go/ast/inspector/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ast/inspector/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ast/inspector/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,27 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5782,7 +6130,7 @@
 +    ],
 +)
 diff -urN b/go/buildutil/BUILD.bazel c/go/buildutil/BUILD.bazel
---- b/go/buildutil/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/buildutil/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/buildutil/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5821,9 +6169,9 @@
 +    ],
 +)
 diff -urN b/go/callgraph/BUILD.bazel c/go/callgraph/BUILD.bazel
---- b/go/callgraph/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,34 @@
+@@ -0,0 +1,33 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -5853,13 +6201,12 @@
 +        "//go/callgraph/static",
 +        "//go/callgraph/vta",
 +        "//go/loader",
-+        "//go/pointer",
 +        "//go/ssa",
 +        "//go/ssa/ssautil",
 +    ],
 +)
 diff -urN b/go/callgraph/cha/BUILD.bazel c/go/callgraph/cha/BUILD.bazel
---- b/go/callgraph/cha/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/cha/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/cha/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,132 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -5995,7 +6342,7 @@
 +    }),
 +)
 diff -urN b/go/callgraph/cha/testdata/BUILD.bazel c/go/callgraph/cha/testdata/BUILD.bazel
---- b/go/callgraph/cha/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/cha/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/cha/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -6013,9 +6360,9 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/callgraph/rta/BUILD.bazel c/go/callgraph/rta/BUILD.bazel
---- b/go/callgraph/rta/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/rta/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/rta/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,132 @@
+@@ -0,0 +1,133 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -6027,6 +6374,7 @@
 +        "//go/callgraph",
 +        "//go/ssa",
 +        "//go/types/typeutil",
++        "//internal/compat",
 +    ],
 +)
 +
@@ -6039,7 +6387,7 @@
 +go_test(
 +    name = "rta_test",
 +    srcs = ["rta_test.go"],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:aix": [
 +            ":rta",
@@ -6149,7 +6497,7 @@
 +    }),
 +)
 diff -urN b/go/callgraph/static/BUILD.bazel c/go/callgraph/static/BUILD.bazel
---- b/go/callgraph/static/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/static/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/static/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6185,7 +6533,7 @@
 +    ],
 +)
 diff -urN b/go/callgraph/vta/BUILD.bazel c/go/callgraph/vta/BUILD.bazel
---- b/go/callgraph/vta/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/vta/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/vta/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,50 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6239,7 +6587,7 @@
 +    ],
 +)
 diff -urN b/go/callgraph/vta/internal/trie/BUILD.bazel c/go/callgraph/vta/internal/trie/BUILD.bazel
---- b/go/callgraph/vta/internal/trie/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/vta/internal/trie/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/vta/internal/trie/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6272,14 +6620,15 @@
 +    embed = [":trie"],
 +)
 diff -urN b/go/callgraph/vta/testdata/src/BUILD.bazel c/go/callgraph/vta/testdata/src/BUILD.bazel
---- b/go/callgraph/vta/testdata/src/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/vta/testdata/src/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/vta/testdata/src/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,47 @@
+@@ -0,0 +1,48 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
 +
 +go_library(
 +    name = "src",
 +    srcs = [
++        "arrays_generics.go",
 +        "callgraph_collections.go",
 +        "callgraph_field_funcs.go",
 +        "callgraph_fields.go",
@@ -6323,7 +6672,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/callgraph/vta/testdata/src/d/BUILD.bazel c/go/callgraph/vta/testdata/src/d/BUILD.bazel
---- b/go/callgraph/vta/testdata/src/d/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/vta/testdata/src/d/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/vta/testdata/src/d/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6341,7 +6690,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/callgraph/vta/testdata/src/t/BUILD.bazel c/go/callgraph/vta/testdata/src/t/BUILD.bazel
---- b/go/callgraph/vta/testdata/src/t/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/callgraph/vta/testdata/src/t/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/callgraph/vta/testdata/src/t/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6359,7 +6708,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/cfg/BUILD.bazel c/go/cfg/BUILD.bazel
---- b/go/cfg/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/cfg/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/cfg/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6386,7 +6735,7 @@
 +    embed = [":cfg"],
 +)
 diff -urN b/go/expect/BUILD.bazel c/go/expect/BUILD.bazel
---- b/go/expect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/expect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/expect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6414,7 +6763,7 @@
 +    deps = [":expect"],
 +)
 diff -urN b/go/expect/testdata/BUILD.bazel c/go/expect/testdata/BUILD.bazel
---- b/go/expect/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/expect/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/expect/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6432,7 +6781,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/gccgoexportdata/BUILD.bazel c/go/gccgoexportdata/BUILD.bazel
---- b/go/gccgoexportdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/gccgoexportdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/gccgoexportdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6454,13 +6803,13 @@
 +go_test(
 +    name = "gccgoexportdata_test",
 +    srcs = ["gccgoexportdata_test.go"],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [":gccgoexportdata"],
 +)
 diff -urN b/go/gcexportdata/BUILD.bazel c/go/gcexportdata/BUILD.bazel
---- b/go/gcexportdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/gcexportdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/gcexportdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,59 @@
+@@ -0,0 +1,56 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -6496,9 +6845,6 @@
 +        "@io_bazel_rules_go//go/platform:freebsd": [
 +            ":gcexportdata",
 +        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            ":gcexportdata",
-+        ],
 +        "@io_bazel_rules_go//go/platform:linux": [
 +            ":gcexportdata",
 +        ],
@@ -6521,7 +6867,7 @@
 +    }),
 +)
 diff -urN b/go/internal/cgo/BUILD.bazel c/go/internal/cgo/BUILD.bazel
---- b/go/internal/cgo/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/internal/cgo/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/internal/cgo/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6543,9 +6889,9 @@
 +    visibility = ["//go:__subpackages__"],
 +)
 diff -urN b/go/internal/gccgoimporter/BUILD.bazel c/go/internal/gccgoimporter/BUILD.bazel
---- b/go/internal/gccgoimporter/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/internal/gccgoimporter/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/internal/gccgoimporter/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -6578,11 +6924,12 @@
 +        "parser_test.go",
 +        "testenv_test.go",
 +    ],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":gccgoimporter"],
++    deps = ["//internal/testenv"],
 +)
 diff -urN b/go/internal/packagesdriver/BUILD.bazel c/go/internal/packagesdriver/BUILD.bazel
---- b/go/internal/packagesdriver/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/internal/packagesdriver/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/internal/packagesdriver/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6601,7 +6948,7 @@
 +    visibility = ["//go:__subpackages__"],
 +)
 diff -urN b/go/loader/BUILD.bazel c/go/loader/BUILD.bazel
---- b/go/loader/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/loader/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/loader/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,37 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6642,7 +6989,7 @@
 +    ],
 +)
 diff -urN b/go/loader/testdata/BUILD.bazel c/go/loader/testdata/BUILD.bazel
---- b/go/loader/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/loader/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/loader/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6664,7 +7011,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/loader/testdata/issue46877/BUILD.bazel c/go/loader/testdata/issue46877/BUILD.bazel
---- b/go/loader/testdata/issue46877/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/loader/testdata/issue46877/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/loader/testdata/issue46877/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6686,7 +7033,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/BUILD.bazel c/go/packages/BUILD.bazel
---- b/go/packages/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,47 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6737,7 +7084,7 @@
 +    ],
 +)
 diff -urN b/go/packages/gopackages/BUILD.bazel c/go/packages/gopackages/BUILD.bazel
---- b/go/packages/gopackages/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/gopackages/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/gopackages/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,19 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -6759,8 +7106,27 @@
 +    embed = [":gopackages_lib"],
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/packages/internal/nodecount/BUILD.bazel c/go/packages/internal/nodecount/BUILD.bazel
+--- b/go/packages/internal/nodecount/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/packages/internal/nodecount/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,15 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
++
++go_library(
++    name = "nodecount_lib",
++    srcs = ["nodecount.go"],
++    importpath = "golang.org/x/tools/go/packages/internal/nodecount",
++    visibility = ["//visibility:private"],
++    deps = ["//go/packages"],
++)
++
++go_binary(
++    name = "nodecount",
++    embed = [":nodecount_lib"],
++    visibility = ["//go/packages:__subpackages__"],
++)
 diff -urN b/go/packages/packagestest/BUILD.bazel c/go/packages/packagestest/BUILD.bazel
---- b/go/packages/packagestest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,42 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6806,7 +7172,7 @@
 +    ],
 +)
 diff -urN b/go/packages/packagestest/testdata/BUILD.bazel c/go/packages/packagestest/testdata/BUILD.bazel
---- b/go/packages/packagestest/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -6833,7 +7199,7 @@
 +    embed = [":testdata"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/one/modules/example.com/extra/BUILD.bazel c/go/packages/packagestest/testdata/groups/one/modules/example.com/extra/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/one/modules/example.com/extra/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/one/modules/example.com/extra/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/one/modules/example.com/extra/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6851,7 +7217,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/one/primarymod/BUILD.bazel c/go/packages/packagestest/testdata/groups/one/primarymod/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/one/primarymod/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/one/primarymod/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/one/primarymod/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6869,7 +7235,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6887,7 +7253,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/geez/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/geez/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/geez/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/geez/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/geez/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6905,7 +7271,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6923,7 +7289,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/geez/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/geez/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/geez/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/geez/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/extra/v2/geez/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6941,7 +7307,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/tempmod/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/tempmod/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/tempmod/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/tempmod/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/tempmod/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6959,7 +7325,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.0.0/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.0.0/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.0.0/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.0.0/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.0.0/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6977,7 +7343,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.1.0/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.1.0/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.1.0/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.1.0/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/modules/example.com/what@v1.1.0/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -6995,7 +7361,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/primarymod/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/primarymod/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/primarymod/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/primarymod/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/primarymod/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7013,7 +7379,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/packages/packagestest/testdata/groups/two/primarymod/expect/BUILD.bazel c/go/packages/packagestest/testdata/groups/two/primarymod/expect/BUILD.bazel
---- b/go/packages/packagestest/testdata/groups/two/primarymod/expect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/packages/packagestest/testdata/groups/two/primarymod/expect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/packages/packagestest/testdata/groups/two/primarymod/expect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,19 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -7035,160 +7401,10 @@
 +    name = "expect_test",
 +    srcs = ["yo_test.go"],
 +)
-diff -urN b/go/pointer/BUILD.bazel c/go/pointer/BUILD.bazel
---- b/go/pointer/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/pointer/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,124 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-+
-+go_library(
-+    name = "pointer",
-+    srcs = [
-+        "analysis.go",
-+        "api.go",
-+        "callgraph.go",
-+        "constraint.go",
-+        "doc.go",
-+        "gen.go",
-+        "hvn.go",
-+        "intrinsics.go",
-+        "labels.go",
-+        "opt.go",
-+        "print.go",
-+        "query.go",
-+        "reflect.go",
-+        "solve.go",
-+        "util.go",
-+    ],
-+    importpath = "golang.org/x/tools/go/pointer",
-+    visibility = ["//visibility:public"],
-+    deps = [
-+        "//container/intsets",
-+        "//go/callgraph",
-+        "//go/ssa",
-+        "//go/types/typeutil",
-+        "//internal/typeparams",
-+        "@org_golang_x_sys//execabs:go_default_library",
-+    ],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":pointer",
-+    visibility = ["//visibility:public"],
-+)
-+
-+go_test(
-+    name = "pointer_test",
-+    srcs = [
-+        "example_test.go",
-+        "pointer_go117_test.go",
-+        "pointer_race_test.go",
-+        "pointer_test.go",
-+        "query_test.go",
-+        "stdlib_test.go",
-+    ],
-+    embed = [":pointer"],
-+    deps = [
-+        "//go/callgraph",
-+        "//go/loader",
-+        "//go/ssa",
-+        "//go/ssa/ssautil",
-+    ] + select({
-+        "@io_bazel_rules_go//go/platform:aix": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:darwin": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:dragonfly": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:freebsd": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:ios": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:js": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:linux": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:netbsd": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:openbsd": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:plan9": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:solaris": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            "//go/packages",
-+            "//go/types/typeutil",
-+            "//internal/typeparams",
-+        ],
-+        "//conditions:default": [],
-+    }),
-+)
-diff -urN b/go/pointer/testdata/BUILD.bazel c/go/pointer/testdata/BUILD.bazel
---- b/go/pointer/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/pointer/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,18 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
-+
-+go_library(
-+    name = "testdata_lib",
-+    srcs = [
-+        "finalizer.go",
-+        "issue9002.go",
-+        "rtti.go",
-+    ],
-+    importpath = "golang.org/x/tools/go/pointer/testdata",
-+    visibility = ["//visibility:private"],
-+)
-+
-+go_binary(
-+    name = "testdata",
-+    embed = [":testdata_lib"],
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/go/ssa/BUILD.bazel c/go/ssa/BUILD.bazel
---- b/go/ssa/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,117 @@
+@@ -0,0 +1,118 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -7254,6 +7470,7 @@
 +        "subst_test.go",
 +        "testhelper_test.go",
 +    ],
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":ssa"],
 +    deps = [
 +        "//go/ast/astutil",
@@ -7307,7 +7524,7 @@
 +    }),
 +)
 diff -urN b/go/ssa/interp/BUILD.bazel c/go/ssa/interp/BUILD.bazel
---- b/go/ssa/interp/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,41 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -7339,8 +7556,8 @@
 +go_test(
 +    name = "interp_test",
 +    srcs = [
-+        "interp_go117_test.go",
 +        "interp_go120_test.go",
++        "interp_go121_test.go",
 +        "interp_test.go",
 +    ],
 +    deps = [
@@ -7352,9 +7569,9 @@
 +    ],
 +)
 diff -urN b/go/ssa/interp/testdata/fixedbugs/BUILD.bazel c/go/ssa/interp/testdata/fixedbugs/BUILD.bazel
---- b/go/ssa/interp/testdata/fixedbugs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/fixedbugs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/fixedbugs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,19 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
 +
 +go_library(
@@ -7363,6 +7580,7 @@
 +        "issue52342.go",
 +        "issue52835.go",
 +        "issue55086.go",
++        "issue55115.go",
 +    ],
 +    importpath = "golang.org/x/tools/go/ssa/interp/testdata/fixedbugs",
 +    visibility = ["//visibility:private"],
@@ -7374,7 +7592,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/encoding/BUILD.bazel c/go/ssa/interp/testdata/src/encoding/BUILD.bazel
---- b/go/ssa/interp/testdata/src/encoding/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/encoding/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/encoding/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7392,7 +7610,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/errors/BUILD.bazel c/go/ssa/interp/testdata/src/errors/BUILD.bazel
---- b/go/ssa/interp/testdata/src/errors/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/errors/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/errors/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7410,7 +7628,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/fmt/BUILD.bazel c/go/ssa/interp/testdata/src/fmt/BUILD.bazel
---- b/go/ssa/interp/testdata/src/fmt/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/fmt/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/fmt/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7428,7 +7646,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/io/BUILD.bazel c/go/ssa/interp/testdata/src/io/BUILD.bazel
---- b/go/ssa/interp/testdata/src/io/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/io/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/io/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7446,7 +7664,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/log/BUILD.bazel c/go/ssa/interp/testdata/src/log/BUILD.bazel
---- b/go/ssa/interp/testdata/src/log/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/log/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/log/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7464,7 +7682,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/math/BUILD.bazel c/go/ssa/interp/testdata/src/math/BUILD.bazel
---- b/go/ssa/interp/testdata/src/math/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/math/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/math/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7482,7 +7700,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/os/BUILD.bazel c/go/ssa/interp/testdata/src/os/BUILD.bazel
---- b/go/ssa/interp/testdata/src/os/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/os/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/os/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7500,7 +7718,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/reflect/BUILD.bazel c/go/ssa/interp/testdata/src/reflect/BUILD.bazel
---- b/go/ssa/interp/testdata/src/reflect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/reflect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/reflect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,17 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7521,7 +7739,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/runtime/BUILD.bazel c/go/ssa/interp/testdata/src/runtime/BUILD.bazel
---- b/go/ssa/interp/testdata/src/runtime/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/runtime/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/runtime/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7539,7 +7757,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/sort/BUILD.bazel c/go/ssa/interp/testdata/src/sort/BUILD.bazel
---- b/go/ssa/interp/testdata/src/sort/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/sort/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/sort/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7557,7 +7775,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/strconv/BUILD.bazel c/go/ssa/interp/testdata/src/strconv/BUILD.bazel
---- b/go/ssa/interp/testdata/src/strconv/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/strconv/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/strconv/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7575,7 +7793,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/strings/BUILD.bazel c/go/ssa/interp/testdata/src/strings/BUILD.bazel
---- b/go/ssa/interp/testdata/src/strings/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/strings/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/strings/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7593,7 +7811,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/sync/BUILD.bazel c/go/ssa/interp/testdata/src/sync/BUILD.bazel
---- b/go/ssa/interp/testdata/src/sync/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/sync/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/sync/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7611,7 +7829,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/time/BUILD.bazel c/go/ssa/interp/testdata/src/time/BUILD.bazel
---- b/go/ssa/interp/testdata/src/time/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/time/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/time/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7629,7 +7847,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/unicode/utf8/BUILD.bazel c/go/ssa/interp/testdata/src/unicode/utf8/BUILD.bazel
---- b/go/ssa/interp/testdata/src/unicode/utf8/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/unicode/utf8/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/unicode/utf8/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7647,7 +7865,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/interp/testdata/src/unsafe/BUILD.bazel c/go/ssa/interp/testdata/src/unsafe/BUILD.bazel
---- b/go/ssa/interp/testdata/src/unsafe/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/interp/testdata/src/unsafe/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/interp/testdata/src/unsafe/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7665,7 +7883,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/ssautil/BUILD.bazel c/go/ssa/ssautil/BUILD.bazel
---- b/go/ssa/ssautil/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/ssautil/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/ssautil/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,81 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -7699,7 +7917,7 @@
 +        "load_test.go",
 +        "switch_test.go",
 +    ],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = [
 +        ":ssautil",
 +        "//go/packages",
@@ -7750,7 +7968,7 @@
 +    }),
 +)
 diff -urN b/go/ssa/testdata/src/bytes/BUILD.bazel c/go/ssa/testdata/src/bytes/BUILD.bazel
---- b/go/ssa/testdata/src/bytes/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/bytes/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/bytes/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7768,7 +7986,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/context/BUILD.bazel c/go/ssa/testdata/src/context/BUILD.bazel
---- b/go/ssa/testdata/src/context/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/context/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/context/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7786,7 +8004,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/encoding/BUILD.bazel c/go/ssa/testdata/src/encoding/BUILD.bazel
---- b/go/ssa/testdata/src/encoding/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/encoding/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/encoding/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7804,7 +8022,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/encoding/json/BUILD.bazel c/go/ssa/testdata/src/encoding/json/BUILD.bazel
---- b/go/ssa/testdata/src/encoding/json/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/encoding/json/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/encoding/json/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7822,7 +8040,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/encoding/xml/BUILD.bazel c/go/ssa/testdata/src/encoding/xml/BUILD.bazel
---- b/go/ssa/testdata/src/encoding/xml/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/encoding/xml/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/encoding/xml/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7840,7 +8058,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/errors/BUILD.bazel c/go/ssa/testdata/src/errors/BUILD.bazel
---- b/go/ssa/testdata/src/errors/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/errors/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/errors/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7858,7 +8076,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/fmt/BUILD.bazel c/go/ssa/testdata/src/fmt/BUILD.bazel
---- b/go/ssa/testdata/src/fmt/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/fmt/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/fmt/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7876,7 +8094,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/io/BUILD.bazel c/go/ssa/testdata/src/io/BUILD.bazel
---- b/go/ssa/testdata/src/io/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/io/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/io/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7894,7 +8112,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/log/BUILD.bazel c/go/ssa/testdata/src/log/BUILD.bazel
---- b/go/ssa/testdata/src/log/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/log/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/log/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7912,7 +8130,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/math/BUILD.bazel c/go/ssa/testdata/src/math/BUILD.bazel
---- b/go/ssa/testdata/src/math/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/math/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/math/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7930,7 +8148,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/os/BUILD.bazel c/go/ssa/testdata/src/os/BUILD.bazel
---- b/go/ssa/testdata/src/os/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/os/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/os/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7948,7 +8166,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/reflect/BUILD.bazel c/go/ssa/testdata/src/reflect/BUILD.bazel
---- b/go/ssa/testdata/src/reflect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/reflect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/reflect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7966,7 +8184,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/runtime/BUILD.bazel c/go/ssa/testdata/src/runtime/BUILD.bazel
---- b/go/ssa/testdata/src/runtime/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/runtime/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/runtime/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -7984,7 +8202,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/sort/BUILD.bazel c/go/ssa/testdata/src/sort/BUILD.bazel
---- b/go/ssa/testdata/src/sort/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/sort/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/sort/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8002,7 +8220,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/strconv/BUILD.bazel c/go/ssa/testdata/src/strconv/BUILD.bazel
---- b/go/ssa/testdata/src/strconv/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/strconv/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/strconv/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8020,7 +8238,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/strings/BUILD.bazel c/go/ssa/testdata/src/strings/BUILD.bazel
---- b/go/ssa/testdata/src/strings/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/strings/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/strings/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8037,26 +8255,8 @@
 +    actual = ":strings",
 +    visibility = ["//visibility:public"],
 +)
-diff -urN b/go/ssa/testdata/src/sync/atomic/BUILD.bazel c/go/ssa/testdata/src/sync/atomic/BUILD.bazel
---- b/go/ssa/testdata/src/sync/atomic/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/ssa/testdata/src/sync/atomic/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
-+
-+go_library(
-+    name = "atomic",
-+    srcs = ["atomic.go"],
-+    importpath = "golang.org/x/tools/go/ssa/testdata/src/sync/atomic",
-+    visibility = ["//visibility:public"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":atomic",
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/go/ssa/testdata/src/sync/BUILD.bazel c/go/ssa/testdata/src/sync/BUILD.bazel
---- b/go/ssa/testdata/src/sync/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/sync/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/sync/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8073,8 +8273,26 @@
 +    actual = ":sync",
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/ssa/testdata/src/sync/atomic/BUILD.bazel c/go/ssa/testdata/src/sync/atomic/BUILD.bazel
+--- b/go/ssa/testdata/src/sync/atomic/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/ssa/testdata/src/sync/atomic/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "atomic",
++    srcs = ["atomic.go"],
++    importpath = "golang.org/x/tools/go/ssa/testdata/src/sync/atomic",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":atomic",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/go/ssa/testdata/src/time/BUILD.bazel c/go/ssa/testdata/src/time/BUILD.bazel
---- b/go/ssa/testdata/src/time/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/time/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/time/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8092,7 +8310,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/go/ssa/testdata/src/unsafe/BUILD.bazel c/go/ssa/testdata/src/unsafe/BUILD.bazel
---- b/go/ssa/testdata/src/unsafe/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/ssa/testdata/src/unsafe/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/ssa/testdata/src/unsafe/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8109,10 +8327,34 @@
 +    actual = ":unsafe",
 +    visibility = ["//visibility:public"],
 +)
+diff -urN b/go/types/internal/play/BUILD.bazel c/go/types/internal/play/BUILD.bazel
+--- b/go/types/internal/play/BUILD.bazel	1970-01-01 08:00:00
++++ c/go/types/internal/play/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,20 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
++
++go_library(
++    name = "play_lib",
++    srcs = ["play.go"],
++    importpath = "golang.org/x/tools/go/types/internal/play",
++    visibility = ["//visibility:private"],
++    deps = [
++        "//go/ast/astutil",
++        "//go/packages",
++        "//go/types/typeutil",
++        "//internal/typeparams",
++    ],
++)
++
++go_binary(
++    name = "play",
++    embed = [":play_lib"],
++    visibility = ["//go/types:__subpackages__"],
++)
 diff -urN b/go/types/objectpath/BUILD.bazel c/go/types/objectpath/BUILD.bazel
---- b/go/types/objectpath/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/types/objectpath/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/types/objectpath/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,29 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -8120,7 +8362,10 @@
 +    srcs = ["objectpath.go"],
 +    importpath = "golang.org/x/tools/go/types/objectpath",
 +    visibility = ["//visibility:public"],
-+    deps = ["//internal/typeparams"],
++    deps = [
++        "//internal/typeparams",
++        "//internal/typesinternal",
++    ],
 +)
 +
 +alias(
@@ -8143,7 +8388,7 @@
 +    ],
 +)
 diff -urN b/go/types/typeutil/BUILD.bazel c/go/types/typeutil/BUILD.bazel
---- b/go/types/typeutil/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/go/types/typeutil/BUILD.bazel	1970-01-01 08:00:00
 +++ c/go/types/typeutil/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,39 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8185,59 +8430,8 @@
 +        "//internal/typeparams",
 +    ],
 +)
-diff -urN b/go/vcs/BUILD.bazel c/go/vcs/BUILD.bazel
---- b/go/vcs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/go/vcs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,26 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-+
-+go_library(
-+    name = "vcs",
-+    srcs = [
-+        "discovery.go",
-+        "env.go",
-+        "http.go",
-+        "vcs.go",
-+    ],
-+    importpath = "golang.org/x/tools/go/vcs",
-+    visibility = ["//visibility:public"],
-+    deps = ["@org_golang_x_sys//execabs:go_default_library"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":vcs",
-+    visibility = ["//visibility:public"],
-+)
-+
-+go_test(
-+    name = "vcs_test",
-+    srcs = ["vcs_test.go"],
-+    embed = [":vcs"],
-+)
-diff -urN b/godoc/analysis/BUILD.bazel c/godoc/analysis/BUILD.bazel
---- b/godoc/analysis/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/godoc/analysis/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,17 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
-+
-+go_library(
-+    name = "analysis",
-+    srcs = [
-+        "analysis.go",
-+        "json.go",
-+    ],
-+    importpath = "golang.org/x/tools/godoc/analysis",
-+    visibility = ["//visibility:public"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":analysis",
-+    visibility = ["//visibility:public"],
-+)
 diff -urN b/godoc/BUILD.bazel c/godoc/BUILD.bazel
---- b/godoc/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,66 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8306,8 +8500,29 @@
 +        "//internal/typeparams",
 +    ],
 +)
+diff -urN b/godoc/analysis/BUILD.bazel c/godoc/analysis/BUILD.bazel
+--- b/godoc/analysis/BUILD.bazel	1970-01-01 08:00:00
++++ c/godoc/analysis/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,17 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "analysis",
++    srcs = [
++        "analysis.go",
++        "json.go",
++    ],
++    importpath = "golang.org/x/tools/godoc/analysis",
++    visibility = ["//visibility:public"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":analysis",
++    visibility = ["//visibility:public"],
++)
 diff -urN b/godoc/redirect/BUILD.bazel c/godoc/redirect/BUILD.bazel
---- b/godoc/redirect/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/redirect/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/redirect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8331,7 +8546,7 @@
 +    embed = [":redirect"],
 +)
 diff -urN b/godoc/static/BUILD.bazel c/godoc/static/BUILD.bazel
---- b/godoc/static/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/static/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/static/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8359,7 +8574,7 @@
 +    embed = [":static"],
 +)
 diff -urN b/godoc/util/BUILD.bazel c/godoc/util/BUILD.bazel
---- b/godoc/util/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/util/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/util/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8381,7 +8596,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/godoc/vfs/BUILD.bazel c/godoc/vfs/BUILD.bazel
---- b/godoc/vfs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/vfs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/vfs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8417,7 +8632,7 @@
 +    ],
 +)
 diff -urN b/godoc/vfs/gatefs/BUILD.bazel c/godoc/vfs/gatefs/BUILD.bazel
---- b/godoc/vfs/gatefs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/vfs/gatefs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/vfs/gatefs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8445,7 +8660,7 @@
 +    ],
 +)
 diff -urN b/godoc/vfs/httpfs/BUILD.bazel c/godoc/vfs/httpfs/BUILD.bazel
---- b/godoc/vfs/httpfs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/vfs/httpfs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/vfs/httpfs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8464,7 +8679,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/godoc/vfs/mapfs/BUILD.bazel c/godoc/vfs/mapfs/BUILD.bazel
---- b/godoc/vfs/mapfs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/vfs/mapfs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/vfs/mapfs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8489,7 +8704,7 @@
 +    embed = [":mapfs"],
 +)
 diff -urN b/godoc/vfs/zipfs/BUILD.bazel c/godoc/vfs/zipfs/BUILD.bazel
---- b/godoc/vfs/zipfs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/godoc/vfs/zipfs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/godoc/vfs/zipfs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8515,7 +8730,7 @@
 +    deps = ["//godoc/vfs"],
 +)
 diff -urN b/imports/BUILD.bazel c/imports/BUILD.bazel
---- b/imports/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/imports/BUILD.bazel	1970-01-01 08:00:00
 +++ c/imports/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8537,7 +8752,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/internal/analysisinternal/BUILD.bazel c/internal/analysisinternal/BUILD.bazel
---- b/internal/analysisinternal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/analysisinternal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/analysisinternal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8555,7 +8770,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/apidiff/BUILD.bazel c/internal/apidiff/BUILD.bazel
---- b/internal/apidiff/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/apidiff/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/apidiff/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,30 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8589,7 +8804,7 @@
 +    ],
 +)
 diff -urN b/internal/apidiff/testdata/BUILD.bazel c/internal/apidiff/testdata/BUILD.bazel
---- b/internal/apidiff/testdata/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/apidiff/testdata/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/apidiff/testdata/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8607,7 +8822,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/apidiff/testdata/exported_fields/BUILD.bazel c/internal/apidiff/testdata/exported_fields/BUILD.bazel
---- b/internal/apidiff/testdata/exported_fields/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/apidiff/testdata/exported_fields/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/apidiff/testdata/exported_fields/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8624,32 +8839,110 @@
 +    actual = ":exported_fields",
 +    visibility = ["//:__subpackages__"],
 +)
-diff -urN b/internal/bug/BUILD.bazel c/internal/bug/BUILD.bazel
---- b/internal/bug/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/internal/bug/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+diff -urN b/internal/bisect/BUILD.bazel c/internal/bisect/BUILD.bazel
+--- b/internal/bisect/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/bisect/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
-+    name = "bug",
-+    srcs = ["bug.go"],
-+    importpath = "golang.org/x/tools/internal/bug",
++    name = "bisect",
++    srcs = ["bisect.go"],
++    importpath = "golang.org/x/tools/internal/bisect",
 +    visibility = ["//:__subpackages__"],
 +)
 +
 +alias(
 +    name = "go_default_library",
-+    actual = ":bug",
++    actual = ":bisect",
 +    visibility = ["//:__subpackages__"],
 +)
 +
 +go_test(
-+    name = "bug_test",
-+    srcs = ["bug_test.go"],
-+    embed = [":bug"],
++    name = "bisect_test",
++    srcs = ["bisect_test.go"],
++    embed = [":bisect"],
++)
+diff -urN b/internal/cmd/deadcode/BUILD.bazel c/internal/cmd/deadcode/BUILD.bazel
+--- b/internal/cmd/deadcode/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/cmd/deadcode/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,34 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
++
++go_library(
++    name = "deadcode_lib",
++    srcs = [
++        "deadcode.go",
++        "doc.go",
++    ],
++    embedsrcs = ["doc.go"],
++    importpath = "golang.org/x/tools/internal/cmd/deadcode",
++    visibility = ["//visibility:private"],
++    deps = [
++        "//go/callgraph/rta",
++        "//go/packages",
++        "//go/ssa",
++        "//go/ssa/ssautil",
++    ],
++)
++
++go_binary(
++    name = "deadcode",
++    embed = [":deadcode_lib"],
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "deadcode_test",
++    srcs = ["deadcode_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    deps = [
++        "//internal/testenv",
++        "//txtar",
++    ],
++)
+diff -urN b/internal/compat/BUILD.bazel c/internal/compat/BUILD.bazel
+--- b/internal/compat/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/compat/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,18 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "compat",
++    srcs = [
++        "appendf.go",
++        "appendf_118.go",
++        "doc.go",
++    ],
++    importpath = "golang.org/x/tools/internal/compat",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":compat",
++    visibility = ["//:__subpackages__"],
++)
+diff -urN b/internal/constraints/BUILD.bazel c/internal/constraints/BUILD.bazel
+--- b/internal/constraints/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/constraints/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "constraints",
++    srcs = ["constraint.go"],
++    importpath = "golang.org/x/tools/internal/constraints",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":constraints",
++    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/diff/BUILD.bazel c/internal/diff/BUILD.bazel
---- b/internal/diff/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/diff/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/diff/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8685,7 +8978,7 @@
 +    ],
 +)
 diff -urN b/internal/diff/difftest/BUILD.bazel c/internal/diff/difftest/BUILD.bazel
---- b/internal/diff/difftest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/diff/difftest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/diff/difftest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8713,7 +9006,7 @@
 +    ],
 +)
 diff -urN b/internal/diff/lcs/BUILD.bazel c/internal/diff/lcs/BUILD.bazel
---- b/internal/diff/lcs/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/diff/lcs/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/diff/lcs/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8746,7 +9039,7 @@
 +    embed = [":lcs"],
 +)
 diff -urN b/internal/diff/myers/BUILD.bazel c/internal/diff/myers/BUILD.bazel
---- b/internal/diff/myers/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/diff/myers/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/diff/myers/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8773,8 +9066,58 @@
 +        "//internal/diff/difftest",
 +    ],
 +)
+diff -urN b/internal/diffp/BUILD.bazel c/internal/diffp/BUILD.bazel
+--- b/internal/diffp/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/diffp/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,22 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "diffp",
++    srcs = ["diff.go"],
++    importpath = "golang.org/x/tools/internal/diffp",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":diffp",
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "diffp_test",
++    srcs = ["diff_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    embed = [":diffp"],
++    deps = ["//txtar"],
++)
+diff -urN b/internal/edit/BUILD.bazel c/internal/edit/BUILD.bazel
+--- b/internal/edit/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/edit/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,20 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "edit",
++    srcs = ["edit.go"],
++    importpath = "golang.org/x/tools/internal/edit",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":edit",
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "edit_test",
++    srcs = ["edit_test.go"],
++    embed = [":edit"],
++)
 diff -urN b/internal/event/BUILD.bazel c/internal/event/BUILD.bazel
---- b/internal/event/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,34 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8812,7 +9155,7 @@
 +    ],
 +)
 diff -urN b/internal/event/core/BUILD.bazel c/internal/event/core/BUILD.bazel
---- b/internal/event/core/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/core/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/core/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8838,7 +9181,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/event/export/BUILD.bazel c/internal/event/export/BUILD.bazel
---- b/internal/event/export/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,38 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8880,7 +9223,7 @@
 +    ],
 +)
 diff -urN b/internal/event/export/eventtest/BUILD.bazel c/internal/event/export/eventtest/BUILD.bazel
---- b/internal/event/export/eventtest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/eventtest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/eventtest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8904,7 +9247,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/event/export/metric/BUILD.bazel c/internal/event/export/metric/BUILD.bazel
---- b/internal/event/export/metric/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/metric/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/metric/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -8932,7 +9275,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/event/export/ocagent/BUILD.bazel c/internal/event/export/ocagent/BUILD.bazel
---- b/internal/event/export/ocagent/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/ocagent/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/ocagent/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,44 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -8980,7 +9323,7 @@
 +    ],
 +)
 diff -urN b/internal/event/export/ocagent/wire/BUILD.bazel c/internal/event/export/ocagent/wire/BUILD.bazel
---- b/internal/event/export/ocagent/wire/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/ocagent/wire/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/ocagent/wire/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,25 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9009,7 +9352,7 @@
 +    embed = [":wire"],
 +)
 diff -urN b/internal/event/export/prometheus/BUILD.bazel c/internal/event/export/prometheus/BUILD.bazel
---- b/internal/event/export/prometheus/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/export/prometheus/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/export/prometheus/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9033,7 +9376,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/event/keys/BUILD.bazel c/internal/event/keys/BUILD.bazel
---- b/internal/event/keys/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/keys/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/keys/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9055,7 +9398,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/event/label/BUILD.bazel c/internal/event/label/BUILD.bazel
---- b/internal/event/label/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/label/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/label/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,23 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9082,7 +9425,7 @@
 +    ],
 +)
 diff -urN b/internal/event/tag/BUILD.bazel c/internal/event/tag/BUILD.bazel
---- b/internal/event/tag/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/event/tag/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/event/tag/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9101,9 +9444,9 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/facts/BUILD.bazel c/internal/facts/BUILD.bazel
---- b/internal/facts/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/facts/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/facts/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,34 @@
+@@ -0,0 +1,35 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9118,13 +9461,14 @@
 +        "//go/analysis",
 +        "//go/types/objectpath",
 +        "//internal/typeparams",
++        "//internal/typesinternal",
 +    ],
 +)
 +
 +alias(
 +    name = "go_default_library",
 +    actual = ":facts",
-+    visibility = ["//visibility:public"],
++    visibility = ["//:__subpackages__"],
 +)
 +
 +go_test(
@@ -9139,7 +9483,7 @@
 +    ],
 +)
 diff -urN b/internal/fakenet/BUILD.bazel c/internal/fakenet/BUILD.bazel
---- b/internal/fakenet/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/fakenet/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/fakenet/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9157,7 +9501,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/fastwalk/BUILD.bazel c/internal/fastwalk/BUILD.bazel
---- b/internal/fastwalk/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/fastwalk/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/fastwalk/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,30 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9191,9 +9535,9 @@
 +    deps = [":fastwalk"],
 +)
 diff -urN b/internal/fuzzy/BUILD.bazel c/internal/fuzzy/BUILD.bazel
---- b/internal/fuzzy/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/fuzzy/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/fuzzy/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,28 @@
+@@ -0,0 +1,32 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9218,12 +9562,16 @@
 +    srcs = [
 +        "input_test.go",
 +        "matcher_test.go",
++        "self_test.go",
 +        "symbol_test.go",
 +    ],
-+    deps = [":fuzzy"],
++    deps = [
++        ":fuzzy",
++        "//go/packages",
++    ],
 +)
 diff -urN b/internal/gcimporter/BUILD.bazel c/internal/gcimporter/BUILD.bazel
---- b/internal/gcimporter/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,60 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9231,7 +9579,6 @@
 +go_library(
 +    name = "gcimporter",
 +    srcs = [
-+        "bexport.go",
 +        "bimport.go",
 +        "exportdata.go",
 +        "gcimporter.go",
@@ -9248,6 +9595,7 @@
 +    importpath = "golang.org/x/tools/internal/gcimporter",
 +    visibility = ["//:__subpackages__"],
 +    deps = [
++        "//go/types/objectpath",
 +        "//internal/pkgbits",
 +        "//internal/tokeninternal",
 +        "//internal/typeparams",
@@ -9287,7 +9635,7 @@
 +    ],
 +)
 diff -urN b/internal/gcimporter/testdata/a/BUILD.bazel c/internal/gcimporter/testdata/a/BUILD.bazel
---- b/internal/gcimporter/testdata/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9304,26 +9652,8 @@
 +    actual = ":a",
 +    visibility = ["//:__subpackages__"],
 +)
-diff -urN b/internal/gcimporter/testdata/issue51836/a/BUILD.bazel c/internal/gcimporter/testdata/issue51836/a/BUILD.bazel
---- b/internal/gcimporter/testdata/issue51836/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/internal/gcimporter/testdata/issue51836/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
-+
-+go_library(
-+    name = "a",
-+    srcs = ["a.go"],
-+    importpath = "golang.org/x/tools/internal/gcimporter/testdata/issue51836/a",
-+    visibility = ["//:__subpackages__"],
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":a",
-+    visibility = ["//:__subpackages__"],
-+)
 diff -urN b/internal/gcimporter/testdata/issue51836/BUILD.bazel c/internal/gcimporter/testdata/issue51836/BUILD.bazel
---- b/internal/gcimporter/testdata/issue51836/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/issue51836/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/issue51836/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9344,8 +9674,26 @@
 +    actual = ":issue51836",
 +    visibility = ["//:__subpackages__"],
 +)
+diff -urN b/internal/gcimporter/testdata/issue51836/a/BUILD.bazel c/internal/gcimporter/testdata/issue51836/a/BUILD.bazel
+--- b/internal/gcimporter/testdata/issue51836/a/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/gcimporter/testdata/issue51836/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "a",
++    srcs = ["a.go"],
++    importpath = "golang.org/x/tools/internal/gcimporter/testdata/issue51836/a",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":a",
++    visibility = ["//:__subpackages__"],
++)
 diff -urN b/internal/gcimporter/testdata/issue58296/a/BUILD.bazel c/internal/gcimporter/testdata/issue58296/a/BUILD.bazel
---- b/internal/gcimporter/testdata/issue58296/a/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/issue58296/a/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/issue58296/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9363,7 +9711,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/gcimporter/testdata/issue58296/b/BUILD.bazel c/internal/gcimporter/testdata/issue58296/b/BUILD.bazel
---- b/internal/gcimporter/testdata/issue58296/b/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/issue58296/b/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/issue58296/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9381,7 +9729,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/gcimporter/testdata/issue58296/c/BUILD.bazel c/internal/gcimporter/testdata/issue58296/c/BUILD.bazel
---- b/internal/gcimporter/testdata/issue58296/c/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/issue58296/c/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/issue58296/c/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9399,7 +9747,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/gcimporter/testdata/versions/BUILD.bazel c/internal/gcimporter/testdata/versions/BUILD.bazel
---- b/internal/gcimporter/testdata/versions/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gcimporter/testdata/versions/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gcimporter/testdata/versions/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9417,9 +9765,9 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/gocommand/BUILD.bazel c/internal/gocommand/BUILD.bazel
---- b/internal/gocommand/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gocommand/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gocommand/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,32 @@
+@@ -0,0 +1,36 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9433,6 +9781,9 @@
 +    visibility = ["//:__subpackages__"],
 +    deps = [
 +        "//internal/event",
++        "//internal/event/keys",
++        "//internal/event/label",
++        "//internal/event/tag",
 +        "@org_golang_x_mod//semver:go_default_library",
 +        "@org_golang_x_sys//execabs:go_default_library",
 +    ],
@@ -9451,9 +9802,10 @@
 +        "version_test.go",
 +    ],
 +    embed = [":gocommand"],
++    deps = ["//internal/testenv"],
 +)
 diff -urN b/internal/gopathwalk/BUILD.bazel c/internal/gopathwalk/BUILD.bazel
---- b/internal/gopathwalk/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/gopathwalk/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/gopathwalk/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9478,7 +9830,7 @@
 +    embed = [":gopathwalk"],
 +)
 diff -urN b/internal/goroot/BUILD.bazel c/internal/goroot/BUILD.bazel
---- b/internal/goroot/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/goroot/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/goroot/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9496,9 +9848,9 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/imports/BUILD.bazel c/internal/imports/BUILD.bazel
---- b/internal/imports/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/imports/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/imports/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,48 @@
+@@ -0,0 +1,49 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9515,6 +9867,7 @@
 +    visibility = ["//:__subpackages__"],
 +    deps = [
 +        "//go/ast/astutil",
++        "//internal/event",
 +        "//internal/gocommand",
 +        "//internal/gopathwalk",
 +        "@org_golang_x_mod//module:go_default_library",
@@ -9535,7 +9888,7 @@
 +        "mod_cache_test.go",
 +        "mod_test.go",
 +    ],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":imports"],
 +    deps = [
 +        "//go/packages/packagestest",
@@ -9548,9 +9901,9 @@
 +    ],
 +)
 diff -urN b/internal/jsonrpc2/BUILD.bazel c/internal/jsonrpc2/BUILD.bazel
---- b/internal/jsonrpc2/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/jsonrpc2/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/jsonrpc2/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,41 @@
+@@ -0,0 +1,42 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9590,10 +9943,11 @@
 +    deps = [
 +        "//internal/event/export/eventtest",
 +        "//internal/stack/stacktest",
++        "//internal/testenv",
 +    ],
 +)
 diff -urN b/internal/jsonrpc2/servertest/BUILD.bazel c/internal/jsonrpc2/servertest/BUILD.bazel
---- b/internal/jsonrpc2/servertest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/jsonrpc2/servertest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/jsonrpc2/servertest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,22 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9619,9 +9973,9 @@
 +    deps = ["//internal/jsonrpc2"],
 +)
 diff -urN b/internal/jsonrpc2_v2/BUILD.bazel c/internal/jsonrpc2_v2/BUILD.bazel
---- b/internal/jsonrpc2_v2/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/jsonrpc2_v2/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/jsonrpc2_v2/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,44 @@
+@@ -0,0 +1,45 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
@@ -9664,200 +10018,11 @@
 +        ":jsonrpc2_v2",
 +        "//internal/event/export/eventtest",
 +        "//internal/stack/stacktest",
++        "//internal/testenv",
 +    ],
 +)
-diff -urN b/internal/lockedfile/BUILD.bazel c/internal/lockedfile/BUILD.bazel
---- b/internal/lockedfile/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/internal/lockedfile/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,111 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-+
-+go_library(
-+    name = "lockedfile",
-+    srcs = [
-+        "lockedfile.go",
-+        "lockedfile_filelock.go",
-+        "lockedfile_plan9.go",
-+        "mutex.go",
-+    ],
-+    importpath = "golang.org/x/tools/internal/lockedfile",
-+    visibility = ["//:__subpackages__"],
-+    deps = select({
-+        "@io_bazel_rules_go//go/platform:aix": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:android": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:darwin": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:dragonfly": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:freebsd": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:ios": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:js": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:linux": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:netbsd": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:openbsd": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:solaris": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            "//internal/lockedfile/internal/filelock",
-+        ],
-+        "//conditions:default": [],
-+    }),
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":lockedfile",
-+    visibility = ["//:__subpackages__"],
-+)
-+
-+go_test(
-+    name = "lockedfile_test",
-+    srcs = [
-+        "lockedfile_test.go",
-+        "transform_test.go",
-+    ],
-+    deps = select({
-+        "@io_bazel_rules_go//go/platform:aix": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:android": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:darwin": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:dragonfly": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:freebsd": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:ios": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:linux": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:netbsd": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:openbsd": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:plan9": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:solaris": [
-+            ":lockedfile",
-+        ],
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            ":lockedfile",
-+        ],
-+        "//conditions:default": [],
-+    }),
-+)
-diff -urN b/internal/lockedfile/internal/filelock/BUILD.bazel c/internal/lockedfile/internal/filelock/BUILD.bazel
---- b/internal/lockedfile/internal/filelock/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
-+++ c/internal/lockedfile/internal/filelock/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,71 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
-+
-+go_library(
-+    name = "filelock",
-+    srcs = [
-+        "filelock.go",
-+        "filelock_fcntl.go",
-+        "filelock_other.go",
-+        "filelock_plan9.go",
-+        "filelock_unix.go",
-+        "filelock_windows.go",
-+    ],
-+    importpath = "golang.org/x/tools/internal/lockedfile/internal/filelock",
-+    visibility = ["//:__subpackages__"],
-+    deps = select({
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            "@org_golang_x_sys//windows",
-+        ],
-+        "//conditions:default": [],
-+    }),
-+)
-+
-+alias(
-+    name = "go_default_library",
-+    actual = ":filelock",
-+    visibility = ["//:__subpackages__"],
-+)
-+
-+go_test(
-+    name = "filelock_test",
-+    srcs = ["filelock_test.go"],
-+    deps = select({
-+        "@io_bazel_rules_go//go/platform:aix": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:android": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:darwin": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:dragonfly": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:freebsd": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:illumos": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:ios": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:linux": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:netbsd": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:openbsd": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:solaris": [
-+            ":filelock",
-+        ],
-+        "@io_bazel_rules_go//go/platform:windows": [
-+            ":filelock",
-+        ],
-+        "//conditions:default": [],
-+    }),
-+)
 diff -urN b/internal/memoize/BUILD.bazel c/internal/memoize/BUILD.bazel
---- b/internal/memoize/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/memoize/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/memoize/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9882,7 +10047,7 @@
 +    deps = [":memoize"],
 +)
 diff -urN b/internal/packagesinternal/BUILD.bazel c/internal/packagesinternal/BUILD.bazel
---- b/internal/packagesinternal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/packagesinternal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/packagesinternal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9901,16 +10066,20 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/persistent/BUILD.bazel c/internal/persistent/BUILD.bazel
---- b/internal/persistent/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/persistent/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/persistent/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,20 @@
+@@ -0,0 +1,28 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "persistent",
-+    srcs = ["map.go"],
++    srcs = [
++        "map.go",
++        "set.go",
++    ],
 +    importpath = "golang.org/x/tools/internal/persistent",
 +    visibility = ["//:__subpackages__"],
++    deps = ["//internal/constraints"],
 +)
 +
 +alias(
@@ -9921,11 +10090,15 @@
 +
 +go_test(
 +    name = "persistent_test",
-+    srcs = ["map_test.go"],
++    srcs = [
++        "map_test.go",
++        "set_test.go",
++    ],
 +    embed = [":persistent"],
++    deps = ["//internal/constraints"],
 +)
 diff -urN b/internal/pkgbits/BUILD.bazel c/internal/pkgbits/BUILD.bazel
---- b/internal/pkgbits/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/pkgbits/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/pkgbits/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,26 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -9954,8 +10127,33 @@
 +    actual = ":pkgbits",
 +    visibility = ["//:__subpackages__"],
 +)
+diff -urN b/internal/pprof/BUILD.bazel c/internal/pprof/BUILD.bazel
+--- b/internal/pprof/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/pprof/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,21 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "pprof",
++    srcs = ["pprof.go"],
++    importpath = "golang.org/x/tools/internal/pprof",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":pprof",
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "pprof_test",
++    srcs = ["pprof_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    deps = [":pprof"],
++)
 diff -urN b/internal/proxydir/BUILD.bazel c/internal/proxydir/BUILD.bazel
---- b/internal/proxydir/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/proxydir/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/proxydir/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,21 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -9979,8 +10177,134 @@
 +    srcs = ["proxydir_test.go"],
 +    embed = [":proxydir"],
 +)
+diff -urN b/internal/refactor/inline/BUILD.bazel c/internal/refactor/inline/BUILD.bazel
+--- b/internal/refactor/inline/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/refactor/inline/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,50 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "inline",
++    srcs = [
++        "callee.go",
++        "calleefx.go",
++        "doc.go",
++        "escape.go",
++        "falcon.go",
++        "inline.go",
++        "util.go",
++    ],
++    importpath = "golang.org/x/tools/internal/refactor/inline",
++    visibility = ["//:__subpackages__"],
++    deps = [
++        "//go/ast/astutil",
++        "//go/types/typeutil",
++        "//imports",
++        "//internal/typeparams",
++    ],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":inline",
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "inline_test",
++    srcs = [
++        "calleefx_test.go",
++        "everything_test.go",
++        "export_test.go",
++        "falcon_test.go",
++        "inline_test.go",
++    ],
++    data = glob(["testdata/**"], allow_empty = True),
++    embed = [":inline"],
++    deps = [
++        "//go/ast/astutil",
++        "//go/expect",
++        "//go/packages",
++        "//go/types/typeutil",
++        "//internal/diff",
++        "//internal/testenv",
++        "//txtar",
++    ],
++)
+diff -urN b/internal/refactor/inline/analyzer/BUILD.bazel c/internal/refactor/inline/analyzer/BUILD.bazel
+--- b/internal/refactor/inline/analyzer/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/refactor/inline/analyzer/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,32 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
++
++go_library(
++    name = "analyzer",
++    srcs = ["analyzer.go"],
++    importpath = "golang.org/x/tools/internal/refactor/inline/analyzer",
++    visibility = ["//:__subpackages__"],
++    deps = [
++        "//go/analysis",
++        "//go/analysis/passes/inspect",
++        "//go/ast/inspector",
++        "//go/types/typeutil",
++        "//internal/diff",
++        "//internal/refactor/inline",
++    ],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":analyzer",
++    visibility = ["//:__subpackages__"],
++)
++
++go_test(
++    name = "analyzer_test",
++    srcs = ["analyzer_test.go"],
++    data = glob(["testdata/**"], allow_empty = True),
++    deps = [
++        ":analyzer",
++        "//go/analysis/analysistest",
++    ],
++)
+diff -urN b/internal/refactor/inline/analyzer/testdata/src/a/BUILD.bazel c/internal/refactor/inline/analyzer/testdata/src/a/BUILD.bazel
+--- b/internal/refactor/inline/analyzer/testdata/src/a/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/refactor/inline/analyzer/testdata/src/a/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "a",
++    srcs = ["a.go"],
++    importpath = "golang.org/x/tools/internal/refactor/inline/analyzer/testdata/src/a",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":a",
++    visibility = ["//:__subpackages__"],
++)
+diff -urN b/internal/refactor/inline/analyzer/testdata/src/b/BUILD.bazel c/internal/refactor/inline/analyzer/testdata/src/b/BUILD.bazel
+--- b/internal/refactor/inline/analyzer/testdata/src/b/BUILD.bazel	1970-01-01 08:00:00
++++ c/internal/refactor/inline/analyzer/testdata/src/b/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
+@@ -0,0 +1,14 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library")
++
++go_library(
++    name = "b",
++    srcs = ["b.go"],
++    importpath = "golang.org/x/tools/internal/refactor/inline/analyzer/testdata/src/b",
++    visibility = ["//:__subpackages__"],
++)
++
++alias(
++    name = "go_default_library",
++    actual = ":b",
++    visibility = ["//:__subpackages__"],
++)
 diff -urN b/internal/robustio/BUILD.bazel c/internal/robustio/BUILD.bazel
---- b/internal/robustio/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/robustio/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/robustio/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,29 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10013,7 +10337,7 @@
 +    deps = [":robustio"],
 +)
 diff -urN b/internal/stack/BUILD.bazel c/internal/stack/BUILD.bazel
---- b/internal/stack/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/stack/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/stack/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10041,7 +10365,7 @@
 +    deps = [":stack"],
 +)
 diff -urN b/internal/stack/gostacks/BUILD.bazel c/internal/stack/gostacks/BUILD.bazel
---- b/internal/stack/gostacks/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/stack/gostacks/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/stack/gostacks/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
@@ -10060,7 +10384,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/stack/stacktest/BUILD.bazel c/internal/stack/stacktest/BUILD.bazel
---- b/internal/stack/stacktest/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/stack/stacktest/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/stack/stacktest/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,15 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -10079,9 +10403,9 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/testenv/BUILD.bazel c/internal/testenv/BUILD.bazel
---- b/internal/testenv/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/testenv/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/testenv/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,23 @@
+@@ -0,0 +1,24 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
 +
 +go_library(
@@ -10096,6 +10420,7 @@
 +    visibility = ["//:__subpackages__"],
 +    deps = [
 +        "//internal/goroot",
++        "@org_golang_x_mod//modfile:go_default_library",
 +        "@org_golang_x_sys//execabs:go_default_library",
 +    ],
 +)
@@ -10106,10 +10431,10 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/tokeninternal/BUILD.bazel c/internal/tokeninternal/BUILD.bazel
---- b/internal/tokeninternal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/tokeninternal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/tokeninternal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
-@@ -0,0 +1,14 @@
-+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+@@ -0,0 +1,20 @@
++load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 +
 +go_library(
 +    name = "tokeninternal",
@@ -10123,8 +10448,14 @@
 +    actual = ":tokeninternal",
 +    visibility = ["//:__subpackages__"],
 +)
++
++go_test(
++    name = "tokeninternal_test",
++    srcs = ["tokeninternal_test.go"],
++    deps = [":tokeninternal"],
++)
 diff -urN b/internal/tool/BUILD.bazel c/internal/tool/BUILD.bazel
---- b/internal/tool/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/tool/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/tool/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -10142,7 +10473,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/typeparams/BUILD.bazel c/internal/typeparams/BUILD.bazel
---- b/internal/typeparams/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/typeparams/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/typeparams/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,39 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10185,7 +10516,7 @@
 +    ],
 +)
 diff -urN b/internal/typeparams/genericfeatures/BUILD.bazel c/internal/typeparams/genericfeatures/BUILD.bazel
---- b/internal/typeparams/genericfeatures/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/typeparams/genericfeatures/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/typeparams/genericfeatures/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,18 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -10207,7 +10538,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/internal/typesinternal/BUILD.bazel c/internal/typesinternal/BUILD.bazel
---- b/internal/typesinternal/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/typesinternal/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/typesinternal/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,25 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10217,12 +10548,12 @@
 +    srcs = [
 +        "errorcode.go",
 +        "errorcode_string.go",
++        "objectpath.go",
 +        "types.go",
 +        "types_118.go",
 +    ],
 +    importpath = "golang.org/x/tools/internal/typesinternal",
 +    visibility = ["//:__subpackages__"],
-+    deps = ["//go/types/objectpath"],
 +)
 +
 +alias(
@@ -10236,7 +10567,7 @@
 +    srcs = ["errorcode_test.go"],
 +)
 diff -urN b/internal/xcontext/BUILD.bazel c/internal/xcontext/BUILD.bazel
---- b/internal/xcontext/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/internal/xcontext/BUILD.bazel	1970-01-01 08:00:00
 +++ c/internal/xcontext/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -10254,7 +10585,7 @@
 +    visibility = ["//:__subpackages__"],
 +)
 diff -urN b/playground/BUILD.bazel c/playground/BUILD.bazel
---- b/playground/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/playground/BUILD.bazel	1970-01-01 08:00:00
 +++ c/playground/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,14 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library")
@@ -10272,7 +10603,7 @@
 +    visibility = ["//visibility:public"],
 +)
 diff -urN b/playground/socket/BUILD.bazel c/playground/socket/BUILD.bazel
---- b/playground/socket/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/playground/socket/BUILD.bazel	1970-01-01 08:00:00
 +++ c/playground/socket/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,25 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10301,7 +10632,7 @@
 +    embed = [":socket"],
 +)
 diff -urN b/present/BUILD.bazel c/present/BUILD.bazel
---- b/present/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/present/BUILD.bazel	1970-01-01 08:00:00
 +++ c/present/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,44 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10345,11 +10676,11 @@
 +        "parse_test.go",
 +        "style_test.go",
 +    ],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    embed = [":present"],
 +)
 diff -urN b/refactor/eg/BUILD.bazel c/refactor/eg/BUILD.bazel
---- b/refactor/eg/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/refactor/eg/BUILD.bazel	1970-01-01 08:00:00
 +++ c/refactor/eg/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,93 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10375,7 +10706,7 @@
 +go_test(
 +    name = "eg_test",
 +    srcs = ["eg_test.go"],
-+    data = glob(["testdata/**"]),
++    data = glob(["testdata/**"], allow_empty = True),
 +    deps = select({
 +        "@io_bazel_rules_go//go/platform:aix": [
 +            ":eg",
@@ -10446,7 +10777,7 @@
 +    }),
 +)
 diff -urN b/refactor/importgraph/BUILD.bazel c/refactor/importgraph/BUILD.bazel
---- b/refactor/importgraph/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/refactor/importgraph/BUILD.bazel	1970-01-01 08:00:00
 +++ c/refactor/importgraph/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,75 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10525,7 +10856,7 @@
 +    }),
 +)
 diff -urN b/refactor/rename/BUILD.bazel c/refactor/rename/BUILD.bazel
---- b/refactor/rename/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/refactor/rename/BUILD.bazel	1970-01-01 08:00:00
 +++ c/refactor/rename/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,42 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10571,7 +10902,7 @@
 +    ],
 +)
 diff -urN b/refactor/satisfy/BUILD.bazel c/refactor/satisfy/BUILD.bazel
---- b/refactor/satisfy/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/refactor/satisfy/BUILD.bazel	1970-01-01 08:00:00
 +++ c/refactor/satisfy/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,28 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
@@ -10603,7 +10934,7 @@
 +    ],
 +)
 diff -urN b/txtar/BUILD.bazel c/txtar/BUILD.bazel
---- b/txtar/BUILD.bazel	1970-01-01 00:00:00.000000000 +0000
+--- b/txtar/BUILD.bazel	1970-01-01 08:00:00
 +++ c/txtar/BUILD.bazel	2000-01-01 00:00:00.000000000 -0000
 @@ -0,0 +1,20 @@
 +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")