internal/lsp: don't add multiple views for the same folder

When we add a view, we should check if we already have a view for the
given folder.

Updates golang/go#48844

Change-Id: I0de27d420e2b4df3b33b913ae27b108bab6b7d12
Reviewed-on: https://go-review.googlesource.com/c/tools/+/356933
Trust: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go
index bcb799a..48acf46 100644
--- a/internal/lsp/cache/session.go
+++ b/internal/lsp/cache/session.go
@@ -159,6 +159,11 @@
 func (s *Session) NewView(ctx context.Context, name string, folder, tempWorkspace span.URI, options *source.Options) (source.View, source.Snapshot, func(), error) {
 	s.viewMu.Lock()
 	defer s.viewMu.Unlock()
+	for _, view := range s.views {
+		if span.CompareURI(view.folder, folder) == 0 {
+			return nil, nil, nil, source.ErrViewExists
+		}
+	}
 	view, snapshot, release, err := s.createView(ctx, name, folder, tempWorkspace, options, 0)
 	if err != nil {
 		return nil, nil, func() {}, err
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index e699188..44715f0 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -232,6 +232,9 @@
 		}
 		work := s.progress.Start(ctx, "Setting up workspace", "Loading packages...", nil, nil)
 		snapshot, release, err := s.addView(ctx, folder.Name, uri)
+		if err == source.ErrViewExists {
+			continue
+		}
 		if err != nil {
 			viewErrors[uri] = err
 			work.End(fmt.Sprintf("Error loading packages: %s", err))
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index 2dd0dbc..2285e5a 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -373,6 +373,8 @@
 	SetProgressTracker(tracker *progress.Tracker)
 }
 
+var ErrViewExists = errors.New("view already exists for session")
+
 // Overlay is the type for a file held in memory on a session.
 type Overlay interface {
 	VersionedFileHandle