From 277815fd9499a523ae2e48b94cbf3ff0ca454ca0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 14 Aug 2026 20:15:42 +0000 Subject: [PATCH] language-server: Stub out support for some messages we don't handle yet. (#7637) This suppresses warnings for unhandled messages where we currently have nothing to do. No functionality change, except for less spam in the VS Code output tab. Assisted-by: Claude Code --- toolchain/language_server/handle.h | 9 +++++++ .../language_server/handle_initialize.cpp | 10 ++++++++ .../language_server/handle_text_document.cpp | 13 ++++++++++ .../language_server/incoming_messages.cpp | 10 ++++++++ .../basics/quiet_notifications.carbon | 25 +++++++++++++++++++ 5 files changed, 67 insertions(+) create mode 100644 toolchain/language_server/testdata/basics/quiet_notifications.carbon diff --git a/toolchain/language_server/handle.h b/toolchain/language_server/handle.h index 82aa3a1b6616..fe4fb681c7d6 100644 --- a/toolchain/language_server/handle.h +++ b/toolchain/language_server/handle.h @@ -20,6 +20,11 @@ auto HandleDidCloseTextDocument( Context& context, const clang::clangd::DidCloseTextDocumentParams& params) -> void; +// Acknowledges that a document was saved. +auto HandleDidSaveTextDocument( + Context& context, const clang::clangd::DidSaveTextDocumentParams& params) + -> void; + // Updates the content of already-open documents. auto HandleDidOpenTextDocument( Context& context, const clang::clangd::DidOpenTextDocumentParams& params) @@ -39,6 +44,10 @@ auto HandleInitialize( llvm::function_ref)->void> on_done) -> void; +// Acknowledges that the client finished initializing. +auto HandleInitialized(Context& context, const clang::clangd::NoParams& params) + -> void; + // Prepares LSP for shutdown. auto HandleShutdown( Context& /*context*/, diff --git a/toolchain/language_server/handle_initialize.cpp b/toolchain/language_server/handle_initialize.cpp index bf74c3597b43..bf145e40babb 100644 --- a/toolchain/language_server/handle_initialize.cpp +++ b/toolchain/language_server/handle_initialize.cpp @@ -19,4 +19,14 @@ auto HandleInitialize( on_done(reply); } +// Implements `initialized`: +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialized +auto HandleInitialized(Context& /*context*/, + const clang::clangd::NoParams& /*params*/) -> void { + // Nothing to do, but every client sends this, so we handle it rather than + // warning about an unsupported notification. + // TODO: This is when we would use `client/registerCapability` for any + // capabilities we want to register dynamically. +} + } // namespace Carbon::LanguageServer diff --git a/toolchain/language_server/handle_text_document.cpp b/toolchain/language_server/handle_text_document.cpp index 2d5a5e0fafe9..bf80be3e2651 100644 --- a/toolchain/language_server/handle_text_document.cpp +++ b/toolchain/language_server/handle_text_document.cpp @@ -115,6 +115,19 @@ auto HandleDidChangeTextDocument( } } +// Implements `textDocument/didSave`: +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didSave +auto HandleDidSaveTextDocument( + Context& /*context*/, + const clang::clangd::DidSaveTextDocumentParams& /*params*/) -> void { + // Saving doesn't change the content we're tracking: we always use the text + // provided by the client, which is already up-to-date from `didChange`. We + // handle this rather than warning about an unsupported notification. + // TODO: Other open files that import this one may now be stale, because they + // read it from disk rather than from the client. Re-check them here, or + // handle `workspace/didChangeWatchedFiles` instead. +} + // Implements `textDocument/didClose`: // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didClose auto HandleDidCloseTextDocument( diff --git a/toolchain/language_server/incoming_messages.cpp b/toolchain/language_server/incoming_messages.cpp index 80397a501bc2..d13bc5ce56de 100644 --- a/toolchain/language_server/incoming_messages.cpp +++ b/toolchain/language_server/incoming_messages.cpp @@ -76,10 +76,12 @@ IncomingMessages::IncomingMessages(clang::clangd::Transport* transport, AddCallHandler("textDocument/documentSymbol", &HandleDocumentSymbol); AddCallHandler("initialize", &HandleInitialize); AddCallHandler("shutdown", &HandleShutdown); + AddNotificationHandler("initialized", &HandleInitialized); AddNotificationHandler("textDocument/didChange", &HandleDidChangeTextDocument); AddNotificationHandler("textDocument/didClose", &HandleDidCloseTextDocument); AddNotificationHandler("textDocument/didOpen", &HandleDidOpenTextDocument); + AddNotificationHandler("textDocument/didSave", &HandleDidSaveTextDocument); } auto IncomingMessages::onCall(llvm::StringRef name, llvm::json::Value params, @@ -103,6 +105,14 @@ auto IncomingMessages::onNotify(llvm::StringRef name, llvm::json::Value value) if (name == "exit") { return false; } + // Notifications prefixed with `$/` are implementation dependent, and LSP says + // a recipient is free to ignore ones it doesn't implement. Note this doesn't + // apply to calls, which must be answered with `MethodNotFound`; `onCall` + // already does that for anything unhandled. + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#dollarRequests + if (name.starts_with("$/")) { + return true; + } if (auto result = notification_handlers_.Lookup(name)) { (result.value())(*context_, std::move(value)); } else { diff --git a/toolchain/language_server/testdata/basics/quiet_notifications.carbon b/toolchain/language_server/testdata/basics/quiet_notifications.carbon new file mode 100644 index 000000000000..1ec8527d4fb3 --- /dev/null +++ b/toolchain/language_server/testdata/basics/quiet_notifications.carbon @@ -0,0 +1,25 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/language_server/testdata/basics/quiet_notifications.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/language_server/testdata/basics/quiet_notifications.carbon + +// Notifications that we accept without doing anything, and so should produce no +// output at all. `$/` notifications are ignored whether or not we know them. + +// --- STDIN +[[@LSP-NOTIFY:initialized]] +[[@LSP-NOTIFY:textDocument/didSave: + "textDocument": {"uri": "file:/unknown.carbon"} +]] +[[@LSP-NOTIFY:$/cancelRequest:"id": 1]] +[[@LSP-NOTIFY:$/unknown-notify]] +[[@LSP-NOTIFY:exit]] + +// --- AUTOUPDATE-SPLIT + +// CHECK:STDOUT: