diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go index 1c787ac5d1d..d42e184ae57 100644 --- a/internal/lsp/diagnostics.go +++ b/internal/lsp/diagnostics.go @@ -13,24 +13,28 @@ import ( "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" + "golang.org/x/tools/internal/telemetry/trace" + errors "golang.org/x/xerrors" ) -func (s *Server) Diagnostics(ctx context.Context, view source.View, uri span.URI) { +func (s *Server) diagnostics(view source.View, uri span.URI) error { + ctx := view.BackgroundContext() + ctx, done := trace.StartSpan(ctx, "lsp:background-worker") + defer done() + ctx = telemetry.File.With(ctx, uri) f, err := view.GetFile(ctx, uri) if err != nil { - log.Error(ctx, "no file", err, telemetry.File) - return + return err } // For non-Go files, don't return any diagnostics. gof, ok := f.(source.GoFile) if !ok { - return + return errors.Errorf("%s is not a Go file", f.URI()) } reports, err := source.Diagnostics(ctx, view, gof, view.Options().DisabledAnalyses) if err != nil { - log.Error(ctx, "failed to compute diagnostics", err, telemetry.File) - return + return err } s.undeliveredMu.Lock() @@ -57,6 +61,7 @@ func (s *Server) Diagnostics(ctx context.Context, view source.View, uri span.URI // If we fail to deliver the same diagnostics twice, just give up. delete(s.undelivered, uri) } + return nil } func (s *Server) publishDiagnostics(ctx context.Context, uri span.URI, diagnostics []source.Diagnostic) error { diff --git a/internal/lsp/text_synchronization.go b/internal/lsp/text_synchronization.go index 96066eecda7..9e9072a62a0 100644 --- a/internal/lsp/text_synchronization.go +++ b/internal/lsp/text_synchronization.go @@ -15,7 +15,6 @@ import ( "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" - "golang.org/x/tools/internal/telemetry/trace" errors "golang.org/x/xerrors" ) @@ -32,12 +31,8 @@ func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocume view := s.session.ViewOf(uri) // Run diagnostics on the newly-changed file. - go func() { - ctx := view.BackgroundContext() - ctx, done := trace.StartSpan(ctx, "lsp:background-worker") - defer done() - s.Diagnostics(ctx, view, uri) - }() + go s.diagnostics(view, uri) + return nil } @@ -84,12 +79,8 @@ func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDo } // Run diagnostics on the newly-changed file. - go func() { - ctx := view.BackgroundContext() - ctx, done := trace.StartSpan(ctx, "lsp:background-worker") - defer done() - s.Diagnostics(ctx, view, uri) - }() + go s.diagnostics(view, uri) + return nil } diff --git a/internal/lsp/watched_files.go b/internal/lsp/watched_files.go index 5740149ee97..08758d7f0cb 100644 --- a/internal/lsp/watched_files.go +++ b/internal/lsp/watched_files.go @@ -13,7 +13,6 @@ import ( "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" - "golang.org/x/tools/internal/telemetry/trace" ) func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.DidChangeWatchedFilesParams) error { @@ -48,12 +47,7 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did s.session.DidChangeOutOfBand(ctx, gof, change.Type) // Refresh diagnostics to reflect updated file contents. - go func(view source.View) { - ctx := view.BackgroundContext() - ctx, done := trace.StartSpan(ctx, "lsp:background-worker") - defer done() - s.Diagnostics(ctx, view, uri) - }(view) + go s.diagnostics(view, uri) case protocol.Created: log.Print(ctx, "watched file created", telemetry.File) case protocol.Deleted: @@ -85,18 +79,14 @@ func (s *Server) didChangeWatchedFiles(ctx context.Context, params *protocol.Did } s.session.DidChangeOutOfBand(ctx, gof, change.Type) - if otherFile != nil { - // Refresh diagnostics to reflect updated file contents. - go func(view source.View) { - ctx := view.BackgroundContext() - ctx, done := trace.StartSpan(ctx, "lsp:background-worker") - defer done() - s.Diagnostics(ctx, view, otherFile.URI()) - }(view) - } else { - // TODO: Handle case when there is no other file (i.e. deleted - // file was the only file in the package). + // If this was the only file in the package, clear its diagnostics. + if otherFile == nil { + if err := s.publishDiagnostics(ctx, uri, []source.Diagnostic{}); err != nil { + log.Error(ctx, "failed to clear diagnostics", err, telemetry.URI.Of(uri)) + } + return nil } + go s.diagnostics(view, uri) } } }