internal/lsp, go/packages: work-around invalid files in GOPATH mode

This change adds a test for this case (empty test file in GOPATH mode)
to go/packages. It is skipped for now, as the go/packages work-around is
too brittle to justify adding. Instead, we suppress gopls-generated
error messages in pop-ups--users should only see error messages if they
come from go/packages.

Fixes golang/go#40825

Change-Id: I0e2af53578d65739ebae582075498d997fc019d7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/250949
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/go/packages/overlay_test.go b/go/packages/overlay_test.go
index 22aade1..6d9be43 100644
--- a/go/packages/overlay_test.go
+++ b/go/packages/overlay_test.go
@@ -831,3 +831,35 @@
 		})
 	}
 }
+
+func TestInvalidXTestInGOPATH(t *testing.T) {
+	packagestest.TestAll(t, testInvalidXTestInGOPATH)
+}
+func testInvalidXTestInGOPATH(t *testing.T, exporter packagestest.Exporter) {
+	t.Skip("Not fixed yet. See golang.org/issue/40825.")
+
+	exported := packagestest.Export(t, exporter, []packagestest.Module{
+		{
+			Name: "golang.org/fake",
+			Files: map[string]interface{}{
+				"x/x.go":      `package x`,
+				"x/x_test.go": ``,
+			},
+		},
+	})
+	defer exported.Cleanup()
+
+	dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "x/x.go")))
+
+	exported.Config.Mode = everythingMode
+	exported.Config.Tests = true
+
+	initial, err := packages.Load(exported.Config, fmt.Sprintf("%s/...", dir))
+	if err != nil {
+		t.Fatal(err)
+	}
+	pkg := initial[0]
+	if len(pkg.CompiledGoFiles) != 2 {
+		t.Fatalf("expected at least 2 CompiledGoFiles for %s, got %v", pkg.PkgPath, len(pkg.CompiledGoFiles))
+	}
+}
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index 135e2e5..27bfbc8 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -121,6 +121,7 @@
 		}
 		event.Error(ctx, "go/packages.Load", err, tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
 	} else {
+		err = fmt.Errorf("no packages returned")
 		event.Log(ctx, "go/packages.Load", tag.Snapshot.Of(s.ID()), tag.Directory.Of(cfg.Dir), tag.Query.Of(query), tag.PackageCount.Of(len(pkgs)))
 	}
 	if len(pkgs) == 0 {
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index 17fd1da..00bbc3b 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -101,14 +101,17 @@
 		if s.handleFatalErrors(ctx, snapshot, modErr, err) {
 			return nil, nil
 		}
-		msg := `The code in the workspace failed to compile (see the error message below).
-If you believe this is a mistake, please file an issue: https://github.com/golang/go/issues/new.`
-		event.Error(ctx, msg, err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder()))
-		if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
-			Type:    protocol.Error,
-			Message: fmt.Sprintf("%s\n%v", msg, err),
-		}); err != nil {
-			event.Error(ctx, "ShowMessage failed", err, tag.Directory.Of(snapshot.View().Folder().Filename()))
+		event.Error(ctx, "errors diagnosing workspace", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder()))
+		// Present any `go list` errors directly to the user.
+		if errors.Is(err, source.PackagesLoadError) {
+			if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
+				Type: protocol.Error,
+				Message: fmt.Sprintf(`The code in the workspace failed to compile (see the error message below).
+If you believe this is a mistake, please file an issue: https://github.com/golang/go/issues/new.
+%v`, err),
+			}); err != nil {
+				event.Error(ctx, "ShowMessage failed", err, tag.Directory.Of(snapshot.View().Folder().Filename()))
+			}
 		}
 		return nil, nil
 	}
diff --git a/internal/lsp/regtest/diagnostics_test.go b/internal/lsp/regtest/diagnostics_test.go
index 428da7a..23ed172 100644
--- a/internal/lsp/regtest/diagnostics_test.go
+++ b/internal/lsp/regtest/diagnostics_test.go
@@ -837,7 +837,6 @@
 
 // Reproduces golang/go#40825.
 func TestEmptyGOPATHXTest_40825(t *testing.T) {
-	t.Skip("bug isn't fixed yet")
 	const files = `
 -- x.go --
 package x
diff --git a/internal/lsp/regtest/wrappers.go b/internal/lsp/regtest/wrappers.go
index b4271ec..b84175f 100644
--- a/internal/lsp/regtest/wrappers.go
+++ b/internal/lsp/regtest/wrappers.go
@@ -244,8 +244,8 @@
 	return lens
 }
 
-// References calls textDocument/references for the given path at the
-// position of the given regexp.
+// References calls textDocument/references for the given path at the given
+// position.
 func (e *Env) References(path string, pos fake.Pos) []protocol.Location {
 	e.T.Helper()
 	locations, err := e.Editor.References(e.Ctx, path, pos)