mirror of
https://github.com/MaskRay/ccls.git
synced 2025-04-14 21:02:14 +00:00
Better error reporting in ResponseMessage. Fix #317
This commit is contained in:
parent
8eff5e2e4f
commit
90c2a54bbc
@ -238,33 +238,30 @@ void LaunchStdinLoop(Config* config,
|
|||||||
WorkThread::StartThread("stdin", [request_times]() {
|
WorkThread::StartThread("stdin", [request_times]() {
|
||||||
auto* queue = QueueManager::instance();
|
auto* queue = QueueManager::instance();
|
||||||
while (true) {
|
while (true) {
|
||||||
std::variant<std::string, std::unique_ptr<BaseIpcMessage>> err_or_message =
|
std::unique_ptr<BaseIpcMessage> message;
|
||||||
|
optional<std::string> err =
|
||||||
MessageRegistry::instance()->ReadMessageFromStdin(
|
MessageRegistry::instance()->ReadMessageFromStdin(
|
||||||
g_log_stdin_stdout_to_stderr);
|
g_log_stdin_stdout_to_stderr, &message);
|
||||||
|
|
||||||
// Message parsing can fail if we don't recognize the method.
|
// Message parsing can fail if we don't recognize the method.
|
||||||
auto* err = std::get_if<std::string>(&err_or_message);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
// FIXME LanguageClient-neovim will error without the check, probably
|
// The message may be partially deserialized.
|
||||||
// because we do not support didChangeConfiguration and do not fill in
|
// Emit an error ResponseMessage if |id| is available.
|
||||||
// the |id| field.
|
if (message) {
|
||||||
if (err->find("workspace/didChangeConfiguration") ==
|
|
||||||
std::string::npos) {
|
|
||||||
Out_Error out;
|
Out_Error out;
|
||||||
// TODO We cannot fill in out.id because RequestMessage.id is not a base
|
out.id = message->GetRequestId();
|
||||||
// field.
|
if (!std::holds_alternative<std::monostate>(out.id)) {
|
||||||
out.error.code = lsErrorCodes::InvalidParams;
|
out.error.code = lsErrorCodes::InvalidParams;
|
||||||
out.error.message = std::move(*err);
|
out.error.message = std::move(*err);
|
||||||
queue->WriteStdout(IpcId::Unknown, out);
|
queue->WriteStdout(IpcId::Unknown, out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache |method_id| so we can access it after moving |message|.
|
// Cache |method_id| so we can access it after moving |message|.
|
||||||
auto& message = std::get<std::unique_ptr<BaseIpcMessage>>(err_or_message);
|
|
||||||
IpcId method_id = message->method_id;
|
IpcId method_id = message->method_id;
|
||||||
|
(*request_times)[method_id] = Timer();
|
||||||
(*request_times)[message->method_id] = Timer();
|
|
||||||
|
|
||||||
switch (method_id) {
|
switch (method_id) {
|
||||||
case IpcId::Initialized: {
|
case IpcId::Initialized: {
|
||||||
|
@ -113,8 +113,9 @@ optional<char> ReadCharFromStdinBlocking() {
|
|||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::variant<std::string, std::unique_ptr<BaseIpcMessage>>
|
optional<std::string> MessageRegistry::ReadMessageFromStdin(
|
||||||
MessageRegistry::ReadMessageFromStdin(bool log_stdin_to_stderr) {
|
bool log_stdin_to_stderr,
|
||||||
|
std::unique_ptr<BaseIpcMessage>* message) {
|
||||||
optional<std::string> content =
|
optional<std::string> content =
|
||||||
ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
|
ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@ -135,11 +136,12 @@ MessageRegistry::ReadMessageFromStdin(bool log_stdin_to_stderr) {
|
|||||||
assert(!document.HasParseError());
|
assert(!document.HasParseError());
|
||||||
|
|
||||||
JsonReader json_reader{&document};
|
JsonReader json_reader{&document};
|
||||||
return Parse(json_reader);
|
return Parse(json_reader, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::variant<std::string, std::unique_ptr<BaseIpcMessage>>
|
optional<std::string> MessageRegistry::Parse(
|
||||||
MessageRegistry::Parse(Reader& visitor) {
|
Reader& visitor,
|
||||||
|
std::unique_ptr<BaseIpcMessage>* message) {
|
||||||
if (!visitor.HasMember("jsonrpc") ||
|
if (!visitor.HasMember("jsonrpc") ||
|
||||||
std::string(visitor["jsonrpc"]->GetString()) != "2.0") {
|
std::string(visitor["jsonrpc"]->GetString()) != "2.0") {
|
||||||
LOG_S(FATAL) << "Bad or missing jsonrpc version";
|
LOG_S(FATAL) << "Bad or missing jsonrpc version";
|
||||||
@ -155,8 +157,11 @@ std::variant<std::string, std::unique_ptr<BaseIpcMessage>>
|
|||||||
|
|
||||||
Allocator& allocator = allocators[method];
|
Allocator& allocator = allocators[method];
|
||||||
try {
|
try {
|
||||||
return allocator(visitor);
|
allocator(visitor, message);
|
||||||
|
return nullopt;
|
||||||
} catch (std::invalid_argument& e) {
|
} catch (std::invalid_argument& e) {
|
||||||
|
// *message is partially deserialized but some field (e.g. |id|) are likely
|
||||||
|
// available.
|
||||||
return std::string("Unable to deserialize request '") + method + "' " +
|
return std::string("Unable to deserialize request '") + method + "' " +
|
||||||
static_cast<JsonReader&>(visitor).GetPath() + " " + e.what();
|
static_cast<JsonReader&>(visitor).GetPath() + " " + e.what();
|
||||||
}
|
}
|
||||||
|
@ -40,24 +40,26 @@ struct MessageRegistry {
|
|||||||
static MessageRegistry* instance();
|
static MessageRegistry* instance();
|
||||||
|
|
||||||
using Allocator =
|
using Allocator =
|
||||||
std::function<std::unique_ptr<BaseIpcMessage>(Reader& visitor)>;
|
std::function<void(Reader& visitor, std::unique_ptr<BaseIpcMessage>*)>;
|
||||||
std::unordered_map<std::string, Allocator> allocators;
|
std::unordered_map<std::string, Allocator> allocators;
|
||||||
|
|
||||||
std::variant<std::string, std::unique_ptr<BaseIpcMessage>>
|
optional<std::string> ReadMessageFromStdin(
|
||||||
ReadMessageFromStdin(bool log_stdin_to_stderr);
|
bool log_stdin_to_stderr,
|
||||||
std::variant<std::string, std::unique_ptr<BaseIpcMessage>> Parse(
|
std::unique_ptr<BaseIpcMessage>* message);
|
||||||
Reader& visitor);
|
optional<std::string> Parse(Reader& visitor,
|
||||||
|
std::unique_ptr<BaseIpcMessage>* message);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct MessageRegistryRegister {
|
struct MessageRegistryRegister {
|
||||||
MessageRegistryRegister() {
|
MessageRegistryRegister() {
|
||||||
std::string method_name = IpcIdToString(T::kIpcId);
|
std::string method_name = IpcIdToString(T::kIpcId);
|
||||||
MessageRegistry::instance()->allocators[method_name] = [](Reader& visitor) {
|
MessageRegistry::instance()->allocators[method_name] =
|
||||||
auto result = MakeUnique<T>();
|
[](Reader& visitor, std::unique_ptr<BaseIpcMessage>* message) {
|
||||||
Reflect(visitor, *result);
|
*message = MakeUnique<T>();
|
||||||
return result;
|
// Reflect may throw and *message will be partially deserialized.
|
||||||
};
|
Reflect(visitor, static_cast<T&>(**message));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user