13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/Support/Error.h"
16 #include <system_error>
33 Reply(
const llvm::json::Value &
id, StringRef method,
JSONTransport &transport,
34 std::mutex &transportOutputMutex);
36 Reply &operator=(Reply &&) =
delete;
37 Reply(
const Reply &) =
delete;
38 Reply &operator=(
const Reply &) =
delete;
44 std::atomic<bool> replied = {
false};
47 std::mutex &transportOutputMutex;
51 Reply::Reply(
const llvm::json::Value &
id, llvm::StringRef method,
53 : method(method), id(id), transport(&transport),
54 transportOutputMutex(transportOutputMutex) {}
56 Reply::Reply(Reply &&other)
57 : method(other.method), replied(other.replied.load()),
58 id(std::move(other.id)), transport(other.transport),
59 transportOutputMutex(other.transportOutputMutex) {
60 other.transport =
nullptr;
64 if (replied.exchange(
true)) {
65 Logger::error(
"Replied twice to message {0}({1})", method,
id);
66 assert(
false &&
"must reply to each call only once!");
69 assert(transport &&
"expected valid transport to reply to");
71 std::lock_guard<std::mutex> transportLock(transportOutputMutex);
73 Logger::info(
"--> reply:{0}({1})", method,
id);
74 transport->reply(std::move(
id), std::move(reply));
76 llvm::Error error = reply.takeError();
77 Logger::info(
"--> reply:{0}({1}): {2}", method,
id, error);
78 transport->reply(std::move(
id), std::move(error));
86 bool MessageHandler::onNotify(llvm::StringRef method, llvm::json::Value value) {
94 auto it = notificationHandlers.find(
method);
95 if (it != notificationHandlers.end())
96 it->second(std::move(value));
102 llvm::json::Value
id) {
105 Reply reply(
id,
method, transport, transportOutputMutex);
107 auto it = methodHandlers.find(
method);
108 if (it != methodHandlers.end()) {
109 it->second(std::move(params), std::move(reply));
111 reply(llvm::make_error<LSPError>(
"method not found: " +
method.str(),
121 ResponseHandlerTy responseHandler;
123 std::lock_guard<std::mutex> responseHandlersLock(responseHandlersMutex);
125 if (it != responseHandlers.end()) {
126 responseHandler = std::move(it->second);
127 responseHandlers.erase(it);
132 if (responseHandler.second) {
133 Logger::info(
"--> reply:{0}({1})", responseHandler.first,
id);
134 responseHandler.second(std::move(
id), std::move(result));
137 "received a reply with ID {0}, but there was no such outgoing request",
140 llvm::consumeError(result.takeError());
153 auto handlerFn = [&](
const LSPError &lspError) -> llvm::Error {
154 message = lspError.message;
155 code = lspError.code;
156 return llvm::Error::success();
158 if (llvm::Error unhandled = llvm::handleErrors(std::move(error), handlerFn))
161 return llvm::json::Object{
162 {
"message", std::move(message)},
163 {
"code", int64_t(code)},
169 StringRef msg = o.getString(
"message").value_or(
"Unspecified error");
170 if (std::optional<int64_t> code = o.getInteger(
"code"))
171 return llvm::make_error<LSPError>(msg.str(),
ErrorCode(*code));
172 return llvm::make_error<llvm::StringError>(llvm::inconvertibleErrorCode(),
177 sendMessage(llvm::json::Object{
180 {
"params", std::move(params)},
184 llvm::json::Value
id) {
185 sendMessage(llvm::json::Object{
187 {
"id", std::move(
id)},
189 {
"params", std::move(params)},
195 return sendMessage(llvm::json::Object{
197 {
"id", std::move(
id)},
198 {
"result", std::move(*result)},
202 sendMessage(llvm::json::Object{
204 {
"id", std::move(
id)},
211 while (!in->isEndOfInput()) {
212 if (in->hasError()) {
213 return llvm::errorCodeToError(
214 std::error_code(errno, std::system_category()));
217 if (succeeded(in->readMessage(json))) {
219 if (!handleMessage(std::move(*doc), handler))
220 return llvm::Error::success();
226 return llvm::errorCodeToError(std::make_error_code(std::errc::io_error));
229 void JSONTransport::sendMessage(llvm::json::Value msg) {
230 outputBuffer.clear();
231 llvm::raw_svector_ostream os(outputBuffer);
232 os << llvm::formatv(prettyOutput ?
"{0:2}\n" :
"{0}", msg);
233 out <<
"Content-Length: " << outputBuffer.size() <<
"\r\n\r\n"
239 bool JSONTransport::handleMessage(llvm::json::Value msg,
242 llvm::json::Object *
object = msg.getAsObject();
244 object->getString(
"jsonrpc") != std::optional<StringRef>(
"2.0"))
248 std::optional<llvm::json::Value> id;
249 if (llvm::json::Value *i = object->get(
"id"))
251 std::optional<StringRef> method =
object->getString(
"method");
257 if (
auto *err = object->getObject(
"error"))
260 llvm::json::Value result =
nullptr;
261 if (llvm::json::Value *r = object->get(
"result"))
262 result = std::move(*r);
263 return handler.
onReply(std::move(*
id), std::move(result));
267 llvm::json::Value params =
nullptr;
268 if (llvm::json::Value *p = object->get(
"params"))
269 params = std::move(*p);
272 return handler.
onCall(*method, std::move(params), std::move(*
id));
273 return handler.
onNotify(*method, std::move(params));
281 static constexpr
int bufSize = 128;
285 out.resize_for_overwrite(size + bufSize);
286 if (!std::fgets(&out[size], bufSize, in))
293 size_t read = std::strlen(&out[size]);
294 if (read > 0 && out[size + read - 1] ==
'\n') {
295 out.resize(size + read);
309 unsigned long long contentLength = 0;
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);
356 while (succeeded(
readLine(in, line))) {
357 StringRef lineRef = line.str().trim();
358 if (lineRef.starts_with(
"//")) {
368 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)