internal/lsp/source: add a FileSource interface

Rename Snapshot.GetFile to GetVersionedFile, and make the signature of
GetFile consistent with the corresponding method on session and cache.
This allows algorithms that depend only on file state to be expressed
using this API. In a subsequent CL, this is used for building and
testing the workspace module.

Preeemptively add the FileSource interface for use in these algorithms.

Change-Id: I550906e554fd290dcdf4cac442d5f223e0f644c1
Reviewed-on: https://go-review.googlesource.com/c/tools/+/263522
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Trust: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index c96ad69..d141c51 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -791,12 +791,12 @@
 	return s.files[f.URI()]
 }
 
-// GetFile returns a File for the given URI. If the file is unknown it is added
-// to the managed set.
+// GetVersionedFile returns a File for the given URI. If the file is unknown it
+// is added to the managed set.
 //
 // GetFile succeeds even if the file does not exist. A non-nil error return
 // indicates some type of internal error, for example if ctx is cancelled.
-func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.VersionedFileHandle, error) {
+func (s *snapshot) GetVersionedFile(ctx context.Context, uri span.URI) (source.VersionedFileHandle, error) {
 	f, err := s.view.getFile(uri)
 	if err != nil {
 		return nil, err
@@ -807,6 +807,11 @@
 	return s.getFileLocked(ctx, f)
 }
 
+// GetFile implements the fileSource interface by wrapping GetVersionedFile.
+func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
+	return s.GetVersionedFile(ctx, uri)
+}
+
 func (s *snapshot) getFileLocked(ctx context.Context, f *fileBase) (source.VersionedFileHandle, error) {
 	if fh, ok := s.files[f.URI()]; ok {
 		return fh, nil
diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go
index 20e9f99..cb45045 100644
--- a/internal/lsp/code_action.go
+++ b/internal/lsp/code_action.go
@@ -282,7 +282,7 @@
 				Edit:        protocol.WorkspaceEdit{},
 			}
 			for uri, edits := range fix.Edits {
-				fh, err := snapshot.GetFile(ctx, uri)
+				fh, err := snapshot.GetVersionedFile(ctx, uri)
 				if err != nil {
 					return nil, nil, err
 				}
@@ -481,7 +481,7 @@
 			return nil, nil
 		}
 		var err error
-		modFH, err = snapshot.GetFile(ctx, modURI)
+		modFH, err = snapshot.GetVersionedFile(ctx, modURI)
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index f3e59c6..7469a36 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -337,7 +337,7 @@
 			Severity: protocol.SeverityError,
 			Source:   e.Category,
 		}
-		fh, err := snapshot.GetFile(ctx, e.URI)
+		fh, err := snapshot.GetVersionedFile(ctx, e.URI)
 		if err != nil {
 			return err
 		}
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index ff76d58..307660b 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -470,7 +470,7 @@
 		return nil, nil, false, func() {}, err
 	}
 	snapshot, release := view.Snapshot(ctx)
-	fh, err := snapshot.GetFile(ctx, uri)
+	fh, err := snapshot.GetVersionedFile(ctx, uri)
 	if err != nil {
 		release()
 		return nil, nil, false, func() {}, err
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index b24b436..d94b8f0 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -467,7 +467,7 @@
 	snapshot, release := view.Snapshot(r.ctx)
 	defer release()
 
-	fh, err := snapshot.GetFile(r.ctx, uri)
+	fh, err := snapshot.GetVersionedFile(r.ctx, uri)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -577,7 +577,7 @@
 	snapshot, release := view.Snapshot(r.ctx)
 	defer release()
 
-	fh, err := snapshot.GetFile(r.ctx, uri)
+	fh, err := snapshot.GetVersionedFile(r.ctx, uri)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/internal/lsp/mod/diagnostics.go b/internal/lsp/mod/diagnostics.go
index e8c4533..8904ba2 100644
--- a/internal/lsp/mod/diagnostics.go
+++ b/internal/lsp/mod/diagnostics.go
@@ -21,7 +21,7 @@
 
 	reports := map[source.VersionedFileIdentity][]*source.Diagnostic{}
 	for _, uri := range snapshot.ModFiles() {
-		fh, err := snapshot.GetFile(ctx, uri)
+		fh, err := snapshot.GetVersionedFile(ctx, uri)
 		if err != nil {
 			return nil, err
 		}
@@ -44,7 +44,7 @@
 			} else {
 				diag.Severity = protocol.SeverityWarning
 			}
-			fh, err := snapshot.GetFile(ctx, e.URI)
+			fh, err := snapshot.GetVersionedFile(ctx, e.URI)
 			if err != nil {
 				return nil, err
 			}
diff --git a/internal/lsp/rename.go b/internal/lsp/rename.go
index cb364a1..cef0638 100644
--- a/internal/lsp/rename.go
+++ b/internal/lsp/rename.go
@@ -24,7 +24,7 @@
 
 	var docChanges []protocol.TextDocumentEdit
 	for uri, e := range edits {
-		fh, err := snapshot.GetFile(ctx, uri)
+		fh, err := snapshot.GetVersionedFile(ctx, uri)
 		if err != nil {
 			return nil, err
 		}
diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go
index c1f5826..2f0e7d6 100644
--- a/internal/lsp/source/diagnostics.go
+++ b/internal/lsp/source/diagnostics.go
@@ -128,7 +128,7 @@
 }
 
 func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (VersionedFileIdentity, []*Diagnostic, error) {
-	fh, err := snapshot.GetFile(ctx, uri)
+	fh, err := snapshot.GetVersionedFile(ctx, uri)
 	if err != nil {
 		return VersionedFileIdentity{}, nil, err
 	}
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index 291dfe3..c84ff06 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -44,9 +44,13 @@
 	// in the given snapshot.
 	FindFile(uri span.URI) VersionedFileHandle
 
-	// GetFile returns the FileHandle for a given URI, initializing it
-	// if it is not already part of the snapshot.
-	GetFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
+	// GetVersionedFile returns the VersionedFileHandle for a given URI,
+	// initializing it if it is not already part of the snapshot.
+	GetVersionedFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
+
+	// GetFile returns the FileHandle for a given URI, initializing it if it is
+	// not already part of the snapshot.
+	GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
 
 	// AwaitInitialized waits until the snapshot's view is initialized.
 	AwaitInitialized(ctx context.Context)
@@ -203,6 +207,14 @@
 	IsGoPrivatePath(path string) bool
 }
 
+// A FileSource maps uris to FileHandles. This abstraction exists both for
+// testability, and so that algorithms can be run equally on session and
+// snapshot files.
+type FileSource interface {
+	// GetFile returns the FileHandle for a given URI.
+	GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
+}
+
 type BuiltinPackage struct {
 	Package    *ast.Package
 	ParsedFile *ParsedGoFile