internal/lsp: don't queue content changes
This updates overlays immeditely, and uses the handle identity change to
correctly update the content on demand.
Fixes golang/go#32348
Change-Id: I3125a6350cac358b7c0f7dc11f2bd11ae1f41031
Reviewed-on: https://go-review.googlesource.com/c/tools/+/179922
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/cache/file.go b/internal/lsp/cache/file.go
index 424a322..e37ddcf 100644
--- a/internal/lsp/cache/file.go
+++ b/internal/lsp/cache/file.go
@@ -29,6 +29,7 @@
fname string
view *view
+ fh source.FileHandle
fc *source.FileContent
token *token.File
}
@@ -70,20 +71,12 @@
f.fc = &source.FileContent{Error: err}
return
}
- if f.fc != nil {
- if len(f.view.contentChanges) == 0 {
- return
- }
-
- f.view.mcache.mu.Lock()
- err := f.view.applyContentChanges(ctx)
- f.view.mcache.mu.Unlock()
-
- if err != nil {
- f.fc = &source.FileContent{Error: err}
- return
- }
+ oldFH := f.fh
+ f.fh = f.view.Session().GetFile(f.URI())
+ // do we already have the right contents?
+ if f.fc != nil && f.fh.Identity() == oldFH.Identity() {
+ return
}
- // We don't know the content yet, so read it.
- f.fc = f.view.Session().GetFile(f.URI()).Read(ctx)
+ // update the contents
+ f.fc = f.fh.Read(ctx)
}
diff --git a/internal/lsp/cache/gofile.go b/internal/lsp/cache/gofile.go
index ac6d5c4..350c84e 100644
--- a/internal/lsp/cache/gofile.go
+++ b/internal/lsp/cache/gofile.go
@@ -85,7 +85,7 @@
// isDirty is true if the file needs to be type-checked.
// It assumes that the file's view's mutex is held by the caller.
func (f *goFile) isDirty() bool {
- return f.meta == nil || f.imports == nil || f.token == nil || f.ast == nil || f.pkg == nil || len(f.view.contentChanges) > 0
+ return f.meta == nil || f.imports == nil || f.token == nil || f.ast == nil || f.pkg == nil
}
func (f *goFile) astIsTrimmed() bool {
diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go
index 772c350..8fdd6f0 100644
--- a/internal/lsp/cache/load.go
+++ b/internal/lsp/cache/load.go
@@ -13,11 +13,6 @@
v.mcache.mu.Lock()
defer v.mcache.mu.Unlock()
- // Apply any queued-up content changes.
- if err := v.applyContentChanges(ctx); err != nil {
- return nil, err
- }
-
// If the package for the file has not been invalidated by the application
// of the pending changes, there is no need to continue.
if !f.isDirty() {
diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go
index 1d71e0e..6bf962d 100644
--- a/internal/lsp/cache/session.go
+++ b/internal/lsp/cache/session.go
@@ -65,17 +65,16 @@
ctx := context.Background()
backgroundCtx, cancel := context.WithCancel(ctx)
v := &view{
- session: s,
- id: strconv.FormatInt(index, 10),
- baseCtx: ctx,
- backgroundCtx: backgroundCtx,
- cancel: cancel,
- name: name,
- env: os.Environ(),
- folder: folder,
- filesByURI: make(map[span.URI]viewFile),
- filesByBase: make(map[string][]viewFile),
- contentChanges: make(map[span.URI]func()),
+ session: s,
+ id: strconv.FormatInt(index, 10),
+ baseCtx: ctx,
+ backgroundCtx: backgroundCtx,
+ cancel: cancel,
+ name: name,
+ env: os.Environ(),
+ folder: folder,
+ filesByURI: make(map[span.URI]viewFile),
+ filesByBase: make(map[string][]viewFile),
mcache: &metadataCache{
packages: make(map[string]*metadata),
},
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index e18db6b..a2e7a81 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -56,13 +56,6 @@
filesByURI map[span.URI]viewFile
filesByBase map[string][]viewFile
- // contentChanges saves the content changes for a given state of the view.
- // When type information is requested by the view, all of the dirty changes
- // are applied, potentially invalidating some data in the caches. The
- // closures in the dirty slice assume that their caller is holding the
- // view's mutex.
- contentChanges map[span.URI]func()
-
// mcache caches metadata for the packages of the opened files in a view.
mcache *metadataCache
@@ -224,33 +217,14 @@
v.cancel()
v.backgroundCtx, v.cancel = context.WithCancel(v.baseCtx)
- v.contentChanges[uri] = func() {
- v.session.SetOverlay(uri, content)
- }
-
- return nil
-}
-
-// applyContentChanges applies all of the changed content stored in the view.
-// It is assumed that the caller has locked both the view's and the mcache's
-// mutexes.
-func (v *view) applyContentChanges(ctx context.Context) error {
- if ctx.Err() != nil {
- return ctx.Err()
- }
-
- v.pcache.mu.Lock()
- defer v.pcache.mu.Unlock()
-
- for uri, change := range v.contentChanges {
- change()
- delete(v.contentChanges, uri)
- }
+ v.session.SetOverlay(uri, content)
return nil
}
func (f *goFile) invalidate() {
+ f.view.pcache.mu.Lock()
+ defer f.view.pcache.mu.Unlock()
// TODO(rstambler): Should we recompute these here?
f.ast = nil
f.token = nil