LLVM: lib/Support/LSP/Transport.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
14#include
15#include
16#include <system_error>
17#include
18
19using namespace llvm;
21
22
23
24
25
26namespace {
27
28
29
30
31class Reply {
32public:
33 Reply(const llvm::json::Value &Id, StringRef Method, JSONTransport &Transport,
34 std::mutex &TransportOutputMutex);
35 Reply(Reply &&Other);
36 Reply &operator=(Reply &&) = delete;
37 Reply(const Reply &) = delete;
38 Reply &operator=(const Reply &) = delete;
39
40 void operator()(llvm::Expectedllvm::json::Value Reply);
41
42private:
43 std::string Method;
44 std::atomic Replied = {false};
45 llvm::json::Value Id;
46 JSONTransport *Transport;
47 std::mutex &TransportOutputMutex;
48};
49}
50
52 JSONTransport &Transport, std::mutex &TransportOutputMutex)
54 TransportOutputMutex(TransportOutputMutex) {}
55
56Reply::Reply(Reply &&Other)
59 TransportOutputMutex(Other.TransportOutputMutex) {
60 Other.Transport = nullptr;
61}
62
64 if (Replied.exchange(true)) {
66 assert(false && "must reply to each call only once!");
67 return;
68 }
69 assert(Transport && "expected valid transport to reply to");
70
71 std::lock_guardstd::mutex TransportLock(TransportOutputMutex);
72 if (Reply) {
74 Transport->reply(std::move(Id), std::move(Reply));
75 } else {
78 Transport->reply(std::move(Id), std::move(Error));
79 }
80}
81
82
83
84
85
88
90 return false;
91 if (Method == "$cancel") {
92
93 } else {
94 auto It = NotificationHandlers.find(Method);
95 if (It != NotificationHandlers.end())
96 It->second(std::move(Value));
97 }
98 return true;
99}
100
104
105 Reply Reply(Id, Method, Transport, TransportOutputMutex);
106
107 auto It = MethodHandlers.find(Method);
108 if (It != MethodHandlers.end()) {
109 It->second(std::move(Params), std::move(Reply));
110 } else {
113 }
114 return true;
115}
116
119
120
121 ResponseHandlerTy ResponseHandler;
122 {
123 std::lock_guardstd::mutex responseHandlersLock(ResponseHandlersMutex);
124 auto It = ResponseHandlers.find(debugString(Id));
125 if (It != ResponseHandlers.end()) {
126 ResponseHandler = std::move(It->second);
127 ResponseHandlers.erase(It);
128 }
129 }
130
131
132 if (ResponseHandler.second) {
133 Logger::info("--> reply:{0}({1})", ResponseHandler.first, Id);
134 ResponseHandler.second(std::move(Id), std::move(Result));
135 } else {
137 "received a reply with ID {0}, but there was no such outgoing request",
138 Id);
139 if (!Result)
141 }
142 return true;
143}
144
145
146
147
148
149
151 std::string Message;
154 Message = LspError.message;
155 Code = LspError.code;
157 };
160
162 {"message", std::move(Message)},
163 {"code", int64_t(Code)},
164 };
165}
166
167
169 StringRef Msg = O.getString("message").value_or("Unspecified error");
170 if (std::optional<int64_t> Code = O.getInteger("code"))
173 Msg.str());
174}
175
178 {"jsonrpc", "2.0"},
180 {"params", std::move(Params)},
181 });
182}
186 {"jsonrpc", "2.0"},
187 {"id", std::move(Id)},
189 {"params", std::move(Params)},
190 });
191}
194 if (Result) {
196 {"jsonrpc", "2.0"},
197 {"id", std::move(Id)},
198 {"result", std::move(*Result)},
199 });
200 }
201
203 {"jsonrpc", "2.0"},
204 {"id", std::move(Id)},
205 {"error", encodeError(Result.takeError())},
206 });
207}
208
210 std::string Json;
211 while (!In->isEndOfInput()) {
212 if (In->hasError()) {
214 std::error_code(errno, std::system_category()));
215 }
216
217 if (succeeded(In->readMessage(Json))) {
219 if (!handleMessage(std::move(*Doc), Handler))
221 } else {
223 }
224 }
225 }
227}
228
232 os << llvm::formatv(PrettyOutput ? "{0:2}\n" : "{0}", Msg);
233 Out << "Content-Length: " << OutputBuffer.size() << "\r\n\r\n"
235 Out.flush();
237}
238
241
244 Object->getString("jsonrpc") != std::optional("2.0"))
245 return false;
246
247
248 std::optionalllvm::json::Value Id;
250 Id = std::move(*I);
251 std::optional Method = Object->getString("method");
252
253
255 if (!Id)
256 return false;
257 if (auto *Err = Object->getObject("error"))
259
262 Result = std::move(*R);
263 return Handler.onReply(std::move(*Id), std::move(Result));
264 }
265
266
269 Params = std::move(*P);
270
271 if (Id)
272 return Handler.onCall(*Method, std::move(Params), std::move(*Id));
274}
275
276
277
279
280
281 static constexpr int BufSize = 128;
282 size_t Size = 0;
284 for (;;) {
286 if (!std::fgets(&Out[Size], BufSize, In))
288
289 clearerr(In);
290
291
292
293 size_t Read = std::strlen(&Out[Size]);
294 if (Read > 0 && Out[Size + Read - 1] == '\n') {
297 }
299 }
300}
301
302
303
304
305LogicalResult
307
308
309 unsigned long long ContentLength = 0;
311 while (true) {
314
315
319 } else if (!LineRef.trim().empty()) {
320
321 continue;
322 } else {
323
324 break;
325 }
326 }
327
328
329 if (ContentLength == 0 || ContentLength > 1 << 30)
331
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);
335 if (Read == 0)
337
338
339
340 clearerr(In);
342 }
344}
345
346
347
348
349
350
351
354 Json.clear();
359
360 if (LineRef == "// -----")
361 break;
362 continue;
363 }
364
365 Json += Line;
366 }
367
368 return failure(ferror(In));
369}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Mark last scratch load
This file defines the SmallString class.
static llvm::json::Object encodeError(llvm::Error Error)
Encode the given error as a JSON object.
Definition Transport.cpp:150
LogicalResult readLine(std::FILE *In, SmallVectorImpl< char > &Out)
Tries to read a line up to and including .
Definition Transport.cpp:278
llvm::Error decodeError(const llvm::json::Object &O)
Decode the given JSON object into an error.
Definition Transport.cpp:168
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void resize_for_overwrite(size_type N)
Like resize, but T is POD, the new values won't be initialized.
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
An Object is a JSON object, which maps strings to heterogenous JSON values.
A Value is an JSON value of unknown type.
const json::Object * getAsObject() const
LLVM_ABI_FOR_TEST LogicalResult readStandardMessage(std::string &Json) final
Definition Transport.cpp:306
bool hasError() const final
LLVM_ABI_FOR_TEST LogicalResult readDelimitedMessage(std::string &Json) final
For lit tests we support a simplified syntax:
Definition Transport.cpp:353
A transport class that performs the JSON-RPC communication with the LSP client.
LLVM_ABI_FOR_TEST void reply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)
Definition Transport.cpp:192
LLVM_ABI_FOR_TEST llvm::Error run(MessageHandler &Handler)
Start executing the JSON-RPC transport.
Definition Transport.cpp:209
LLVM_ABI_FOR_TEST void notify(StringRef Method, llvm::json::Value Params)
The following methods are used to send a message to the LSP client.
Definition Transport.cpp:176
LLVM_ABI_FOR_TEST void call(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)
Definition Transport.cpp:183
This class models an LSP error as an llvm::Error.
static void error(const char *Fmt, Ts &&...Vals)
static void debug(const char *Fmt, Ts &&...Vals)
Initiate a log message at various severity levels.
static void info(const char *Fmt, Ts &&...Vals)
A handler used to process the incoming transport messages.
bool onNotify(StringRef Method, llvm::json::Value Value)
Definition Transport.cpp:86
bool onCall(StringRef Method, llvm::json::Value Params, llvm::json::Value Id)
Definition Transport.cpp:101
bool onReply(llvm::json::Value Id, llvm::Expected< llvm::json::Value > Result)
Definition Transport.cpp:117
A raw_ostream that writes to an SmallVector or SmallString.
LLVM_ABI llvm::Expected< Value > parse(llvm::StringRef JSON)
Parses the provided JSON source, or returns a ParseError.
This is an optimization pass for GlobalISel generic memory operations.
bool succeeded(LogicalResult Result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
bool failed(LogicalResult Result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
LogicalResult failure(bool IsFailure=true)
Utility function to generate a LogicalResult.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
static std::string debugString(T &&Op)
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI bool getAsUnsignedInteger(StringRef Str, unsigned Radix, unsigned long long &Result)
Helper functions for StringRef::getAsInteger.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
This class represents an efficient way to signal success or failure.