incoming_messages.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/language_server/incoming_messages.h"
  5. #include "common/ostream.h"
  6. #include "common/raw_string_ostream.h"
  7. #include "toolchain/language_server/handle.h"
  8. namespace Carbon::LanguageServer {
  9. // Parses a JSON value into a specific parameter type. The name of the method is
  10. // used when producing errors.
  11. template <typename ParamsT>
  12. inline auto Parse(llvm::StringRef name, const llvm::json::Value& raw_params)
  13. -> llvm::Expected<ParamsT> {
  14. ParamsT params;
  15. llvm::json::Path::Root root;
  16. if (!clang::clangd::fromJSON(raw_params, params, root)) {
  17. return llvm::make_error<clang::clangd::LSPError>(
  18. llvm::formatv("in call to `{0}`, JSON parse failed: {1}", name,
  19. llvm::fmt_consume(root.getError())),
  20. clang::clangd::ErrorCode::InvalidParams);
  21. }
  22. return std::move(params);
  23. }
  24. template <typename ParamsT, typename ResultT>
  25. auto IncomingMessages::AddCallHandler(
  26. llvm::StringRef name,
  27. void (*handler)(Context&, const ParamsT&,
  28. llvm::function_ref<void(llvm::Expected<ResultT>)>))
  29. -> void {
  30. CallHandler parsing_handler =
  31. [name, handler](
  32. Context& context, llvm::json::Value raw_params,
  33. llvm::function_ref<void(llvm::Expected<llvm::json::Value>)> on_done)
  34. -> void {
  35. auto params = Parse<ParamsT>(name, raw_params);
  36. if (!params) {
  37. on_done(params.takeError());
  38. return;
  39. }
  40. handler(context, *params, on_done);
  41. };
  42. auto result = call_handlers_.Insert(name, parsing_handler);
  43. CARBON_CHECK(result.is_inserted(), "Duplicate handler: {0}", name);
  44. }
  45. template <typename ParamsT>
  46. auto IncomingMessages::AddNotificationHandler(llvm::StringRef name,
  47. void (*handler)(Context&,
  48. const ParamsT&))
  49. -> void {
  50. NotificationHandler parsing_handler =
  51. [name, handler](Context& context, llvm::json::Value raw_params) -> void {
  52. auto params = Parse<ParamsT>(name, raw_params);
  53. if (!params) {
  54. // TODO: Maybe we should do something more with this error?
  55. llvm::consumeError(params.takeError());
  56. }
  57. handler(context, *params);
  58. };
  59. auto result = notification_handlers_.Insert(name, parsing_handler);
  60. CARBON_CHECK(result.is_inserted(), "Duplicate handler: {0}", name);
  61. }
  62. IncomingMessages::IncomingMessages(clang::clangd::Transport* transport,
  63. Context* context)
  64. : transport_(transport), context_(context) {
  65. AddCallHandler("textDocument/documentSymbol", &HandleDocumentSymbol);
  66. AddCallHandler("initialize", &HandleInitialize);
  67. AddNotificationHandler("textDocument/didChange",
  68. &HandleDidChangeTextDocument);
  69. AddNotificationHandler("textDocument/didOpen", &HandleDidOpenTextDocument);
  70. }
  71. auto IncomingMessages::onCall(llvm::StringRef name, llvm::json::Value params,
  72. llvm::json::Value id) -> bool {
  73. if (auto result = call_handlers_.Lookup(name)) {
  74. (result.value())(*context_, std::move(params),
  75. [&](llvm::Expected<llvm::json::Value> reply) {
  76. transport_->reply(id, std::move(reply));
  77. });
  78. } else {
  79. transport_->reply(id, llvm::make_error<clang::clangd::LSPError>(
  80. llvm::formatv("unsupported call `{0}`", name),
  81. clang::clangd::ErrorCode::MethodNotFound));
  82. }
  83. return true;
  84. }
  85. auto IncomingMessages::onNotify(llvm::StringRef name, llvm::json::Value value)
  86. -> bool {
  87. if (name == "exit") {
  88. return false;
  89. }
  90. if (auto result = notification_handlers_.Lookup(name)) {
  91. (result.value())(*context_, std::move(value));
  92. } else {
  93. CARBON_DIAGNOSTIC(LanguageServerUnsupportedNotification, Warning,
  94. "unsupported notification `{0}`", std::string);
  95. context_->no_loc_emitter().Emit(LanguageServerUnsupportedNotification,
  96. name.str());
  97. }
  98. return true;
  99. }
  100. auto IncomingMessages::onReply(llvm::json::Value id,
  101. llvm::Expected<llvm::json::Value> result)
  102. -> bool {
  103. RawStringOstream id_str;
  104. id_str << id;
  105. RawStringOstream result_str;
  106. if (result) {
  107. result_str << result.get();
  108. } else {
  109. result_str << result.takeError();
  110. }
  111. CARBON_DIAGNOSTIC(LanguageServerUnexpectedReply, Warning,
  112. "unexpected reply to request ID {0}: {1}", std::string,
  113. std::string);
  114. context_->no_loc_emitter().Emit(LanguageServerUnexpectedReply,
  115. id_str.TakeStr(), result_str.TakeStr());
  116. return true;
  117. }
  118. } // namespace Carbon::LanguageServer