internal/lsp: parse Go files through the new snapshot's cache in clone

I think we had discussed making this change after you finished your
cache rewrites, but I never got back to it. Let me know if you think
there's a better way to do this.

Change-Id: Ia7dfe6830110f21e0d2683e64f8ee0d2549afdea
Reviewed-on: https://go-review.googlesource.com/c/tools/+/253280
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index 9621987..ddb3626 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -9,7 +9,6 @@
 	"context"
 	"fmt"
 	"go/ast"
-	"go/parser"
 	"go/token"
 	"go/types"
 	"io"
@@ -908,7 +907,7 @@
 
 		// Check if the file's package name or imports have changed,
 		// and if so, invalidate this file's packages' metadata.
-		invalidateMetadata := forceReloadMetadata || s.shouldInvalidateMetadata(ctx, originalFH, currentFH)
+		invalidateMetadata := forceReloadMetadata || s.shouldInvalidateMetadata(ctx, result, originalFH, currentFH)
 
 		// Invalidate the previous modTidyHandle if any of the files have been
 		// saved or if any of the metadata has been invalidated.
@@ -1088,7 +1087,7 @@
 
 // shouldInvalidateMetadata reparses a file's package and import declarations to
 // determine if the file requires a metadata reload.
-func (s *snapshot) shouldInvalidateMetadata(ctx context.Context, originalFH, currentFH source.FileHandle) bool {
+func (s *snapshot) shouldInvalidateMetadata(ctx context.Context, newSnapshot *snapshot, originalFH, currentFH source.FileHandle) bool {
 	if originalFH == nil {
 		return currentFH.Kind() == source.Go
 	}
@@ -1100,33 +1099,26 @@
 	if kind := originalFH.Kind(); kind == source.Mod {
 		return originalFH.URI() == s.view.modURI
 	}
-	// Get the original and current parsed files in order to check package name and imports.
-	// Use the direct parsing API to avoid modifying the snapshot we're cloning.
-	parse := func(fh source.FileHandle) (*ast.File, error) {
-		data, err := fh.Read()
-		if err != nil {
-			return nil, err
-		}
-		fset := token.NewFileSet()
-		return parser.ParseFile(fset, fh.URI().Filename(), data, parser.ImportsOnly)
-	}
-	original, originalErr := parse(originalFH)
-	current, currentErr := parse(currentFH)
+	// Get the original and current parsed files in order to check package name
+	// and imports. Use the new snapshot to parse to avoid modifying the
+	// current snapshot.
+	original, originalErr := newSnapshot.ParseGo(ctx, originalFH, source.ParseHeader)
+	current, currentErr := newSnapshot.ParseGo(ctx, currentFH, source.ParseHeader)
 	if originalErr != nil || currentErr != nil {
 		return (originalErr == nil) != (currentErr == nil)
 	}
 	// Check if the package's metadata has changed. The cases handled are:
 	//    1. A package's name has changed
 	//    2. A file's imports have changed
-	if original.Name.Name != current.Name.Name {
+	if original.File.Name.Name != current.File.Name.Name {
 		return true
 	}
 	importSet := make(map[string]struct{})
-	for _, importSpec := range original.Imports {
+	for _, importSpec := range original.File.Imports {
 		importSet[importSpec.Path.Value] = struct{}{}
 	}
 	// If any of the current imports were not in the original imports.
-	for _, importSpec := range current.Imports {
+	for _, importSpec := range current.File.Imports {
 		if _, ok := importSet[importSpec.Path.Value]; ok {
 			continue
 		}