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(llvm::errnoAsErrorCode());
111 if (readRawMessage(JSON)) {
112 ThreadCrashReporter ScopedReporter([&JSON]() {
113 auto &
OS = llvm::errs();
114 OS <<
"Signalled while processing message:\n";
117 if (
auto Doc = llvm::json::parse(JSON)) {
118 vlog(Pretty ?
"<<< {0:2}\n" :
"<<< {0}\n", *Doc);
119 if (!handleMessage(std::move(*Doc), Handler))
120 return llvm::Error::success();
123 vlog(
"<<< {0}\n", JSON);
124 elog(
"JSON parse error: {0}", llvm::toString(Doc.takeError()));
128 return llvm::errorCodeToError(std::make_error_code(std::errc::io_error));
133 bool handleMessage(llvm::json::Value Message, MessageHandler &Handler);
135 void sendMessage(llvm::json::Value Message) {
136 OutputBuffer.clear();
137 llvm::raw_svector_ostream
OS(OutputBuffer);
138 OS << llvm::formatv(Pretty ?
"{0:2}" :
"{0}", Message);
139 Out <<
"Content-Length: " << OutputBuffer.size() <<
"\r\n\r\n"
142 vlog(
">>> {0}\n", OutputBuffer);
146 bool readRawMessage(std::string &JSON) {
148 : readStandardMessage(JSON);
150 bool readDelimitedMessage(std::string &JSON);
151 bool readStandardMessage(std::string &JSON);
153 llvm::SmallVector<char, 0> OutputBuffer;
155 llvm::raw_ostream &
Out;
156 llvm::raw_ostream &InMirror;
161bool JSONTransport::handleMessage(llvm::json::Value Message,
162 MessageHandler &Handler) {
166 Object->getString(
"jsonrpc") != std::optional<llvm::StringRef>(
"2.0")) {
167 elog(
"Not a JSON-RPC 2.0 message: {0:2}", Message);
171 std::optional<llvm::json::Value>
ID;
172 if (
auto *I =
Object->get(
"id"))
177 elog(
"No method and no response ID: {0:2}", Message);
180 if (
auto *Err =
Object->getObject(
"error"))
181 return Handler.onReply(std::move(*
ID), decodeError(*Err));
183 llvm::json::Value Result =
nullptr;
184 if (
auto *R =
Object->get(
"result"))
185 Result = std::move(*R);
186 return Handler.onReply(std::move(*
ID), std::move(Result));
189 llvm::json::Value Params =
nullptr;
190 if (
auto *P =
Object->get(
"params"))
191 Params = std::move(*P);
194 return Handler.onCall(*
Method, std::move(Params), std::move(*
ID));
195 return Handler.onNotify(*
Method, std::move(Params));
203 static constexpr int BufSize = 128;
207 Out.resize_for_overwrite(Size + BufSize);
210 nullptr, [&] {
return std::fgets(&
Out[Size], BufSize, In); }))
215 size_t Read = std::strlen(&
Out[Size]);
227bool JSONTransport::readStandardMessage(std::string &JSON) {
230 unsigned long long ContentLength = 0;
231 llvm::SmallString<128>
Line;
233 if (feof(In) || ferror(In) || !readLine(In, Line))
237 llvm::StringRef LineRef =
Line;
242 if (LineRef.starts_with(
"#"))
246 if (LineRef.consume_front(
"Content-Length: ")) {
247 if (ContentLength != 0) {
248 elog(
"Warning: Duplicate Content-Length header received. "
249 "The previous value for this message ({0}) was ignored.",
252 llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
258 if (LineRef.trim().empty())
265 if (ContentLength > 1 << 30) {
266 elog(
"Refusing to read message with long Content-Length: {0}. "
267 "Expect protocol errors",
271 if (ContentLength == 0) {
272 log(
"Warning: Missing Content-Length header, or zero-length message.");
276 JSON.resize(ContentLength);
280 return std::fread(&JSON[
Pos], 1, ContentLength -
Pos, In);
283 elog(
"Input was aborted. Read only {0} bytes of expected {1}.",
Pos,
287 InMirror << llvm::StringRef(&JSON[
Pos],
Read);
300bool JSONTransport::readDelimitedMessage(std::string &JSON) {
302 llvm::SmallString<128>
Line;
303 while (readLine(In, Line)) {
305 auto LineRef =
Line.str().trim();
306 if (LineRef.starts_with(
"#"))
310 if (LineRef.rtrim() ==
"---")
319 elog(
"Input error while reading message!");
328 llvm::raw_ostream &
Out,
329 llvm::raw_ostream *InMirror,
332 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.