13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/Support/Errno.h"
15 #include "llvm/Support/Error.h"
17 #include <system_error>
34 Reply(
const llvm::json::Value &
id, StringRef method,
JSONTransport &transport,
35 std::mutex &transportOutputMutex);
37 Reply &operator=(Reply &&) =
delete;
38 Reply(
const Reply &) =
delete;
39 Reply &operator=(
const Reply &) =
delete;
45 std::atomic<bool> replied = {
false};
48 std::mutex &transportOutputMutex;
52 Reply::Reply(
const llvm::json::Value &
id, llvm::StringRef method,
54 : method(method), id(id), transport(&transport),
55 transportOutputMutex(transportOutputMutex) {}
57 Reply::Reply(Reply &&other)
58 : method(other.method), replied(other.replied.load()),
59 id(std::move(other.id)), transport(other.transport),
60 transportOutputMutex(other.transportOutputMutex) {
61 other.transport =
nullptr;
65 if (replied.exchange(
true)) {
66 Logger::error(
"Replied twice to message {0}({1})", method,
id);
67 assert(
false &&
"must reply to each call only once!");
70 assert(transport &&
"expected valid transport to reply to");
72 std::lock_guard<std::mutex> transportLock(transportOutputMutex);
74 Logger::info(
"--> reply:{0}({1})", method,
id);
75 transport->reply(std::move(
id), std::move(reply));
77 llvm::Error error = reply.takeError();
78 Logger::info(
"--> reply:{0}({1}): {2}", method,
id, error);
79 transport->reply(std::move(
id), std::move(error));
87 bool MessageHandler::onNotify(llvm::StringRef method, llvm::json::Value value) {
95 auto it = notificationHandlers.find(
method);
96 if (it != notificationHandlers.end())
97 it->second(std::move(value));
103 llvm::json::Value
id) {
106 Reply reply(
id,
method, transport, transportOutputMutex);
108 auto it = methodHandlers.find(
method);
109 if (it != methodHandlers.end()) {
110 it->second(std::move(params), std::move(reply));
112 reply(llvm::make_error<LSPError>(
"method not found: " +
method.str(),
122 ResponseHandlerTy responseHandler;
124 std::lock_guard<std::mutex> responseHandlersLock(responseHandlersMutex);
126 if (it != responseHandlers.end()) {
127 responseHandler = std::move(it->second);
128 responseHandlers.erase(it);
133 if (responseHandler.second) {
134 Logger::info(
"--> reply:{0}({1})", responseHandler.first,
id);
135 responseHandler.second(std::move(
id), std::move(result));
138 "received a reply with ID {0}, but there was no such outgoing request",
141 llvm::consumeError(result.takeError());
154 auto handlerFn = [&](
const LSPError &lspError) -> llvm::Error {
155 message = lspError.message;
156 code = lspError.code;
157 return llvm::Error::success();
159 if (llvm::Error unhandled = llvm::handleErrors(std::move(error), handlerFn))
162 return llvm::json::Object{
163 {
"message", std::move(message)},
164 {
"code", int64_t(code)},
170 StringRef msg = o.getString(
"message").value_or(
"Unspecified error");
171 if (std::optional<int64_t> code = o.getInteger(
"code"))
172 return llvm::make_error<LSPError>(msg.str(),
ErrorCode(*code));
173 return llvm::make_error<llvm::StringError>(llvm::inconvertibleErrorCode(),
178 sendMessage(llvm::json::Object{
181 {
"params", std::move(params)},
185 llvm::json::Value
id) {
186 sendMessage(llvm::json::Object{
188 {
"id", std::move(
id)},
190 {
"params", std::move(params)},
196 return sendMessage(llvm::json::Object{
198 {
"id", std::move(
id)},
199 {
"result", std::move(*result)},
203 sendMessage(llvm::json::Object{
205 {
"id", std::move(
id)},
214 return llvm::errorCodeToError(
215 std::error_code(errno, std::system_category()));
218 if (succeeded(readMessage(json))) {
220 if (!handleMessage(std::move(*doc), handler))
221 return llvm::Error::success();
227 return llvm::errorCodeToError(std::make_error_code(std::errc::io_error));
230 void JSONTransport::sendMessage(llvm::json::Value msg) {
231 outputBuffer.clear();
232 llvm::raw_svector_ostream os(outputBuffer);
233 os << llvm::formatv(prettyOutput ?
"{0:2}\n" :
"{0}", msg);
234 out <<
"Content-Length: " << outputBuffer.size() <<
"\r\n\r\n"
240 bool JSONTransport::handleMessage(llvm::json::Value msg,
243 llvm::json::Object *
object = msg.getAsObject();
245 object->getString(
"jsonrpc") != std::optional<StringRef>(
"2.0"))
249 std::optional<llvm::json::Value> id;
250 if (llvm::json::Value *i = object->get(
"id"))
252 std::optional<StringRef> method =
object->getString(
"method");
258 if (
auto *err = object->getObject(
"error"))
261 llvm::json::Value result =
nullptr;
262 if (llvm::json::Value *r = object->get(
"result"))
263 result = std::move(*r);
264 return handler.
onReply(std::move(*
id), std::move(result));
268 llvm::json::Value params =
nullptr;
269 if (llvm::json::Value *p = object->get(
"params"))
270 params = std::move(*p);
273 return handler.
onCall(*method, std::move(params), std::move(*
id));
274 return handler.
onNotify(*method, std::move(params));
282 static constexpr
int bufSize = 128;
286 out.resize_for_overwrite(size + bufSize);
287 if (!std::fgets(&out[size], bufSize, in))
294 size_t read = std::strlen(&out[size]);
295 if (read > 0 && out[size + read - 1] ==
'\n') {
296 out.resize(size + read);
306 LogicalResult JSONTransport::readStandardMessage(std::string &json) {
309 unsigned long long contentLength = 0;
312 if (feof(in) || ferror(in) || failed(
readLine(in, line)))
316 StringRef lineRef = line;
317 if (lineRef.consume_front(
"Content-Length: ")) {
318 llvm::getAsUnsignedInteger(lineRef.trim(), 0, contentLength);
319 }
else if (!lineRef.trim().empty()) {
329 if (contentLength == 0 || contentLength > 1 << 30)
332 json.resize(contentLength);
333 for (
size_t pos = 0, read; pos < contentLength; pos += read) {
334 read = std::fread(&json[pos], 1, contentLength - pos, in);
352 LogicalResult JSONTransport::readDelimitedMessage(std::string &json) {
355 while (succeeded(
readLine(in, line))) {
356 StringRef lineRef = line.str().trim();
357 if (lineRef.starts_with(
"//")) {
367 return failure(ferror(in));
static std::string toString(bytecode::Section::ID sectionID)
Stringify the given section ID.
static llvm::json::Object encodeError(llvm::Error error)
Encode the given error as a JSON object.
llvm::Error decodeError(const llvm::json::Object &o)
Decode the given JSON object into an error.
LogicalResult readLine(std::FILE *in, SmallVectorImpl< char > &out)
Tries to read a line up to and including .
A transport class that performs the JSON-RPC communication with the LSP client.
void notify(StringRef method, llvm::json::Value params)
The following methods are used to send a message to the LSP client.
void call(StringRef method, llvm::json::Value params, llvm::json::Value id)
llvm::Error run(MessageHandler &handler)
Start executing the JSON-RPC transport.
void reply(llvm::json::Value id, llvm::Expected< llvm::json::Value > result)
This class models an LSP error as an llvm::Error.
static void debug(const char *fmt, Ts &&...vals)
Initiate a log message at various severity levels.
static void info(const char *fmt, Ts &&...vals)
static void error(const char *fmt, Ts &&...vals)
A handler used to process the incoming transport messages.
bool onCall(StringRef method, llvm::json::Value params, llvm::json::Value id)
void method(llvm::StringLiteral method, ThisT *thisPtr, void(ThisT::*handler)(const Param &, Callback< Result >))
bool onReply(llvm::json::Value id, llvm::Expected< llvm::json::Value > result)
bool onNotify(StringRef method, llvm::json::Value value)
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
const char *const kDefaultSplitMarker
static std::string debugString(T &&op)