15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/Support/Error.h"
19#include "llvm/Support/JSON.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/raw_ostream.h"
22#include "gtest/gtest.h"
23#include <condition_variable>
40 std::unique_lock<std::mutex> Lock(Mu);
41 static constexpr size_t TimeoutSecs = 60;
43 [
this] {
return Value.has_value(); })) {
44 ADD_FAILURE() <<
"No result from call after " << TimeoutSecs <<
" seconds!";
45 return llvm::json::Value(
nullptr);
47 auto Res = std::move(*
Value);
53 auto ExpValue =
take();
55 ADD_FAILURE() <<
"takeValue(): " << llvm::toString(ExpValue.takeError());
56 return llvm::json::Value(
nullptr);
58 return std::move(*ExpValue);
61void LSPClient::CallResult::set(llvm::Expected<llvm::json::Value> V) {
62 std::lock_guard<std::mutex> Lock(Mu);
64 ADD_FAILURE() <<
"Multiple replies";
65 llvm::consumeError(V.takeError());
74 ADD_FAILURE() << llvm::toString(
Value->takeError());
78static void logBody(llvm::StringRef
Method, llvm::json::Value V,
bool Send) {
80 vlog(
"{0} {1}: {2:2}", Send ?
"<<<" :
">>>",
Method, V);
86 std::lock_guard<std::mutex> Lock(Mu);
87 unsigned ID = CallResults.size();
88 CallResults.emplace_back();
89 return {
ID, &CallResults.back()};
94 std::lock_guard<std::mutex> Lock(Mu);
95 Actions.push(std::move(
Action));
100 std::vector<llvm::json::Value> Result;
102 std::lock_guard<std::mutex> Lock(Mu);
103 std::swap(Result, Notifications[
Method]);
109 void reply(llvm::json::Value
ID,
110 llvm::Expected<llvm::json::Value> V)
override {
113 std::lock_guard<std::mutex> Lock(Mu);
114 if (
auto I =
ID.getAsInteger()) {
115 if (*I >= 0 && *I <
static_cast<int64_t
>(CallResults.size())) {
116 CallResults[*I].set(std::move(V));
120 ADD_FAILURE() <<
"Invalid reply to ID " <<
ID;
121 llvm::consumeError(std::move(V).takeError());
124 void notify(llvm::StringRef Method, llvm::json::Value V)
override {
125 logBody(Method, V,
false);
126 std::lock_guard<std::mutex> Lock(Mu);
127 Notifications[Method].push_back(std::move(V));
130 void call(llvm::StringRef Method, llvm::json::Value Params,
131 llvm::json::Value
ID)
override {
132 logBody(Method, Params,
false);
133 ADD_FAILURE() <<
"Unexpected server->client call " <<
Method;
136 llvm::Error loop(MessageHandler &H)
override {
137 std::unique_lock<std::mutex> Lock(Mu);
139 CV.wait(Lock, [&] {
return !Actions.empty(); });
140 if (!Actions.front())
141 return llvm::Error::success();
142 auto Action = std::move(Actions.front());
151 std::deque<CallResult> CallResults;
152 std::queue<std::function<void(Transport::MessageHandler &)>> Actions;
153 std::condition_variable CV;
154 llvm::StringMap<std::vector<llvm::json::Value>> Notifications;
161 llvm::json::Value Params) {
162 auto Slot = T->addCallSlot();
166 H.onCall(
Method, std::move(Params),
ID);
175 H.onNotify(
Method, std::move(Params));
179std::vector<llvm::json::Value>
181 return T->takeNotifications(
Method);
188using Obj = llvm::json::Object;
192 if (!llvm::sys::path::is_absolute(
Path))
202 "textDocument/didOpen",
204 Obj{{
"uri",
uri(
Path)}, {
"text", Content}, {
"languageId",
"cpp"}}}});
207 notify(
"textDocument/didChange",
209 {
"contentChanges", llvm::json::Array{
Obj{{
"text", Content}}}}});
217std::optional<std::vector<llvm::json::Value>>
221 for (
const auto &
Notification : llvm::reverse(Notifications)) {
222 if (
const auto *PubDiagsParams =
Notification.getAsObject()) {
223 auto U = PubDiagsParams->getString(
"uri");
224 auto *D = PubDiagsParams->getArray(
"diagnostics");
226 ADD_FAILURE() <<
"Bad PublishDiagnosticsParams: " << PubDiagsParams;
230 return std::vector<llvm::json::Value>(D->begin(), D->end());
llvm::Expected< llvm::json::Value > take()
llvm::json::Value takeValue()
std::vector< llvm::json::Value > takeNotifications(llvm::StringRef Method)
void enqueue(std::function< void(MessageHandler &)> Action)
std::pair< llvm::json::Value, CallResult * > addCallSlot()
CallResult & call(llvm::StringRef Method, llvm::json::Value Params)
std::vector< llvm::json::Value > takeNotifications(llvm::StringRef Method)
static llvm::json::Value uri(llvm::StringRef Path)
static llvm::json::Value documentID(llvm::StringRef Path)
void didClose(llvm::StringRef Path)
void notify(llvm::StringRef Method, llvm::json::Value Params)
void didOpen(llvm::StringRef Path, llvm::StringRef Content)
void didChange(llvm::StringRef Path, llvm::StringRef Content)
std::optional< std::vector< llvm::json::Value > > diagnostics(llvm::StringRef Path)
A threadsafe flag that is initially clear.
std::string Path
A typedef to represent a file path.
void vlog(const char *Fmt, Ts &&... Vals)
static void logBody(llvm::StringRef Method, llvm::json::Value V, bool Send)
std::string testPath(PathRef File, llvm::sys::path::Style Style)
llvm::json::Value toJSON(const FuzzyFindRequest &Request)
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Deadline timeoutSeconds(std::optional< double > Seconds)
Makes a deadline from a timeout in seconds. std::nullopt means wait forever.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.