2 #include "gtest/gtest.h"
3 #include <condition_variable>
9 #include "llvm/Support/Path.h"
10 #include "llvm/Support/raw_ostream.h"
17 std::unique_lock<std::mutex> Lock(Mu);
19 [
this] {
return Value.hasValue(); })) {
20 ADD_FAILURE() <<
"No result from call after 10 seconds!";
21 return llvm::json::Value(
nullptr);
23 auto Res = std::move(*Value);
29 auto ExpValue =
take();
31 ADD_FAILURE() <<
"takeValue(): " <<
llvm::toString(ExpValue.takeError());
32 return llvm::json::Value(
nullptr);
34 return std::move(*ExpValue);
37 void LSPClient::CallResult::set(llvm::Expected<llvm::json::Value> V) {
38 std::lock_guard<std::mutex> Lock(Mu);
40 ADD_FAILURE() <<
"Multiple replies";
41 llvm::consumeError(V.takeError());
54 static void logBody(llvm::StringRef
Method, llvm::json::Value V,
bool Send) {
56 vlog(
"{0} {1}: {2:2}", Send ?
"<<<" :
">>>",
Method, V);
62 std::lock_guard<std::mutex> Lock(Mu);
63 unsigned ID = CallResults.size();
64 CallResults.emplace_back();
65 return {ID, &CallResults.back()};
70 std::lock_guard<std::mutex> Lock(Mu);
71 Actions.push(std::move(
Action));
76 std::vector<llvm::json::Value> Result;
78 std::lock_guard<std::mutex> Lock(Mu);
79 std::swap(Result, Notifications[
Method]);
85 void reply(llvm::json::Value ID,
86 llvm::Expected<llvm::json::Value> V)
override {
89 std::lock_guard<std::mutex> Lock(Mu);
90 if (
auto I = ID.getAsInteger()) {
91 if (*I >= 0 && *I < static_cast<int64_t>(CallResults.size())) {
92 CallResults[*I].set(std::move(V));
96 ADD_FAILURE() <<
"Invalid reply to ID " << ID;
97 llvm::consumeError(std::move(V).takeError());
100 void notify(llvm::StringRef
Method, llvm::json::Value V)
override {
102 std::lock_guard<std::mutex> Lock(Mu);
103 Notifications[
Method].push_back(std::move(V));
106 void call(llvm::StringRef
Method, llvm::json::Value Params,
107 llvm::json::Value ID)
override {
109 ADD_FAILURE() <<
"Unexpected server->client call " <<
Method;
113 std::unique_lock<std::mutex> Lock(Mu);
115 CV.wait(Lock, [&] {
return !Actions.empty(); });
116 if (!Actions.front())
117 return llvm::Error::success();
118 auto Action = std::move(Actions.front());
127 std::deque<CallResult> CallResults;
128 std::queue<std::function<void(Transport::MessageHandler &)>> Actions;
129 std::condition_variable CV;
130 llvm::StringMap<std::vector<llvm::json::Value>> Notifications;
137 llvm::json::Value Params) {
138 auto Slot = T->addCallSlot();
142 H.onCall(
Method, std::move(Params), ID);
151 H.onNotify(
Method, std::move(Params));
155 std::vector<llvm::json::Value>
157 return T->takeNotifications(
Method);
164 using Obj = llvm::json::Object;
168 if (!llvm::sys::path::is_absolute(
Path))
178 "textDocument/didOpen",
180 Obj{{
"uri",
uri(
Path)}, {
"text", Content}, {
"languageId",
"cpp"}}}});
183 notify(
"textDocument/didChange",
185 {
"contentChanges", llvm::json::Array{
Obj{{
"text", Content}}}}});
193 llvm::Optional<std::vector<llvm::json::Value>>
197 for (
const auto &
Notification : llvm::reverse(Notifications)) {
198 if (
const auto *PubDiagsParams =
Notification.getAsObject()) {
199 auto U = PubDiagsParams->getString(
"uri");
200 auto *D = PubDiagsParams->getArray(
"diagnostics");
202 ADD_FAILURE() <<
"Bad PublishDiagnosticsParams: " << PubDiagsParams;
206 return std::vector<llvm::json::Value>(D->begin(), D->end());