internal/lsp: a cleaner way of doing overlays

Change-Id: I3ee053cfc4b63f54b9bf43d0ce6a2bae713e3a0d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/172638
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cmd/cmd_test.go b/internal/lsp/cmd/cmd_test.go
index 8a56587..4151af5 100644
--- a/internal/lsp/cmd/cmd_test.go
+++ b/internal/lsp/cmd/cmd_test.go
@@ -7,6 +7,7 @@
 import (
 	"io/ioutil"
 	"os"
+	"path/filepath"
 	"strings"
 	"testing"
 
@@ -18,7 +19,7 @@
 // We hardcode the expected number of test cases to ensure that all tests
 // are being executed. If a test is added, this number must be changed.
 const (
-	expectedCompletionsCount = 64
+	expectedCompletionsCount = 65
 	expectedDiagnosticsCount = 16
 	expectedFormatCount      = 4
 )
@@ -31,16 +32,28 @@
 	const dir = "../testdata"
 
 	files := packagestest.MustCopyFileTree(dir)
+	overlays := map[string][]byte{}
 	for fragment, operation := range files {
 		if trimmed := strings.TrimSuffix(fragment, ".in"); trimmed != fragment {
 			delete(files, fragment)
 			files[trimmed] = operation
 		}
+		const overlay = ".overlay"
+		if index := strings.Index(fragment, overlay); index >= 0 {
+			delete(files, fragment)
+			partial := fragment[:index] + fragment[index+len(overlay):]
+			contents, err := ioutil.ReadFile(filepath.Join(dir, fragment))
+			if err != nil {
+				t.Fatal(err)
+			}
+			overlays[partial] = contents
+		}
 	}
 	modules := []packagestest.Module{
 		{
-			Name:  "golang.org/x/tools/internal/lsp",
-			Files: files,
+			Name:    "golang.org/x/tools/internal/lsp",
+			Files:   files,
+			Overlay: overlays,
 		},
 	}
 	exported := packagestest.Export(t, exporter, modules)
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 4c27c4f..55ed962 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -11,6 +11,7 @@
 	"go/ast"
 	"go/parser"
 	"go/token"
+	"io/ioutil"
 	"os/exec"
 	"path/filepath"
 	"runtime"
@@ -18,7 +19,6 @@
 	"strings"
 	"testing"
 
-	"golang.org/x/tools/go/packages"
 	"golang.org/x/tools/go/packages/packagestest"
 	"golang.org/x/tools/internal/lsp/cache"
 	"golang.org/x/tools/internal/lsp/diff"
@@ -48,24 +48,34 @@
 	const expectedSignaturesCount = 19
 
 	files := packagestest.MustCopyFileTree(dir)
+	overlays := map[string][]byte{}
 	for fragment, operation := range files {
 		if trimmed := strings.TrimSuffix(fragment, ".in"); trimmed != fragment {
 			delete(files, fragment)
 			files[trimmed] = operation
 		}
+		const overlay = ".overlay"
+		if index := strings.Index(fragment, overlay); index >= 0 {
+			delete(files, fragment)
+			partial := fragment[:index] + fragment[index+len(overlay):]
+			contents, err := ioutil.ReadFile(filepath.Join(dir, fragment))
+			if err != nil {
+				t.Fatal(err)
+			}
+			overlays[partial] = contents
+		}
 	}
 	modules := []packagestest.Module{
 		{
-			Name:  "golang.org/x/tools/internal/lsp",
-			Files: files,
+			Name:    "golang.org/x/tools/internal/lsp",
+			Files:   files,
+			Overlay: overlays,
 		},
 	}
 	exported := packagestest.Export(t, exporter, modules)
 	defer exported.Cleanup()
 
 	// Merge the exported.Config with the view.Config.
-	addUnsavedFiles(t, exported.Config, exported)
-
 	cfg := *exported.Config
 
 	cfg.Fset = token.NewFileSet()
@@ -190,25 +200,6 @@
 	})
 }
 
-func addUnsavedFiles(t *testing.T, cfg *packages.Config, exported *packagestest.Exported) {
-	if cfg.Overlay == nil {
-		cfg.Overlay = make(map[string][]byte)
-	}
-	// For now, we hardcode a file that we know is in the testdata.
-	// TODO(rstambler): Figure out a way to do this better.
-	dir := filepath.Dir(filepath.Dir(exported.File("golang.org/x/tools/internal/lsp", filepath.Join("complit", "complit.go"))))
-	cfg.Overlay[filepath.Join(dir, "nodisk", "nodisk.go")] = []byte(`package nodisk
-
-import (
-	"golang.org/x/tools/internal/lsp/foo"
-)
-
-func _() {
-	foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
-}
-`)
-}
-
 type diagnostics map[span.URI][]protocol.Diagnostic
 type completionItems map[token.Pos]*protocol.CompletionItem
 type completions map[token.Position][]token.Pos
diff --git a/internal/lsp/testdata/nodisk/nodisk.overlay.go b/internal/lsp/testdata/nodisk/nodisk.overlay.go
new file mode 100644
index 0000000..f9194be
--- /dev/null
+++ b/internal/lsp/testdata/nodisk/nodisk.overlay.go
@@ -0,0 +1,9 @@
+package nodisk
+
+import (
+	"golang.org/x/tools/internal/lsp/foo"
+)
+
+func _() {
+	foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
+}