diff --git a/toolchain/language_server/context.cpp b/toolchain/language_server/context.cpp index f1bcb8bfa664..f36aea95b291 100644 --- a/toolchain/language_server/context.cpp +++ b/toolchain/language_server/context.cpp @@ -61,7 +61,9 @@ class PublishDiagnosticConsumer : public DiagnosticConsumer { } // Returns the constructed request. - auto params() -> llvm::json::Value { return params_; } + auto params() -> const clang::clangd::PublishDiagnosticsParams& { + return params_; + } private: // Returns the LSP range for a diagnostic. Note that Carbon uses 1-based @@ -151,8 +153,7 @@ auto Context::File::SetText(Context& context, std::optional version, // Note we need to publish diagnostics even when empty. // TODO: Consider caching previously published diagnostics and only publishing // when they change. - context.outgoing().notify("textDocument/publishDiagnostics", - consumer.params()); + context.PublishDiagnostics(consumer.params()); } auto Context::LookupFile(llvm::StringRef filename) -> File* { diff --git a/toolchain/language_server/context.h b/toolchain/language_server/context.h index 8c4c8b1b784b..16f573a6d216 100644 --- a/toolchain/language_server/context.h +++ b/toolchain/language_server/context.h @@ -61,12 +61,15 @@ class Context { // null. auto LookupFile(llvm::StringRef filename) -> File*; + // Wrapper for LSP notification. + auto PublishDiagnostics(clang::clangd::PublishDiagnosticsParams params) + -> void { + outgoing_->notify("textDocument/publishDiagnostics", params); + } + auto vlog_stream() -> llvm::raw_ostream* { return vlog_stream_; } auto file_emitter() -> FileDiagnosticEmitter& { return file_emitter_; } auto no_loc_emitter() -> NoLocDiagnosticEmitter& { return no_loc_emitter_; } - auto outgoing() -> clang::clangd::LSPBinder::RawOutgoing& { - return *outgoing_; - } auto files() -> Map& { return files_; } diff --git a/toolchain/language_server/handle_text_document.cpp b/toolchain/language_server/handle_text_document.cpp index 6be977d10e72..84653c99c3e1 100644 --- a/toolchain/language_server/handle_text_document.cpp +++ b/toolchain/language_server/handle_text_document.cpp @@ -58,7 +58,11 @@ auto HandleDidCloseTextDocument( return; } - if (!context.files().Erase(filename)) { + if (context.files().Erase(filename)) { + // Clear diagnostics when the document closes. Otherwise, any diagnostics + // will linger. + context.PublishDiagnostics({.uri = params.textDocument.uri}); + } else { CARBON_DIAGNOSTIC(LanguageServerCloseUnknownFile, Warning, "tried closing unknown file; ignoring request"); context.file_emitter().Emit(filename, LanguageServerCloseUnknownFile); diff --git a/toolchain/language_server/testdata/text_document/diagnostics.carbon b/toolchain/language_server/testdata/text_document/diagnostics.carbon index d570d2ebd463..0c01fb601010 100644 --- a/toolchain/language_server/testdata/text_document/diagnostics.carbon +++ b/toolchain/language_server/testdata/text_document/diagnostics.carbon @@ -119,6 +119,15 @@ // CHECK:STDOUT: "uri": "file:///test.carbon", // CHECK:STDOUT: "version": 2 // CHECK:STDOUT: } +// CHECK:STDOUT: }Content-Length: 144{{\r}} +// CHECK:STDOUT: {{\r}} +// CHECK:STDOUT: { +// CHECK:STDOUT: "jsonrpc": "2.0", +// CHECK:STDOUT: "method": "textDocument/publishDiagnostics", +// CHECK:STDOUT: "params": { +// CHECK:STDOUT: "diagnostics": [], +// CHECK:STDOUT: "uri": "file:///test.carbon" +// CHECK:STDOUT: } // CHECK:STDOUT: }Content-Length: 51{{\r}} // CHECK:STDOUT: {{\r}} // CHECK:STDOUT: { diff --git a/toolchain/language_server/testdata/text_document/open_change_close.carbon b/toolchain/language_server/testdata/text_document/open_change_close.carbon index 6ba033d81785..8b54f1c12aa3 100644 --- a/toolchain/language_server/testdata/text_document/open_change_close.carbon +++ b/toolchain/language_server/testdata/text_document/open_change_close.carbon @@ -55,6 +55,15 @@ // CHECK:STDOUT: "diagnostics": [], // CHECK:STDOUT: "uri": "file:///test.carbon" // CHECK:STDOUT: } +// CHECK:STDOUT: }Content-Length: 144{{\r}} +// CHECK:STDOUT: {{\r}} +// CHECK:STDOUT: { +// CHECK:STDOUT: "jsonrpc": "2.0", +// CHECK:STDOUT: "method": "textDocument/publishDiagnostics", +// CHECK:STDOUT: "params": { +// CHECK:STDOUT: "diagnostics": [], +// CHECK:STDOUT: "uri": "file:///test.carbon" +// CHECK:STDOUT: } // CHECK:STDOUT: }Content-Length: 51{{\r}} // CHECK:STDOUT: {{\r}} // CHECK:STDOUT: {