internal/lsp: use the view options, not the session options

Previous changes to the config mechanism made the config options
per-view, not per-session. We should now make sure to obey config
changes per-view. This does not fix the configuration handling for
"watchChangedFile" however. This should be done in a future CL.

Change-Id: I73f6236386c36d2587fdb9c0601670833a4366c3
Reviewed-on: https://go-review.googlesource.com/c/tools/+/194818
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 5168ebd..f5696e0 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -117,6 +117,10 @@
 	return v.options
 }
 
+func (v *view) SetOptions(options source.Options) {
+	v.options = options
+}
+
 // Config returns the configuration used for the view's interaction with the
 // go/packages API. It is shared across all views.
 func (v *view) Config(ctx context.Context) *packages.Config {
diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go
index 39eec9d..fe87a1a 100644
--- a/internal/lsp/code_action.go
+++ b/internal/lsp/code_action.go
@@ -47,7 +47,7 @@
 
 	// Determine the supported actions for this file kind.
 	fileKind := f.Handle(ctx).Kind()
-	supportedCodeActions, ok := s.session.Options().SupportedCodeActions[fileKind]
+	supportedCodeActions, ok := view.Options().SupportedCodeActions[fileKind]
 	if !ok {
 		return nil, fmt.Errorf("no supported code actions for %v file kind", fileKind)
 	}
diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go
index df2659f..119a6a9 100644
--- a/internal/lsp/completion.go
+++ b/internal/lsp/completion.go
@@ -19,7 +19,7 @@
 func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
 	uri := span.NewURI(params.TextDocument.URI)
 	view := s.session.ViewOf(uri)
-	options := s.session.Options()
+	options := view.Options()
 	f, err := getGoFile(ctx, view, uri)
 	if err != nil {
 		return nil, err
diff --git a/internal/lsp/debug/info.go b/internal/lsp/debug/info.go
index 37f72bd..f5b3908 100644
--- a/internal/lsp/debug/info.go
+++ b/internal/lsp/debug/info.go
@@ -20,7 +20,7 @@
 )
 
 // Version is a manually-updated mechanism for tracking versions.
-var Version = "v0.1.4"
+var Version = "v0.1.5"
 
 // This writes the version and environment information to a writer.
 func PrintVersionInfo(w io.Writer, verbose bool, mode PrintMode) {
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index b771286..1c787ac 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -27,7 +27,7 @@
 	if !ok {
 		return
 	}
-	reports, err := source.Diagnostics(ctx, view, gof, s.session.Options().DisabledAnalyses)
+	reports, err := source.Diagnostics(ctx, view, gof, view.Options().DisabledAnalyses)
 	if err != nil {
 		log.Error(ctx, "failed to compute diagnostics", err, telemetry.File)
 		return
diff --git a/internal/lsp/folding_range.go b/internal/lsp/folding_range.go
index f891315..49de603 100644
--- a/internal/lsp/folding_range.go
+++ b/internal/lsp/folding_range.go
@@ -15,7 +15,7 @@
 	if err != nil {
 		return nil, err
 	}
-	ranges, err := source.FoldingRange(ctx, view, f, s.session.Options().LineFoldingOnly)
+	ranges, err := source.FoldingRange(ctx, view, f, view.Options().LineFoldingOnly)
 	if err != nil {
 		return nil, err
 	}
diff --git a/internal/lsp/hover.go b/internal/lsp/hover.go
index 475a42f..c79ba6e 100644
--- a/internal/lsp/hover.go
+++ b/internal/lsp/hover.go
@@ -34,15 +34,14 @@
 	if err != nil {
 		return nil, err
 	}
-	contents := s.toProtocolHoverContents(ctx, hover)
+	contents := s.toProtocolHoverContents(ctx, hover, view.Options())
 	return &protocol.Hover{
 		Contents: contents,
 		Range:    &rng,
 	}, nil
 }
 
-func (s *Server) toProtocolHoverContents(ctx context.Context, h *source.HoverInformation) protocol.MarkupContent {
-	options := s.session.Options()
+func (s *Server) toProtocolHoverContents(ctx context.Context, h *source.HoverInformation, options source.Options) protocol.MarkupContent {
 	content := protocol.MarkupContent{
 		Kind: options.PreferredContentFormat,
 	}
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index ce03f67..4bc9e35 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -110,14 +110,14 @@
 }
 
 func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests.CompletionSnippets, items tests.CompletionItems) {
-	original := r.server.session.Options()
-	modified := original
-	defer func() { r.server.session.SetOptions(original) }()
-
-	// Set this as a default.
-	modified.Completion.Documentation = true
-
 	for src, test := range data {
+		view := r.server.session.ViewOf(src.URI())
+		original := view.Options()
+		modified := original
+
+		// Set this as a default.
+		modified.Completion.Documentation = true
+
 		var want []source.CompletionItem
 		for _, pos := range test.CompletionItems {
 			want = append(want, *items[pos])
@@ -126,7 +126,7 @@
 		modified.Completion.Deep = strings.Contains(string(src.URI()), "deepcomplete")
 		modified.Completion.FuzzyMatching = strings.Contains(string(src.URI()), "fuzzymatch")
 		modified.Completion.Unimported = strings.Contains(string(src.URI()), "unimported")
-		r.server.session.SetOptions(modified)
+		view.SetOptions(modified)
 
 		list := r.runCompletion(t, src)
 
@@ -149,15 +149,22 @@
 				t.Errorf("%s: %s", src, msg)
 			}
 		}
+		view.SetOptions(original)
 	}
-	modified.InsertTextFormat = protocol.SnippetTextFormat
+
 	for _, usePlaceholders := range []bool{true, false} {
+
 		for src, want := range snippets {
+			view := r.server.session.ViewOf(src.URI())
+			original := view.Options()
+			modified := original
+
+			modified.InsertTextFormat = protocol.SnippetTextFormat
 			modified.Completion.Deep = strings.Contains(string(src.URI()), "deepcomplete")
 			modified.Completion.FuzzyMatching = strings.Contains(string(src.URI()), "fuzzymatch")
 			modified.Completion.Unimported = strings.Contains(string(src.URI()), "unimported")
 			modified.Completion.Placeholders = usePlaceholders
-			r.server.session.SetOptions(modified)
+			view.SetOptions(modified)
 
 			list := r.runCompletion(t, src)
 
@@ -181,6 +188,7 @@
 			if expected != got.TextEdit.NewText {
 				t.Errorf("%s: expected snippet %q, got %q", src, expected, got.TextEdit.NewText)
 			}
+			view.SetOptions(original)
 		}
 	}
 }
@@ -306,16 +314,15 @@
 }
 
 func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
-	original := r.server.session.Options()
-	modified := original
-	defer func() { r.server.session.SetOptions(original) }()
-
 	for _, spn := range data {
 		uri := spn.URI()
+		view := r.server.session.ViewOf(uri)
+		original := view.Options()
+		modified := original
 
 		// Test all folding ranges.
 		modified.LineFoldingOnly = false
-		r.server.session.SetOptions(modified)
+		view.SetOptions(modified)
 		ranges, err := r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{
 			TextDocument: protocol.TextDocumentIdentifier{
 				URI: protocol.NewURI(uri),
@@ -329,7 +336,7 @@
 
 		// Test folding ranges with lineFoldingOnly = true.
 		modified.LineFoldingOnly = true
-		r.server.session.SetOptions(modified)
+		view.SetOptions(modified)
 		ranges, err = r.server.FoldingRange(r.ctx, &protocol.FoldingRangeParams{
 			TextDocument: protocol.TextDocumentIdentifier{
 				URI: protocol.NewURI(uri),
@@ -340,7 +347,7 @@
 			continue
 		}
 		r.foldingRanges(t, "foldingRange-lineFolding", uri, ranges)
-
+		view.SetOptions(original)
 	}
 }
 
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index a9c92b3..1d8b61d 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -245,8 +245,13 @@
 	// Note: the process env contains cached module and filesystem state.
 	RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error, opts *imports.Options) error
 
-	// Options returns a copy of the ViewOptions for this view.
+	// Options returns a copy of the Options for this view.
 	Options() Options
+
+	// SetOptions sets the options of this view to new values.
+	// Warning: Do not use this, unless in a test.
+	// This function does not correctly invalidate the view when needed.
+	SetOptions(Options)
 }
 
 // File represents a source file of any type.