14#include "llvm/ADT/SmallString.h"
15#include "llvm/Support/Error.h"
17#include <system_error>
23llvm::json::Object encodeError(llvm::Error
E) {
28 if (llvm::Error Unhandled = llvm::handleErrors(
30 [&](
const CancelledError &
C) -> llvm::Error {
32 case static_cast<int>(ErrorCode::ContentModified):
33 Code = ErrorCode::ContentModified;
34 Message =
"Request cancelled because the document was modified";
37 Code = ErrorCode::RequestCancelled;
38 Message =
"Request cancelled";
41 return llvm::Error::success();
43 [&](
const LSPError &L) -> llvm::Error {
46 return llvm::Error::success();
48 Message = llvm::toString(std::move(Unhandled));
50 return llvm::json::Object{
51 {
"message", std::move(Message)},
52 {
"code", int64_t(
Code)},
56llvm::Error decodeError(
const llvm::json::Object &O) {
57 llvm::StringRef Msg = O.getString(
"message").value_or(
"Unspecified error");
58 if (
auto Code = O.getInteger(
"code"))
59 return llvm::make_error<LSPError>(Msg.str(),
ErrorCode(*
Code));
60 return error(Msg.str());
63class JSONTransport :
public Transport {
65 JSONTransport(std::FILE *In, llvm::raw_ostream &Out,
67 : In(In),
Out(
Out), InMirror(InMirror ? *InMirror :
llvm::nulls()),
68 Pretty(Pretty), Style(Style) {}
70 void notify(llvm::StringRef
Method, llvm::json::Value Params)
override {
71 sendMessage(llvm::json::Object{
74 {
"params", std::move(Params)},
77 void call(llvm::StringRef
Method, llvm::json::Value Params,
78 llvm::json::Value
ID)
override {
79 sendMessage(llvm::json::Object{
81 {
"id", std::move(
ID)},
83 {
"params", std::move(Params)},
86 void reply(llvm::json::Value
ID,
87 llvm::Expected<llvm::json::Value> Result)
override {
89 sendMessage(llvm::json::Object{
91 {
"id", std::move(
ID)},
92 {
"result", std::move(*Result)},
95 sendMessage(llvm::json::Object{
97 {
"id", std::move(
ID)},
98 {
"error", encodeError(Result.takeError())},
103 llvm::Error loop(MessageHandler &Handler)
override {
107 return error(std::make_error_code(std::errc::operation_canceled),
108 "Got signal, shutting down");
110 return llvm::errorCodeToError(
111 std::error_code(errno, std::system_category()));
112 if (readRawMessage(JSON)) {
113 ThreadCrashReporter ScopedReporter([&JSON]() {
114 auto &
OS = llvm::errs();
115 OS <<
"Signalled while processing message:\n";
118 if (
auto Doc = llvm::json::parse(JSON)) {
119 vlog(Pretty ?
"<<< {0:2}\n" :
"<<< {0}\n", *Doc);
120 if (!handleMessage(std::move(*Doc), Handler))
121 return llvm::Error::success();
124 vlog(
"<<< {0}\n", JSON);
125 elog(
"JSON parse error: {0}", llvm::toString(Doc.takeError()));
129 return llvm::errorCodeToError(std::make_error_code(std::errc::io_error));
134 bool handleMessage(llvm::json::Value Message, MessageHandler &Handler);
136 void sendMessage(llvm::json::Value Message) {
137 OutputBuffer.clear();
138 llvm::raw_svector_ostream
OS(OutputBuffer);
139 OS << llvm::formatv(Pretty ?
"{0:2}" :
"{0}", Message);
140 Out <<
"Content-Length: " << OutputBuffer.size() <<
"\r\n\r\n"
143 vlog(
">>> {0}\n", OutputBuffer);
147 bool readRawMessage(std::string &JSON) {
149 : readStandardMessage(JSON);
151 bool readDelimitedMessage(std::string &JSON);
152 bool readStandardMessage(std::string &JSON);
154 llvm::SmallVector<char, 0> OutputBuffer;
156 llvm::raw_ostream &
Out;
157 llvm::raw_ostream &InMirror;
162bool JSONTransport::handleMessage(llvm::json::Value Message,
163 MessageHandler &Handler) {
167 Object->getString(
"jsonrpc") != std::optional<llvm::StringRef>(
"2.0")) {
168 elog(
"Not a JSON-RPC 2.0 message: {0:2}", Message);
172 std::optional<llvm::json::Value>
ID;
173 if (
auto *I =
Object->get(
"id"))
178 elog(
"No method and no response ID: {0:2}", Message);
181 if (
auto *Err =
Object->getObject(
"error"))
182 return Handler.onReply(std::move(*
ID), decodeError(*Err));
184 llvm::json::Value Result =
nullptr;
185 if (
auto *R =
Object->get(
"result"))
186 Result = std::move(*R);
187 return Handler.onReply(std::move(*
ID), std::move(Result));
190 llvm::json::Value Params =
nullptr;
191 if (
auto *P =
Object->get(
"params"))
192 Params = std::move(*P);
195 return Handler.onCall(*
Method, std::move(Params), std::move(*
ID));
196 return Handler.onNotify(*
Method, std::move(Params));
204 static constexpr int BufSize = 128;
208 Out.resize_for_overwrite(Size + BufSize);
211 nullptr, [&] {
return std::fgets(&
Out[Size], BufSize, In); }))
216 size_t Read = std::strlen(&
Out[Size]);
228bool JSONTransport::readStandardMessage(std::string &JSON) {
231 unsigned long long ContentLength = 0;
232 llvm::SmallString<128>
Line;
234 if (feof(In) || ferror(In) || !readLine(In, Line))
238 llvm::StringRef LineRef =
Line;
243 if (LineRef.startswith(
"#"))
247 if (LineRef.consume_front(
"Content-Length: ")) {
248 if (ContentLength != 0) {
249 elog(
"Warning: Duplicate Content-Length header received. "
250 "The previous value for this message ({0}) was ignored.",
253 llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
259 if (LineRef.trim().empty())
266 if (ContentLength > 1 << 30) {
267 elog(
"Refusing to read message with long Content-Length: {0}. "
268 "Expect protocol errors",
272 if (ContentLength == 0) {
273 log(
"Warning: Missing Content-Length header, or zero-length message.");
277 JSON.resize(ContentLength);
281 return std::fread(&JSON[
Pos], 1, ContentLength -
Pos, In);
284 elog(
"Input was aborted. Read only {0} bytes of expected {1}.",
Pos,
288 InMirror << llvm::StringRef(&JSON[
Pos],
Read);
301bool JSONTransport::readDelimitedMessage(std::string &JSON) {
303 llvm::SmallString<128>
Line;
304 while (readLine(In, Line)) {
306 auto LineRef =
Line.str().trim();
307 if (LineRef.startswith(
"#"))
311 if (LineRef.rtrim() ==
"---")
320 elog(
"Input error while reading message!");
329 llvm::raw_ostream &
Out,
330 llvm::raw_ostream *InMirror,
333 return std::make_unique<JSONTransport>(In,
Out, InMirror, Pretty, Style);
CompiledFragmentImpl & Out
llvm::raw_string_ostream OS
Ret retryAfterSignalUnlessShutdown(const std::enable_if_t< true, Ret > &Fail, const Fun &F)
Retry an operation if it gets interrupted by a signal.
void vlog(const char *Fmt, Ts &&... Vals)
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
void log(const char *Fmt, Ts &&... Vals)
std::unique_ptr< Transport > newJSONTransport(std::FILE *In, llvm::raw_ostream &Out, llvm::raw_ostream *InMirror, bool Pretty, JSONStreamStyle Style)
bool shutdownRequested()
Checks whether requestShutdown() was called.
void elog(const char *Fmt, Ts &&... Vals)
constexpr llvm::StringLiteral Message
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.