gopls/internal/lsp: fix diagnostic suppression when folders change
Diagnostic suppression used the view-relative snapshot ID to avoid
publishing stale diagnostics. When the layout of views changes due to a
didChangeWorkspaceFolders notification, this suppression is broken as
snapshot IDs reset to 0. Fix this (hopefully temporarily) by introducing
a globally monotonic snapshot ID.
Fixes golang/go#56731
Change-Id: Ib108b1436e800cf5a45fbba298c9975a2cf1d735
Reviewed-on: https://go-review.googlesource.com/c/tools/+/450275
Reviewed-by: Alan Donovan <adonovan@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Findley <rfindley@google.com>
diff --git a/gopls/internal/lsp/cache/snapshot.go b/gopls/internal/lsp/cache/snapshot.go
index f280304..70c26f2 100644
--- a/gopls/internal/lsp/cache/snapshot.go
+++ b/gopls/internal/lsp/cache/snapshot.go
@@ -44,8 +44,9 @@
)
type snapshot struct {
- id uint64
- view *View
+ sequenceID uint64
+ globalID source.GlobalSnapshotID
+ view *View
cancel func()
backgroundCtx context.Context
@@ -156,6 +157,12 @@
unprocessedSubdirChanges []*fileChange
}
+var globalSnapshotID uint64
+
+func nextSnapshotID() source.GlobalSnapshotID {
+ return source.GlobalSnapshotID(atomic.AddUint64(&globalSnapshotID, 1))
+}
+
var _ memoize.RefCounted = (*snapshot)(nil) // snapshots are reference-counted
// Acquire prevents the snapshot from being destroyed until the returned function is called.
@@ -170,7 +177,7 @@
func (s *snapshot) Acquire() func() {
type uP = unsafe.Pointer
if destroyedBy := atomic.LoadPointer((*uP)(uP(&s.destroyedBy))); destroyedBy != nil {
- log.Panicf("%d: acquire() after Destroy(%q)", s.id, *(*string)(destroyedBy))
+ log.Panicf("%d: acquire() after Destroy(%q)", s.globalID, *(*string)(destroyedBy))
}
s.refcount.Add(1)
return s.refcount.Done
@@ -209,7 +216,7 @@
// Not foolproof: another thread could acquire() at this moment.
type uP = unsafe.Pointer // looking forward to generics...
if old := atomic.SwapPointer((*uP)(uP(&s.destroyedBy)), uP(&destroyedBy)); old != nil {
- log.Panicf("%d: Destroy(%q) after Destroy(%q)", s.id, destroyedBy, *(*string)(old))
+ log.Panicf("%d: Destroy(%q) after Destroy(%q)", s.globalID, destroyedBy, *(*string)(old))
}
s.packages.Destroy()
@@ -232,8 +239,12 @@
}
}
-func (s *snapshot) ID() uint64 {
- return s.id
+func (s *snapshot) SequenceID() uint64 {
+ return s.sequenceID
+}
+
+func (s *snapshot) GlobalID() source.GlobalSnapshotID {
+ return s.globalID
}
func (s *snapshot) View() source.View {
@@ -1726,7 +1737,8 @@
bgCtx, cancel := context.WithCancel(bgCtx)
result := &snapshot{
- id: s.id + 1,
+ sequenceID: s.sequenceID + 1,
+ globalID: nextSnapshotID(),
store: s.store,
view: s.view,
backgroundCtx: bgCtx,