diff --git a/internal/lsp/cache/overlay.go b/internal/lsp/cache/overlay.go index 42ce1eabe8..dfe868720c 100644 --- a/internal/lsp/cache/overlay.go +++ b/internal/lsp/cache/overlay.go @@ -41,10 +41,10 @@ func (o *overlay) Read(ctx context.Context) ([]byte, string, error) { return o.text, o.hash, nil } -func (s *session) updateOverlay(ctx context.Context, c source.FileModification) (source.FileKind, error) { +func (s *session) updateOverlay(ctx context.Context, c source.FileModification) error { // Make sure that the file was not changed on disk. if c.OnDisk { - return source.UnknownKind, errors.Errorf("updateOverlay called for an on-disk change: %s", c.URI) + return errors.Errorf("updateOverlay called for an on-disk change: %s", c.URI) } s.overlayMu.Lock() @@ -59,18 +59,18 @@ func (s *session) updateOverlay(ctx context.Context, c source.FileModification) kind = source.DetectLanguage(c.LanguageID, c.URI.Filename()) default: if !ok { - return -1, errors.Errorf("updateOverlay: modifying unopened overlay %v", c.URI) + return errors.Errorf("updateOverlay: modifying unopened overlay %v", c.URI) } kind = o.kind } if kind == source.UnknownKind { - return -1, errors.Errorf("updateOverlay: unknown file kind for %s", c.URI) + return errors.Errorf("updateOverlay: unknown file kind for %s", c.URI) } // Closing a file just deletes its overlay. if c.Action == source.Close { delete(s.overlays, c.URI) - return kind, nil + return nil } // If the file is on disk, check if its content is the same as the overlay. @@ -87,10 +87,10 @@ func (s *session) updateOverlay(ctx context.Context, c source.FileModification) case source.Save: // Make sure the version and content (if present) is the same. if o.version != c.Version { - return -1, errors.Errorf("updateOverlay: saving %s at version %v, currently at %v", c.URI, c.Version, o.version) + return errors.Errorf("updateOverlay: saving %s at version %v, currently at %v", c.URI, c.Version, o.version) } if c.Text != nil && o.hash != hash { - return -1, errors.Errorf("updateOverlay: overlay %s changed on save", c.URI) + return errors.Errorf("updateOverlay: overlay %s changed on save", c.URI) } sameContentOnDisk = true } @@ -103,7 +103,7 @@ func (s *session) updateOverlay(ctx context.Context, c source.FileModification) hash: hash, saved: sameContentOnDisk, } - return kind, nil + return nil } func (s *session) readOverlay(uri span.URI) *overlay { diff --git a/internal/lsp/cache/session.go b/internal/lsp/cache/session.go index d421b34fcf..58fe475ecb 100644 --- a/internal/lsp/cache/session.go +++ b/internal/lsp/cache/session.go @@ -257,10 +257,8 @@ func (s *session) DidModifyFile(ctx context.Context, c source.FileModification) ctx = telemetry.URI.With(ctx, c.URI) // Update overlays only if the file was changed in the editor. - var kind source.FileKind if !c.OnDisk { - kind, err = s.updateOverlay(ctx, c) - if err != nil { + if err := s.updateOverlay(ctx, c); err != nil { return nil, err } } @@ -279,22 +277,10 @@ func (s *session) DidModifyFile(ctx context.Context, c source.FileModification) } } // Make sure that the file is added to the view. - f, err := view.getFile(c.URI) - if err != nil { + if _, err := view.getFile(c.URI); err != nil { return nil, err } - // If the file change was on disk, the file kind is not known. - if c.OnDisk { - // If the file was already known in the snapshot, - // then use the already known file kind. Otherwise, - // detect the file kind. This should only be needed for file creates. - if fh := view.getSnapshot().findFileHandle(f); fh != nil { - kind = fh.Identity().Kind - } else { - kind = source.DetectLanguage("", c.URI.Filename()) - } - } - snapshots = append(snapshots, view.invalidateContent(ctx, c.URI, kind, c.Action)) + snapshots = append(snapshots, view.invalidateContent(ctx, []span.URI{c.URI}, c.Action == source.Save)) } return snapshots, nil } diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index e7122d452e..3c2b2ad0e8 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -577,19 +577,20 @@ func (v *view) awaitInitialized(ctx context.Context) error { // invalidateContent invalidates the content of a Go file, // including any position and type information that depends on it. // It returns true if we were already tracking the given file, false otherwise. -func (v *view) invalidateContent(ctx context.Context, uri span.URI, kind source.FileKind, action source.FileAction) source.Snapshot { +func (v *view) invalidateContent(ctx context.Context, uris []span.URI, containsFileSave bool) source.Snapshot { // Detach the context so that content invalidation cannot be canceled. ctx = xcontext.Detach(ctx) + if containsFileSave && len(uris) > 1 { + panic("file save among multiple content invalidations") + } + // Cancel all still-running previous requests, since they would be // operating on stale data. // - // TODO(rstambler): All actions should lead to cancellation, - // but this will only be possible when all text synchronization events - // trigger diagnostics. - switch action { - case source.Save: - default: + // TODO(rstambler): File saves should also lead to cancellation, + // but this will only be possible when they trigger workspace-level diagnostics. + if !containsFileSave { v.cancelBackground() } @@ -600,7 +601,7 @@ func (v *view) invalidateContent(ctx context.Context, uri span.URI, kind source. v.snapshotMu.Lock() defer v.snapshotMu.Unlock() - v.snapshot = v.snapshot.clone(ctx, []span.URI{uri}) + v.snapshot = v.snapshot.clone(ctx, uris) return v.snapshot }