[gopls-release-branch.0.6] all: merge master into gopls-release-branch.0.6

42984c42 internal/lsp/regtest: run one quick fix at a time in TestUnknownRevision
19b1717e go.mod: upgrade to Go 1.17
a1fbb681 all: upgrade go.mod files to Go 1.16
062bf4eb internal/lsp: make ShowDocument RPC available to gopls
3e17c62e internal/lsp: warn users who have built gopls with go-diff v1.2.0
def02638 gopls: clarify policy with respect to support for older Go versions
7a6108e9 internal/lsp: don't use ast.NewPackage to build builtin
edbe9bef internal/lsp/completion: indicate completion candidates that are deprecated
9b9633e0 internal/lsp/regtest: force GOPACKAGESDRIVER=off
291330a8 gopls/internal/regtest/modfile: set an explicit go version in the TestUnknownRevision modules
aec13729 gopls/internal/regtest: unskip tests for golang/go#37098
28c1392e internal/lsp: don't call PackagesForFile on builtin.go
800adbe2 go/packages: enable TestIssue37098 for Go 1.17 and later
16b25d25 internal/lsp: print comments that would be lost during extract func
7c72a848 go/analysis/passes/fieldalignment: clarify reported diagnostics in docs
9ff86487 internal/lsp: add support for extracting non-nested returns
d0768c91 internal/lsp/source/completion: suggest only valid package names
6397a116 internal/lsp/debug: splice in updated servers rather than overwrite
7b9993c5 internal/lsp/cmd: add a command-line command to start daemon debugging
fe1c5480 gopls/test: it is safe to ignore json unmarshalling errors
735ed62f gopls: tidy module
e3dc99f8 cmd/guru: update referrers-json testdata to reflect new line numbering
3f1e7240 cmd/guru: remove test assertions involving unsafe to fix the build
cf354b66 internal/lsp/cache: improve snapshot clone perfomance
7657be6e gopls/doc: fix broken link
7c93484b internal/lsp: add a command to start the debug server
716a04c6 lsp/completion: fix postfix completions preceding assignments
f74a6698 internal/lsp/cache: preallocate internal maps when cloning snapshots
e435455a internal/lsp: introduce MemoryMode
f7e8e244 internal/lsp: support Check For Upgrades in vendor mode
a8e7c0c9 internal/lsp: move gopls/internal/regtest ->  internal/lsp/regtest
f946a157 passes/sigchanyzer: allow valid inlined unbuffered signal channel
4934781c lsp/completion: offer candidates converting arrays to slices
b3e5b999 internal/lsp: update unsafe completion test for upcoming spec changes
e74674ae internal/lsp/protocol: latest version of LSP
dbc87476 internal/lsp/semantic: avoid doing semantic tokens for large files
a13dbf1a lsp/completion: omit deep completions into unimported package names
10909d8c internal/lsp/cache: remove type info trimming
1dce19db internal/lsp/cache: don't trim types.Info with staticcheck enabled
07295caa internal/lsp/cache: prune types.Info entries in slice literals
1a0c6081 internal/lsp/protocol/typescript: update documentation and generated code
fe503716 internal/lsp/source: fix Deref function for cyclic types
cb5dc85c internal/lsp/cache: add a scheme for types error code links
799b6824 gopls/internal/hooks: respect the default checks of the staticcheck tool
d1362d7a internal/lsp/source: fix an infinite loop in Deref function
59a2b45a internal/lsp/source: update process of hover signature creation for type declarations
2140ccea fix the argument of the goimports example
ec686a2a all: upgrade all dependencies except for go-diff
0243799c gopls/internal/coverage: apply gofmt to the build tag syntax
be791d07 internal/lsp/source: small fixes to directory filters

Change-Id: If0eb9499020d2baab77f05523197adb95044705f
diff --git a/cmd/guru/testdata/src/describe/main.go b/cmd/guru/testdata/src/describe/main.go
index dad321d..2e24396 100644
--- a/cmd/guru/testdata/src/describe/main.go
+++ b/cmd/guru/testdata/src/describe/main.go
@@ -10,7 +10,10 @@
 	"lib"
 	"nosuchpkg"            // @describe badimport1 "nosuchpkg"
 	nosuchpkg2 "nosuchpkg" // @describe badimport2 "nosuchpkg2"
-	_ "unsafe"             // @describe unsafe "unsafe"
+	// The unsafe package changed in Go 1.17 with the addition of
+	// unsafe.Add and unsafe.Slice. While we still support older versions
+	// of Go, the test case below cannot be enabled.
+	// _ "unsafe"             // @describe unsafe "unsafe"
 )
 
 var _ nosuchpkg.T
diff --git a/cmd/guru/testdata/src/describe/main.golden b/cmd/guru/testdata/src/describe/main.golden
index fe8c878..68de527 100644
--- a/cmd/guru/testdata/src/describe/main.golden
+++ b/cmd/guru/testdata/src/describe/main.golden
@@ -20,13 +20,6 @@
 -------- @describe badimport2 --------
 reference to package "nosuchpkg"
 
--------- @describe unsafe --------
-import of package "unsafe"
-	builtin Alignof 
-	builtin Offsetof
-	type  Pointer  unsafe.Pointer
-	builtin Sizeof  
-
 -------- @describe type-ref-builtin --------
 reference to built-in type float64
 
diff --git a/cmd/guru/testdata/src/referrers-json/main.golden b/cmd/guru/testdata/src/referrers-json/main.golden
index 0e5ff9c..9f8c931 100644
--- a/cmd/guru/testdata/src/referrers-json/main.golden
+++ b/cmd/guru/testdata/src/referrers-json/main.golden
@@ -43,7 +43,7 @@
 	"package": "describe",
 	"refs": [
 		{
-			"pos": "testdata/src/describe/main.go:92:8",
+			"pos": "testdata/src/describe/main.go:95:8",
 			"text": "\tvar _ lib.Outer // @describe lib-outer \"Outer\""
 		}
 	]
diff --git a/go.mod b/go.mod
index 2a972ec..e5c451a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,12 @@
 module golang.org/x/tools
 
-go 1.12
+go 1.17
 
 require (
-	github.com/yuin/goldmark v1.2.1
-	golang.org/x/mod v0.4.1
-	golang.org/x/net v0.0.0-20201021035429-f5854403a974
-	golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
-	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
+	github.com/yuin/goldmark v1.3.3
+	golang.org/x/mod v0.4.2
+	golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
+	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+	golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
 )
diff --git a/go.sum b/go.sum
index 3b8d9e4..7d8a0e7 100644
--- a/go.sum
+++ b/go.sum
@@ -1,22 +1,23 @@
-github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0=
+github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
-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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/go/analysis/passes/fieldalignment/fieldalignment.go b/go/analysis/passes/fieldalignment/fieldalignment.go
index ca7ceb2..78afe94 100644
--- a/go/analysis/passes/fieldalignment/fieldalignment.go
+++ b/go/analysis/passes/fieldalignment/fieldalignment.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package fieldalignment defines an Analyzer that detects structs that would take less
+// Package fieldalignment defines an Analyzer that detects structs that would use less
 // memory if their fields were sorted.
 package fieldalignment
 
@@ -20,10 +20,27 @@
 	"golang.org/x/tools/go/ast/inspector"
 )
 
-const Doc = `find structs that would take less memory if their fields were sorted
+const Doc = `find structs that would use less memory if their fields were sorted
 
-This analyzer find structs that can be rearranged to take less memory, and provides
+This analyzer find structs that can be rearranged to use less memory, and provides
 a suggested edit with the optimal order.
+
+Note that there are two different diagnostics reported. One checks struct size,
+and the other reports "pointer bytes" used. Pointer bytes is how many bytes of the
+object that the garbage collector has to potentially scan for pointers, for example:
+
+	struct { uint32; string }
+
+have 16 pointer bytes because the garbage collector has to scan up through the string's
+inner pointer.
+
+	struct { string; *uint32 }
+
+has 24 pointer bytes because it has to scan further through the *uint32.
+
+	struct { string; uint32 }
+
+has 8 because it can stop immediately after the string pointer.
 `
 
 var Analyzer = &analysis.Analyzer{
diff --git a/go/analysis/passes/sigchanyzer/sigchanyzer.go b/go/analysis/passes/sigchanyzer/sigchanyzer.go
index 3d89061..b00aa7e 100644
--- a/go/analysis/passes/sigchanyzer/sigchanyzer.go
+++ b/go/analysis/passes/sigchanyzer/sigchanyzer.go
@@ -49,6 +49,11 @@
 				chanDecl = decl
 			}
 		case *ast.CallExpr:
+			// Only signal.Notify(make(chan os.Signal), os.Interrupt) is safe,
+			// conservatively treate others as not safe, see golang/go#45043
+			if isBuiltinMake(pass.TypesInfo, arg) {
+				return
+			}
 			chanDecl = arg
 		}
 		if chanDecl == nil || len(chanDecl.Args) != 1 {
@@ -127,3 +132,16 @@
 	}
 	return nil
 }
+
+func isBuiltinMake(info *types.Info, call *ast.CallExpr) bool {
+	typVal := info.Types[call.Fun]
+	if !typVal.IsBuiltin() {
+		return false
+	}
+	switch fun := call.Fun.(type) {
+	case *ast.Ident:
+		return info.ObjectOf(fun).Name() == "make"
+	default:
+		return false
+	}
+}
diff --git a/go/analysis/passes/sigchanyzer/testdata/src/a/a.go b/go/analysis/passes/sigchanyzer/testdata/src/a/a.go
index 277bf20..34dee88 100644
--- a/go/analysis/passes/sigchanyzer/testdata/src/a/a.go
+++ b/go/analysis/passes/sigchanyzer/testdata/src/a/a.go
@@ -36,3 +36,19 @@
 	f := signal.Notify
 	f(c, os.Interrupt) // want "misuse of unbuffered os.Signal channel as argument to signal.Notify"
 }
+
+func k() {
+	signal.Notify(make(chan os.Signal), os.Interrupt) // ok
+}
+
+func l() {
+	signal.Notify(make(chan os.Signal, 1), os.Interrupt) // ok
+}
+
+func m() {
+	signal.Notify(make(chan ao.Signal, 1), os.Interrupt) // ok
+}
+
+func n() {
+	signal.Notify(make(chan ao.Signal), os.Interrupt) // ok
+}
diff --git a/go/analysis/passes/sigchanyzer/testdata/src/a/a.go.golden b/go/analysis/passes/sigchanyzer/testdata/src/a/a.go.golden
index e3702d7..1158ff5 100644
--- a/go/analysis/passes/sigchanyzer/testdata/src/a/a.go.golden
+++ b/go/analysis/passes/sigchanyzer/testdata/src/a/a.go.golden
@@ -36,3 +36,19 @@
 	f := signal.Notify
 	f(c, os.Interrupt) // want "misuse of unbuffered os.Signal channel as argument to signal.Notify"
 }
+
+func k() {
+	signal.Notify(make(chan os.Signal), os.Interrupt) // ok
+}
+
+func l() {
+	signal.Notify(make(chan os.Signal, 1), os.Interrupt) // ok
+}
+
+func m() {
+	signal.Notify(make(chan ao.Signal, 1), os.Interrupt) // ok
+}
+
+func n() {
+	signal.Notify(make(chan ao.Signal), os.Interrupt) // ok
+}
diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go
index 06b01f6..25866ec 100644
--- a/go/packages/packages_test.go
+++ b/go/packages/packages_test.go
@@ -2355,7 +2355,16 @@
 	// (*Package).CompiledGoFiles.  This tests #37098, where using SWIG to
 	// causes C++ sources to be inadvertently included in
 	// (*Package).CompiledGoFiles.
-	t.Skip("Issue #37098: SWIG causes generated C++ sources in CompiledGoFiles")
+
+	// This is fixed in Go 1.17, but not earlier.
+	testenv.NeedsGo1Point(t, 17)
+
+	if _, err := exec.LookPath("swig"); err != nil {
+		t.Skip("skipping test: swig not available")
+	}
+	if _, err := exec.LookPath("g++"); err != nil {
+		t.Skip("skipping test: g++ not available")
+	}
 
 	// Create a fake package with an empty Go source, and a SWIG interface
 	// file.
diff --git a/gopls/README.md b/gopls/README.md
index 18798e1..85de62a 100644
--- a/gopls/README.md
+++ b/gopls/README.md
@@ -72,11 +72,18 @@
 
 ## Supported Go versions and build systems
 
-`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. Though we
-try not to break older versions, we do not prioritize issues only affecting
-legacy Go releases.
+`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](golang.org/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.
+
+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.
 
 `gopls` currently only supports the `go` command, so if you are using a
 different build system, `gopls` will not work well. Bazel support is currently
diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md
index e067d0c..80ee65d 100644
--- a/gopls/doc/analyzers.md
+++ b/gopls/doc/analyzers.md
@@ -119,11 +119,28 @@
 
 ## **fieldalignment**
 
-find structs that would take less memory if their fields were sorted
+find structs that would use less memory if their fields were sorted
 
-This analyzer find structs that can be rearranged to take less memory, and provides
+This analyzer find structs that can be rearranged to use less memory, and provides
 a suggested edit with the optimal order.
 
+Note that there are two different diagnostics reported. One checks struct size,
+and the other reports "pointer bytes" used. Pointer bytes is how many bytes of the
+object that the garbage collector has to potentially scan for pointers, for example:
+
+	struct { uint32; string }
+
+have 16 pointer bytes because the garbage collector has to scan up through the string's
+inner pointer.
+
+	struct { string; *uint32 }
+
+has 24 pointer bytes because it has to scan further through the *uint32.
+
+	struct { string; uint32 }
+
+has 8 because it can stop immediately after the string pointer.
+
 
 **Disabled by default. Enable it by setting `"analyses": {"fieldalignment": true}`.**
 
diff --git a/gopls/doc/commands.md b/gopls/doc/commands.md
index c9cc41a..22ff379 100644
--- a/gopls/doc/commands.md
+++ b/gopls/doc/commands.md
@@ -199,6 +199,32 @@
 }
 ```
 
+### ****
+Identifier: `gopls.start_debugging`
+
+
+
+Args:
+
+```
+{
+	// 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,
+}
+```
+
 ### **Run test(s) (legacy)**
 Identifier: `gopls.test`
 
diff --git a/gopls/doc/contributing.md b/gopls/doc/contributing.md
index a99dc6e..8229eca 100644
--- a/gopls/doc/contributing.md
+++ b/gopls/doc/contributing.md
@@ -97,7 +97,15 @@
 to run gopls tests in various environments that would be difficult to add to
 the TryBots. Notably, Kokoro runs tests on
 [older Go versions](../README.md#supported-go-versions) that are no longer supported
-by the TryBots.
+by the TryBots. Per that that policy, support for these older Go versions is
+best-effort, and test failures may be skipped rather than fixed.
+
+Kokoro runs are triggered by the `Run-TryBot=1` label, just like TryBots, but
+unlike TryBots they do not automatically re-run if the "gopls-CI" result is
+removed in Gerrit. In order to force a new run, you must upload a new patch
+set. (Technically, Googlers can force a new run on an existing patch-set via an
+internal Kokoro dashboard, but unfortunately this ability can't be made more
+generally available).
 
 ## Debugging
 
diff --git a/gopls/doc/settings.md b/gopls/doc/settings.md
index f0e7314..963ef00 100644
--- a/gopls/doc/settings.md
+++ b/gopls/doc/settings.md
@@ -63,12 +63,33 @@
 The path prefix can be empty, so an initial `-` excludes everything.
 
 Examples:
+
 Exclude node_modules: `-node_modules`
+
 Include only project_a: `-` (exclude everything), `+project_a`
+
 Include only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`
 
 Default: `[]`.
 
+#### **memoryMode** *enum*
+
+**This setting is experimental and may be deleted.**
+
+memoryMode controls the tradeoff `gopls` makes between memory usage and
+correctness.
+
+Values other than `Normal` are untested and may break in surprising ways.
+
+Must be one of:
+
+* `"DegradeClosed"`: In DegradeClosed mode, `gopls` will collect less information about
+packages without open files. As a result, features like Find
+References and Rename will miss results in such packages.
+
+* `"Normal"`
+Default: `"Normal"`.
+
 #### **expandWorkspaceToModule** *bool*
 
 **This setting is experimental and may be deleted.**
diff --git a/gopls/doc/vim.md b/gopls/doc/vim.md
index 8a49a4d..4ee175d 100644
--- a/gopls/doc/vim.md
+++ b/gopls/doc/vim.md
@@ -164,7 +164,7 @@
 lua <<EOF
   -- …
 
-  function goimports(timeoutms)
+  function goimports(timeout_ms)
     local context = { source = { organizeImports = true } }
     vim.validate { context = { context, "t", true } }
 
diff --git a/gopls/doc/workspace.md b/gopls/doc/workspace.md
index ed30dae..821ba49 100644
--- a/gopls/doc/workspace.md
+++ b/gopls/doc/workspace.md
@@ -23,7 +23,7 @@
 will need to create a "workspace folder" for each module. This means that each
 module has its own scope, and features will not work across modules. We are
 currently working on addressing this limitation--see details about
-[experimental workspace module mode](#experimental-workspace-module-mode)
+[experimental workspace module mode](#workspace-module-experimental)
 below.
 
 In VS Code, you can create a workspace folder by setting up a
diff --git a/gopls/go.mod b/gopls/go.mod
index 27dfae1..62b9f6c 100644
--- a/gopls/go.mod
+++ b/gopls/go.mod
@@ -1,16 +1,18 @@
 module golang.org/x/tools/gopls
 
-go 1.12
+go 1.16
 
 require (
+	github.com/google/go-cmp v0.5.5
 	github.com/jba/templatecheck v0.5.0
-	github.com/sanity-io/litter v1.3.0
+	github.com/sanity-io/litter v1.5.0
 	github.com/sergi/go-diff v1.1.0
-	golang.org/x/mod v0.4.1
-	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
+	golang.org/x/mod v0.4.2
+	golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
 	golang.org/x/tools v0.1.1-0.20210408155258-593413344da1
-	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
 	honnef.co/go/tools v0.1.3
 	mvdan.cc/gofumpt v0.1.1
 	mvdan.cc/xurls/v2 v2.2.0
 )
+
+replace golang.org/x/tools => ../
diff --git a/gopls/go.sum b/gopls/go.sum
index 29e869d..9951230 100644
--- a/gopls/go.sum
+++ b/gopls/go.sum
@@ -4,68 +4,56 @@
 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/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/safehtml v0.0.2 h1:ZOt2VXg4x24bW0m2jtzAOkhoXV0iM8vNKc0paByCZqM=
 github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
 github.com/jba/templatecheck v0.5.0 h1:sZwNjXG3xNApuwKmgUWEo2JuxmG0sgNaELl0zwRQ9x8=
 github.com/jba/templatecheck v0.5.0/go.mod h1:/1k7EajoSErFI9GLHAsiIJEaNLt3ALKNw2TV7z2SYv4=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 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.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/sanity-io/litter v1.3.0 h1:5ZO+weUsqdSWMUng5JnpkW/Oz8iTXiIdeumhQr1sSjs=
-github.com/sanity-io/litter v1.3.0/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
+github.com/sanity-io/litter v1.5.0 h1:cHM1wTJiOETY9LKRPd3tqUHGquaBaTteD1tZFesEoi8=
+github.com/sanity-io/litter v1.5.0/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
 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 v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.1 h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=
-golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.1.1-0.20210408155258-593413344da1 h1:B+9Jhwu5uM+kDMAkoQH6IUoIoS48VbRqwLyceNdpRK8=
-golang.org/x/tools v0.1.1-0.20210408155258-593413344da1/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
-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=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 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=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/gopls/internal/hooks/analysis.go b/gopls/internal/hooks/analysis.go
index 23d4ab6..04c97e1 100644
--- a/gopls/internal/hooks/analysis.go
+++ b/gopls/internal/hooks/analysis.go
@@ -10,33 +10,31 @@
 import (
 	"golang.org/x/tools/go/analysis"
 	"golang.org/x/tools/internal/lsp/source"
+	"honnef.co/go/tools/analysis/lint"
 	"honnef.co/go/tools/simple"
 	"honnef.co/go/tools/staticcheck"
 	"honnef.co/go/tools/stylecheck"
 )
 
 func updateAnalyzers(options *source.Options) {
-	var analyzers []*analysis.Analyzer
-	for _, a := range simple.Analyzers {
-		analyzers = append(analyzers, a)
-	}
-	for _, a := range staticcheck.Analyzers {
-		switch a.Name {
-		case "SA5009":
-			// This check conflicts with the vet printf check (golang/go#34494).
-		case "SA5011":
-			// This check relies on facts from dependencies, which
-			// we don't currently compute.
-		default:
-			analyzers = append(analyzers, a)
+	add := func(analyzers map[string]*analysis.Analyzer, docs map[string]*lint.Documentation, skip map[string]struct{}) {
+		for check, a := range analyzers {
+			if _, ok := skip[check]; ok {
+				continue
+			}
+
+			enabled := !docs[check].NonDefault
+			options.AddStaticcheckAnalyzer(a, enabled)
 		}
 	}
-	for _, a := range stylecheck.Analyzers {
-		analyzers = append(analyzers, a)
-	}
-	// Always add hooks for all available analyzers, but disable them if the
-	// user does not have staticcheck enabled (they may enable it later on).
-	for _, a := range analyzers {
-		options.AddStaticcheckAnalyzer(a)
-	}
+
+	add(simple.Analyzers, simple.Docs, nil)
+	add(staticcheck.Analyzers, staticcheck.Docs, map[string]struct{}{
+		// This check conflicts with the vet printf check (golang/go#34494).
+		"SA5009": {},
+		// This check relies on facts from dependencies, which
+		// we don't currently compute.
+		"SA5011": {},
+	})
+	add(stylecheck.Analyzers, stylecheck.Docs, nil)
 }
diff --git a/gopls/internal/regtest/bench/bench_test.go b/gopls/internal/regtest/bench/bench_test.go
index 1702e84..14e6e4d 100644
--- a/gopls/internal/regtest/bench/bench_test.go
+++ b/gopls/internal/regtest/bench/bench_test.go
@@ -9,13 +9,14 @@
 	"fmt"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 func printBenchmarkResults(result testing.BenchmarkResult) {
diff --git a/gopls/internal/regtest/bench/completion_bench_test.go b/gopls/internal/regtest/bench/completion_bench_test.go
index be36d45..c677339 100644
--- a/gopls/internal/regtest/bench/completion_bench_test.go
+++ b/gopls/internal/regtest/bench/completion_bench_test.go
@@ -11,7 +11,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/fake"
 )
diff --git a/gopls/internal/regtest/bench/stress_test.go b/gopls/internal/regtest/bench/stress_test.go
index 8cdbcfe..88ecbaf 100644
--- a/gopls/internal/regtest/bench/stress_test.go
+++ b/gopls/internal/regtest/bench/stress_test.go
@@ -11,7 +11,7 @@
 	"testing"
 	"time"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 // Pilosa is a repository that has historically caused significant memory
diff --git a/gopls/internal/regtest/codelens/codelens_test.go b/gopls/internal/regtest/codelens/codelens_test.go
index 87d0863..fe351ea 100644
--- a/gopls/internal/regtest/codelens/codelens_test.go
+++ b/gopls/internal/regtest/codelens/codelens_test.go
@@ -5,12 +5,14 @@
 package codelens
 
 import (
+	"fmt"
 	"runtime"
 	"strings"
 	"testing"
 	"time"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/command"
 	"golang.org/x/tools/internal/lsp/fake"
@@ -20,7 +22,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 func TestDisablingCodeLens(t *testing.T) {
@@ -102,7 +104,7 @@
 -- go.mod --
 module mod.com
 
-go 1.12
+go 1.14
 
 require golang.org/x/hello v1.2.3
 -- go.sum --
@@ -120,7 +122,7 @@
 
 	const wantGoMod = `module mod.com
 
-go 1.12
+go 1.14
 
 require golang.org/x/hello v1.3.3
 `
@@ -158,20 +160,25 @@
 			})
 		})
 	}
-	t.Run("Upgrade individual dependency", func(t *testing.T) {
-		WithOptions(ProxyFiles(proxyWithLatest)).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
-			env.OpenFile("go.mod")
-			env.ExecuteCodeLensCommand("go.mod", command.CheckUpgrades)
-			d := &protocol.PublishDiagnosticsParams{}
-			env.Await(OnceMet(env.DiagnosticAtRegexpWithMessage("go.mod", `require`, "can be upgraded"),
-				ReadDiagnostics("go.mod", d)))
-			env.ApplyQuickFixes("go.mod", d.Diagnostics)
-			env.Await(env.DoneWithChangeWatchedFiles())
-			if got := env.Editor.BufferText("go.mod"); got != wantGoMod {
-				t.Fatalf("go.mod upgrade failed:\n%s", tests.Diff(t, wantGoMod, got))
-			}
+	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) {
+				if vendoring {
+					env.RunGoCommand("mod", "vendor")
+				}
+				env.OpenFile("go.mod")
+				env.ExecuteCodeLensCommand("go.mod", command.CheckUpgrades)
+				d := &protocol.PublishDiagnosticsParams{}
+				env.Await(OnceMet(env.DiagnosticAtRegexpWithMessage("go.mod", `require`, "can be upgraded"),
+					ReadDiagnostics("go.mod", d)))
+				env.ApplyQuickFixes("go.mod", d.Diagnostics)
+				env.Await(env.DoneWithChangeWatchedFiles())
+				if got := env.Editor.BufferText("go.mod"); got != wantGoMod {
+					t.Fatalf("go.mod upgrade failed:\n%s", tests.Diff(t, wantGoMod, got))
+				}
+			})
 		})
-	})
+	}
 }
 
 func TestUnusedDependenciesCodelens(t *testing.T) {
diff --git a/gopls/internal/regtest/completion/completion_test.go b/gopls/internal/regtest/completion/completion_test.go
index 6e89c4f..d57a4b2 100644
--- a/gopls/internal/regtest/completion/completion_test.go
+++ b/gopls/internal/regtest/completion/completion_test.go
@@ -9,7 +9,8 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/fake"
 	"golang.org/x/tools/internal/lsp/protocol"
@@ -17,7 +18,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 const proxy = `
@@ -69,6 +70,11 @@
 
 -- fruits/testfile3.go --
 pac
+-- 123f_r.u~its-123/testfile.go --
+package
+
+-- .invalid-dir@-name/testfile.go --
+package
 `
 	var (
 		testfile4 = ""
@@ -146,6 +152,21 @@
 			want:          []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
 			editRegexp:    `\*\/\n()`,
 		},
+		// Issue golang/go#44680
+		{
+			name:          "package completion for dir name with punctuation",
+			filename:      "123f_r.u~its-123/testfile.go",
+			triggerRegexp: "package()",
+			want:          []string{"package fruits123", "package fruits123_test", "package main"},
+			editRegexp:    "package\n",
+		},
+		{
+			name:          "package completion for invalid dir name",
+			filename:      ".invalid-dir@-name/testfile.go",
+			triggerRegexp: "package()",
+			want:          []string{"package main"},
+			editRegexp:    "package\n",
+		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
 			Run(t, files, func(t *testing.T, env *Env) {
@@ -374,3 +395,111 @@
 		}
 	})
 }
+
+func TestCompletion_Issue45510(t *testing.T) {
+	const files = `
+-- go.mod --
+module mod.com
+
+go 1.12
+-- main.go --
+package main
+
+func _() {
+	type a *a
+	var aaaa1, aaaa2 a
+	var _ a = aaaa
+
+	type b a
+	var bbbb1, bbbb2 b
+	var _ b = bbbb
+}
+
+type (
+	c *d
+	d *e
+	e **c
+)
+
+func _() {
+	var (
+		xxxxc c
+		xxxxd d
+		xxxxe e
+	)
+
+	var _ c = xxxx
+	var _ d = xxxx
+	var _ e = xxxx
+}
+`
+
+	Run(t, files, func(t *testing.T, env *Env) {
+		env.OpenFile("main.go")
+
+		tests := []struct {
+			re   string
+			want []string
+		}{
+			{`var _ a = aaaa()`, []string{"aaaa1", "aaaa2"}},
+			{`var _ b = bbbb()`, []string{"bbbb1", "bbbb2"}},
+			{`var _ c = xxxx()`, []string{"***xxxxd", "**xxxxe", "xxxxc"}},
+			{`var _ d = xxxx()`, []string{"***xxxxe", "*xxxxc", "xxxxd"}},
+			{`var _ e = xxxx()`, []string{"**xxxxc", "*xxxxd", "xxxxe"}},
+		}
+		for _, tt := range tests {
+			completions := env.Completion("main.go", env.RegexpSearch("main.go", tt.re))
+			diff := compareCompletionResults(tt.want, completions.Items)
+			if diff != "" {
+				t.Errorf("%s: %s", tt.re, diff)
+			}
+		}
+	})
+}
+
+func TestCompletionDeprecation(t *testing.T) {
+	const files = `
+-- go.mod --
+module test.com
+
+go 1.16
+-- prog.go --
+package waste
+// Deprecated, use newFoof
+func fooFunc() bool {
+	return false
+}
+
+// Deprecated
+const badPi = 3.14
+
+func doit() {
+	if fooF
+	panic()
+	x := badP
+}
+`
+	Run(t, files, func(t *testing.T, env *Env) {
+		env.OpenFile("prog.go")
+		pos := env.RegexpSearch("prog.go", "if fooF")
+		pos.Column += len("if fooF")
+		completions := env.Completion("prog.go", pos)
+		diff := compareCompletionResults([]string{"fooFunc"}, completions.Items)
+		if diff != "" {
+			t.Error(diff)
+		}
+		if completions.Items[0].Tags == nil {
+			t.Errorf("expected Tags to show deprecation %#v", diff[0])
+		}
+		pos = env.RegexpSearch("prog.go", "= badP")
+		pos.Column += len("= badP")
+		completions = env.Completion("prog.go", pos)
+		diff = compareCompletionResults([]string{"badPi"}, completions.Items)
+		if diff != "" {
+			t.Error(diff)
+		}
+		if completions.Items[0].Tags == nil {
+			t.Errorf("expected Tags to show deprecation %#v", diff[0])
+		}
+	})
+}
diff --git a/gopls/internal/regtest/completion/postfix_snippet_test.go b/gopls/internal/regtest/completion/postfix_snippet_test.go
index 4c59ef9..1f5b7cf 100644
--- a/gopls/internal/regtest/completion/postfix_snippet_test.go
+++ b/gopls/internal/regtest/completion/postfix_snippet_test.go
@@ -8,7 +8,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 	"golang.org/x/tools/internal/lsp/source"
 )
 
diff --git a/gopls/internal/regtest/diagnostics/builtin_test.go b/gopls/internal/regtest/diagnostics/builtin_test.go
new file mode 100644
index 0000000..775e7ec
--- /dev/null
+++ b/gopls/internal/regtest/diagnostics/builtin_test.go
@@ -0,0 +1,38 @@
+// 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.
+
+package diagnostics
+
+import (
+	"strings"
+	"testing"
+
+	. "golang.org/x/tools/internal/lsp/regtest"
+)
+
+func TestIssue44866(t *testing.T) {
+	src := `
+-- go.mod --
+module mod.com
+
+go 1.12
+-- a.go --
+package a
+
+const (
+	c = iota
+)
+`
+	Run(t, src, func(t *testing.T, env *Env) {
+		env.OpenFile("a.go")
+		name, _ := env.GoToDefinition("a.go", env.RegexpSearch("a.go", "iota"))
+		if !strings.HasSuffix(name, "builtin.go") {
+			t.Fatalf("jumped to %q, want builtin.go", name)
+		}
+		env.Await(OnceMet(
+			env.DoneWithOpen(),
+			NoDiagnostics("builtin.go"),
+		))
+	})
+}
diff --git a/gopls/internal/regtest/diagnostics/diagnostics_test.go b/gopls/internal/regtest/diagnostics/diagnostics_test.go
index 3a4beee..5ab4f5f 100644
--- a/gopls/internal/regtest/diagnostics/diagnostics_test.go
+++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go
@@ -8,9 +8,11 @@
 	"context"
 	"fmt"
 	"log"
+	"os/exec"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp"
 	"golang.org/x/tools/internal/lsp/fake"
@@ -19,7 +21,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 // Use mod.com for all go.mod files due to golang/go#35230.
@@ -1380,7 +1382,15 @@
 }
 
 func TestSwig(t *testing.T) {
-	t.Skipf("skipped until golang/go#37098 is resolved")
+	// This is fixed in Go 1.17, but not earlier.
+	testenv.NeedsGo1Point(t, 17)
+
+	if _, err := exec.LookPath("swig"); err != nil {
+		t.Skip("skipping test: swig not available")
+	}
+	if _, err := exec.LookPath("g++"); err != nil {
+		t.Skip("skipping test: g++ not available")
+	}
 
 	const mod = `
 -- go.mod --
diff --git a/gopls/internal/regtest/misc/configuration_test.go b/gopls/internal/regtest/misc/configuration_test.go
index 2aa2f14..17116ad 100644
--- a/gopls/internal/regtest/misc/configuration_test.go
+++ b/gopls/internal/regtest/misc/configuration_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/fake"
 	"golang.org/x/tools/internal/testenv"
@@ -27,8 +27,10 @@
 -- a/a.go --
 package a
 
-// NotThisVariable should really start with ThisVariable.
-const ThisVariable = 7
+import "errors"
+
+// FooErr should be called ErrFoo (ST1012)
+var FooErr = errors.New("foo")
 `
 	Run(t, files, func(t *testing.T, env *Env) {
 		env.OpenFile("a/a.go")
@@ -41,7 +43,7 @@
 		cfg.EnableStaticcheck = true
 		env.ChangeConfiguration(t, cfg)
 		env.Await(
-			DiagnosticAt("a/a.go", 2, 0),
+			DiagnosticAt("a/a.go", 5, 4),
 		)
 	})
 }
diff --git a/gopls/internal/regtest/misc/debugserver_test.go b/gopls/internal/regtest/misc/debugserver_test.go
new file mode 100644
index 0000000..88cfded
--- /dev/null
+++ b/gopls/internal/regtest/misc/debugserver_test.go
@@ -0,0 +1,45 @@
+// 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.
+package misc
+
+import (
+	"net/http"
+	"testing"
+
+	"golang.org/x/tools/internal/lsp/command"
+	"golang.org/x/tools/internal/lsp/protocol"
+
+	. "golang.org/x/tools/internal/lsp/regtest"
+)
+
+func TestStartDebugging(t *testing.T) {
+	WithOptions(
+		Modes(Forwarded),
+	).Run(t, "", func(t *testing.T, env *Env) {
+		args, err := command.MarshalArgs(command.DebuggingArgs{})
+		if err != nil {
+			t.Fatal(err)
+		}
+		params := &protocol.ExecuteCommandParams{
+			Command:   command.StartDebugging.ID(),
+			Arguments: args,
+		}
+		var result command.DebuggingResult
+		env.ExecuteCommand(params, &result)
+		if got, want := len(result.URLs), 2; got != want {
+			t.Fatalf("got %d urls, want %d; urls: %#v", got, want, result.URLs)
+		}
+		for i, u := range result.URLs {
+			resp, err := http.Get(u)
+			if err != nil {
+				t.Errorf("getting url #%d (%q): %v", i, u, err)
+				continue
+			}
+			defer resp.Body.Close()
+			if got, want := resp.StatusCode, http.StatusOK; got != want {
+				t.Errorf("debug server #%d returned HTTP %d, want %d", i, got, want)
+			}
+		}
+	})
+}
diff --git a/gopls/internal/regtest/misc/definition_test.go b/gopls/internal/regtest/misc/definition_test.go
index 48b7617..970658c 100644
--- a/gopls/internal/regtest/misc/definition_test.go
+++ b/gopls/internal/regtest/misc/definition_test.go
@@ -9,7 +9,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/fake"
 	"golang.org/x/tools/internal/lsp/tests"
diff --git a/gopls/internal/regtest/misc/embed_test.go b/gopls/internal/regtest/misc/embed_test.go
index 76d1225..8fb654b 100644
--- a/gopls/internal/regtest/misc/embed_test.go
+++ b/gopls/internal/regtest/misc/embed_test.go
@@ -6,7 +6,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 	"golang.org/x/tools/internal/testenv"
 )
 
diff --git a/gopls/internal/regtest/misc/failures_test.go b/gopls/internal/regtest/misc/failures_test.go
index 41a833e..23fccfd 100644
--- a/gopls/internal/regtest/misc/failures_test.go
+++ b/gopls/internal/regtest/misc/failures_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 // This test passes (TestHoverOnError in definition_test.go) without
diff --git a/gopls/internal/regtest/misc/fix_test.go b/gopls/internal/regtest/misc/fix_test.go
index 9225a83..8c5662a 100644
--- a/gopls/internal/regtest/misc/fix_test.go
+++ b/gopls/internal/regtest/misc/fix_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/tests"
diff --git a/gopls/internal/regtest/misc/formatting_test.go b/gopls/internal/regtest/misc/formatting_test.go
index 0ad5fbb..52d89e4 100644
--- a/gopls/internal/regtest/misc/formatting_test.go
+++ b/gopls/internal/regtest/misc/formatting_test.go
@@ -8,7 +8,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/tests"
 )
diff --git a/gopls/internal/regtest/misc/generate_test.go b/gopls/internal/regtest/misc/generate_test.go
index a7631d9..6904fe0 100644
--- a/gopls/internal/regtest/misc/generate_test.go
+++ b/gopls/internal/regtest/misc/generate_test.go
@@ -12,7 +12,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 func TestGenerateProgress(t *testing.T) {
diff --git a/gopls/internal/regtest/misc/highlight_test.go b/gopls/internal/regtest/misc/highlight_test.go
index 56e6116..affbffd 100644
--- a/gopls/internal/regtest/misc/highlight_test.go
+++ b/gopls/internal/regtest/misc/highlight_test.go
@@ -8,9 +8,9 @@
 	"sort"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
 	"golang.org/x/tools/internal/lsp/fake"
 	"golang.org/x/tools/internal/lsp/protocol"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 func TestWorkspacePackageHighlight(t *testing.T) {
diff --git a/gopls/internal/regtest/misc/imports_test.go b/gopls/internal/regtest/misc/imports_test.go
index 2a666c4..4ae2be6 100644
--- a/gopls/internal/regtest/misc/imports_test.go
+++ b/gopls/internal/regtest/misc/imports_test.go
@@ -11,7 +11,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/testenv"
diff --git a/gopls/internal/regtest/misc/link_test.go b/gopls/internal/regtest/misc/link_test.go
index 320a3ea..daea742 100644
--- a/gopls/internal/regtest/misc/link_test.go
+++ b/gopls/internal/regtest/misc/link_test.go
@@ -8,7 +8,7 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/testenv"
 )
diff --git a/gopls/internal/regtest/misc/misc_test.go b/gopls/internal/regtest/misc/misc_test.go
index 0f42470..3694b07 100644
--- a/gopls/internal/regtest/misc/misc_test.go
+++ b/gopls/internal/regtest/misc/misc_test.go
@@ -7,9 +7,10 @@
 import (
 	"testing"
 
-	"golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	"golang.org/x/tools/internal/lsp/regtest"
 )
 
 func TestMain(m *testing.M) {
-	regtest.Main(m)
+	regtest.Main(m, hooks.Options)
 }
diff --git a/gopls/internal/regtest/misc/references_test.go b/gopls/internal/regtest/misc/references_test.go
index 9327636..f3a23e4 100644
--- a/gopls/internal/regtest/misc/references_test.go
+++ b/gopls/internal/regtest/misc/references_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 func TestStdlibReferences(t *testing.T) {
diff --git a/gopls/internal/regtest/misc/shared_test.go b/gopls/internal/regtest/misc/shared_test.go
index 376d378..129a5ff 100644
--- a/gopls/internal/regtest/misc/shared_test.go
+++ b/gopls/internal/regtest/misc/shared_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 )
 
 const sharedProgram = `
diff --git a/gopls/internal/regtest/misc/vendor_test.go b/gopls/internal/regtest/misc/vendor_test.go
index 1c9a4ec..4e02799 100644
--- a/gopls/internal/regtest/misc/vendor_test.go
+++ b/gopls/internal/regtest/misc/vendor_test.go
@@ -7,7 +7,7 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/testenv"
diff --git a/gopls/internal/regtest/modfile/modfile_test.go b/gopls/internal/regtest/modfile/modfile_test.go
index 33b65fe..6c94bfb 100644
--- a/gopls/internal/regtest/modfile/modfile_test.go
+++ b/gopls/internal/regtest/modfile/modfile_test.go
@@ -9,7 +9,8 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/tests"
@@ -17,7 +18,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 const workspaceProxy = `
@@ -553,8 +554,12 @@
 					ReadDiagnostics("a/go.mod", &d),
 				),
 			)
-			env.ApplyQuickFixes("a/go.mod", d.Diagnostics)
-			env.SaveBuffer("a/go.mod") // Save to trigger diagnostics.
+			qfs := env.GetQuickFixes("a/go.mod", d.Diagnostics)
+			if len(qfs) == 0 {
+				t.Fatalf("got 0 code actions to fix %v, wanted at least 1", d.Diagnostics)
+			}
+			env.ApplyCodeAction(qfs[0]) // Arbitrarily pick a single fix to apply. Applying all of them seems to cause trouble in this particular test.
+			env.SaveBuffer("a/go.mod")  // Save to trigger diagnostics.
 			env.Await(
 				EmptyDiagnostics("a/go.mod"),
 				env.DiagnosticAtRegexp("a/main.go", "x = "),
diff --git a/gopls/internal/regtest/watch/watch_test.go b/gopls/internal/regtest/watch/watch_test.go
index 9cc9d0a..82a5933 100644
--- a/gopls/internal/regtest/watch/watch_test.go
+++ b/gopls/internal/regtest/watch/watch_test.go
@@ -7,7 +7,8 @@
 import (
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/fake"
 	"golang.org/x/tools/internal/lsp/protocol"
@@ -15,7 +16,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 func TestEditFile(t *testing.T) {
diff --git a/gopls/internal/regtest/workspace/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go
index 21e33b6..09efce3 100644
--- a/gopls/internal/regtest/workspace/workspace_test.go
+++ b/gopls/internal/regtest/workspace/workspace_test.go
@@ -12,7 +12,8 @@
 	"strings"
 	"testing"
 
-	. "golang.org/x/tools/gopls/internal/regtest"
+	"golang.org/x/tools/gopls/internal/hooks"
+	. "golang.org/x/tools/internal/lsp/regtest"
 
 	"golang.org/x/tools/internal/lsp/command"
 	"golang.org/x/tools/internal/lsp/fake"
@@ -21,7 +22,7 @@
 )
 
 func TestMain(m *testing.M) {
-	Main(m)
+	Main(m, hooks.Options)
 }
 
 const workspaceProxy = `
diff --git a/gopls/test/json_test.go b/gopls/test/json_test.go
new file mode 100644
index 0000000..5ea5b34
--- /dev/null
+++ b/gopls/test/json_test.go
@@ -0,0 +1,134 @@
+// 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.
+
+package gopls_test
+
+import (
+	"encoding/json"
+	"fmt"
+	"regexp"
+	"strings"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"golang.org/x/tools/internal/lsp/protocol"
+)
+
+// verify that type errors in Initialize lsp messages don't cause
+// any other unmarshalling errors. The code looks at single values and the
+// first component of array values. Each occurrence is replaced by something
+// of a different type,  the resulting string unmarshalled, and compared to
+// the unmarshalling of the unchanged strings. The test passes if there is no
+// more than a single difference reported. That is, if changing a single value
+// in the message changes no more than a single value in the unmarshalled struct,
+// it is safe to ignore *json.UnmarshalTypeError.
+
+// strings are changed to numbers or bools (true)
+// bools are changed to numbers or strings
+// numbers are changed to strings or bools
+
+// a recent Initialize message taken from a log
+const input = `{"processId":38349,"clientInfo":{"name":"vscode","version":"1.56.0-insider"},"rootPath":"/Users/pjw/latest/tools","rootUri":"file:///Users/pjw/latest/tools","capabilities":{"workspace":{"applyEdit":true,"workspaceEdit":{"documentChanges":true,"resourceOperations":["create","rename","delete"],"failureHandling":"textOnlyTransactional"},"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true},"symbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"tagSupport":{"valueSet":[1]}},"executeCommand":{"dynamicRegistration":true},"configuration":true,"workspaceFolders":true,"semanticTokens":{"refreshSupport":true}},"textDocument":{"publishDiagnostics":{"relatedInformation":true,"versionSupport":false,"tagSupport":{"valueSet":[1,2]},"codeDescriptionSupport":true,"dataSupport":true},"synchronization":{"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":true,"contextSupport":true,"completionItem":{"snippetSupport":true,"commitCharactersSupport":true,"documentationFormat":["markdown","plaintext"],"deprecatedSupport":true,"preselectSupport":true,"tagSupport":{"valueSet":[1]},"insertReplaceSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]}},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]}},"hover":{"dynamicRegistration":true,"contentFormat":["markdown","plaintext"]},"signatureHelp":{"dynamicRegistration":true,"signatureInformation":{"documentationFormat":["markdown","plaintext"],"parameterInformation":{"labelOffsetSupport":true},"activeParameterSupport":true},"contextSupport":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"references":{"dynamicRegistration":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]},"hierarchicalDocumentSymbolSupport":true,"tagSupport":{"valueSet":[1]},"labelSupport":true},"codeAction":{"dynamicRegistration":true,"isPreferredSupport":true,"disabledSupport":true,"dataSupport":true,"resolveSupport":{"properties":["edit"]},"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}}},"codeLens":{"dynamicRegistration":true},"formatting":{"dynamicRegistration":true},"rangeFormatting":{"dynamicRegistration":true},"onTypeFormatting":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true,"prepareSupportDefaultBehavior":true},"documentLink":{"dynamicRegistration":true,"tooltipSupport":true},"typeDefinition":{"dynamicRegistration":true,"linkSupport":true},"implementation":{"dynamicRegistration":true,"linkSupport":true},"colorProvider":{"dynamicRegistration":true},"foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true},"declaration":{"dynamicRegistration":true,"linkSupport":true},"selectionRange":{"dynamicRegistration":true},"callHierarchy":{"dynamicRegistration":true},"semanticTokens":{"dynamicRegistration":true,"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","member","macro","keyword","modifier","comment","string","number","regexp","operator"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"],"formats":["relative"],"requests":{"range":true,"full":{"delta":true}}}},"window":{"workDoneProgress":true}},"initializationOptions":{"usePlaceholders":true,"completionDocumentation":true,"verboseOutput":false,"codelenses":{"gc_details":true},"analyses":{"fillstruct":true,"staticcheck":true},"experimentalWorkspaceModule":true,"semanticTokens":true},"trace":"off","workspaceFolders":[{"uri":"file:///Users/pjw/latest/tools","name":"tools"}]}`
+
+type DiffReporter struct {
+	path  cmp.Path
+	diffs []string
+}
+
+func (r *DiffReporter) PushStep(ps cmp.PathStep) {
+	r.path = append(r.path, ps)
+}
+
+func (r *DiffReporter) Report(rs cmp.Result) {
+	if !rs.Equal() {
+		vx, vy := r.path.Last().Values()
+		r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy))
+	}
+}
+
+func (r *DiffReporter) PopStep() {
+	r.path = r.path[:len(r.path)-1]
+}
+
+func (r *DiffReporter) String() string {
+	return strings.Join(r.diffs, "\n")
+}
+
+func TestStringChanges(t *testing.T) {
+	// string as value
+	stringLeaf := regexp.MustCompile(`:("[^"]*")`)
+	leafs := stringLeaf.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, leafs, "23", "true")
+	// string as first element of array
+	stringArray := regexp.MustCompile(`[[]("[^"]*")`)
+	arrays := stringArray.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, arrays, "23", "true")
+}
+
+func TestBoolChanges(t *testing.T) {
+	boolLeaf := regexp.MustCompile(`:(true|false)(,|})`)
+	leafs := boolLeaf.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, leafs, "23", `"xx"`)
+	boolArray := regexp.MustCompile(`:[[](true|false)(,|])`)
+	arrays := boolArray.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, arrays, "23", `"xx"`)
+}
+
+func TestNumberChanges(t *testing.T) {
+	numLeaf := regexp.MustCompile(`:(\d+)(,|})`)
+	leafs := numLeaf.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, leafs, "true", `"xx"`)
+	numArray := regexp.MustCompile(`:[[](\d+)(,|])`)
+	arrays := numArray.FindAllStringSubmatchIndex(input, -1)
+	allDeltas(t, arrays, "true", `"xx"`)
+}
+
+// v is a set of matches. check that substituting any repl never
+// creates more than 1 unmarshaling error
+func allDeltas(t *testing.T, v [][]int, repls ...string) {
+	t.Helper()
+	for _, repl := range repls {
+		for i, x := range v {
+			err := tryChange(x[2], x[3], repl)
+			if err != nil {
+				t.Errorf("%d:%q %v", i, input[x[2]:x[3]], err)
+			}
+		}
+	}
+}
+
+func tryChange(start, end int, repl string) error {
+	var p, q protocol.InitializeParams
+	mod := input[:start] + repl + input[end:]
+	excerpt := func() (string, string) {
+		a := start - 5
+		if a < 0 {
+			a = 0
+		}
+		b := end + 5
+		if b > len(input) {
+			// trusting repl to be no longer than what it replaces
+			b = len(input)
+		}
+		ma := input[a:b]
+		mb := mod[a:b]
+		return ma, mb
+	}
+	if err := json.Unmarshal([]byte(input), &p); err != nil {
+		return fmt.Errorf("%s %v", repl, err)
+	}
+	if err := json.Unmarshal([]byte(mod), &q); err == nil {
+		return nil // no errors is ok
+	} else if _, ok := err.(*json.UnmarshalTypeError); !ok {
+		return fmt.Errorf("%T, not *json.UnmarshalTypeError", err)
+	}
+
+	var r DiffReporter
+	cmp.Diff(p, q, cmp.Reporter(&r))
+	if len(r.diffs) > 1 { // 0 is possible, e.g., for interface{}
+		ma, mb := excerpt()
+		return fmt.Errorf("got %d diffs for %q\n%s\n%s", len(r.diffs), repl, ma, mb)
+	}
+	return nil
+}
diff --git a/internal/lsp/analysis/unusedparams/unusedparams.go b/internal/lsp/analysis/unusedparams/unusedparams.go
index f79d25a..e6f2274 100644
--- a/internal/lsp/analysis/unusedparams/unusedparams.go
+++ b/internal/lsp/analysis/unusedparams/unusedparams.go
@@ -70,7 +70,7 @@
 			fieldList, body = f.Type.Params, f.Body
 		}
 		// If there are no arguments or the function is empty, then return.
-		if fieldList.NumFields() == 0 || len(body.List) == 0 {
+		if fieldList.NumFields() == 0 || body == nil || len(body.List) == 0 {
 			return
 		}
 
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index 65c3371..50f75c0 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -187,11 +187,27 @@
 }
 
 func (s *snapshot) workspaceParseMode(id packageID) source.ParseMode {
-	if _, ws := s.isWorkspacePackage(id); ws {
-		return source.ParseFull
-	} else {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	_, ws := s.workspacePackages[id]
+	if !ws {
 		return source.ParseExported
 	}
+	if s.view.Options().MemoryMode == source.ModeNormal {
+		return source.ParseFull
+	}
+
+	// Degraded mode. Check for open files.
+	m, ok := s.metadata[id]
+	if !ok {
+		return source.ParseExported
+	}
+	for _, cgf := range m.compiledGoFiles {
+		if s.isOpenLocked(cgf) {
+			return source.ParseFull
+		}
+	}
+	return source.ParseExported
 }
 
 func checkPackageKey(id packageID, pghs []*parseGoHandle, cfg *packages.Config, deps []packageHandleKey, mode source.ParseMode, experimentalKey bool) packageHandleKey {
@@ -547,7 +563,7 @@
 		}
 
 		directImporter := depsError.ImportStack[directImporterIdx]
-		if _, ok := s.isWorkspacePackage(packageID(directImporter)); ok {
+		if s.isWorkspacePackage(packageID(directImporter)) {
 			continue
 		}
 		relevantErrors = append(relevantErrors, depsError)
@@ -582,7 +598,7 @@
 	for _, depErr := range relevantErrors {
 		for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
 			item := depErr.ImportStack[i]
-			if _, ok := s.isWorkspacePackage(packageID(item)); ok {
+			if s.isWorkspacePackage(packageID(item)) {
 				break
 			}
 
diff --git a/internal/lsp/cache/errors.go b/internal/lsp/cache/errors.go
index 9d109de..42fafae 100644
--- a/internal/lsp/cache/errors.go
+++ b/internal/lsp/cache/errors.go
@@ -244,7 +244,7 @@
 
 func typesCodeHref(snapshot *snapshot, code typesinternal.ErrorCode) string {
 	target := snapshot.View().Options().LinkTarget
-	return fmt.Sprintf("https://%s/golang.org/x/tools/internal/typesinternal#%s", target, code.String())
+	return source.BuildLink(target, "golang.org/x/tools/internal/typesinternal", code.String())
 }
 
 func suggestedAnalysisFixes(snapshot *snapshot, pkg *pkg, diag *analysis.Diagnostic, kinds []protocol.CodeActionKind) ([]source.SuggestedFix, error) {
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index f958a56..ae161ca 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -148,9 +148,10 @@
 		}
 		// Special case for the builtin package, as it has no dependencies.
 		if pkg.PkgPath == "builtin" {
-			if err := s.buildBuiltinPackage(ctx, pkg.GoFiles); err != nil {
-				return err
+			if len(pkg.GoFiles) != 1 {
+				return errors.Errorf("only expected 1 file for builtin, got %v", len(pkg.GoFiles))
 			}
+			s.setBuiltin(pkg.GoFiles[0])
 			continue
 		}
 		// Skip test main packages.
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index 28d0449..50de35e 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -50,9 +50,6 @@
 	// the cache generation that contains the data for this snapshot.
 	generation *memoize.Generation
 
-	// builtin pins the AST and package for builtin.go in memory.
-	builtin *builtinPackageHandle
-
 	// The snapshot's initialization state is controlled by the fields below.
 	//
 	// initializeOnce guards snapshot initialization. Each snapshot is
@@ -64,9 +61,12 @@
 	// to avoid too many go/packages calls.
 	initializedErr *source.CriticalError
 
-	// mu guards all of the maps in the snapshot.
+	// 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 span.URI
+
 	// ids maps file URIs to package IDs.
 	// It may be invalidated on calls to go/packages.
 	ids map[span.URI][]packageID
@@ -351,22 +351,25 @@
 		return "", nil, cleanup, err
 	}
 
-	mutableModFlag := ""
-	if s.view.goversion >= 16 {
-		mutableModFlag = "mod"
-	}
+	// If the mod flag isn't set, populate it based on the mode and workspace.
+	if inv.ModFlag == "" {
+		mutableModFlag := ""
+		if s.view.goversion >= 16 {
+			mutableModFlag = "mod"
+		}
 
-	switch mode {
-	case source.LoadWorkspace, source.Normal:
-		if vendorEnabled {
-			inv.ModFlag = "vendor"
-		} else if !allowModfileModificationOption {
-			inv.ModFlag = "readonly"
-		} else {
+		switch mode {
+		case source.LoadWorkspace, source.Normal:
+			if vendorEnabled {
+				inv.ModFlag = "vendor"
+			} else if !allowModfileModificationOption {
+				inv.ModFlag = "readonly"
+			} else {
+				inv.ModFlag = mutableModFlag
+			}
+		case source.UpdateUserModFile, source.WriteTemporaryModFile:
 			inv.ModFlag = mutableModFlag
 		}
-	case source.UpdateUserModFile, source.WriteTemporaryModFile:
-		inv.ModFlag = mutableModFlag
 	}
 
 	wantTempMod := mode != source.UpdateUserModFile
@@ -960,12 +963,12 @@
 	return strings.Contains(s, "command-line-arguments")
 }
 
-func (s *snapshot) isWorkspacePackage(id packageID) (packagePath, bool) {
+func (s *snapshot) isWorkspacePackage(id packageID) bool {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 
-	scope, ok := s.workspacePackages[id]
-	return scope, ok
+	_, ok := s.workspacePackages[id]
+	return ok
 }
 
 func (s *snapshot) FindFile(uri span.URI) source.VersionedFileHandle {
@@ -1279,13 +1282,12 @@
 }
 
 func inVendor(uri span.URI) bool {
-	toSlash := filepath.ToSlash(uri.Filename())
-	if !strings.Contains(toSlash, "/vendor/") {
+	if !strings.Contains(string(uri), "/vendor/") {
 		return false
 	}
 	// Only packages in _subdirectories_ of /vendor/ are considered vendored
 	// (/vendor/a/foo.go is vendored, /vendor/foo.go is not).
-	split := strings.Split(toSlash, "/vendor/")
+	split := strings.Split(string(uri), "/vendor/")
 	if len(split) < 2 {
 		return false
 	}
@@ -1339,18 +1341,18 @@
 		builtin:           s.builtin,
 		initializeOnce:    s.initializeOnce,
 		initializedErr:    s.initializedErr,
-		ids:               make(map[span.URI][]packageID),
-		importedBy:        make(map[packageID][]packageID),
-		metadata:          make(map[packageID]*metadata),
-		packages:          make(map[packageKey]*packageHandle),
-		actions:           make(map[actionKey]*actionHandle),
-		files:             make(map[span.URI]source.VersionedFileHandle),
-		goFiles:           make(map[parseKey]*parseGoHandle),
-		workspacePackages: make(map[packageID]packagePath),
-		unloadableFiles:   make(map[span.URI]struct{}),
-		parseModHandles:   make(map[span.URI]*parseModHandle),
-		modTidyHandles:    make(map[span.URI]*modTidyHandle),
-		modWhyHandles:     make(map[span.URI]*modWhyHandle),
+		ids:               make(map[span.URI][]packageID, len(s.ids)),
+		importedBy:        make(map[packageID][]packageID, len(s.importedBy)),
+		metadata:          make(map[packageID]*metadata, len(s.metadata)),
+		packages:          make(map[packageKey]*packageHandle, len(s.packages)),
+		actions:           make(map[actionKey]*actionHandle, len(s.actions)),
+		files:             make(map[span.URI]source.VersionedFileHandle, len(s.files)),
+		goFiles:           make(map[parseKey]*parseGoHandle, len(s.goFiles)),
+		workspacePackages: make(map[packageID]packagePath, len(s.workspacePackages)),
+		unloadableFiles:   make(map[span.URI]struct{}, len(s.unloadableFiles)),
+		parseModHandles:   make(map[span.URI]*parseModHandle, len(s.parseModHandles)),
+		modTidyHandles:    make(map[span.URI]*modTidyHandle, len(s.modTidyHandles)),
+		modWhyHandles:     make(map[span.URI]*modWhyHandle, len(s.modWhyHandles)),
 		workspace:         newWorkspace,
 	}
 
@@ -1359,10 +1361,6 @@
 		newGen.Inherit(s.workspaceDirHandle)
 	}
 
-	if s.builtin != nil {
-		newGen.Inherit(s.builtin.handle)
-	}
-
 	// Copy all of the FileHandles.
 	for k, v := range s.files {
 		result.files[k] = v
@@ -1548,7 +1546,7 @@
 				// For internal tests, we need _test files, not just the normal
 				// ones. External tests only have _test files, but we can check
 				// them anyway.
-				if m.forTest != "" && !strings.HasSuffix(uri.Filename(), "_test.go") {
+				if m.forTest != "" && !strings.HasSuffix(string(uri), "_test.go") {
 					continue
 				}
 				if _, ok := result.files[uri]; ok {
@@ -1747,55 +1745,37 @@
 	return results
 }
 
-func (s *snapshot) BuiltinPackage(ctx context.Context) (*source.BuiltinPackage, error) {
+func (s *snapshot) BuiltinFile(ctx context.Context) (*source.ParsedGoFile, error) {
 	s.AwaitInitialized(ctx)
 
-	if s.builtin == nil {
+	s.mu.Lock()
+	builtin := s.builtin
+	s.mu.Unlock()
+
+	if builtin == "" {
 		return nil, errors.Errorf("no builtin package for view %s", s.view.name)
 	}
-	d, err := s.builtin.handle.Get(ctx, s.generation, s)
+
+	fh, err := s.GetFile(ctx, builtin)
 	if err != nil {
 		return nil, err
 	}
-	data := d.(*builtinPackageData)
-	return data.parsed, data.err
+	return s.ParseGo(ctx, fh, source.ParseFull)
 }
 
-func (s *snapshot) buildBuiltinPackage(ctx context.Context, goFiles []string) error {
-	if len(goFiles) != 1 {
-		return errors.Errorf("only expected 1 file, got %v", len(goFiles))
-	}
-	uri := span.URIFromPath(goFiles[0])
+func (s *snapshot) IsBuiltin(ctx context.Context, 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
+	// string comparison here. span.CompareURI is too expensive.
+	return uri == s.builtin
+}
 
-	// Get the FileHandle through the cache to avoid adding it to the snapshot
-	// and to get the file content from disk.
-	fh, err := s.view.session.cache.getFile(ctx, uri)
-	if err != nil {
-		return err
-	}
-	h := s.generation.Bind(fh.FileIdentity(), func(ctx context.Context, arg memoize.Arg) interface{} {
-		snapshot := arg.(*snapshot)
+func (s *snapshot) setBuiltin(path string) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
 
-		pgh := snapshot.parseGoHandle(ctx, fh, source.ParseFull)
-		pgf, _, err := snapshot.parseGo(ctx, pgh)
-		if err != nil {
-			return &builtinPackageData{err: err}
-		}
-		pkg, err := ast.NewPackage(snapshot.view.session.cache.fset, map[string]*ast.File{
-			pgf.URI.Filename(): pgf.File,
-		}, nil, nil)
-		if err != nil {
-			return &builtinPackageData{err: err}
-		}
-		return &builtinPackageData{
-			parsed: &source.BuiltinPackage{
-				ParsedFile: pgf,
-				Package:    pkg,
-			},
-		}
-	}, nil)
-	s.builtin = &builtinPackageHandle{handle: h}
-	return nil
+	s.builtin = span.URIFromPath(path)
 }
 
 // BuildGoplsMod generates a go.mod file for all modules in the workspace. It
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index af00c39..8c27344 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -151,11 +151,6 @@
 	handle *memoize.Handle
 }
 
-type builtinPackageData struct {
-	parsed *source.BuiltinPackage
-	err    error
-}
-
 // fileBase holds the common functionality for all files.
 // It is intended to be embedded in the file implementations
 type fileBase struct {
@@ -254,6 +249,9 @@
 	if !reflect.DeepEqual(a.DirectoryFilters, b.DirectoryFilters) {
 		return false
 	}
+	if a.MemoryMode != b.MemoryMode {
+		return false
+	}
 	aBuildFlags := make([]string, len(a.BuildFlags))
 	bBuildFlags := make([]string, len(b.BuildFlags))
 	copy(aBuildFlags, a.BuildFlags)
diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go
index 41c2bce..1acf197 100644
--- a/internal/lsp/cmd/cmd.go
+++ b/internal/lsp/cmd/cmd.go
@@ -185,7 +185,8 @@
 		&highlight{app: app},
 		&implementation{app: app},
 		&imports{app: app},
-		&inspect{app: app},
+		newRemote(app, ""),
+		newRemote(app, "inspect"),
 		&links{app: app},
 		&prepareRename{app: app},
 		&references{app: app},
@@ -194,7 +195,7 @@
 		&signature{app: app},
 		&suggestedFix{app: app},
 		&symbols{app: app},
-		&workspace{app: app},
+		newWorkspace(app),
 		&workspaceSymbol{app: app},
 	}
 }
@@ -246,8 +247,7 @@
 
 func (app *Application) connectRemote(ctx context.Context, remote string) (*connection, error) {
 	connection := newConnection(app)
-	network, addr := parseAddr(remote)
-	conn, err := lsprpc.ConnectToRemote(ctx, network, addr)
+	conn, err := lsprpc.ConnectToRemote(ctx, remote)
 	if err != nil {
 		return nil, err
 	}
@@ -443,6 +443,10 @@
 	return nil
 }
 
+func (c *cmdClient) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
+	return nil, nil
+}
+
 func (c *cmdClient) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
 	return nil
 }
@@ -504,13 +508,9 @@
 	return file
 }
 
-func (c *connection) semanticTokens(ctx context.Context, file span.URI) (*protocol.SemanticTokens, error) {
-	p := &protocol.SemanticTokensParams{
-		TextDocument: protocol.TextDocumentIdentifier{
-			URI: protocol.URIFromSpanURI(file),
-		},
-	}
-	resp, err := c.Server.SemanticTokensFull(ctx, p)
+func (c *connection) semanticTokens(ctx context.Context, p *protocol.SemanticTokensRangeParams) (*protocol.SemanticTokens, error) {
+	// use range to avoid limits on full
+	resp, err := c.Server.SemanticTokensRange(ctx, p)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/lsp/cmd/inspect.go b/internal/lsp/cmd/inspect.go
deleted file mode 100644
index d3f08b7..0000000
--- a/internal/lsp/cmd/inspect.go
+++ /dev/null
@@ -1,101 +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 cmd
-
-import (
-	"context"
-	"encoding/json"
-	"flag"
-	"fmt"
-	"log"
-	"os"
-
-	"golang.org/x/tools/internal/lsp/lsprpc"
-	"golang.org/x/tools/internal/tool"
-)
-
-type inspect struct {
-	app *Application
-}
-
-func (i *inspect) subCommands() []tool.Application {
-	return []tool.Application{
-		&listSessions{app: i.app},
-	}
-}
-
-func (i *inspect) Name() string  { return "inspect" }
-func (i *inspect) Usage() string { return "<subcommand> [args...]" }
-func (i *inspect) ShortHelp() string {
-	return "inspect server state (daemon mode only)"
-}
-func (i *inspect) DetailedHelp(f *flag.FlagSet) {
-	fmt.Fprint(f.Output(), "\nsubcommands:\n")
-	for _, c := range i.subCommands() {
-		fmt.Fprintf(f.Output(), "  %s: %s\n", c.Name(), c.ShortHelp())
-	}
-	f.PrintDefaults()
-}
-
-func (i *inspect) Run(ctx context.Context, args ...string) error {
-	if len(args) == 0 {
-		return tool.CommandLineErrorf("must provide subcommand to %q", i.Name())
-	}
-	command, args := args[0], args[1:]
-	for _, c := range i.subCommands() {
-		if c.Name() == command {
-			return tool.Run(ctx, c, args)
-		}
-	}
-	return tool.CommandLineErrorf("unknown command %v", command)
-}
-
-// listSessions is an inspect subcommand to list current sessions.
-type listSessions struct {
-	app *Application
-}
-
-func (c *listSessions) Name() string  { return "sessions" }
-func (c *listSessions) Usage() string { return "" }
-func (c *listSessions) ShortHelp() string {
-	return "print information about current gopls sessions"
-}
-
-const listSessionsExamples = `
-Examples:
-
-1) list sessions for the default daemon:
-
-$ gopls -remote=auto inspect sessions
-or just
-$ gopls inspect sessions
-
-2) list sessions for a specific daemon:
-
-$ gopls -remote=localhost:8082 inspect sessions
-`
-
-func (c *listSessions) DetailedHelp(f *flag.FlagSet) {
-	fmt.Fprint(f.Output(), listSessionsExamples)
-	f.PrintDefaults()
-}
-
-func (c *listSessions) Run(ctx context.Context, args ...string) error {
-	remote := c.app.Remote
-	if remote == "" {
-		remote = "auto"
-	}
-	network, address := parseAddr(remote)
-	state, err := lsprpc.QueryServerState(ctx, network, address)
-	if err != nil {
-		return err
-	}
-	v, err := json.MarshalIndent(state, "", "\t")
-	if err != nil {
-		log.Fatal(err)
-	}
-	os.Stdout.Write(v)
-	return nil
-}
diff --git a/internal/lsp/cmd/remote.go b/internal/lsp/cmd/remote.go
new file mode 100644
index 0000000..86c2299
--- /dev/null
+++ b/internal/lsp/cmd/remote.go
@@ -0,0 +1,159 @@
+// 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 cmd
+
+import (
+	"context"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+
+	"golang.org/x/tools/internal/lsp/command"
+	"golang.org/x/tools/internal/lsp/lsprpc"
+	errors "golang.org/x/xerrors"
+)
+
+type remote struct {
+	subcommands
+
+	// For backward compatibility, allow aliasing this command (it was previously
+	// called 'inspect').
+	//
+	// TODO(rFindley): delete this after allowing some transition time in case
+	//                 there were any users of 'inspect' (I suspect not).
+	alias string
+}
+
+func newRemote(app *Application, alias string) *remote {
+	return &remote{
+		subcommands: subcommands{
+			&listSessions{app: app},
+			&startDebugging{app: app},
+		},
+		alias: alias,
+	}
+}
+
+func (r *remote) Name() string {
+	if r.alias != "" {
+		return r.alias
+	}
+	return "remote"
+}
+
+func (r *remote) ShortHelp() string {
+	short := "interact with the gopls daemon"
+	if r.alias != "" {
+		short += " (deprecated: use 'remote')"
+	}
+	return short
+}
+
+// listSessions is an inspect subcommand to list current sessions.
+type listSessions struct {
+	app *Application
+}
+
+func (c *listSessions) Name() string  { return "sessions" }
+func (c *listSessions) Usage() string { return "" }
+func (c *listSessions) ShortHelp() string {
+	return "print information about current gopls sessions"
+}
+
+const listSessionsExamples = `
+Examples:
+
+1) list sessions for the default daemon:
+
+$ gopls -remote=auto remote sessions
+or just
+$ gopls remote sessions
+
+2) list sessions for a specific daemon:
+
+$ gopls -remote=localhost:8082 remote sessions
+`
+
+func (c *listSessions) DetailedHelp(f *flag.FlagSet) {
+	fmt.Fprint(f.Output(), listSessionsExamples)
+	f.PrintDefaults()
+}
+
+func (c *listSessions) Run(ctx context.Context, args ...string) error {
+	remote := c.app.Remote
+	if remote == "" {
+		remote = "auto"
+	}
+	state, err := lsprpc.QueryServerState(ctx, remote)
+	if err != nil {
+		return err
+	}
+	v, err := json.MarshalIndent(state, "", "\t")
+	if err != nil {
+		log.Fatal(err)
+	}
+	os.Stdout.Write(v)
+	return nil
+}
+
+type startDebugging struct {
+	app *Application
+}
+
+func (c *startDebugging) Name() string  { return "debug" }
+func (c *startDebugging) Usage() string { return "[host:port]" }
+func (c *startDebugging) ShortHelp() string {
+	return "start the debug server"
+}
+
+const startDebuggingExamples = `
+Examples:
+
+1) start a debug server for the default daemon, on an arbitrary port:
+
+$ gopls -remote=auto remote debug
+or just
+$ gopls remote debug
+
+2) start for a specific daemon, on a specific port:
+
+$ gopls -remote=localhost:8082 remote debug localhost:8083
+`
+
+func (c *startDebugging) DetailedHelp(f *flag.FlagSet) {
+	fmt.Fprint(f.Output(), startDebuggingExamples)
+	f.PrintDefaults()
+}
+
+func (c *startDebugging) Run(ctx context.Context, args ...string) error {
+	if len(args) > 1 {
+		fmt.Fprintln(os.Stderr, c.Usage())
+		return errors.New("invalid usage")
+	}
+	remote := c.app.Remote
+	if remote == "" {
+		remote = "auto"
+	}
+	debugAddr := ""
+	if len(args) > 0 {
+		debugAddr = args[0]
+	}
+	debugArgs := command.DebuggingArgs{
+		Addr: debugAddr,
+	}
+	var result command.DebuggingResult
+	if err := lsprpc.ExecuteCommand(ctx, remote, command.StartDebugging.ID(), debugArgs, &result); err != nil {
+		return err
+	}
+	if len(result.URLs) == 0 {
+		return errors.New("no debugging URLs")
+	}
+	for _, url := range result.URLs {
+		fmt.Printf("debugging on %s\n", url)
+	}
+	return nil
+}
diff --git a/internal/lsp/cmd/semantictokens.go b/internal/lsp/cmd/semantictokens.go
index 41e353c..e8f9018 100644
--- a/internal/lsp/cmd/semantictokens.go
+++ b/internal/lsp/cmd/semantictokens.go
@@ -94,13 +94,24 @@
 		return file.err
 	}
 
-	resp, err := conn.semanticTokens(ctx, uri)
+	buf, err := ioutil.ReadFile(args[0])
 	if err != nil {
 		return err
 	}
-	buf, err := ioutil.ReadFile(args[0])
+	lines := bytes.Split(buf, []byte{'\n'})
+	p := &protocol.SemanticTokensRangeParams{
+		TextDocument: protocol.TextDocumentIdentifier{
+			URI: protocol.URIFromSpanURI(uri),
+		},
+		Range: protocol.Range{Start: protocol.Position{Line: 0, Character: 0},
+			End: protocol.Position{
+				Line:      uint32(len(lines) - 1),
+				Character: uint32(len(lines[len(lines)-1]))},
+		},
+	}
+	resp, err := conn.semanticTokens(ctx, p)
 	if err != nil {
-		log.Fatal(err)
+		return err
 	}
 	fset := token.NewFileSet()
 	f, err := parser.ParseFile(fset, args[0], buf, 0)
diff --git a/internal/lsp/cmd/serve.go b/internal/lsp/cmd/serve.go
index c45790d..6d0787e 100644
--- a/internal/lsp/cmd/serve.go
+++ b/internal/lsp/cmd/serve.go
@@ -11,7 +11,6 @@
 	"io"
 	"log"
 	"os"
-	"strings"
 	"time"
 
 	"golang.org/x/tools/internal/fakenet"
@@ -73,13 +72,12 @@
 		}
 		defer closeLog()
 		di.ServerAddress = s.Address
-		di.DebugAddress = s.Debug
-		di.Serve(ctx)
 		di.MonitorMemory(ctx)
+		di.Serve(ctx, s.Debug)
 	}
 	var ss jsonrpc2.StreamServer
 	if s.app.Remote != "" {
-		network, addr := parseAddr(s.app.Remote)
+		network, addr := lsprpc.ParseAddr(s.app.Remote)
 		ss = lsprpc.NewForwarder(network, addr,
 			lsprpc.RemoteDebugAddress(s.RemoteDebug),
 			lsprpc.RemoteListenTimeout(s.RemoteListenTimeout),
@@ -91,7 +89,7 @@
 
 	var network, addr string
 	if s.Address != "" {
-		network, addr = parseAddr(s.Address)
+		network, addr = lsprpc.ParseAddr(s.Address)
 	}
 	if s.Port != 0 {
 		network = "tcp"
@@ -113,16 +111,3 @@
 	}
 	return err
 }
-
-// parseAddr parses the -listen flag in to a network, and address.
-func parseAddr(listen string) (network string, address string) {
-	// Allow passing just -remote=auto, as a shorthand for using automatic remote
-	// resolution.
-	if listen == lsprpc.AutoNetwork {
-		return lsprpc.AutoNetwork, ""
-	}
-	if parts := strings.SplitN(listen, ";", 2); len(parts) == 2 {
-		return parts[0], parts[1]
-	}
-	return "tcp", listen
-}
diff --git a/internal/lsp/cmd/serve_test.go b/internal/lsp/cmd/serve_test.go
deleted file mode 100644
index 7b3bc9a..0000000
--- a/internal/lsp/cmd/serve_test.go
+++ /dev/null
@@ -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.
-
-package cmd
-
-import "testing"
-
-func TestListenParsing(t *testing.T) {
-	tests := []struct {
-		input, wantNetwork, wantAddr string
-	}{
-		{"127.0.0.1:0", "tcp", "127.0.0.1:0"},
-		{"unix;/tmp/sock", "unix", "/tmp/sock"},
-		{"auto", "auto", ""},
-		{"auto;foo", "auto", "foo"},
-	}
-
-	for _, test := range tests {
-		gotNetwork, gotAddr := parseAddr(test.input)
-		if gotNetwork != test.wantNetwork {
-			t.Errorf("network = %q, want %q", gotNetwork, test.wantNetwork)
-		}
-		if gotAddr != test.wantAddr {
-			t.Errorf("addr = %q, want %q", gotAddr, test.wantAddr)
-		}
-	}
-}
diff --git a/internal/lsp/cmd/subcommands.go b/internal/lsp/cmd/subcommands.go
new file mode 100644
index 0000000..5af5923
--- /dev/null
+++ b/internal/lsp/cmd/subcommands.go
@@ -0,0 +1,40 @@
+// 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.
+
+package cmd
+
+import (
+	"context"
+	"flag"
+	"fmt"
+
+	"golang.org/x/tools/internal/tool"
+)
+
+// subcommands is a helper that may be embedded for commands that delegate to
+// subcommands.
+type subcommands []tool.Application
+
+func (s subcommands) DetailedHelp(f *flag.FlagSet) {
+	fmt.Fprint(f.Output(), "\nsubcommands:\n")
+	for _, c := range s {
+		fmt.Fprintf(f.Output(), "  %s: %s\n", c.Name(), c.ShortHelp())
+	}
+	f.PrintDefaults()
+}
+
+func (s subcommands) Usage() string { return "<subcommand> [args...]" }
+
+func (s subcommands) Run(ctx context.Context, args ...string) error {
+	if len(args) == 0 {
+		return tool.CommandLineErrorf("must provide subcommand")
+	}
+	command, args := args[0], args[1:]
+	for _, c := range s {
+		if c.Name() == command {
+			return tool.Run(ctx, c, args)
+		}
+	}
+	return tool.CommandLineErrorf("unknown subcommand %v", command)
+}
diff --git a/internal/lsp/cmd/workspace.go b/internal/lsp/cmd/workspace.go
index a099599..61757d2 100644
--- a/internal/lsp/cmd/workspace.go
+++ b/internal/lsp/cmd/workspace.go
@@ -12,7 +12,6 @@
 	"golang.org/x/tools/internal/lsp/command"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
-	"golang.org/x/tools/internal/tool"
 )
 
 // workspace is a top-level command for working with the gopls workspace. This
@@ -20,42 +19,22 @@
 // used for manipulating the workspace mod file, rather than editing it
 // manually.
 type workspace struct {
-	app *Application
+	subcommands
 }
 
-func (w *workspace) subCommands() []tool.Application {
-	return []tool.Application{
-		&generateWorkspaceMod{app: w.app},
+func newWorkspace(app *Application) *workspace {
+	return &workspace{
+		subcommands: subcommands{
+			&generateWorkspaceMod{app: app},
+		},
 	}
 }
 
-func (w *workspace) Name() string  { return "workspace" }
-func (w *workspace) Usage() string { return "<subcommand> [args...]" }
+func (w *workspace) Name() string { return "workspace" }
 func (w *workspace) ShortHelp() string {
 	return "manage the gopls workspace (experimental: under development)"
 }
 
-func (w *workspace) DetailedHelp(f *flag.FlagSet) {
-	fmt.Fprint(f.Output(), "\nsubcommands:\n")
-	for _, c := range w.subCommands() {
-		fmt.Fprintf(f.Output(), "  %s: %s\n", c.Name(), c.ShortHelp())
-	}
-	f.PrintDefaults()
-}
-
-func (w *workspace) Run(ctx context.Context, args ...string) error {
-	if len(args) == 0 {
-		return tool.CommandLineErrorf("must provide subcommand to %q", w.Name())
-	}
-	command, args := args[0], args[1:]
-	for _, c := range w.subCommands() {
-		if c.Name() == command {
-			return tool.Run(ctx, c, args)
-		}
-	}
-	return tool.CommandLineErrorf("unknown command %v", command)
-}
-
 // generateWorkspaceMod (re)generates the gopls.mod file for the current
 // workspace.
 type generateWorkspaceMod struct {
diff --git a/internal/lsp/command.go b/internal/lsp/command.go
index 24fd719..bc521c9 100644
--- a/internal/lsp/command.go
+++ b/internal/lsp/command.go
@@ -20,6 +20,7 @@
 	"golang.org/x/tools/internal/gocommand"
 	"golang.org/x/tools/internal/lsp/cache"
 	"golang.org/x/tools/internal/lsp/command"
+	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/protocol"
 	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/span"
@@ -584,6 +585,7 @@
 		Verb:       "list",
 		Args:       append([]string{"-m", "-u", "-json"}, modules...),
 		WorkingDir: filepath.Dir(uri.Filename()),
+		ModFlag:    "readonly",
 	})
 	if err != nil {
 		return nil, err
@@ -694,3 +696,20 @@
 	}
 	return result, nil
 }
+
+func (c *commandHandler) StartDebugging(ctx context.Context, args command.DebuggingArgs) (result command.DebuggingResult, _ error) {
+	addr := args.Addr
+	if addr == "" {
+		addr = "localhost:0"
+	}
+	di := debug.GetInstance(ctx)
+	if di == nil {
+		return result, errors.New("internal error: server has no debugging instance")
+	}
+	listenedAddr, err := di.Serve(ctx, addr)
+	if err != nil {
+		return result, errors.Errorf("starting debug server: %w", err)
+	}
+	result.URLs = []string{"http://" + listenedAddr}
+	return result, nil
+}
diff --git a/internal/lsp/command/command_gen.go b/internal/lsp/command/command_gen.go
index 9cdcb41..d734345 100644
--- a/internal/lsp/command/command_gen.go
+++ b/internal/lsp/command/command_gen.go
@@ -31,6 +31,7 @@
 	RegenerateCgo     Command = "regenerate_cgo"
 	RemoveDependency  Command = "remove_dependency"
 	RunTests          Command = "run_tests"
+	StartDebugging    Command = "start_debugging"
 	Test              Command = "test"
 	Tidy              Command = "tidy"
 	ToggleGCDetails   Command = "toggle_gc_details"
@@ -53,6 +54,7 @@
 	RegenerateCgo,
 	RemoveDependency,
 	RunTests,
+	StartDebugging,
 	Test,
 	Tidy,
 	ToggleGCDetails,
@@ -136,6 +138,12 @@
 			return nil, err
 		}
 		return nil, s.RunTests(ctx, a0)
+	case "gopls.start_debugging":
+		var a0 DebuggingArgs
+		if err := UnmarshalArgs(params.Arguments, &a0); err != nil {
+			return nil, err
+		}
+		return s.StartDebugging(ctx, a0)
 	case "gopls.test":
 		var a0 protocol.DocumentURI
 		var a1 []string
@@ -324,6 +332,18 @@
 	}, nil
 }
 
+func NewStartDebuggingCommand(title string, a0 DebuggingArgs) (protocol.Command, error) {
+	args, err := MarshalArgs(a0)
+	if err != nil {
+		return protocol.Command{}, err
+	}
+	return protocol.Command{
+		Title:     title,
+		Command:   "gopls.start_debugging",
+		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 {
diff --git a/internal/lsp/command/interface.go b/internal/lsp/command/interface.go
index 1712327..03040bf 100644
--- a/internal/lsp/command/interface.go
+++ b/internal/lsp/command/interface.go
@@ -120,6 +120,8 @@
 	AddImport(context.Context, AddImportArgs) (AddImportResult, error)
 
 	WorkspaceMetadata(context.Context) (WorkspaceMetadataResult, error)
+
+	StartDebugging(context.Context, DebuggingArgs) (DebuggingResult, error)
 }
 
 type RunTestsArgs struct {
@@ -220,3 +222,34 @@
 	Name      string
 	ModuleDir string
 }
+
+type DebuggingArgs struct {
+	// 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
+}
+
+type DebuggingResult struct {
+	// 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
+	// slice. If any intermediate gopls instance fails to start debugging, no
+	// error will be returned but the debug URL for that server in the URLs slice
+	// will be empty.
+	URLs []string
+}
diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go
index 3762b7a..fa0586a 100644
--- a/internal/lsp/completion.go
+++ b/internal/lsp/completion.go
@@ -154,6 +154,8 @@
 
 			Preselect:     i == 0,
 			Documentation: candidate.Documentation,
+			Tags:          candidate.Tags,
+			Deprecated:    candidate.Deprecated,
 		}
 		items = append(items, item)
 	}
diff --git a/internal/lsp/debug/info.go b/internal/lsp/debug/info.go
index 7013396..e19f1e1 100644
--- a/internal/lsp/debug/info.go
+++ b/internal/lsp/debug/info.go
@@ -26,7 +26,7 @@
 )
 
 // Version is a manually-updated mechanism for tracking versions.
-const Version = "v0.6.10"
+const Version = "v0.6.11"
 
 // 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.
@@ -100,7 +100,7 @@
 		fmt.Fprintf(w, "LogFile: %s\n", i.Logfile)
 		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)
+		fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress())
 	})
 	PrintVersionInfo(ctx, w, true, HTML)
 	section(w, HTML, "Command Line", func() {
diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go
index 473518e..58e59b5 100644
--- a/internal/lsp/debug/serve.go
+++ b/internal/lsp/debug/serve.go
@@ -50,13 +50,11 @@
 
 // An Instance holds all debug information associated with a gopls instance.
 type Instance struct {
-	Logfile              string
-	StartTime            time.Time
-	ServerAddress        string
-	DebugAddress         string
-	ListenedDebugAddress string
-	Workdir              string
-	OCAgentConfig        string
+	Logfile       string
+	StartTime     time.Time
+	ServerAddress string
+	Workdir       string
+	OCAgentConfig string
 
 	LogWriter io.Writer
 
@@ -67,6 +65,10 @@
 	rpcs       *Rpcs
 	traces     *traces
 	State      *State
+
+	serveMu              sync.Mutex
+	debugAddress         string
+	listenedDebugAddress string
 }
 
 // State holds debugging information related to the server state.
@@ -216,9 +218,20 @@
 
 // AddServer adds a server to the set being queried. In practice, there should
 // be at most one remote server.
-func (st *State) addServer(server *Server) {
+func (st *State) updateServer(server *Server) {
 	st.mu.Lock()
 	defer st.mu.Unlock()
+	for i, existing := range st.servers {
+		if existing.ID == server.ID {
+			// Replace, rather than mutate, to avoid a race.
+			newServers := make([]*Server, len(st.servers))
+			copy(newServers, st.servers[:i])
+			newServers[i] = server
+			copy(newServers[i+1:], st.servers[i+1:])
+			st.servers = newServers
+			return
+		}
+	}
 	st.servers = append(st.servers, server)
 }
 
@@ -274,11 +287,11 @@
 	return i.State.Session(path.Base(r.URL.Path))
 }
 
-func (i Instance) getClient(r *http.Request) interface{} {
+func (i *Instance) getClient(r *http.Request) interface{} {
 	return i.State.Client(path.Base(r.URL.Path))
 }
 
-func (i Instance) getServer(r *http.Request) interface{} {
+func (i *Instance) getServer(r *http.Request) interface{} {
 	i.State.mu.Lock()
 	defer i.State.mu.Unlock()
 	id := path.Base(r.URL.Path)
@@ -290,7 +303,7 @@
 	return nil
 }
 
-func (i Instance) getView(r *http.Request) interface{} {
+func (i *Instance) getView(r *http.Request) interface{} {
 	return i.State.View(path.Base(r.URL.Path))
 }
 
@@ -395,22 +408,31 @@
 	return closeLog, nil
 }
 
-// Serve starts and runs a debug server in the background.
+// Serve starts and runs a debug server in the background on the given addr.
 // It also logs the port the server starts on, to allow for :0 auto assigned
 // ports.
-func (i *Instance) Serve(ctx context.Context) error {
+func (i *Instance) Serve(ctx context.Context, addr string) (string, error) {
 	stdlog.SetFlags(stdlog.Lshortfile)
-	if i.DebugAddress == "" {
-		return nil
+	if addr == "" {
+		return "", nil
 	}
-	listener, err := net.Listen("tcp", i.DebugAddress)
+	i.serveMu.Lock()
+	defer i.serveMu.Unlock()
+
+	if i.listenedDebugAddress != "" {
+		// Already serving. Return the bound address.
+		return i.listenedDebugAddress, nil
+	}
+
+	i.debugAddress = addr
+	listener, err := net.Listen("tcp", i.debugAddress)
 	if err != nil {
-		return err
+		return "", err
 	}
-	i.ListenedDebugAddress = listener.Addr().String()
+	i.listenedDebugAddress = listener.Addr().String()
 
 	port := listener.Addr().(*net.TCPAddr).Port
-	if strings.HasSuffix(i.DebugAddress, ":0") {
+	if strings.HasSuffix(i.debugAddress, ":0") {
 		stdlog.Printf("debug server listening at http://localhost:%d", port)
 	}
 	event.Log(ctx, "Debug serving", tag.Port.Of(port))
@@ -446,7 +468,19 @@
 		}
 		event.Log(ctx, "Debug server finished")
 	}()
-	return nil
+	return i.listenedDebugAddress, nil
+}
+
+func (i *Instance) DebugAddress() string {
+	i.serveMu.Lock()
+	defer i.serveMu.Unlock()
+	return i.debugAddress
+}
+
+func (i *Instance) ListenedDebugAddress() string {
+	i.serveMu.Lock()
+	defer i.serveMu.Unlock()
+	return i.listenedDebugAddress
 }
 
 // MonitorMemory starts recording memory statistics each second.
@@ -579,7 +613,7 @@
 				i.State.addClient(s)
 			}
 			if sid := tag.NewServer.Get(ev); sid != "" {
-				i.State.addServer(&Server{
+				i.State.updateServer(&Server{
 					ID:           sid,
 					Logfile:      tag.Logfile.Get(ev),
 					DebugAddress: tag.DebugAddress.Get(ev),
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index f93e525..f892910 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -121,6 +121,7 @@
 func (s *Server) diagnoseChangedFiles(ctx context.Context, snapshot source.Snapshot, uris []span.URI, onDisk bool) {
 	ctx, done := event.Start(ctx, "Server.diagnoseChangedFiles", tag.Snapshot.Of(snapshot.ID()))
 	defer done()
+
 	packages := make(map[source.Package]struct{})
 	for _, uri := range uris {
 		// If the change is only on-disk and the file is not open, don't
@@ -133,6 +134,11 @@
 		if snapshot.FindFile(uri) == nil {
 			continue
 		}
+		// Don't call PackagesForFile for builtin.go, as it results in a
+		// command-line-arguments load.
+		if snapshot.IsBuiltin(ctx, uri) {
+			continue
+		}
 		pkgs, err := snapshot.PackagesForFile(ctx, uri, source.TypecheckFull)
 		if err != nil {
 			// TODO (findleyr): we should probably do something with the error here,
@@ -393,6 +399,10 @@
 	if fh.Kind() != source.Go {
 		return nil
 	}
+	// builtin files won't have a package, but they are never orphaned.
+	if snapshot.IsBuiltin(ctx, fh.URI()) {
+		return nil
+	}
 	pkgs, err := snapshot.PackagesForFile(ctx, fh.URI(), source.TypecheckWorkspace)
 	if len(pkgs) > 0 || err == nil {
 		return nil
diff --git a/internal/lsp/fake/client.go b/internal/lsp/fake/client.go
index acc4ea5..a105110 100644
--- a/internal/lsp/fake/client.go
+++ b/internal/lsp/fake/client.go
@@ -111,6 +111,10 @@
 	return nil
 }
 
+func (c *Client) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
+	return nil, nil
+}
+
 // ApplyEdit applies edits sent from the server.
 func (c *Client) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResponse, error) {
 	if len(params.Edit.Changes) != 0 {
diff --git a/internal/lsp/fake/editor.go b/internal/lsp/fake/editor.go
index f10ea44..2eb8782 100644
--- a/internal/lsp/fake/editor.go
+++ b/internal/lsp/fake/editor.go
@@ -270,6 +270,7 @@
 	params.Capabilities.Workspace.Configuration = true
 	params.Capabilities.Window.WorkDoneProgress = true
 	// TODO: set client capabilities
+	params.Capabilities.TextDocument.Completion.CompletionItem.TagSupport.ValueSet = []protocol.CompletionItemTag{protocol.ComplDeprecated}
 	params.InitializationOptions = e.configuration()
 	if e.Config.SendPID {
 		params.ProcessID = int32(os.Getpid())
@@ -693,7 +694,7 @@
 }
 
 // GoToDefinition jumps to the definition of the symbol at the given position
-// in an open buffer.
+// in an open buffer. It returns the path and position of the resulting jump.
 func (e *Editor) GoToDefinition(ctx context.Context, path string, pos Pos) (string, Pos, error) {
 	if err := e.checkBufferPosition(path, pos); err != nil {
 		return "", Pos{}, err
@@ -753,13 +754,13 @@
 
 // OrganizeImports requests and performs the source.organizeImports codeAction.
 func (e *Editor) OrganizeImports(ctx context.Context, path string) error {
-	_, err := e.codeAction(ctx, path, nil, nil, protocol.SourceOrganizeImports)
+	_, err := e.applyCodeActions(ctx, path, nil, nil, protocol.SourceOrganizeImports)
 	return err
 }
 
 // RefactorRewrite requests and performs the source.refactorRewrite codeAction.
 func (e *Editor) RefactorRewrite(ctx context.Context, path string, rng *protocol.Range) error {
-	applied, err := e.codeAction(ctx, path, rng, nil, protocol.RefactorRewrite)
+	applied, err := e.applyCodeActions(ctx, path, rng, nil, protocol.RefactorRewrite)
 	if applied == 0 {
 		return errors.Errorf("no refactorings were applied")
 	}
@@ -768,19 +769,46 @@
 
 // ApplyQuickFixes requests and performs the quickfix codeAction.
 func (e *Editor) ApplyQuickFixes(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic) error {
-	applied, err := e.codeAction(ctx, path, rng, diagnostics, protocol.QuickFix, protocol.SourceFixAll)
+	applied, err := e.applyCodeActions(ctx, path, rng, diagnostics, protocol.SourceFixAll, protocol.QuickFix)
 	if applied == 0 {
 		return errors.Errorf("no quick fixes were applied")
 	}
 	return err
 }
 
+// ApplyCodeAction applies the given code action.
+func (e *Editor) ApplyCodeAction(ctx context.Context, action protocol.CodeAction) error {
+	for _, change := range action.Edit.DocumentChanges {
+		path := e.sandbox.Workdir.URIToPath(change.TextDocument.URI)
+		if int32(e.buffers[path].version) != change.TextDocument.Version {
+			// Skip edits for old versions.
+			continue
+		}
+		edits := convertEdits(change.Edits)
+		if err := e.EditBuffer(ctx, path, edits); err != nil {
+			return errors.Errorf("editing buffer %q: %w", path, err)
+		}
+	}
+	// Execute any commands. The specification says that commands are
+	// executed after edits are applied.
+	if action.Command != nil {
+		if _, err := e.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
+			Command:   action.Command.Command,
+			Arguments: action.Command.Arguments,
+		}); err != nil {
+			return err
+		}
+	}
+	// Some commands may edit files on disk.
+	return e.sandbox.Workdir.CheckForFileChanges(ctx)
+}
+
 // GetQuickFixes returns the available quick fix code actions.
 func (e *Editor) GetQuickFixes(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic) ([]protocol.CodeAction, error) {
 	return e.getCodeActions(ctx, path, rng, diagnostics, protocol.QuickFix, protocol.SourceFixAll)
 }
 
-func (e *Editor) codeAction(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) (int, error) {
+func (e *Editor) applyCodeActions(ctx context.Context, path string, rng *protocol.Range, diagnostics []protocol.Diagnostic, only ...protocol.CodeActionKind) (int, error) {
 	actions, err := e.getCodeActions(ctx, path, rng, diagnostics, only...)
 	if err != nil {
 		return 0, err
@@ -801,29 +829,7 @@
 			continue
 		}
 		applied++
-		for _, change := range action.Edit.DocumentChanges {
-			path := e.sandbox.Workdir.URIToPath(change.TextDocument.URI)
-			if int32(e.buffers[path].version) != change.TextDocument.Version {
-				// Skip edits for old versions.
-				continue
-			}
-			edits := convertEdits(change.Edits)
-			if err := e.EditBuffer(ctx, path, edits); err != nil {
-				return 0, errors.Errorf("editing buffer %q: %w", path, err)
-			}
-		}
-		// Execute any commands. The specification says that commands are
-		// executed after edits are applied.
-		if action.Command != nil {
-			if _, err := e.ExecuteCommand(ctx, &protocol.ExecuteCommandParams{
-				Command:   action.Command.Command,
-				Arguments: action.Command.Arguments,
-			}); err != nil {
-				return 0, err
-			}
-		}
-		// Some commands may edit files on disk.
-		if err := e.sandbox.Workdir.CheckForFileChanges(ctx); err != nil {
+		if err := e.ApplyCodeAction(ctx, action); err != nil {
 			return 0, err
 		}
 	}
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index 6603e47..7165db9 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -96,7 +96,24 @@
 		}
 	}
 
-	goplsVersion, err := json.Marshal(debug.VersionInfo())
+	versionInfo := debug.VersionInfo()
+
+	// golang/go#45732: Warn users who've installed sergi/go-diff@v1.2.0, since
+	// it will corrupt the formatting of their files.
+	for _, dep := range versionInfo.Deps {
+		if dep.Path == "github.com/sergi/go-diff" && dep.Version == "v1.2.0" {
+			if err := s.eventuallyShowMessage(ctx, &protocol.ShowMessageParams{
+				Message: `It looks like you have a bad gopls installation.
+Please reinstall gopls by running 'GO111MODULE=on go get golang.org/x/tools/gopls@latest'.
+See https://github.com/golang/go/issues/45732 for more information.`,
+				Type: protocol.Error,
+			}); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	goplsVersion, err := json.Marshal(versionInfo)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/lsp/helper/helper.go b/internal/lsp/helper/helper.go
index 59438f1..e9e71e6 100644
--- a/internal/lsp/helper/helper.go
+++ b/internal/lsp/helper/helper.go
@@ -45,7 +45,10 @@
 }
 
 // replace "\\\n" with nothing before using
-var tmpl = `
+var tmpl = `// 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.
+
 package lsp
 
 // code generated by helper. DO NOT EDIT.
diff --git a/internal/lsp/lsprpc/lsprpc.go b/internal/lsp/lsprpc/lsprpc.go
index 5126791..04cf5ca 100644
--- a/internal/lsp/lsprpc/lsprpc.go
+++ b/internal/lsp/lsprpc/lsprpc.go
@@ -14,6 +14,8 @@
 	"net"
 	"os"
 	"strconv"
+	"strings"
+	"sync"
 	"sync/atomic"
 	"time"
 
@@ -22,6 +24,7 @@
 	"golang.org/x/tools/internal/jsonrpc2"
 	"golang.org/x/tools/internal/lsp"
 	"golang.org/x/tools/internal/lsp/cache"
+	"golang.org/x/tools/internal/lsp/command"
 	"golang.org/x/tools/internal/lsp/debug"
 	"golang.org/x/tools/internal/lsp/debug/tag"
 	"golang.org/x/tools/internal/lsp/protocol"
@@ -104,6 +107,12 @@
 
 	// configuration for the auto-started gopls remote.
 	remoteConfig remoteConfig
+
+	mu sync.Mutex
+	// Hold on to the server connection so that we can redo the handshake if any
+	// information changes.
+	serverConn jsonrpc2.Conn
+	serverID   string
 }
 
 type remoteConfig struct {
@@ -171,7 +180,23 @@
 }
 
 // QueryServerState queries the server state of the current server.
-func QueryServerState(ctx context.Context, network, address string) (*ServerState, error) {
+func QueryServerState(ctx context.Context, addr string) (*ServerState, error) {
+	serverConn, err := dialRemote(ctx, addr)
+	if err != nil {
+		return nil, err
+	}
+	var state ServerState
+	if err := protocol.Call(ctx, serverConn, sessionsMethod, nil, &state); err != nil {
+		return nil, errors.Errorf("querying server state: %w", err)
+	}
+	return &state, nil
+}
+
+// dialRemote is used for making calls into the gopls daemon. addr should be a
+// URL, possibly on the synthetic 'auto' network (e.g. tcp://..., unix://...,
+// or auto://...).
+func dialRemote(ctx context.Context, addr string) (jsonrpc2.Conn, error) {
+	network, address := ParseAddr(addr)
 	if network == AutoNetwork {
 		gp, err := os.Executable()
 		if err != nil {
@@ -185,11 +210,23 @@
 	}
 	serverConn := jsonrpc2.NewConn(jsonrpc2.NewHeaderStream(netConn))
 	serverConn.Go(ctx, jsonrpc2.MethodNotFound)
-	var state ServerState
-	if err := protocol.Call(ctx, serverConn, sessionsMethod, nil, &state); err != nil {
-		return nil, errors.Errorf("querying server state: %w", err)
+	return serverConn, nil
+}
+
+func ExecuteCommand(ctx context.Context, addr string, id string, request, result interface{}) error {
+	serverConn, err := dialRemote(ctx, addr)
+	if err != nil {
+		return err
 	}
-	return &state, nil
+	args, err := command.MarshalArgs(request)
+	if err != nil {
+		return err
+	}
+	params := protocol.ExecuteCommandParams{
+		Command:   id,
+		Arguments: args,
+	}
+	return protocol.Call(ctx, serverConn, "workspace/executeCommand", params, result)
 }
 
 // ServeStream dials the forwarder remote and binds the remote to serve the LSP
@@ -209,41 +246,20 @@
 		protocol.Handlers(
 			protocol.ClientHandler(client,
 				jsonrpc2.MethodNotFound)))
+
 	// Don't run the clientConn yet, so that we can complete the handshake before
 	// processing any client messages.
 
 	// Do a handshake with the server instance to exchange debug information.
 	index := atomic.AddInt64(&serverIndex, 1)
-	serverID := strconv.FormatInt(index, 10)
-	var (
-		hreq = handshakeRequest{
-			ServerID:  serverID,
-			GoplsPath: f.goplsPath,
-		}
-		hresp handshakeResponse
-	)
-	if di := debug.GetInstance(ctx); di != nil {
-		hreq.Logfile = di.Logfile
-		hreq.DebugAddr = di.ListenedDebugAddress
-	}
-	if err := protocol.Call(ctx, serverConn, handshakeMethod, hreq, &hresp); err != nil {
-		// TODO(rfindley): at some point in the future we should return an error
-		// here.  Handshakes have become functional in nature.
-		event.Error(ctx, "forwarder: gopls handshake failed", err)
-	}
-	if hresp.GoplsPath != f.goplsPath {
-		event.Error(ctx, "", fmt.Errorf("forwarder: gopls path mismatch: forwarder is %q, remote is %q", f.goplsPath, hresp.GoplsPath))
-	}
-	event.Log(ctx, "New server",
-		tag.NewServer.Of(serverID),
-		tag.Logfile.Of(hresp.Logfile),
-		tag.DebugAddress.Of(hresp.DebugAddr),
-		tag.GoplsPath.Of(hresp.GoplsPath),
-		tag.ClientID.Of(hresp.SessionID),
-	)
+	f.mu.Lock()
+	f.serverConn = serverConn
+	f.serverID = strconv.FormatInt(index, 10)
+	f.mu.Unlock()
+	f.handshake(ctx)
 	clientConn.Go(ctx,
 		protocol.Handlers(
-			forwarderHandler(
+			f.handler(
 				protocol.ServerHandler(server,
 					jsonrpc2.MethodNotFound))))
 
@@ -264,11 +280,40 @@
 	return err
 }
 
+func (f *Forwarder) handshake(ctx context.Context) {
+	var (
+		hreq = handshakeRequest{
+			ServerID:  f.serverID,
+			GoplsPath: f.goplsPath,
+		}
+		hresp handshakeResponse
+	)
+	if di := debug.GetInstance(ctx); di != nil {
+		hreq.Logfile = di.Logfile
+		hreq.DebugAddr = di.ListenedDebugAddress()
+	}
+	if err := protocol.Call(ctx, f.serverConn, handshakeMethod, hreq, &hresp); err != nil {
+		// TODO(rfindley): at some point in the future we should return an error
+		// here.  Handshakes have become functional in nature.
+		event.Error(ctx, "forwarder: gopls handshake failed", err)
+	}
+	if hresp.GoplsPath != f.goplsPath {
+		event.Error(ctx, "", fmt.Errorf("forwarder: gopls path mismatch: forwarder is %q, remote is %q", f.goplsPath, hresp.GoplsPath))
+	}
+	event.Log(ctx, "New server",
+		tag.NewServer.Of(f.serverID),
+		tag.Logfile.Of(hresp.Logfile),
+		tag.DebugAddress.Of(hresp.DebugAddr),
+		tag.GoplsPath.Of(hresp.GoplsPath),
+		tag.ClientID.Of(hresp.SessionID),
+	)
+}
+
 func (f *Forwarder) connectToRemote(ctx context.Context) (net.Conn, error) {
 	return connectToRemote(ctx, f.network, f.addr, f.goplsPath, f.remoteConfig)
 }
 
-func ConnectToRemote(ctx context.Context, network, addr string, opts ...RemoteOption) (net.Conn, error) {
+func ConnectToRemote(ctx context.Context, addr string, opts ...RemoteOption) (net.Conn, error) {
 	rcfg := defaultRemoteConfig()
 	for _, opt := range opts {
 		opt.set(&rcfg)
@@ -279,7 +324,8 @@
 	if err != nil {
 		return nil, fmt.Errorf("unable to resolve gopls path: %v", err)
 	}
-	return connectToRemote(ctx, network, addr, goplsPath, rcfg)
+	network, address := ParseAddr(addr)
+	return connectToRemote(ctx, network, address, goplsPath, rcfg)
 }
 
 func connectToRemote(ctx context.Context, inNetwork, inAddr, goplsPath string, rcfg remoteConfig) (net.Conn, error) {
@@ -365,24 +411,39 @@
 	return nil, errors.Errorf("dialing remote: %w", err)
 }
 
-// forwarderHandler intercepts 'exit' messages to prevent the shared gopls
-// instance from exiting. In the future it may also intercept 'shutdown' to
-// provide more graceful shutdown of the client connection.
-func forwarderHandler(handler jsonrpc2.Handler) jsonrpc2.Handler {
+// handler intercepts messages to the daemon to enrich them with local
+// information.
+func (f *Forwarder) handler(handler jsonrpc2.Handler) jsonrpc2.Handler {
 	return func(ctx context.Context, reply jsonrpc2.Replier, r jsonrpc2.Request) error {
+		// Intercept certain messages to add special handling.
+		switch r.Method() {
+		case "initialize":
+			if newr, err := addGoEnvToInitializeRequest(ctx, r); err == nil {
+				r = newr
+			} else {
+				log.Printf("unable to add local env to initialize request: %v", err)
+			}
+		case "workspace/executeCommand":
+			var params protocol.ExecuteCommandParams
+			if err := json.Unmarshal(r.Params(), &params); err == nil {
+				if params.Command == command.StartDebugging.ID() {
+					var args command.DebuggingArgs
+					if err := command.UnmarshalArgs(params.Arguments, &args); err == nil {
+						reply = f.replyWithDebugAddress(ctx, reply, args)
+					} else {
+						event.Error(ctx, "unmarshaling debugging args", err)
+					}
+				}
+			} else {
+				event.Error(ctx, "intercepting executeCommand request", err)
+			}
+		}
 		// The gopls workspace environment defaults to the process environment in
 		// which gopls daemon was started. To avoid discrepancies in Go environment
 		// between the editor and daemon, inject any unset variables in `go env`
 		// into the options sent by initialize.
 		//
 		// See also golang.org/issue/37830.
-		if r.Method() == "initialize" {
-			if newr, err := addGoEnvToInitializeRequest(ctx, r); err == nil {
-				r = newr
-			} else {
-				log.Printf("unable to add local env to initialize request: %v", err)
-			}
-		}
 		return handler(ctx, reply, r)
 	}
 }
@@ -452,6 +513,45 @@
 	return envmap, nil
 }
 
+func (f *Forwarder) replyWithDebugAddress(outerCtx context.Context, r jsonrpc2.Replier, args command.DebuggingArgs) jsonrpc2.Replier {
+	di := debug.GetInstance(outerCtx)
+	if di == nil {
+		event.Log(outerCtx, "no debug instance to start")
+		return r
+	}
+	return func(ctx context.Context, result interface{}, outerErr error) error {
+		if outerErr != nil {
+			return r(ctx, result, outerErr)
+		}
+		// Enrich the result with our own debugging information. Since we're an
+		// intermediary, the jsonrpc2 package has deserialized the result into
+		// maps, by default. Re-do the unmarshalling.
+		raw, err := json.Marshal(result)
+		if err != nil {
+			event.Error(outerCtx, "marshaling intermediate command result", err)
+			return r(ctx, result, err)
+		}
+		var modified command.DebuggingResult
+		if err := json.Unmarshal(raw, &modified); err != nil {
+			event.Error(outerCtx, "unmarshaling intermediate command result", err)
+			return r(ctx, result, err)
+		}
+		addr := args.Addr
+		if addr == "" {
+			addr = "localhost:0"
+		}
+		addr, err = di.Serve(outerCtx, addr)
+		if err != nil {
+			event.Error(outerCtx, "starting debug server", err)
+			return r(ctx, result, outerErr)
+		}
+		urls := []string{"http://" + addr}
+		modified.URLs = append(urls, modified.URLs...)
+		go f.handshake(ctx)
+		return r(ctx, modified, nil)
+	}
+}
+
 // A handshakeRequest identifies a client to the LSP server.
 type handshakeRequest struct {
 	// ServerID is the ID of the server on the client. This should usually be 0.
@@ -535,10 +635,10 @@
 			}
 			if di := debug.GetInstance(ctx); di != nil {
 				resp.Logfile = di.Logfile
-				resp.DebugAddr = di.ListenedDebugAddress
+				resp.DebugAddr = di.ListenedDebugAddress()
 			}
-
 			return reply(ctx, resp, nil)
+
 		case sessionsMethod:
 			resp := ServerState{
 				GoplsPath:       goplsPath,
@@ -546,7 +646,7 @@
 			}
 			if di := debug.GetInstance(ctx); di != nil {
 				resp.Logfile = di.Logfile
-				resp.DebugAddr = di.ListenedDebugAddress
+				resp.DebugAddr = di.ListenedDebugAddress()
 				for _, c := range di.State.Clients() {
 					resp.Clients = append(resp.Clients, ClientSession{
 						SessionID: c.Session.ID(),
@@ -567,3 +667,18 @@
 		event.Error(ctx, "", err)
 	}
 }
+
+// ParseAddr parses the address of a gopls remote.
+// TODO(rFindley): further document this syntax, and allow URI-style remote
+// addresses such as "auto://...".
+func ParseAddr(listen string) (network string, address string) {
+	// Allow passing just -remote=auto, as a shorthand for using automatic remote
+	// resolution.
+	if listen == AutoNetwork {
+		return AutoNetwork, ""
+	}
+	if parts := strings.SplitN(listen, ";", 2); len(parts) == 2 {
+		return parts[0], parts[1]
+	}
+	return "tcp", listen
+}
diff --git a/internal/lsp/lsprpc/lsprpc_test.go b/internal/lsp/lsprpc/lsprpc_test.go
index 538569b..5fa6b97 100644
--- a/internal/lsp/lsprpc/lsprpc_test.go
+++ b/internal/lsp/lsprpc/lsprpc_test.go
@@ -323,3 +323,24 @@
 		t.Errorf("GONOPROXY environment variable was overwritten")
 	}
 }
+
+func TestListenParsing(t *testing.T) {
+	tests := []struct {
+		input, wantNetwork, wantAddr string
+	}{
+		{"127.0.0.1:0", "tcp", "127.0.0.1:0"},
+		{"unix;/tmp/sock", "unix", "/tmp/sock"},
+		{"auto", "auto", ""},
+		{"auto;foo", "auto", "foo"},
+	}
+
+	for _, test := range tests {
+		gotNetwork, gotAddr := ParseAddr(test.input)
+		if gotNetwork != test.wantNetwork {
+			t.Errorf("network = %q, want %q", gotNetwork, test.wantNetwork)
+		}
+		if gotAddr != test.wantAddr {
+			t.Errorf("addr = %q, want %q", gotAddr, test.wantAddr)
+		}
+	}
+}
diff --git a/internal/lsp/protocol/tsclient.go b/internal/lsp/protocol/tsclient.go
index 0287aca..1f33c02 100644
--- a/internal/lsp/protocol/tsclient.go
+++ b/internal/lsp/protocol/tsclient.go
@@ -6,8 +6,8 @@
 
 // Package protocol contains data types and code for LSP jsonrpcs
 // generated automatically from vscode-languageserver-node
-// commit: dae62de921d25964e8732411ca09e532dde992f5
-// last fetched Thu Feb 04 2021 11:11:02 GMT-0500 (Eastern Standard Time)
+// commit: d58c00bbf8837b9fd0144924db5e7b1c543d839e
+// last fetched Sat Apr 17 2021 08:26:29 GMT-0400 (Eastern Daylight Time)
 
 // Code generated (see typescript/README.md) DO NOT EDIT.
 
@@ -28,6 +28,7 @@
 	WorkspaceFolders(context.Context) ([]WorkspaceFolder /*WorkspaceFolder[] | null*/, error)
 	Configuration(context.Context, *ParamConfiguration) ([]interface{}, error)
 	WorkDoneProgressCreate(context.Context, *WorkDoneProgressCreateParams) error
+	ShowDocument(context.Context, *ShowDocumentParams) (*ShowDocumentResult, error)
 	RegisterCapability(context.Context, *RegistrationParams) error
 	UnregisterCapability(context.Context, *UnregistrationParams) error
 	ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem /*MessageActionItem | null*/, error)
@@ -91,6 +92,13 @@
 		}
 		err := client.WorkDoneProgressCreate(ctx, &params)
 		return true, reply(ctx, nil, err)
+	case "window/showDocument": // req
+		var params ShowDocumentParams
+		if err := json.Unmarshal(r.Params(), &params); err != nil {
+			return true, sendParseError(ctx, reply, err)
+		}
+		resp, err := client.ShowDocument(ctx, &params)
+		return true, reply(ctx, resp, err)
 	case "client/registerCapability": // req
 		var params RegistrationParams
 		if err := json.Unmarshal(r.Params(), &params); err != nil {
@@ -164,6 +172,14 @@
 	return Call(ctx, s.Conn, "window/workDoneProgress/create", params, nil) // Call, not Notify
 }
 
+func (s *clientDispatcher) ShowDocument(ctx context.Context, params *ShowDocumentParams) (*ShowDocumentResult, error) {
+	var result *ShowDocumentResult
+	if err := Call(ctx, s.Conn, "window/showDocument", params, &result); err != nil {
+		return nil, err
+	}
+	return result, nil
+}
+
 func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error {
 	return Call(ctx, s.Conn, "client/registerCapability", params, nil) // Call, not Notify
 }
diff --git a/internal/lsp/protocol/tsprotocol.go b/internal/lsp/protocol/tsprotocol.go
index 0a2590b..51d6142 100644
--- a/internal/lsp/protocol/tsprotocol.go
+++ b/internal/lsp/protocol/tsprotocol.go
@@ -4,8 +4,8 @@
 
 // Package protocol contains data types and code for LSP jsonrpcs
 // generated automatically from vscode-languageserver-node
-// commit: dae62de921d25964e8732411ca09e532dde992f5
-// last fetched Thu Feb 04 2021 11:11:02 GMT-0500 (Eastern Standard Time)
+// commit: d58c00bbf8837b9fd0144924db5e7b1c543d839e
+// last fetched Sat Apr 17 2021 08:26:29 GMT-0400 (Eastern Daylight Time)
 package protocol
 
 // Code generated (see typescript/README.md) DO NOT EDIT.
@@ -219,19 +219,19 @@
  */
 type ChangeAnnotation struct {
 	/**
-	           * A human-readable string describing the actual change. The string
-	  		 * is rendered prominent in the user interface.
+	       * A human-readable string describing the actual change. The string
+	  	 * is rendered prominent in the user interface.
 	*/
 	Label string `json:"label"`
 	/**
-	           * A flag which indicates that user confirmation is needed
-	  		 * before applying the change.
+	       * A flag which indicates that user confirmation is needed
+	  	 * before applying the change.
 	*/
 	NeedsConfirmation bool `json:"needsConfirmation,omitempty"`
 	/**
-	           * A human-readable string which is rendered less prominent in
-	  		 * the user interface.
-	*/
+	 * A human-readable string which is rendered less prominent in
+	 * the user interface.
+	 */
 	Description string `json:"description,omitempty"`
 }
 
@@ -772,6 +772,13 @@
 		InsertTextModeSupport struct {
 			ValueSet []InsertTextMode `json:"valueSet"`
 		} `json:"insertTextModeSupport,omitempty"`
+		/**
+		 * The client has support for completion item label
+		 * details (see also `CompletionItemLabelDetails`).
+		 *
+		 * @since 3.17.0 - proposed state
+		 */
+		LabelDetailsSupport bool `json:"labelDetailsSupport,omitempty"`
 	} `json:"completionItem,omitempty"`
 	CompletionItemKind struct {
 		/**
@@ -822,12 +829,22 @@
  */
 type CompletionItem struct {
 	/**
-	 * The label of this completion item. By default
-	 * also the text that is inserted when selecting
-	 * this completion.
+	 * The label of this completion item.
+	 *
+	 * The label property is also by default the text that
+	 * is inserted when selecting this completion.
+	 *
+	 * If label details are provided the label itself should
+	 * be an unqualified name of the completion item.
 	 */
 	Label string `json:"label"`
 	/**
+	 * Additional details for the label
+	 *
+	 * @since 3.17.0 - proposed state
+	 */
+	LabelDetails CompletionItemLabelDetails `json:"labelDetails,omitempty"`
+	/**
 	 * The kind of this completion item. Based of the kind
 	 * an icon is chosen by the editor.
 	 */
@@ -941,9 +958,8 @@
 	 */
 	Command *Command `json:"command,omitempty"`
 	/**
-	 * A data entry field that is preserved on a completion item between
-	 * a [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest]
-	 * (#CompletionResolveRequest)
+	 * A data entry field that is preserved on a completion item between a
+	 * [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest](#CompletionResolveRequest).
 	 */
 	Data interface{} `json:"data,omitempty"`
 }
@@ -954,6 +970,26 @@
 type CompletionItemKind float64
 
 /**
+ * Additional details for a completion item label.
+ *
+ * @since 3.17.0 - proposed state
+ */
+type CompletionItemLabelDetails struct {
+	/**
+	 * The parameters without the return type.
+	 */
+	Parameters string `json:"parameters,omitempty"`
+	/**
+	 * The fully qualified name, like package name or file path.
+	 */
+	Qualifier string `json:"qualifier,omitempty"`
+	/**
+	 * The return-type of a function or type of a property/variable.
+	 */
+	Type string `json:"type,omitempty"`
+}
+
+/**
  * Completion item tags are extra annotations that tweak the rendering of a completion
  * item.
  *
@@ -1007,6 +1043,22 @@
 	 * information for a completion item.
 	 */
 	ResolveProvider bool `json:"resolveProvider,omitempty"`
+	/**
+	 * The server supports the following `CompletionItem` specific
+	 * capabilities.
+	 *
+	 * @since 3.17.0 - proposed state
+	 */
+	CompletionItem struct {
+		/**
+		 * The server has support for completion item label
+		 * details (see also `CompletionItemLabelDetails`) when
+		 * receiving a completion item in a resolve call.
+		 *
+		 * @since 3.17.0 - proposed state
+		 */
+		LabelDetailsSupport bool `json:"labelDetailsSupport,omitempty"`
+	} `json:"completionItem,omitempty"`
 	WorkDoneProgressOptions
 }
 
@@ -1482,6 +1534,52 @@
 }
 
 /**
+ * @since 3.17.0 - proposed state
+ */
+type DocumentDiagnosticParams struct {
+	/**
+	 * The text document.
+	 */
+	TextDocument TextDocumentIdentifier `json:"textDocument"`
+	/**
+	 * The additional identifier  provided during registration.
+	 */
+	Identifier string `json:"identifier,omitempty"`
+	/**
+	 * The result id of a previous response if provided.
+	 */
+	PreviousResultID string `json:"previousResultId,omitempty"`
+	WorkDoneProgressParams
+	PartialResultParams
+}
+
+/**
+ * The result of a document diagnostic pull request. A report can
+ * either be a new report containing all diagnostics for the
+ * requested document or a unchanged report indicating that nothing
+ * has changed in terms of diagnostics in comparison to the last
+ * pull request.
+ *
+ * @since 3.17.0 - proposed state
+ */
+type DocumentDiagnosticReport = struct {
+	/**
+	 * A new document diagnostic report.
+	 */
+	Kind string `json:"kind"`
+	/**
+	 * An optional result id. If provided it will
+	 * be sent on the next diagnostic request for the
+	 * same document.
+	 */
+	ResultID string `json:"resultId,omitempty"`
+	/**
+	 * The actual items.
+	 */
+	Items []Diagnostic `json:"items"`
+}
+
+/**
  * A document filter denotes a document by different properties like
  * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of
  * its resource, or a glob-pattern that is applied to the [path](#TextDocument.fileName).
@@ -1490,7 +1588,7 @@
  * - `*` to match one or more characters in a path segment
  * - `?` to match on one character in a path segment
  * - `**` to match any number of path segments, including none
- * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
+ * - `{}` to group sub patterns into an OR expression. (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
  * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
  * - `[!...]` 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`)
  *
@@ -2056,7 +2154,7 @@
 	 * - `*` to match one or more characters in a path segment
 	 * - `?` to match on one character in a path segment
 	 * - `**` to match any number of path segments, including none
-	 * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
+	 * - `{}` to group sub patterns into an OR expression. (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files)
 	 * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
 	 * - `[!...]` 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`)
 	 */
@@ -3389,6 +3487,9 @@
 	StaticRegistrationOptions
 }
 
+/**
+ * @since 3.16.0
+ */
 type SemanticTokensWorkspaceClientCapabilities struct {
 	/**
 	 * Whether the client implementation supports a refresh request sent from
@@ -3396,7 +3497,7 @@
 	 *
 	 * Note that this event is global and will force the client to refresh all
 	 * semantic tokens currently shown. It should be used with absolute care
-	 * and is useful for situation where a server for example detect a project
+	 * and is useful for situation where a server for example detects a project
 	 * wide change that requires such a calculation.
 	 */
 	RefreshSupport bool `json:"refreshSupport,omitempty"`
@@ -4288,29 +4389,6 @@
 	Reason TextDocumentSaveReason `json:"reason"`
 }
 
-type WindowClientCapabilities struct {
-	/**
-	 * Whether client supports handling progress notifications. If set
-	 * servers are allowed to report in `workDoneProgress` property in the
-	 * request specific server capabilities.
-	 *
-	 * @since 3.15.0
-	 */
-	WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
-	/**
-	 * Capabilities specific to the showMessage request.
-	 *
-	 * @since 3.16.0
-	 */
-	ShowMessage ShowMessageRequestClientCapabilities `json:"showMessage,omitempty"`
-	/**
-	 * Capabilities specific to the showDocument request.
-	 *
-	 * @since 3.16.0
-	 */
-	ShowDocument ShowDocumentClientCapabilities `json:"showDocument,omitempty"`
-}
-
 type WorkDoneProgressBegin struct {
 	Kind string `json:"kind"`
 	/**
@@ -4486,10 +4564,59 @@
 	FileOperations FileOperationClientCapabilities `json:"fileOperations,omitempty"`
 }
 
+type WorkspaceDiagnosticParams struct {
+	/**
+	 * The additional identifier provided during registration.
+	 */
+	Identifier string `json:"identifier,omitempty"`
+	/**
+	 * The currently known diagnostic reports with their
+	 * previous result ids.
+	 */
+	PreviousResultIds []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"`
+	} `json:"previousResultIds"`
+	WorkDoneProgressParams
+	PartialResultParams
+}
+
+type WorkspaceDiagnosticReport struct {
+	Items []WorkspaceDocumentDiagnosticReport `json:"items"`
+}
+
+type WorkspaceDocumentDiagnosticReport struct {
+	/**
+	 * The URI for which diagnostic information is reported.
+	 */
+	URI DocumentURI `json:"uri"`
+	/**
+	 * The version number for which the diagnostics are reported.
+	 * If the document is not marked as open `null` can be provided.
+	 */
+	Version int32/*integer | null*/ `json:"version"`
+}
+
 /**
  * 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.
+ *
+ * Since version 3.13.0 a workspace edit can contain resource operations as well. If resource
+ * operations are present clients need to execute the operations in the order in which they
+ * are provided. So a workspace edit for example can consist of the following two changes:
+ * (1) a create file a.txt and (2) a text document edit which insert text into file a.txt.
+ *
+ * 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 {
 	/**
diff --git a/internal/lsp/protocol/tsserver.go b/internal/lsp/protocol/tsserver.go
index c93c8ef..a479968 100644
--- a/internal/lsp/protocol/tsserver.go
+++ b/internal/lsp/protocol/tsserver.go
@@ -6,8 +6,8 @@
 
 // Package protocol contains data types and code for LSP jsonrpcs
 // generated automatically from vscode-languageserver-node
-// commit: dae62de921d25964e8732411ca09e532dde992f5
-// last fetched Thu Feb 04 2021 11:11:02 GMT-0500 (Eastern Standard Time)
+// commit: d58c00bbf8837b9fd0144924db5e7b1c543d839e
+// last fetched Sat Apr 17 2021 08:26:29 GMT-0400 (Eastern Daylight Time)
 
 // Code generated (see typescript/README.md) DO NOT EDIT.
 
@@ -47,10 +47,9 @@
 	IncomingCalls(context.Context, *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall /*CallHierarchyIncomingCall[] | null*/, error)
 	OutgoingCalls(context.Context, *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall /*CallHierarchyOutgoingCall[] | null*/, error)
 	SemanticTokensFull(context.Context, *SemanticTokensParams) (*SemanticTokens /*SemanticTokens | null*/, error)
-	SemanticTokensFullDelta(context.Context, *SemanticTokensDeltaParams) (interface{} /* SemanticTokens | SemanticTokensDelta | nil*/, error)
+	SemanticTokensFullDelta(context.Context, *SemanticTokensDeltaParams) (interface{} /* SemanticTokens | SemanticTokensDelta | float64*/, error)
 	SemanticTokensRange(context.Context, *SemanticTokensRangeParams) (*SemanticTokens /*SemanticTokens | null*/, error)
 	SemanticTokensRefresh(context.Context) error
-	ShowDocument(context.Context, *ShowDocumentParams) (*ShowDocumentResult, error)
 	LinkedEditingRange(context.Context, *LinkedEditingRangeParams) (*LinkedEditingRanges /*LinkedEditingRanges | null*/, error)
 	WillCreateFiles(context.Context, *CreateFilesParams) (*WorkspaceEdit /*WorkspaceEdit | null*/, error)
 	WillRenameFiles(context.Context, *RenameFilesParams) (*WorkspaceEdit /*WorkspaceEdit | null*/, error)
@@ -81,6 +80,9 @@
 	Rename(context.Context, *RenameParams) (*WorkspaceEdit /*WorkspaceEdit | null*/, error)
 	PrepareRename(context.Context, *PrepareRenameParams) (*Range /*Range | { range: Range, placeholder: string } | { defaultBehavior: boolean } | null*/, error)
 	ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{} /*any | null*/, error)
+	Diagnostic(context.Context, *string) (*string, error)
+	DiagnosticWorkspace(context.Context, *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error)
+	DiagnosticRefresh(context.Context) error
 	NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error)
 }
 
@@ -291,13 +293,6 @@
 		}
 		err := server.SemanticTokensRefresh(ctx)
 		return true, reply(ctx, nil, err)
-	case "window/showDocument": // req
-		var params ShowDocumentParams
-		if err := json.Unmarshal(r.Params(), &params); err != nil {
-			return true, sendParseError(ctx, reply, err)
-		}
-		resp, err := server.ShowDocument(ctx, &params)
-		return true, reply(ctx, resp, err)
 	case "textDocument/linkedEditingRange": // req
 		var params LinkedEditingRangeParams
 		if err := json.Unmarshal(r.Params(), &params); err != nil {
@@ -336,7 +331,9 @@
 	case "initialize": // req
 		var params ParamInitialize
 		if err := json.Unmarshal(r.Params(), &params); err != nil {
-			return true, sendParseError(ctx, reply, err)
+			if _, ok := err.(*json.UnmarshalTypeError); !ok {
+				return true, sendParseError(ctx, reply, err)
+			}
 		}
 		resp, err := server.Initialize(ctx, &params)
 		return true, reply(ctx, resp, err)
@@ -506,6 +503,26 @@
 		}
 		resp, err := server.ExecuteCommand(ctx, &params)
 		return true, reply(ctx, resp, err)
+	case "textDocument/diagnostic": // req
+		var params string
+		if err := json.Unmarshal(r.Params(), &params); err != nil {
+			return true, sendParseError(ctx, reply, err)
+		}
+		resp, err := server.Diagnostic(ctx, &params)
+		return true, reply(ctx, resp, err)
+	case "workspace/diagnostic": // req
+		var params WorkspaceDiagnosticParams
+		if err := json.Unmarshal(r.Params(), &params); err != nil {
+			return true, sendParseError(ctx, reply, err)
+		}
+		resp, err := server.DiagnosticWorkspace(ctx, &params)
+		return true, reply(ctx, resp, err)
+	case "workspace/diagnostic/refresh": // req
+		if len(r.Params()) > 0 {
+			return true, reply(ctx, nil, errors.Errorf("%w: expected no params", jsonrpc2.ErrInvalidParams))
+		}
+		err := server.DiagnosticRefresh(ctx)
+		return true, reply(ctx, nil, err)
 
 	default:
 		return false, nil
@@ -663,8 +680,8 @@
 	return result, nil
 }
 
-func (s *serverDispatcher) SemanticTokensFullDelta(ctx context.Context, params *SemanticTokensDeltaParams) (interface{} /* SemanticTokens | SemanticTokensDelta | nil*/, error) {
-	var result interface{} /* SemanticTokens | SemanticTokensDelta | nil*/
+func (s *serverDispatcher) SemanticTokensFullDelta(ctx context.Context, params *SemanticTokensDeltaParams) (interface{} /* SemanticTokens | SemanticTokensDelta | float64*/, error) {
+	var result interface{} /* SemanticTokens | SemanticTokensDelta | float64*/
 	if err := Call(ctx, s.Conn, "textDocument/semanticTokens/full/delta", params, &result); err != nil {
 		return nil, err
 	}
@@ -683,14 +700,6 @@
 	return Call(ctx, s.Conn, "workspace/semanticTokens/refresh", nil, nil)
 }
 
-func (s *serverDispatcher) ShowDocument(ctx context.Context, params *ShowDocumentParams) (*ShowDocumentResult, error) {
-	var result *ShowDocumentResult
-	if err := Call(ctx, s.Conn, "window/showDocument", params, &result); err != nil {
-		return nil, err
-	}
-	return result, nil
-}
-
 func (s *serverDispatcher) LinkedEditingRange(ctx context.Context, params *LinkedEditingRangeParams) (*LinkedEditingRanges /*LinkedEditingRanges | null*/, error) {
 	var result *LinkedEditingRanges /*LinkedEditingRanges | null*/
 	if err := Call(ctx, s.Conn, "textDocument/linkedEditingRange", params, &result); err != nil {
@@ -923,6 +932,26 @@
 	return result, nil
 }
 
+func (s *serverDispatcher) Diagnostic(ctx context.Context, params *string) (*string, error) {
+	var result *string
+	if err := Call(ctx, s.Conn, "textDocument/diagnostic", params, &result); err != nil {
+		return nil, err
+	}
+	return result, nil
+}
+
+func (s *serverDispatcher) DiagnosticWorkspace(ctx context.Context, params *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error) {
+	var result *WorkspaceDiagnosticReport
+	if err := Call(ctx, s.Conn, "workspace/diagnostic", params, &result); err != nil {
+		return nil, err
+	}
+	return result, nil
+}
+
+func (s *serverDispatcher) DiagnosticRefresh(ctx context.Context) error {
+	return Call(ctx, s.Conn, "workspace/diagnostic/refresh", nil, nil)
+}
+
 func (s *serverDispatcher) NonstandardRequest(ctx context.Context, method string, params interface{}) (interface{}, error) {
 	var result interface{}
 	if err := Call(ctx, s.Conn, method, params, &result); err != nil {
diff --git a/internal/lsp/protocol/typescript/README.md b/internal/lsp/protocol/typescript/README.md
index bf6dc8d..61ba187 100644
--- a/internal/lsp/protocol/typescript/README.md
+++ b/internal/lsp/protocol/typescript/README.md
@@ -3,14 +3,15 @@
 ## Setup
 
 Make sure `node` and `tsc` are installed and in your PATH. There are detailed instructions below.
+(`tsc -v` should be at least `4.2.4`.)
 Get the typescript code for the jsonrpc protocol with
 
 `git clone git@github.com:microsoft vscode-languageserver-node.git` or
 `git clone https://github.com/microsoft/vscode-languageserver-node.git`
 
-`util.ts`` expects it to be in your HOME directory
+`util.ts` expects it to be in your HOME directory
 
-If you want to reproduce the existing files you need to be on a branch with the same git hash, for instance, `git checkout 7b90c29`
+If you want to reproduce the existing files you need to be on a branch with the same git hash that `util.ts` expects, for instance, `git checkout 7b90c29`
 
 ## Usage
 
@@ -50,5 +51,5 @@
     1. This will likely give warning messages that indicate you've failed to set up a project. Ignore them.
     2. Your home directory will now have new directories `.npm` and `node_modules` (and a `package_lock.json` file)
     3. The typescript executable `tsc` will be in `node_modules/.bin`, so put that directory in your path.
-    4. `tsc -v` should print "Version 3.7.2" (or later). If not you may (as I did) have an obsolete tsc earlier in your path.
+    4. `tsc -v` should print "Version 4.2.4" (or later). If not you may (as I did) have an obsolete tsc earlier in your path.
 6. `npm install @types/node` (Without this there will be many incomprehensible typescript error messages.)
diff --git a/internal/lsp/protocol/typescript/code.ts b/internal/lsp/protocol/typescript/code.ts
index dc5d266..abf7345 100644
--- a/internal/lsp/protocol/typescript/code.ts
+++ b/internal/lsp/protocol/typescript/code.ts
@@ -135,6 +135,7 @@
   receives.set('workspace/applyEdit', 'client');
   receives.set('textDocument/publishDiagnostics', 'client');
   receives.set('window/workDoneProgress/create', 'client');
+  receives.set('window/showDocument', 'client');
   receives.set('$/progress', 'client');
   // a small check
   receives.forEach((_, k) => {
@@ -806,6 +807,8 @@
   if (!n) throw new Error(`goType undefined for ${nm}`);
   if (n.getText() == 'T') return 'interface{}';  // should check it's generic
   if (ts.isTypeReferenceNode(n)) {
+    // DocumentDiagnosticReportKind.unChanged (or .new) value is "new" or "unChanged"
+    if (n.getText().startsWith('DocumentDiagnostic')) return 'string';
     switch (n.getText()) {
       case 'integer': return 'int32';
       case 'uinteger': return 'uint32';
@@ -901,8 +904,12 @@
       if (a == 'TypeLiteral' && nm == 'TextDocumentContentChangeEvent') {
         return `${goType(n.types[0], nm)}`;
       }
-      console.log(`911 ${n.types[1].getText()} ${loc(n.types[1])}`);
-      throw new Error(`912 ${nm}: a:${a} b:${b} ${n.getText()} ${loc(n)}`);
+      if (a == 'TypeLiteral' && b === 'TypeLiteral') {
+        // DocumentDiagnosticReport
+        // the first one includes the second one
+        return `${goType(n.types[0], '9d')}`;
+      }
+      throw new Error(`911 ${nm}: a:${a}/${goType(n.types[0], '9a')} b:${b}/${goType(n.types[1], '9b')} ${loc(n)}`);
     }
     case 3: {
       const aa = strKind(n.types[0]);
@@ -916,18 +923,20 @@
       if (nm == 'textDocument/documentSymbol') {
         return `[]interface{} ${help}`;
       }
-      if (aa == 'TypeReference' && bb == 'ArrayType' && cc == 'NullKeyword') {
+      if (aa == 'TypeReference' && bb == 'ArrayType' && (cc == 'NullKeyword' || cc === 'LiteralType')) {
         return `${goType(n.types[0], 'd')} ${help}`;
       }
       if (aa == 'TypeReference' && bb == aa && cc == 'ArrayType') {
         // should check that this is Hover.Contents
         return `${goType(n.types[0], 'e')} ${help}`;
       }
-      if (aa == 'ArrayType' && bb == 'TypeReference' && cc == 'NullKeyword') {
+      if (aa == 'ArrayType' && bb == 'TypeReference' && (cc == 'NullKeyword' || cc === 'LiteralType')) {
         // check this is nm == 'textDocument/completion'
         return `${goType(n.types[1], 'f')} ${help}`;
       }
       if (aa == 'LiteralType' && bb == aa && cc == aa) return `string ${help}`;
+      // keep this for diagnosing unexpected interface{} results
+      // console.log(`931, interface{} for ${aa}/${goType(n.types[0], 'g')},${bb}/${goType(n.types[1], 'h')},${cc}/${goType(n.types[2], 'i')} ${nm}`);
       break;
     }
     case 4:
@@ -1039,6 +1048,7 @@
     case 'TypeReference': {
       if (!ts.isTypeReferenceNode(te)) throw new Error(`1047 impossible ${strKind(te)}`);
       const d = seenTypes.get(goName(te.typeName.getText()));
+      if (d === undefined) return false;
       if (d.properties.length > 1) return true;
       // alias or interface with a single property (The alias is Uinteger, which we ignore later)
       if (d.alias) return false;
@@ -1206,6 +1216,14 @@
     if err := json.Unmarshal(r.Params(), &params); err != nil {
       return true, sendParseError(ctx, reply, err)
     }`;
+    if (a === 'ParamInitialize') {
+      case1 = `var params ${a}
+    if err := json.Unmarshal(r.Params(), &params); err != nil {
+      if _, ok := err.(*json.UnmarshalTypeError); !ok {
+        return true, sendParseError(ctx, reply, err)
+      }
+    }`;
+    }
   }
   const arg2 = a == '' ? '' : ', &params';
   // if case2 is not explicitly typed string, typescript makes it a union of strings
@@ -1253,8 +1271,7 @@
     x = prefix + suffix;
   }
   if (seenNames.has(x)) {
-    // Resolve, ResolveCodeLens, ResolveDocumentLink
-    if (!x.startsWith('Resolve')) throw new Error(`expected Resolve, not ${x}`);
+    // various Resolve and Diagnostic
     x += m[0].toUpperCase() + m.substring(1, i);
   }
   seenNames.add(x);
diff --git a/internal/lsp/protocol/typescript/util.ts b/internal/lsp/protocol/typescript/util.ts
index a4f5d7e..dde178e 100644
--- a/internal/lsp/protocol/typescript/util.ts
+++ b/internal/lsp/protocol/typescript/util.ts
@@ -15,7 +15,7 @@
   `${dir}/${srcDir}/protocol/src/browser/main.ts`, `${dir}${srcDir}/types/src/main.ts`,
   `${dir}${srcDir}/jsonrpc/src/node/main.ts`
 ];
-export const gitHash = 'dae62de921d25964e8732411ca09e532dde992f5';
+export const gitHash = 'd58c00bbf8837b9fd0144924db5e7b1c543d839e';
 let outFname = 'tsprotocol.go';
 let fda: number, fdb: number, fde: number;  // file descriptors
 
diff --git a/gopls/internal/regtest/doc.go b/internal/lsp/regtest/doc.go
similarity index 100%
rename from gopls/internal/regtest/doc.go
rename to internal/lsp/regtest/doc.go
diff --git a/gopls/internal/regtest/env.go b/internal/lsp/regtest/env.go
similarity index 100%
rename from gopls/internal/regtest/env.go
rename to internal/lsp/regtest/env.go
diff --git a/gopls/internal/regtest/env_test.go b/internal/lsp/regtest/env_test.go
similarity index 100%
rename from gopls/internal/regtest/env_test.go
rename to internal/lsp/regtest/env_test.go
diff --git a/gopls/internal/regtest/expectation.go b/internal/lsp/regtest/expectation.go
similarity index 100%
rename from gopls/internal/regtest/expectation.go
rename to internal/lsp/regtest/expectation.go
diff --git a/gopls/internal/regtest/regtest.go b/internal/lsp/regtest/regtest.go
similarity index 93%
rename from gopls/internal/regtest/regtest.go
rename to internal/lsp/regtest/regtest.go
index 7a4fa27..c1df26d 100644
--- a/gopls/internal/regtest/regtest.go
+++ b/internal/lsp/regtest/regtest.go
@@ -15,6 +15,7 @@
 	"time"
 
 	"golang.org/x/tools/internal/lsp/cmd"
+	"golang.org/x/tools/internal/lsp/source"
 	"golang.org/x/tools/internal/testenv"
 	"golang.org/x/tools/internal/tool"
 )
@@ -83,9 +84,12 @@
 }
 
 // Main sets up and tears down the shared regtest state.
-func Main(m *testing.M) {
+func Main(m *testing.M, hook func(*source.Options)) {
 	testenv.ExitIfSmallMachine()
 
+	// Disable GOPACKAGESDRIVER, as it can cause spurious test failures.
+	os.Setenv("GOPACKAGESDRIVER", "off")
+
 	flag.Parse()
 	if os.Getenv("_GOPLS_TEST_BINARY_RUN_AS_GOPLS") == "true" {
 		tool.Main(context.Background(), cmd.New("gopls", "", nil, nil), os.Args[1:])
@@ -97,6 +101,7 @@
 		Timeout:                  *regtestTimeout,
 		PrintGoroutinesOnFailure: *printGoroutinesOnFailure,
 		SkipCleanup:              *skipCleanup,
+		OptionsHook:              hook,
 	}
 	if *runSubprocessTests {
 		goplsPath := *goplsBinaryPath
diff --git a/gopls/internal/regtest/runner.go b/internal/lsp/regtest/runner.go
similarity index 98%
rename from gopls/internal/regtest/runner.go
rename to internal/lsp/regtest/runner.go
index cfa64af..87cfa6d 100644
--- a/gopls/internal/regtest/runner.go
+++ b/internal/lsp/regtest/runner.go
@@ -21,7 +21,6 @@
 
 	exec "golang.org/x/sys/execabs"
 
-	"golang.org/x/tools/gopls/internal/hooks"
 	"golang.org/x/tools/internal/jsonrpc2"
 	"golang.org/x/tools/internal/jsonrpc2/servertest"
 	"golang.org/x/tools/internal/lsp/cache"
@@ -60,6 +59,7 @@
 	PrintGoroutinesOnFailure bool
 	TempDir                  string
 	SkipCleanup              bool
+	OptionsHook              func(*source.Options)
 
 	mu        sync.Mutex
 	ts        *servertest.TCPServer
@@ -84,7 +84,7 @@
 	return &runConfig{
 		modes:       r.DefaultModes,
 		timeout:     r.Timeout,
-		optionsHook: hooks.Options,
+		optionsHook: r.OptionsHook,
 	}
 }
 
@@ -261,8 +261,7 @@
 			ctx = debug.WithInstance(ctx, "", "off")
 			if config.debugAddr != "" {
 				di := debug.GetInstance(ctx)
-				di.DebugAddress = config.debugAddr
-				di.Serve(ctx)
+				di.Serve(ctx, config.debugAddr)
 				di.MonitorMemory(ctx)
 			}
 
diff --git a/gopls/internal/regtest/wrappers.go b/internal/lsp/regtest/wrappers.go
similarity index 97%
rename from gopls/internal/regtest/wrappers.go
rename to internal/lsp/regtest/wrappers.go
index 2038849..125b8dc 100644
--- a/gopls/internal/regtest/wrappers.go
+++ b/internal/lsp/regtest/wrappers.go
@@ -156,7 +156,7 @@
 }
 
 // GoToDefinition goes to definition in the editor, calling t.Fatal on any
-// error.
+// error. It returns the path and position of the resulting jump.
 func (e *Env) GoToDefinition(name string, pos fake.Pos) (string, fake.Pos) {
 	e.T.Helper()
 	n, p, err := e.Editor.GoToDefinition(e.Ctx, name, pos)
@@ -201,6 +201,14 @@
 	}
 }
 
+// ApplyCodeAction applies the given code action.
+func (e *Env) ApplyCodeAction(action protocol.CodeAction) {
+	e.T.Helper()
+	if err := e.Editor.ApplyCodeAction(e.Ctx, action); err != nil {
+		e.T.Fatal(err)
+	}
+}
+
 // GetQuickFixes returns the available quick fix code actions.
 func (e *Env) GetQuickFixes(path string, diagnostics []protocol.Diagnostic) []protocol.CodeAction {
 	e.T.Helper()
diff --git a/internal/lsp/semantic.go b/internal/lsp/semantic.go
index fbca581..029e5bf 100644
--- a/internal/lsp/semantic.go
+++ b/internal/lsp/semantic.go
@@ -22,6 +22,9 @@
 	errors "golang.org/x/xerrors"
 )
 
+// reject full semantic token requests for large files
+const maxFullFileSize int = 100000
+
 func (s *Server) semanticTokensFull(ctx context.Context, p *protocol.SemanticTokensParams) (*protocol.SemanticTokens, error) {
 	ret, err := s.computeSemanticTokens(ctx, p.TextDocument, nil)
 	return ret, err
@@ -68,6 +71,11 @@
 	if pgf.ParseErr != nil {
 		return nil, pgf.ParseErr
 	}
+	if rng == nil && len(pgf.Src) > maxFullFileSize {
+		err := fmt.Errorf("semantic tokens: file %s too large for full (%d>%d)",
+			td.URI.SpanURI().Filename(), len(pgf.Src), maxFullFileSize)
+		return nil, err
+	}
 	e := &encoded{
 		ctx:      ctx,
 		pgf:      pgf,
@@ -419,6 +427,18 @@
 	}
 }
 
+func isDeprecated(n *ast.CommentGroup) bool {
+	if n == nil {
+		return false
+	}
+	for _, c := range n.List {
+		if strings.HasPrefix(c.Text, "// Deprecated") {
+			return true
+		}
+	}
+	return false
+}
+
 func (e *encoded) definitionFor(x *ast.Ident) (tokenType, []string) {
 	mods := []string{"definition"}
 	for i := len(e.stack) - 1; i >= 0; i-- {
@@ -430,6 +450,9 @@
 			}
 			return "variable", mods
 		case *ast.GenDecl:
+			if isDeprecated(y.Doc) {
+				mods = append(mods, "deprecated")
+			}
 			if y.Tok == token.CONST {
 				mods = append(mods, "readonly")
 			}
@@ -437,6 +460,9 @@
 		case *ast.FuncDecl:
 			// If x is immediately under a FuncDecl, it is a function or method
 			if i == len(e.stack)-2 {
+				if isDeprecated(y.Doc) {
+					mods = append(mods, "deprecated")
+				}
 				if y.Recv != nil {
 					return tokMember, mods
 				}
@@ -491,7 +517,7 @@
 	}
 	span, err := e.pgf.Mapper.RangeSpan(*e.rng)
 	if err != nil {
-		return errors.Errorf("range span error for %s", e.pgf.File.Name)
+		return errors.Errorf("range span (%v) error for %s", err, e.pgf.File.Name)
 	}
 	e.end = e.start + token.Pos(span.End().Offset())
 	e.start += token.Pos(span.Start().Offset())
diff --git a/internal/lsp/server_gen.go b/internal/lsp/server_gen.go
index 59ba823..75069a0 100644
--- a/internal/lsp/server_gen.go
+++ b/internal/lsp/server_gen.go
@@ -1,4 +1,4 @@
-// Copyright 2020 The Go Authors. All rights reserved.
+// 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.
 
@@ -40,6 +40,18 @@
 	return s.definition(ctx, params)
 }
 
+func (s *Server) Diagnostic(context.Context, *string) (*string, error) {
+	return nil, notImplemented("Diagnostic")
+}
+
+func (s *Server) DiagnosticRefresh(context.Context) error {
+	return notImplemented("DiagnosticRefresh")
+}
+
+func (s *Server) DiagnosticWorkspace(context.Context, *protocol.WorkspaceDiagnosticParams) (*protocol.WorkspaceDiagnosticReport, error) {
+	return nil, notImplemented("DiagnosticWorkspace")
+}
+
 func (s *Server) DidChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
 	return s.didChange(ctx, params)
 }
@@ -216,10 +228,6 @@
 	return notImplemented("SetTrace")
 }
 
-func (s *Server) ShowDocument(context.Context, *protocol.ShowDocumentParams) (*protocol.ShowDocumentResult, error) {
-	return nil, notImplemented("ShowDocument")
-}
-
 func (s *Server) Shutdown(ctx context.Context) error {
 	return s.shutdown(ctx)
 }
diff --git a/internal/lsp/source/api_json.go b/internal/lsp/source/api_json.go
index a106c61..3cad876 100755
--- a/internal/lsp/source/api_json.go
+++ b/internal/lsp/source/api_json.go
@@ -34,7 +34,7 @@
 			{
 				Name: "directoryFilters",
 				Type: "[]string",
-				Doc:  "directoryFilters can be used to exclude unwanted directories from the\nworkspace. By default, all directories are included. Filters are an\noperator, `+` to include and `-` to exclude, followed by a path prefix\nrelative to the workspace folder. They are evaluated in order, and\nthe last filter that applies to a path controls whether it is included.\nThe path prefix can be empty, so an initial `-` excludes everything.\n\nExamples:\nExclude node_modules: `-node_modules`\nInclude only project_a: `-` (exclude everything), `+project_a`\nInclude only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`\n",
+				Doc:  "directoryFilters can be used to exclude unwanted directories from the\nworkspace. By default, all directories are included. Filters are an\noperator, `+` to include and `-` to exclude, followed by a path prefix\nrelative to the workspace folder. They are evaluated in order, and\nthe last filter that applies to a path controls whether it is included.\nThe path prefix can be empty, so an initial `-` excludes everything.\n\nExamples:\n\nExclude node_modules: `-node_modules`\n\nInclude only project_a: `-` (exclude everything), `+project_a`\n\nInclude only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`\n",
 				EnumKeys: EnumKeys{
 					ValueType: "",
 					Keys:      nil,
@@ -45,6 +45,28 @@
 				Hierarchy:  "build",
 			},
 			{
+				Name: "memoryMode",
+				Type: "enum",
+				Doc:  "memoryMode controls the tradeoff `gopls` makes between memory usage and\ncorrectness.\n\nValues other than `Normal` are untested and may break in surprising ways.\n",
+				EnumKeys: EnumKeys{
+					ValueType: "",
+					Keys:      nil,
+				},
+				EnumValues: []EnumValue{
+					{
+						Value: "\"DegradeClosed\"",
+						Doc:   "`\"DegradeClosed\"`: In DegradeClosed mode, `gopls` will collect less information about\npackages without open files. As a result, features like Find\nReferences and Rename will miss results in such packages.\n",
+					},
+					{
+						Value: "\"Normal\"",
+						Doc:   "",
+					},
+				},
+				Default:   "\"Normal\"",
+				Status:    "experimental",
+				Hierarchy: "build",
+			},
+			{
 				Name: "expandWorkspaceToModule",
 				Type: "bool",
 				Doc:  "expandWorkspaceToModule instructs `gopls` to adjust the scope of the\nworkspace to find the best available module root. `gopls` first looks for\na go.mod file in any parent directory of the workspace folder, expanding\nthe scope to that directory if it exists. If no viable parent directory is\nfound, gopls will check if there is exactly one child directory containing\na go.mod file, narrowing the scope to that directory if it exists.\n",
@@ -376,7 +398,7 @@
 						},
 						{
 							Name:    "\"fieldalignment\"",
-							Doc:     "find structs that would take less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to take less memory, and provides\na suggested edit with the optimal order.\n",
+							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 optimal 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",
 							Default: "false",
 						},
 						{
@@ -768,6 +790,12 @@
 			ArgDoc:  "{\n\t// The test file containing the tests to run.\n\t\"URI\": string,\n\t// Specific test names to run, e.g. TestFoo.\n\t\"Tests\": []string,\n\t// Specific benchmarks to run, e.g. BenchmarkFoo.\n\t\"Benchmarks\": []string,\n}",
 		},
 		{
+			Command: "gopls.start_debugging",
+			Title:   "",
+			Doc:     "",
+			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}",
+		},
+		{
 			Command: "gopls.test",
 			Title:   "Run test(s) (legacy)",
 			Doc:     "Runs `go test` for a specific set of test or benchmark functions.",
@@ -905,7 +933,7 @@
 		},
 		{
 			Name:    "fieldalignment",
-			Doc:     "find structs that would take less memory if their fields were sorted\n\nThis analyzer find structs that can be rearranged to take less memory, and provides\na suggested edit with the optimal order.\n",
+			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 optimal 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",
 			Default: false,
 		},
 		{
diff --git a/internal/lsp/source/completion/builtin.go b/internal/lsp/source/completion/builtin.go
index 2b59a92..83b7338 100644
--- a/internal/lsp/source/completion/builtin.go
+++ b/internal/lsp/source/completion/builtin.go
@@ -14,13 +14,13 @@
 // argument. It attempts to use the AST hints from builtin.go where
 // possible.
 func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind {
-	builtin, err := c.snapshot.BuiltinPackage(ctx)
+	builtin, err := c.snapshot.BuiltinFile(ctx)
 	if err != nil {
 		return 0
 	}
 	exprIdx := exprAtPos(c.pos, call.Args)
 
-	builtinObj := builtin.Package.Scope.Lookup(obj.Name())
+	builtinObj := builtin.File.Scope.Lookup(obj.Name())
 	if builtinObj == nil {
 		return 0
 	}
diff --git a/internal/lsp/source/completion/completion.go b/internal/lsp/source/completion/completion.go
index 8864081..2c9a826 100644
--- a/internal/lsp/source/completion/completion.go
+++ b/internal/lsp/source/completion/completion.go
@@ -45,7 +45,9 @@
 	// The insert text does not contain snippets.
 	InsertText string
 
-	Kind protocol.CompletionItemKind
+	Kind       protocol.CompletionItemKind
+	Tags       []protocol.CompletionItemTag
+	Deprecated bool // Deprecated, prefer Tags if available
 
 	// An optional array of additional TextEdits that are applied when
 	// selecting this completion.
@@ -386,6 +388,9 @@
 	// For example, dereference=2 turns "foo" into "**foo" when formatting.
 	dereference int
 
+	// takeSlice is true if obj is an array that should be converted to a slice.
+	takeSlice bool
+
 	// variadic is true if this candidate fills a variadic param and
 	// needs "..." appended.
 	variadic bool
@@ -1424,6 +1429,13 @@
 	if c.surrounding != nil {
 		prefix = c.surrounding.Prefix()
 	}
+
+	// Don't suggest unimported packages if we have absolutely nothing
+	// to go on.
+	if prefix == "" {
+		return nil
+	}
+
 	count := 0
 
 	known, err := c.snapshot.CachedImportPaths(ctx)
@@ -1448,8 +1460,15 @@
 			return err
 		}
 	}
+
 	sort.Slice(paths, func(i, j int) bool {
-		return relevances[paths[i]] > relevances[paths[j]]
+		if relevances[paths[i]] != relevances[paths[j]] {
+			return relevances[paths[i]] > relevances[paths[j]]
+		}
+
+		// Fall back to lexical sort to keep truncated set of candidates
+		// in a consistent order.
+		return paths[i] < paths[j]
 	})
 
 	for _, path := range paths {
@@ -1468,7 +1487,8 @@
 			return nil
 		}
 		c.deepState.enqueue(candidate{
-			obj:   types.NewPkgName(0, nil, pkg.GetTypes().Name(), pkg.GetTypes()),
+			// Pass an empty *types.Package to disable deep completions.
+			obj:   types.NewPkgName(0, nil, pkg.GetTypes().Name(), types.NewPackage(path, pkg.Name())),
 			score: unimportedScore(relevances[path]),
 			imp:   imp,
 		})
@@ -2449,6 +2469,13 @@
 		return true
 	}
 
+	if array, ok := objType.Underlying().(*types.Array); ok {
+		if f(types.NewSlice(array.Elem()), false) {
+			c.takeSlice = true
+			return true
+		}
+	}
+
 	return false
 }
 
diff --git a/internal/lsp/source/completion/format.go b/internal/lsp/source/completion/format.go
index 6d8299c..3c9c3b2 100644
--- a/internal/lsp/source/completion/format.go
+++ b/internal/lsp/source/completion/format.go
@@ -150,6 +150,11 @@
 		prefix = typeName + "(" + prefix
 		suffix = ")"
 	}
+
+	if cand.takeSlice {
+		suffix += "[:]"
+	}
+
 	// Add variadic "..." only if snippets if enabled or cand is not a function
 	if cand.variadic && (c.opts.snippets || !cand.expandFuncCall) {
 		suffix += "..."
@@ -238,6 +243,14 @@
 	if c.opts.fullDocumentation {
 		item.Documentation = hover.FullDocumentation
 	}
+	// The desired pattern is `^// Deprecated`, but the prefix has been removed
+	if strings.HasPrefix(hover.FullDocumentation, "Deprecated") {
+		if c.snapshot.View().Options().CompletionTags {
+			item.Tags = []protocol.CompletionItemTag{protocol.ComplDeprecated}
+		} else if c.snapshot.View().Options().CompletionDeprecated {
+			item.Deprecated = true
+		}
+	}
 
 	return item, nil
 }
diff --git a/internal/lsp/source/completion/package.go b/internal/lsp/source/completion/package.go
index 483223a..aea414e 100644
--- a/internal/lsp/source/completion/package.go
+++ b/internal/lsp/source/completion/package.go
@@ -5,6 +5,7 @@
 package completion
 
 import (
+	"bytes"
 	"context"
 	"fmt"
 	"go/ast"
@@ -14,6 +15,7 @@
 	"go/types"
 	"path/filepath"
 	"strings"
+	"unicode"
 
 	"golang.org/x/tools/internal/lsp/fuzzy"
 	"golang.org/x/tools/internal/lsp/protocol"
@@ -207,17 +209,12 @@
 // have the given prefix and are used in the same directory as the given
 // 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) ([]candidate, error) {
+func packageSuggestions(ctx context.Context, snapshot source.Snapshot, fileURI span.URI, prefix string) (packages []candidate, err error) {
 	workspacePackages, err := snapshot.WorkspacePackages(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	dirPath := filepath.Dir(string(fileURI))
-	dirName := filepath.Base(dirPath)
-
-	seenPkgs := make(map[string]struct{})
-
 	toCandidate := func(name string, score float64) candidate {
 		obj := types.NewPkgName(0, nil, name, types.NewPackage("", name))
 		return candidate{obj: obj, name: name, detail: name, score: score}
@@ -225,9 +222,24 @@
 
 	matcher := fuzzy.NewMatcher(prefix)
 
+	// Always try to suggest a main package
+	defer func() {
+		if score := float64(matcher.Score("main")); score > 0 {
+			packages = append(packages, toCandidate("main", score*lowScore))
+		}
+	}()
+
+	dirPath := filepath.Dir(fileURI.Filename())
+	dirName := filepath.Base(dirPath)
+	if !isValidDirName(dirName) {
+		return packages, nil
+	}
+	pkgName := convertDirNameToPkgName(dirName)
+
+	seenPkgs := make(map[string]struct{})
+
 	// The `go` command by default only allows one package per directory but we
 	// support multiple package suggestions since gopls is build system agnostic.
-	var packages []candidate
 	for _, pkg := range workspacePackages {
 		if pkg.Name() == "main" || pkg.Name() == "" {
 			continue
@@ -239,7 +251,7 @@
 		// Only add packages that are previously used in the current directory.
 		var relevantPkg bool
 		for _, pgf := range pkg.CompiledGoFiles() {
-			if filepath.Dir(string(pgf.URI)) == dirPath {
+			if filepath.Dir(pgf.URI.Filename()) == dirPath {
 				relevantPkg = true
 				break
 			}
@@ -267,20 +279,80 @@
 	}
 
 	// Add current directory name as a low relevance suggestion.
-	if _, ok := seenPkgs[dirName]; !ok {
-		if score := float64(matcher.Score(dirName)); score > 0 {
-			packages = append(packages, toCandidate(dirName, score*lowScore))
+	if _, ok := seenPkgs[pkgName]; !ok {
+		if score := float64(matcher.Score(pkgName)); score > 0 {
+			packages = append(packages, toCandidate(pkgName, score*lowScore))
 		}
 
-		testDirName := dirName + "_test"
-		if score := float64(matcher.Score(testDirName)); score > 0 {
-			packages = append(packages, toCandidate(testDirName, score*lowScore))
+		testPkgName := pkgName + "_test"
+		if score := float64(matcher.Score(testPkgName)); score > 0 {
+			packages = append(packages, toCandidate(testPkgName, score*lowScore))
 		}
 	}
 
-	if score := float64(matcher.Score("main")); score > 0 {
-		packages = append(packages, toCandidate("main", score*lowScore))
-	}
-
 	return packages, nil
 }
+
+// isValidDirName checks whether the passed directory name can be used in
+// a package path. Requirements for a package path can be found here:
+// https://golang.org/ref/mod#go-mod-file-ident.
+func isValidDirName(dirName string) bool {
+	if dirName == "" {
+		return false
+	}
+
+	for i, ch := range dirName {
+		if isLetter(ch) || isDigit(ch) {
+			continue
+		}
+		if i == 0 {
+			// Directory name can start only with '_'. '.' is not allowed in module paths.
+			// '-' and '~' are not allowed because elements of package paths must be
+			// safe command-line arguments.
+			if ch == '_' {
+				continue
+			}
+		} else {
+			// Modules path elements can't end with '.'
+			if isAllowedPunctuation(ch) && (i != len(dirName)-1 || ch != '.') {
+				continue
+			}
+		}
+
+		return false
+	}
+	return true
+}
+
+// convertDirNameToPkgName converts a valid directory name to a valid package name.
+// It leaves only letters and digits. All letters are mapped to lower case.
+func convertDirNameToPkgName(dirName string) string {
+	var buf bytes.Buffer
+	for _, ch := range dirName {
+		switch {
+		case isLetter(ch):
+			buf.WriteRune(unicode.ToLower(ch))
+
+		case buf.Len() != 0 && isDigit(ch):
+			buf.WriteRune(ch)
+		}
+	}
+	return buf.String()
+}
+
+// isLetter and isDigit allow only ASCII characters because
+// "Each path element is a non-empty string made of up ASCII letters,
+// ASCII digits, and limited ASCII punctuation"
+// (see https://golang.org/ref/mod#go-mod-file-ident).
+
+func isLetter(ch rune) bool {
+	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z'
+}
+
+func isDigit(ch rune) bool {
+	return '0' <= ch && ch <= '9'
+}
+
+func isAllowedPunctuation(ch rune) bool {
+	return ch == '_' || ch == '-' || ch == '~' || ch == '.'
+}
diff --git a/internal/lsp/source/completion/package_test.go b/internal/lsp/source/completion/package_test.go
new file mode 100644
index 0000000..6436984
--- /dev/null
+++ b/internal/lsp/source/completion/package_test.go
@@ -0,0 +1,77 @@
+// 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.
+
+package completion
+
+import "testing"
+
+func TestIsValidDirName(t *testing.T) {
+	tests := []struct {
+		dirName string
+		valid   bool
+	}{
+		{dirName: "", valid: false},
+		//
+		{dirName: "a", valid: true},
+		{dirName: "abcdef", valid: true},
+		{dirName: "AbCdEf", valid: true},
+		//
+		{dirName: "1a35", valid: true},
+		{dirName: "a16", valid: true},
+		//
+		{dirName: "_a", valid: true},
+		{dirName: "a_", valid: true},
+		//
+		{dirName: "~a", valid: false},
+		{dirName: "a~", valid: true},
+		//
+		{dirName: "-a", valid: false},
+		{dirName: "a-", valid: true},
+		//
+		{dirName: ".a", valid: false},
+		{dirName: "a.", valid: false},
+		//
+		{dirName: "a~_b--c.-e", valid: true},
+		{dirName: "~a~_b--c.-e", valid: false},
+		{dirName: "a~_b--c.-e--~", valid: true},
+		{dirName: "a~_b--2134dc42.-e6--~", valid: true},
+		{dirName: "abc`def", valid: false},
+		{dirName: "тест", valid: false},
+		{dirName: "你好", valid: false},
+	}
+	for _, tt := range tests {
+		valid := isValidDirName(tt.dirName)
+		if tt.valid != valid {
+			t.Errorf("%s: expected %v, got %v", tt.dirName, tt.valid, valid)
+		}
+	}
+}
+
+func TestConvertDirNameToPkgName(t *testing.T) {
+	tests := []struct {
+		dirName string
+		pkgName string
+	}{
+		{dirName: "a", pkgName: "a"},
+		{dirName: "abcdef", pkgName: "abcdef"},
+		{dirName: "AbCdEf", pkgName: "abcdef"},
+		{dirName: "1a35", pkgName: "a35"},
+		{dirName: "14a35", pkgName: "a35"},
+		{dirName: "a16", pkgName: "a16"},
+		{dirName: "_a", pkgName: "a"},
+		{dirName: "a_", pkgName: "a"},
+		{dirName: "a~", pkgName: "a"},
+		{dirName: "a-", pkgName: "a"},
+		{dirName: "a~_b--c.-e", pkgName: "abce"},
+		{dirName: "a~_b--c.-e--~", pkgName: "abce"},
+		{dirName: "a~_b--2134dc42.-e6--~", pkgName: "ab2134dc42e6"},
+	}
+	for _, tt := range tests {
+		pkgName := convertDirNameToPkgName(tt.dirName)
+		if tt.pkgName != pkgName {
+			t.Errorf("%s: expected %v, got %v", tt.dirName, tt.pkgName, pkgName)
+			continue
+		}
+	}
+}
diff --git a/internal/lsp/source/completion/postfix_snippets.go b/internal/lsp/source/completion/postfix_snippets.go
index 2c3c6e9..4c5cb0e 100644
--- a/internal/lsp/source/completion/postfix_snippets.go
+++ b/internal/lsp/source/completion/postfix_snippets.go
@@ -303,11 +303,25 @@
 		return
 	}
 
+	tokFile := c.snapshot.FileSet().File(c.pos)
+
 	// Only replace sel with a statement if sel is already a statement.
 	var stmtOK bool
 	for i, n := range c.path {
 		if n == sel && i < len(c.path)-1 {
-			_, stmtOK = c.path[i+1].(*ast.ExprStmt)
+			switch p := c.path[i+1].(type) {
+			case *ast.ExprStmt:
+				stmtOK = true
+			case *ast.AssignStmt:
+				// In cases like:
+				//
+				//   foo.<>
+				//   bar = 123
+				//
+				// detect that "foo." makes up the entire statement since the
+				// apparent selector spans lines.
+				stmtOK = tokFile.Line(c.pos) < tokFile.Line(p.TokPos)
+			}
 			break
 		}
 	}
@@ -328,7 +342,6 @@
 	//
 	// and adjust afterDot so that we don't mistakenly delete the
 	// newline thinking "bar" is part of our selector.
-	tokFile := c.snapshot.FileSet().File(c.pos)
 	if startLine := tokFile.Line(sel.Pos()); startLine != tokFile.Line(afterDot) {
 		if tokFile.Line(c.pos) != startLine {
 			return
diff --git a/internal/lsp/source/extract.go b/internal/lsp/source/extract.go
index 854dc90..e366095 100644
--- a/internal/lsp/source/extract.go
+++ b/internal/lsp/source/extract.go
@@ -195,11 +195,9 @@
 		return nil, fmt.Errorf("extractFunction: package scope is empty")
 	}
 
-	// TODO: Support non-nested return statements.
 	// A return statement is non-nested if its parent node is equal to the parent node
 	// of the first node in the selection. These cases must be handled separately because
-	// non-nested return statements are guaranteed to execute. Our control flow does not
-	// properly consider these situations yet.
+	// non-nested return statements are guaranteed to execute.
 	var retStmts []*ast.ReturnStmt
 	var hasNonNestedReturn bool
 	startParent := findParent(outer, start)
@@ -216,14 +214,10 @@
 		}
 		if findParent(outer, n) == startParent {
 			hasNonNestedReturn = true
-			return false
 		}
 		retStmts = append(retStmts, ret)
 		return false
 	})
-	if hasNonNestedReturn {
-		return nil, fmt.Errorf("extractFunction: selected block contains non-nested return")
-	}
 	containsReturnStatement := len(retStmts) > 0
 
 	// Now that we have determined the correct range for the selection block,
@@ -396,23 +390,54 @@
 	// in the original function. If the condition is met, the original function should
 	// return a value, mimicking the functionality of the original return statement(s)
 	// in the selection.
+	//
+	// If there is a return that is guaranteed to execute (hasNonNestedReturns=true), then
+	// we don't need to include this additional condition check and can simply return.
+	//
+	// Before:
+	//
+	// func _() int {
+	//     a := 1
+	//     b := 2
+	//     **if a == b {
+	//         return a
+	//     }
+	//	   return b**
+	// }
+	//
+	// After:
+	//
+	// func _() int {
+	//     a := 1
+	//     b := 2
+	//     return x0(a, b)
+	// }
+	//
+	// func x0(a int, b int) int {
+	//     if a == b {
+	//         return a
+	//     }
+	//     return b
+	// }
 
 	var retVars []*returnVariable
 	var ifReturn *ast.IfStmt
 	if containsReturnStatement {
-		// The selected block contained return statements, so we have to modify the
-		// signature of the extracted function as described above. Adjust all of
-		// the return statements in the extracted function to reflect this change in
-		// signature.
-		if err := adjustReturnStatements(returnTypes, seenVars, fset, file,
-			pkg, extractedBlock); err != nil {
-			return nil, err
+		if !hasNonNestedReturn {
+			// The selected block contained return statements, so we have to modify the
+			// signature of the extracted function as described above. Adjust all of
+			// the return statements in the extracted function to reflect this change in
+			// signature.
+			if err := adjustReturnStatements(returnTypes, seenVars, fset, file,
+				pkg, extractedBlock); err != nil {
+				return nil, err
+			}
 		}
 		// Collect the additional return values and types needed to accommodate return
 		// statements in the selection. Update the type signature of the extracted
 		// function and construct the if statement that will be inserted in the enclosing
 		// function.
-		retVars, ifReturn, err = generateReturnInfo(enclosing, pkg, path, file, info, fset, rng.Start)
+		retVars, ifReturn, err = generateReturnInfo(enclosing, pkg, path, file, info, fset, rng.Start, hasNonNestedReturn)
 		if err != nil {
 			return nil, err
 		}
@@ -421,8 +446,10 @@
 	// Add a return statement to the end of the new function. This return statement must include
 	// the values for the types of the original extracted function signature and (if a return
 	// statement is present in the selection) enclosing function signature.
+	// This only needs to be done if the selections does not have a non-nested return, otherwise
+	// it already terminates with a return statement.
 	hasReturnValues := len(returns)+len(retVars) > 0
-	if hasReturnValues {
+	if hasReturnValues && !hasNonNestedReturn {
 		extractedBlock.List = append(extractedBlock.List, &ast.ReturnStmt{
 			Results: append(returns, getZeroVals(retVars)...),
 		})
@@ -439,7 +466,7 @@
 		sym = token.DEFINE
 	}
 	funName := generateAvailableIdentifier(rng.Start, file, path, info, "fn", 0)
-	extractedFunCall := generateFuncCall(hasReturnValues, params,
+	extractedFunCall := generateFuncCall(hasNonNestedReturn, hasReturnValues, params,
 		append(returns, getNames(retVars)...), funName, sym)
 
 	// Build the extracted function.
@@ -460,7 +487,7 @@
 		declarations = initializeVars(uninitialized, retVars, seenUninitialized, seenVars)
 	}
 
-	var declBuf, replaceBuf, newFuncBuf, ifBuf bytes.Buffer
+	var declBuf, replaceBuf, newFuncBuf, ifBuf, commentBuf bytes.Buffer
 	if err := format.Node(&declBuf, fset, declarations); err != nil {
 		return nil, err
 	}
@@ -475,6 +502,15 @@
 	if err := format.Node(&newFuncBuf, fset, newFunc); err != nil {
 		return nil, err
 	}
+	// Find all the comments within the range and print them to be put somewhere.
+	// TODO(suzmue): print these in the extracted function at the correct place.
+	for _, cg := range file.Comments {
+		if cg.Pos().IsValid() && cg.Pos() < rng.End && cg.Pos() >= rng.Start {
+			for _, c := range cg.List {
+				fmt.Fprintln(&commentBuf, c.Text)
+			}
+		}
+	}
 
 	// We're going to replace the whole enclosing function,
 	// so preserve the text before and after the selected block.
@@ -486,6 +522,10 @@
 
 	var fullReplacement strings.Builder
 	fullReplacement.Write(before)
+	if commentBuf.Len() > 0 {
+		comments := strings.ReplaceAll(commentBuf.String(), "\n", newLineIndent)
+		fullReplacement.WriteString(comments)
+	}
 	if declBuf.Len() > 0 { // add any initializations, if needed
 		initializations := strings.ReplaceAll(declBuf.String(), "\n", newLineIndent) +
 			newLineIndent
@@ -951,15 +991,17 @@
 // signature of the extracted function. We prepare names, signatures, and "zero values" that
 // represent the new variables. We also use this information to construct the if statement that
 // is inserted below the call to the extracted function.
-func generateReturnInfo(enclosing *ast.FuncType, pkg *types.Package, path []ast.Node, file *ast.File, info *types.Info, fset *token.FileSet, pos token.Pos) ([]*returnVariable, *ast.IfStmt, error) {
-	// Generate information for the added bool value.
-	cond := &ast.Ident{Name: generateAvailableIdentifier(pos, file, path, info, "cond", 0)}
-	retVars := []*returnVariable{
-		{
+func generateReturnInfo(enclosing *ast.FuncType, pkg *types.Package, path []ast.Node, file *ast.File, info *types.Info, fset *token.FileSet, pos token.Pos, hasNonNestedReturns bool) ([]*returnVariable, *ast.IfStmt, error) {
+	var retVars []*returnVariable
+	var cond *ast.Ident
+	if !hasNonNestedReturns {
+		// Generate information for the added bool value.
+		cond = &ast.Ident{Name: generateAvailableIdentifier(pos, file, path, info, "cond", 0)}
+		retVars = append(retVars, &returnVariable{
 			name:    cond,
 			decl:    &ast.Field{Type: ast.NewIdent("bool")},
 			zeroVal: ast.NewIdent("false"),
-		},
+		})
 	}
 	// Generate information for the values in the return signature of the enclosing function.
 	if enclosing.Results != nil {
@@ -982,13 +1024,16 @@
 			})
 		}
 	}
-	// Create the return statement for the enclosing function. We must exclude the variable
-	// for the condition of the if statement (cond) from the return statement.
-	ifReturn := &ast.IfStmt{
-		Cond: cond,
-		Body: &ast.BlockStmt{
-			List: []ast.Stmt{&ast.ReturnStmt{Results: getNames(retVars)[1:]}},
-		},
+	var ifReturn *ast.IfStmt
+	if !hasNonNestedReturns {
+		// Create the return statement for the enclosing function. We must exclude the variable
+		// for the condition of the if statement (cond) from the return statement.
+		ifReturn = &ast.IfStmt{
+			Cond: cond,
+			Body: &ast.BlockStmt{
+				List: []ast.Stmt{&ast.ReturnStmt{Results: getNames(retVars)[1:]}},
+			},
+		}
 	}
 	return retVars, ifReturn, nil
 }
@@ -1034,17 +1079,26 @@
 
 // generateFuncCall constructs a call expression for the extracted function, described by the
 // given parameters and return variables.
-func generateFuncCall(hasReturnVals bool, params, returns []ast.Expr, name string, token token.Token) ast.Node {
+func generateFuncCall(hasNonNestedReturn, hasReturnVals bool, params, returns []ast.Expr, name string, token token.Token) ast.Node {
 	var replace ast.Node
 	if hasReturnVals {
 		callExpr := &ast.CallExpr{
 			Fun:  ast.NewIdent(name),
 			Args: params,
 		}
-		replace = &ast.AssignStmt{
-			Lhs: returns,
-			Tok: token,
-			Rhs: []ast.Expr{callExpr},
+		if hasNonNestedReturn {
+			// Create a return statement that returns the result of the function call.
+			replace = &ast.ReturnStmt{
+				Return:  0,
+				Results: []ast.Expr{callExpr},
+			}
+		} else {
+			// Assign the result of the function call.
+			replace = &ast.AssignStmt{
+				Lhs: returns,
+				Tok: token,
+				Rhs: []ast.Expr{callExpr},
+			}
 		}
 	} else {
 		replace = &ast.CallExpr{
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index e27216e..89e0903 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -55,9 +55,12 @@
 	source  interface{}
 	comment *ast.CommentGroup
 
-	// isTypeName reports whether the identifier is a type name. In such cases,
-	// the hover has the prefix "type ".
-	isType bool
+	// typeName contains the identifier name when the identifier is a type declaration.
+	// If it is not empty, the hover will have the prefix "type <typeName> ".
+	typeName string
+	// isTypeAlias indicates whether the identifier is a type alias declaration.
+	// If it is true, the hover will have the prefix "type <typeName> = ".
+	isTypeAlias bool
 }
 
 func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) {
@@ -107,8 +110,12 @@
 			return nil, err
 		}
 		h.Signature = b.String()
-		if h.isType {
-			h.Signature = "type " + h.Signature
+		if h.typeName != "" {
+			prefix := "type " + h.typeName + " "
+			if h.isTypeAlias {
+				prefix += "= "
+			}
+			h.Signature = prefix + h.Signature
 		}
 	case types.Object:
 		// If the variable is implicitly declared in a type switch, we need to
@@ -290,7 +297,6 @@
 			if err != nil {
 				return nil, err
 			}
-			_, info.isType = obj.(*types.TypeName)
 		}
 	case *ast.TypeSpec:
 		if obj.Parent() == types.Universe {
@@ -394,12 +400,19 @@
 	// Handle types.
 	switch spec := spec.(type) {
 	case *ast.TypeSpec:
-		if len(node.Specs) > 1 {
-			// If multiple types are declared in the same block.
-			return &HoverInformation{source: spec.Type, comment: spec.Doc}, nil
-		} else {
-			return &HoverInformation{source: spec, comment: node.Doc}, nil
+		comment := spec.Doc
+		if comment == nil {
+			comment = node.Doc
 		}
+		if comment == nil {
+			comment = spec.Comment
+		}
+		return &HoverInformation{
+			source:      spec.Type,
+			comment:     comment,
+			typeName:    spec.Name.Name,
+			isTypeAlias: spec.Assign.IsValid(),
+		}, nil
 	case *ast.ValueSpec:
 		return &HoverInformation{source: spec, comment: spec.Doc}, nil
 	case *ast.ImportSpec:
diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go
index 7c5e62c..5fb9d22 100644
--- a/internal/lsp/source/identifier.go
+++ b/internal/lsp/source/identifier.go
@@ -179,11 +179,11 @@
 
 	// Handle builtins separately.
 	if result.Declaration.obj.Parent() == types.Universe {
-		builtin, err := snapshot.BuiltinPackage(ctx)
+		builtin, err := snapshot.BuiltinFile(ctx)
 		if err != nil {
 			return nil, err
 		}
-		builtinObj := builtin.Package.Scope.Lookup(result.Name)
+		builtinObj := builtin.File.Scope.Lookup(result.Name)
 		if builtinObj == nil {
 			return nil, fmt.Errorf("no builtin object for %s", result.Name)
 		}
@@ -195,7 +195,7 @@
 
 		// The builtin package isn't in the dependency graph, so the usual
 		// utilities won't work here.
-		rng := NewMappedRange(snapshot.FileSet(), builtin.ParsedFile.Mapper, decl.Pos(), decl.Pos()+token.Pos(len(result.Name)))
+		rng := NewMappedRange(snapshot.FileSet(), builtin.Mapper, decl.Pos(), decl.Pos()+token.Pos(len(result.Name)))
 		result.Declaration.MappedRange = append(result.Declaration.MappedRange, rng)
 		return result, nil
 	}
@@ -204,14 +204,14 @@
 	// that this is the builtin Error.
 	if obj := result.Declaration.obj; obj.Parent() == nil && obj.Pkg() == nil && obj.Name() == "Error" {
 		if _, ok := obj.Type().(*types.Signature); ok {
-			builtin, err := snapshot.BuiltinPackage(ctx)
+			builtin, err := snapshot.BuiltinFile(ctx)
 			if err != nil {
 				return nil, err
 			}
 			// Look up "error" and then navigate to its only method.
 			// The Error method does not appear in the builtin package's scope.log.Pri
 			const errorName = "error"
-			builtinObj := builtin.Package.Scope.Lookup(errorName)
+			builtinObj := builtin.File.Scope.Lookup(errorName)
 			if builtinObj == nil {
 				return nil, fmt.Errorf("no builtin object for %s", errorName)
 			}
@@ -236,7 +236,7 @@
 			}
 			name := method.Names[0].Name
 			result.Declaration.node = method
-			rng := NewMappedRange(snapshot.FileSet(), builtin.ParsedFile.Mapper, method.Pos(), method.Pos()+token.Pos(len(name)))
+			rng := NewMappedRange(snapshot.FileSet(), builtin.Mapper, method.Pos(), method.Pos()+token.Pos(len(name)))
 			result.Declaration.MappedRange = append(result.Declaration.MappedRange, rng)
 			return result, nil
 		}
diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go
index 826faa6..702f5f9 100644
--- a/internal/lsp/source/options.go
+++ b/internal/lsp/source/options.go
@@ -107,6 +107,7 @@
 				BuildOptions: BuildOptions{
 					ExpandWorkspaceToModule:     true,
 					ExperimentalPackageCacheKey: true,
+					MemoryMode:                  ModeNormal,
 				},
 				UIOptions: UIOptions{
 					DiagnosticOptions: DiagnosticOptions{
@@ -187,6 +188,8 @@
 	SemanticTypes                     []string
 	SemanticMods                      []string
 	RelatedInformationSupported       bool
+	CompletionTags                    bool
+	CompletionDeprecated              bool
 }
 
 // ServerOptions holds LSP-specific configuration that is provided by the
@@ -213,11 +216,20 @@
 	// The path prefix can be empty, so an initial `-` excludes everything.
 	//
 	// Examples:
+	//
 	// Exclude node_modules: `-node_modules`
+	//
 	// Include only project_a: `-` (exclude everything), `+project_a`
+	//
 	// Include only project_a, but not node_modules inside it: `-`, `+project_a`, `-project_a/node_modules`
 	DirectoryFilters []string
 
+	// MemoryMode controls the tradeoff `gopls` makes between memory usage and
+	// correctness.
+	//
+	// Values other than `Normal` are untested and may break in surprising ways.
+	MemoryMode MemoryMode `status:"experimental"`
+
 	// ExpandWorkspaceToModule instructs `gopls` to adjust the scope of the
 	// workspace to find the best available module root. `gopls` first looks for
 	// a go.mod file in any parent directory of the workspace folder, expanding
@@ -547,6 +559,16 @@
 	Structured HoverKind = "Structured"
 )
 
+type MemoryMode string
+
+const (
+	ModeNormal MemoryMode = "Normal"
+	// In DegradeClosed mode, `gopls` will collect less information about
+	// packages without open files. As a result, features like Find
+	// References and Rename will miss results in such packages.
+	ModeDegradeClosed MemoryMode = "DegradeClosed"
+)
+
 type OptionResults []OptionResult
 
 type OptionResult struct {
@@ -627,6 +649,12 @@
 
 	// Check if the client supports diagnostic related information.
 	o.RelatedInformationSupported = caps.TextDocument.PublishDiagnostics.RelatedInformation
+	// Check if the client completion support incliudes tags (preferred) or deprecation
+	if caps.TextDocument.Completion.CompletionItem.TagSupport.ValueSet != nil {
+		o.CompletionTags = true
+	} else if caps.TextDocument.Completion.CompletionItem.DeprecatedSupport {
+		o.CompletionDeprecated = true
+	}
 }
 
 func (o *Options) Clone() *Options {
@@ -677,8 +705,8 @@
 	return result
 }
 
-func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer) {
-	o.StaticcheckAnalyzers[a.Name] = &Analyzer{Analyzer: a, Enabled: true}
+func (o *Options) AddStaticcheckAnalyzer(a *analysis.Analyzer, enabled bool) {
+	o.StaticcheckAnalyzers[a.Name] = &Analyzer{Analyzer: a, Enabled: enabled}
 }
 
 // enableAllExperiments turns on all of the experimental "off-by-default"
@@ -747,9 +775,16 @@
 				result.errorf("invalid filter %q, must start with + or -", filter)
 				return result
 			}
-			filters = append(filters, filepath.FromSlash(filter))
+			filters = append(filters, strings.TrimRight(filepath.FromSlash(filter), "/"))
 		}
 		o.DirectoryFilters = filters
+	case "memoryMode":
+		if s, ok := result.asOneOf(
+			string(ModeNormal),
+			string(ModeDegradeClosed),
+		); ok {
+			o.MemoryMode = MemoryMode(s)
+		}
 	case "completionDocumentation":
 		result.setBool(&o.CompletionDocumentation)
 	case "usePlaceholders":
diff --git a/internal/lsp/source/types_format.go b/internal/lsp/source/types_format.go
index a7bd3c4..96110cd 100644
--- a/internal/lsp/source/types_format.go
+++ b/internal/lsp/source/types_format.go
@@ -81,11 +81,11 @@
 // NewBuiltinSignature returns signature for the builtin object with a given
 // name, if a builtin object with the name exists.
 func NewBuiltinSignature(ctx context.Context, s Snapshot, name string) (*signature, error) {
-	builtin, err := s.BuiltinPackage(ctx)
+	builtin, err := s.BuiltinFile(ctx)
 	if err != nil {
 		return nil, err
 	}
-	obj := builtin.Package.Scope.Lookup(name)
+	obj := builtin.File.Scope.Lookup(name)
 	if obj == nil {
 		return nil, fmt.Errorf("no builtin object for %s", name)
 	}
diff --git a/internal/lsp/source/util.go b/internal/lsp/source/util.go
index 690a781..69ddb17 100644
--- a/internal/lsp/source/util.go
+++ b/internal/lsp/source/util.go
@@ -221,13 +221,25 @@
 
 // Deref returns a pointer's element type, traversing as many levels as needed.
 // Otherwise it returns typ.
+//
+// It can return a pointer type for cyclic types (see golang/go#45510).
 func Deref(typ types.Type) types.Type {
+	var seen map[types.Type]struct{}
 	for {
 		p, ok := typ.Underlying().(*types.Pointer)
 		if !ok {
 			return typ
 		}
+		if _, ok := seen[p.Elem()]; ok {
+			return typ
+		}
+
 		typ = p.Elem()
+
+		if seen == nil {
+			seen = make(map[types.Type]struct{})
+		}
+		seen[typ] = struct{}{}
 	}
 }
 
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index 412866c..b0aebbb 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -125,8 +125,11 @@
 	// GoModForFile returns the URI of the go.mod file for the given URI.
 	GoModForFile(uri span.URI) span.URI
 
-	// BuiltinPackage returns information about the special builtin package.
-	BuiltinPackage(ctx context.Context) (*BuiltinPackage, error)
+	// BuiltinFile returns information about the special builtin package.
+	BuiltinFile(ctx context.Context) (*ParsedGoFile, error)
+
+	// IsBuiltin reports whether uri is part of the builtin package.
+	IsBuiltin(ctx context.Context, uri span.URI) bool
 
 	// PackagesForFile returns the packages that this file belongs to, checked
 	// in mode.
@@ -256,11 +259,6 @@
 	GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
 }
 
-type BuiltinPackage struct {
-	Package    *ast.Package
-	ParsedFile *ParsedGoFile
-}
-
 // A ParsedGoFile contains the results of parsing a Go file.
 type ParsedGoFile struct {
 	URI  span.URI
diff --git a/internal/lsp/testdata/arraytype/array_type.go.in b/internal/lsp/testdata/arraytype/array_type.go.in
index a53ee74..7e9a96f 100644
--- a/internal/lsp/testdata/arraytype/array_type.go.in
+++ b/internal/lsp/testdata/arraytype/array_type.go.in
@@ -41,3 +41,8 @@
 	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[:]")
+}
diff --git a/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden b/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
index d31fcc1..8d361aa 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_args_returns.go.golden
@@ -3,6 +3,7 @@
 
 func _() {
 	a := 1
+	//@mark(exSt0, "a")
 	a = fn0(a) //@mark(exEn0, "2")
 	//@extractfunc(exSt0, exEn0)
 	b := a * 2 //@mark(exB, "	b")
@@ -24,6 +25,7 @@
 	a = 5     //@mark(exSt0, "a")
 	a = a + 2 //@mark(exEn0, "2")
 	//@extractfunc(exSt0, exEn0)
+	//@mark(exB, "	b")
 	fn0(a)  //@mark(exEnd, "4")
 	//@extractfunc(exB, exEnd)
 }
diff --git a/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden b/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
index 16a7863..b65c8bc 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_basic.go.golden
@@ -2,6 +2,7 @@
 package extract
 
 func _() {
+	//@mark(exSt1, "a")
 	fn0() //@mark(exEn1, "4")
 	//@extractfunc(exSt1, exEn1)
 }
diff --git a/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go b/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go
new file mode 100644
index 0000000..4e2b12f
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go
@@ -0,0 +1,8 @@
+package extract
+
+func _() {
+	a := /* comment in the middle of a line */ 1 //@mark(exSt18, "a")
+	// Comment on its own line
+	_ = 3 + 4 //@mark(exEn18, "4")
+	//@extractfunc(exSt18, exEn18)
+}
diff --git a/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden b/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden
new file mode 100644
index 0000000..5d679ed
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_basic_comment.go.golden
@@ -0,0 +1,17 @@
+-- functionextraction_extract_basic_comment_4_2 --
+package extract
+
+func _() {
+	/* comment in the middle of a line */
+	//@mark(exSt18, "a")
+	// Comment on its own line
+	fn0() //@mark(exEn18, "4")
+	//@extractfunc(exSt18, exEn18)
+}
+
+func fn0() {
+	a := 1
+
+	_ = 3 + 4
+}
+
diff --git a/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden b/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
index 8604745..3d392aa 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_issue_44813.go.golden
@@ -4,6 +4,7 @@
 import "fmt"
 
 func main() {
+	//@mark(exSt9, "x")
 	x := fn0() //@mark(exEn9, "}")
 	//@extractfunc(exSt9, exEn9)
 	fmt.Printf("%x\n", x)
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
index b1a27b7..030ca57 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_basic.go.golden
@@ -3,6 +3,7 @@
 
 func _() bool {
 	x := 1
+	//@mark(exSt2, "if")
 	cond0, ret0 := fn0(x)
 	if cond0 {
 		return ret0
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go b/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go
new file mode 100644
index 0000000..08573ac
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go
@@ -0,0 +1,10 @@
+package extract
+
+func _() bool {
+	x := 1 //@mark(exSt13, "x")
+	if x == 0 {
+		return true
+	}
+	return false //@mark(exEn13, "false")
+	//@extractfunc(exSt13, exEn13)
+}
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden
new file mode 100644
index 0000000..41f8921
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_basic_nonnested.go.golden
@@ -0,0 +1,17 @@
+-- functionextraction_extract_return_basic_nonnested_4_2 --
+package extract
+
+func _() bool {
+	//@mark(exSt13, "x")
+	return fn0() //@mark(exEn13, "false")
+	//@extractfunc(exSt13, exEn13)
+}
+
+func fn0() bool {
+	x := 1
+	if x == 0 {
+		return true
+	}
+	return false
+}
+
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
index 2fee5fb..4c711c4 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_complex.go.golden
@@ -6,6 +6,7 @@
 func _() (int, string, error) {
 	x := 1
 	y := "hello"
+	//@mark(exSt3, "z")
 	z, cond0, ret0, ret1, ret2 := fn0(y, x)
 	if cond0 {
 		return ret0, ret1, ret2
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go b/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go
new file mode 100644
index 0000000..6b2a4d8
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go
@@ -0,0 +1,17 @@
+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 --git a/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden
new file mode 100644
index 0000000..7a43113
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_complex_nonnested.go.golden
@@ -0,0 +1,24 @@
+-- functionextraction_extract_return_complex_nonnested_8_2 --
+package extract
+
+import "fmt"
+
+func _() (int, string, error) {
+	x := 1
+	y := "hello"
+	//@mark(exSt10, "z")
+	return fn0(y, x) //@mark(exEn10, "nil")
+	//@extractfunc(exSt10, exEn10)
+}
+
+func fn0(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 --git a/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
index 6c4fe96..937b3e5 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit.go.golden
@@ -5,6 +5,7 @@
 
 func _() {
 	ast.Inspect(ast.NewIdent("a"), func(n ast.Node) bool {
+		//@mark(exSt4, "if")
 		cond0, ret0 := fn0(n)
 		if cond0 {
 			return ret0
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go
new file mode 100644
index 0000000..c22db2a
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go
@@ -0,0 +1,13 @@
+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 --git a/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden
new file mode 100644
index 0000000..c94a934
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_func_lit_nonnested.go.golden
@@ -0,0 +1,20 @@
+-- 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 fn0(n) //@mark(exEn11, "false")
+	})
+	//@extractfunc(exSt11, exEn11)
+}
+
+func fn0(n ast.Node) bool {
+	if n == nil {
+		return true
+	}
+	return false
+}
+
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
index 40a9773..1a5b4d4 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_init.go.golden
@@ -3,6 +3,7 @@
 
 func _() string {
 	x := 1
+	//@mark(exSt5, "if")
 	cond0, ret0 := fn0(x)
 	if cond0 {
 		return ret0
diff --git a/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go b/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go
new file mode 100644
index 0000000..bb5ed08
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go
@@ -0,0 +1,12 @@
+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 --git a/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden b/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden
new file mode 100644
index 0000000..5a16d0d
--- /dev/null
+++ b/internal/lsp/testdata/extract/extract_function/extract_return_init_nonnested.go.golden
@@ -0,0 +1,19 @@
+-- functionextraction_extract_return_init_nonnested_5_2 --
+package extract
+
+func _() string {
+	x := 1
+	//@mark(exSt12, "if")
+	return fn0(x) //@mark(exEn12, "\"b\"")
+	//@extractfunc(exSt12, exEn12)
+}
+
+func fn0(x int) string {
+	if x == 0 {
+		x = 3
+		return "a"
+	}
+	x = 2
+	return "b"
+}
+
diff --git a/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden b/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
index d0b1d7a..04d7251 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_smart_initialization.go.golden
@@ -3,6 +3,7 @@
 
 func _() {
 	var a []int
+	//@mark(exSt6, "a")
 	a, b := fn0(a)           //@mark(exEn6, "4")
 	//@extractfunc(exSt6, exEn6)
 	a = append(a, b)
diff --git a/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden b/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
index 4c361ca..5d7765a 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_smart_return.go.golden
@@ -4,6 +4,7 @@
 func _() {
 	var b []int
 	var a int
+	//@mark(exSt7, "a")
 	b = fn0(a, b) //@mark(exEn7, ")")
 	b[0] = 1
 	//@extractfunc(exSt7, exEn7)
diff --git a/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden b/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
index f04c212..8afa749 100644
--- a/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
+++ b/internal/lsp/testdata/extract/extract_function/extract_unnecessary_param.go.golden
@@ -4,6 +4,7 @@
 func _() {
 	var b []int
 	var a int
+	//@mark(exSt8, "a")
 	a, b = fn0(b) //@mark(exEn8, ")")
 	b[0] = 1
 	if a == 2 {
diff --git a/internal/lsp/testdata/godef/a/a.go b/internal/lsp/testdata/godef/a/a.go
index b157a71..993fd86 100644
--- a/internal/lsp/testdata/godef/a/a.go
+++ b/internal/lsp/testdata/godef/a/a.go
@@ -72,3 +72,34 @@
 type J interface {
 	Hello() //@mark(AHello, "Hello")
 }
+
+func _() {
+	// 1st type declaration block
+	type (
+		a struct { //@mark(declBlockA, "a"),hover("a", declBlockA)
+			x string
+		}
+	)
+
+	// 2nd type declaration block
+	type (
+		// b has a comment
+		b struct{} //@mark(declBlockB, "b"),hover("b", declBlockB)
+	)
+
+	// 3rd type declaration block
+	type (
+		// c is a struct
+		c struct { //@mark(declBlockC, "c"),hover("c", declBlockC)
+			f string
+		}
+
+		d string //@mark(declBlockD, "d"),hover("d", declBlockD)
+	)
+
+	type (
+		e struct { //@mark(declBlockE, "e"),hover("e", declBlockE)
+			f float64
+		} // e has a comment
+	)
+}
diff --git a/internal/lsp/testdata/godef/a/a.go.golden b/internal/lsp/testdata/godef/a/a.go.golden
index 08a1882..2f7d8de 100644
--- a/internal/lsp/testdata/godef/a/a.go.golden
+++ b/internal/lsp/testdata/godef/a/a.go.golden
@@ -148,3 +148,39 @@
 ```
 
 z is a variable too\.
+-- declBlockA-hover --
+```go
+type a struct {
+	x string
+}
+```
+
+1st type declaration block
+-- declBlockB-hover --
+```go
+type b struct{}
+```
+
+b has a comment
+-- declBlockC-hover --
+```go
+type c struct {
+	f string
+}
+```
+
+c is a struct
+-- declBlockD-hover --
+```go
+type d string
+```
+
+3rd type declaration block
+-- declBlockE-hover --
+```go
+type e struct {
+	f float64
+}
+```
+
+e has a comment
diff --git a/internal/lsp/testdata/godef/b/b.go.golden b/internal/lsp/testdata/godef/b/b.go.golden
index 19ece5d..5537180 100644
--- a/internal/lsp/testdata/godef/b/b.go.golden
+++ b/internal/lsp/testdata/godef/b/b.go.golden
@@ -82,11 +82,12 @@
 [`a` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls)
 -- AString-definition --
 godef/a/a.go:26:6-7: defined here as ```go
-type A string //@mark(AString, "A")
-
+type A string
 ```
 
 [`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)
+
+\@mark\(AString, \"A\"\)
 -- AString-definition-json --
 {
 	"span": {
@@ -102,16 +103,17 @@
 			"offset": 453
 		}
 	},
-	"description": "```go\ntype A string //@mark(AString, \"A\")\n\n```\n\n[`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)"
+	"description": "```go\ntype A string\n```\n\n[`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)\n\n\\@mark\\(AString, \\\"A\\\"\\)"
 }
 
 -- AString-hover --
 ```go
-type A string //@mark(AString, "A")
-
+type A string
 ```
 
 [`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)
+
+\@mark\(AString, \"A\"\)
 -- AStuff-definition --
 godef/a/a.go:28:6-12: defined here as ```go
 func a.AStuff()
@@ -358,9 +360,10 @@
 \@mark\(S2F2, \"F2\"\)
 -- aAlias-definition --
 godef/b/b.go:25:6-12: defined here as ```go
-type aAlias = a.A //@mark(aAlias, "aAlias")
-
+type aAlias = a.A
 ```
+
+\@mark\(aAlias, \"aAlias\"\)
 -- aAlias-definition-json --
 {
 	"span": {
@@ -376,14 +379,15 @@
 			"offset": 527
 		}
 	},
-	"description": "```go\ntype aAlias = a.A //@mark(aAlias, \"aAlias\")\n\n```"
+	"description": "```go\ntype aAlias = a.A\n```\n\n\\@mark\\(aAlias, \\\"aAlias\\\"\\)"
 }
 
 -- aAlias-hover --
 ```go
-type aAlias = a.A //@mark(aAlias, "aAlias")
-
+type aAlias = a.A
 ```
+
+\@mark\(aAlias, \"aAlias\"\)
 -- bX-definition --
 godef/b/b.go:57:7-8: defined here as ```go
 const X untyped int = 0
diff --git a/internal/lsp/testdata/snippets/postfix.go b/internal/lsp/testdata/snippets/postfix.go
index 29b4192..d29694e 100644
--- a/internal/lsp/testdata/snippets/postfix.go
+++ b/internal/lsp/testdata/snippets/postfix.go
@@ -25,3 +25,18 @@
 	var blah func() []int
 	blah().append //@complete(" //")
 }
+
+func _() {
+	/* append! */ //@item(postfixAppend, "append!", "append and re-assign slice", "snippet")
+	/* last! */ //@item(postfixLast, "last!", "s[len(s)-1]", "snippet")
+	/* print! */ //@item(postfixPrint, "print!", "print to stdout", "snippet")
+	/* range! */ //@item(postfixRange, "range!", "range over slice", "snippet")
+	/* reverse! */ //@item(postfixReverse, "reverse!", "reverse slice", "snippet")
+	/* sort! */ //@item(postfixSort, "sort!", "sort.Slice()", "snippet")
+	/* var! */ //@item(postfixVar, "var!", "assign to variable", "snippet")
+
+	var foo []int
+	foo. //@complete(" //", postfixAppend, postfixCopy, postfixLast, postfixPrint, postfixRange, postfixReverse, postfixSort, postfixVar)
+
+		foo = nil
+}
diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden
index 7b9b6ed..8cf51c9 100644
--- a/internal/lsp/testdata/summary.txt.golden
+++ b/internal/lsp/testdata/summary.txt.golden
@@ -1,8 +1,8 @@
 -- summary --
 CallHierarchyCount = 2
 CodeLensCount = 5
-CompletionsCount = 262
-CompletionSnippetCount = 94
+CompletionsCount = 263
+CompletionSnippetCount = 95
 UnimportedCompletionsCount = 5
 DeepCompletionsCount = 5
 FuzzyCompletionsCount = 8
@@ -14,8 +14,8 @@
 ImportCount = 8
 SemanticTokenCount = 3
 SuggestedFixCount = 40
-FunctionExtractionCount = 13
-DefinitionsCount = 90
+FunctionExtractionCount = 18
+DefinitionsCount = 95
 TypeDefinitionsCount = 10
 HighlightsCount = 69
 ReferencesCount = 25
diff --git a/internal/lsp/testdata/unsafe/unsafe.go b/internal/lsp/testdata/unsafe/unsafe.go
index e6a9f8e..5d5e434 100644
--- a/internal/lsp/testdata/unsafe/unsafe.go
+++ b/internal/lsp/testdata/unsafe/unsafe.go
@@ -9,6 +9,5 @@
 

 func _() {

 	x := struct{}{}

-	_ = unsafe.Sizeof(x) //@complete("i", Sizeof)

+	_ = unsafe.Sizeof(x) //@complete("z", Sizeof)

 }

-