diff --git a/internal/lsp/text_synchronization.go b/internal/lsp/text_synchronization.go index fbbd82d2..b0ffc3fe 100644 --- a/internal/lsp/text_synchronization.go +++ b/internal/lsp/text_synchronization.go @@ -10,6 +10,7 @@ import ( "golang.org/x/tools/internal/jsonrpc2" "golang.org/x/tools/internal/lsp/protocol" + "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/span" ) @@ -104,5 +105,47 @@ func (s *Server) didClose(ctx context.Context, params *protocol.DidCloseTextDocu uri := span.NewURI(params.TextDocument.URI) s.session.DidClose(uri) view := s.session.ViewOf(uri) - return view.SetContent(ctx, uri, nil) + if err := view.SetContent(ctx, uri, nil); err != nil { + return err + } + // If the current file was the only open file for its package, + // clear out all diagnostics for the package. + f, err := view.GetFile(ctx, uri) + if err != nil { + s.session.Logger().Errorf(ctx, "no file for %s: %v", uri, err) + return nil + } + // For non-Go files, don't return any diagnostics. + gof, ok := f.(source.GoFile) + if !ok { + return nil + } + pkg := gof.GetPackage(ctx) + if pkg == nil { + s.session.Logger().Errorf(ctx, "no package available for %s", uri) + return nil + } + reports := make(map[span.URI][]source.Diagnostic) + clearDiagnostics := true + for _, filename := range pkg.GetFilenames() { + uri := span.NewURI(filename) + reports[uri] = []source.Diagnostic{} + if span.CompareURI(uri, gof.URI()) == 0 { + continue + } + // If other files from this package are open. + if s.session.IsOpen(uri) { + clearDiagnostics = false + } + } + // We still have open files for this package, so don't clear diagnostics. + if !clearDiagnostics { + return nil + } + for uri, diagnostics := range reports { + if err := s.publishDiagnostics(ctx, view, uri, diagnostics); err != nil { + s.session.Logger().Errorf(ctx, "failed to clear diagnostics for %s: %v", uri, err) + } + } + return nil }