internal/lsp/cache: don't invalidate metadata for new invalid imports

Our metadata reloading model makes typing out import paths manually
very slow. We can avoid some of the slowness by not invalidating
metadata when a new import path is obviously invalid.

Updates golang/go#35877

Change-Id: Ifcf9ebaac0b146a2098ef8d411fa85fefa7ba6ca
Reviewed-on: https://go-review.googlesource.com/c/tools/+/251086
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Danish Dua <danishdua@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index bf9d373..9621987 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -16,6 +16,7 @@
 	"os"
 	"path/filepath"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -1120,19 +1121,29 @@
 	if original.Name.Name != current.Name.Name {
 		return true
 	}
-	// If the package's imports have increased, definitely re-run `go list`.
-	if len(original.Imports) < len(current.Imports) {
-		return true
-	}
 	importSet := make(map[string]struct{})
 	for _, importSpec := range original.Imports {
 		importSet[importSpec.Path.Value] = struct{}{}
 	}
 	// If any of the current imports were not in the original imports.
 	for _, importSpec := range current.Imports {
-		if _, ok := importSet[importSpec.Path.Value]; !ok {
-			return true
+		if _, ok := importSet[importSpec.Path.Value]; ok {
+			continue
 		}
+		// If the import path is obviously not valid, we can skip reloading
+		// metadata. For now, valid means properly quoted and without a
+		// terminal slash.
+		path, err := strconv.Unquote(importSpec.Path.Value)
+		if err != nil {
+			continue
+		}
+		if path == "" {
+			continue
+		}
+		if path[len(path)-1] == '/' {
+			continue
+		}
+		return true
 	}
 	return false
 }