mirror of
https://github.com/golang/go
synced 2024-11-19 00:44:40 -07:00
internal/lsp: use latest file versions in diagnostics
This change makes sure that diagnostics are sent with the most recently seen version for a file, instead of a cached version. Fixes golang/go#36476 Change-Id: Ibac2757099fdfc71989987cf5851a678f589aadf Reviewed-on: https://go-review.googlesource.com/c/tools/+/214422 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
5a294e27f3
commit
294c8f8251
@ -32,7 +32,7 @@ func (s *Server) diagnoseSnapshot(ctx context.Context, snapshot source.Snapshot)
|
|||||||
log.Error(ctx, "diagnoseSnapshot: no diagnostics", err, telemetry.Package.Of(ph.ID()))
|
log.Error(ctx, "diagnoseSnapshot: no diagnostics", err, telemetry.Package.Of(ph.ID()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.publishReports(ctx, reports, false)
|
s.publishReports(ctx, snapshot, reports, false)
|
||||||
}(ph)
|
}(ph)
|
||||||
}
|
}
|
||||||
// Run diagnostics on the go.mod file.
|
// Run diagnostics on the go.mod file.
|
||||||
@ -61,7 +61,7 @@ func (s *Server) diagnoseFile(snapshot source.Snapshot, fh source.FileHandle) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Publish empty diagnostics for files.
|
// Publish empty diagnostics for files.
|
||||||
s.publishReports(ctx, reports, true)
|
s.publishReports(ctx, snapshot, reports, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) diagnoseModfile(snapshot source.Snapshot) {
|
func (s *Server) diagnoseModfile(snapshot source.Snapshot) {
|
||||||
@ -76,11 +76,11 @@ func (s *Server) diagnoseModfile(snapshot source.Snapshot) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Publish empty diagnostics for go.mod files.
|
// Publish empty diagnostics for files.
|
||||||
s.publishReports(ctx, reports, true)
|
s.publishReports(ctx, snapshot, reports, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) publishReports(ctx context.Context, reports map[source.FileIdentity][]source.Diagnostic, publishEmpty bool) {
|
func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, reports map[source.FileIdentity][]source.Diagnostic, publishEmpty bool) {
|
||||||
// Check for context cancellation before publishing diagnostics.
|
// Check for context cancellation before publishing diagnostics.
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
@ -89,11 +89,21 @@ func (s *Server) publishReports(ctx context.Context, reports map[source.FileIden
|
|||||||
s.deliveredMu.Lock()
|
s.deliveredMu.Lock()
|
||||||
defer s.deliveredMu.Unlock()
|
defer s.deliveredMu.Unlock()
|
||||||
|
|
||||||
for fileID, diagnostics := range reports {
|
for identity, diagnostics := range reports {
|
||||||
// Don't deliver diagnostics if the context has already been canceled.
|
// Don't deliver diagnostics if the context has already been canceled.
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// Rather than using the identity provided in the report,
|
||||||
|
// get the FileHandle directly through the snapshot.
|
||||||
|
// This prevents us from using cached file versions.
|
||||||
|
fh, err := snapshot.GetFile(identity.URI)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(ctx, "publishReports: failed to get FileHandle", err, telemetry.File.Of(identity.URI))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileID := fh.Identity()
|
||||||
|
|
||||||
// Pre-sort diagnostics to avoid extra work when we compare them.
|
// Pre-sort diagnostics to avoid extra work when we compare them.
|
||||||
source.SortDiagnostics(diagnostics)
|
source.SortDiagnostics(diagnostics)
|
||||||
toSend := sentDiagnostics{
|
toSend := sentDiagnostics{
|
||||||
@ -112,12 +122,6 @@ func (s *Server) publishReports(ctx context.Context, reports map[source.FileIden
|
|||||||
// Reuse equivalent cached diagnostics for subsequent file versions (if known),
|
// Reuse equivalent cached diagnostics for subsequent file versions (if known),
|
||||||
// or identical files (if versions are not known).
|
// or identical files (if versions are not known).
|
||||||
if ok {
|
if ok {
|
||||||
// If the file is open, and we've already delivered diagnostics for
|
|
||||||
// a later version, do nothing. This only works for open files,
|
|
||||||
// since their contents in the editor are the source of truth.
|
|
||||||
if s.session.IsOpen(fileID.URI); fileID.Version < delivered.version {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
geqVersion := fileID.Version >= delivered.version && delivered.version > 0
|
geqVersion := fileID.Version >= delivered.version && delivered.version > 0
|
||||||
noVersions := (fileID.Version == 0 && delivered.version == 0) && delivered.identifier == fileID.Identifier
|
noVersions := (fileID.Version == 0 && delivered.version == 0) && delivered.identifier == fileID.Identifier
|
||||||
if (geqVersion || noVersions) && equalDiagnostics(delivered.sorted, diagnostics) {
|
if (geqVersion || noVersions) && equalDiagnostics(delivered.sorted, diagnostics) {
|
||||||
@ -126,13 +130,12 @@ func (s *Server) publishReports(ctx context.Context, reports map[source.FileIden
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
|
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
|
||||||
Diagnostics: toProtocolDiagnostics(ctx, diagnostics),
|
Diagnostics: toProtocolDiagnostics(ctx, diagnostics),
|
||||||
URI: protocol.NewURI(fileID.URI),
|
URI: protocol.NewURI(fileID.URI),
|
||||||
Version: fileID.Version,
|
Version: fileID.Version,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error(ctx, "failed to deliver diagnostic", err, telemetry.File)
|
log.Error(ctx, "publishReports: failed to deliver diagnostic", err, telemetry.File)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Update the delivered map.
|
// Update the delivered map.
|
||||||
|
Loading…
Reference in New Issue
Block a user