Revision control

++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant
++
++ #include "qlanguageserverbase_p_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ Q_LOGGING_CATEGORY(lspLog, "qt.languageserver.protocol");
++
++ namespace QLspSpecification {
++
++ ProtocolBase::ProtocolBase(std::unique_ptr<ProtocolBasePrivate> &&priv) : d_ptr(std::move(priv))
++ {
++ Q_D(ProtocolBase);
++ d->typedRpc.setTransport(&d->transport);
++ registerMethods(&d->typedRpc);
++ }
++
++ ProtocolBase::~ProtocolBase() = default;
++
++ void ProtocolBase::registerMethods(QJsonRpc::TypedRpc *typedRpc)
++ {
++ auto defaultHandler = new QJsonRpc::TypedHandler(
++ QByteArray(),
++ [this, typedRpc](const QJsonRpcProtocol::Request &req,
++ const QJsonRpcProtocol::ResponseHandler &handler) {
++ QJsonRpc::IdType id(req.id);
++ QByteArray method = req.method.toUtf8();
++ QJsonRpc::TypedResponse response(id, typedRpc, handler);
++ handleUndispatchedRequest(id, method, std::move(response));
++ },
++ [this](const QJsonRpcProtocol::Notification &notif) {
++ QByteArray method = notif.method.toUtf8();
++ handleUndispatchedNotification(method);
++ });
++ typedRpc->setDefaultMessageHandler(defaultHandler); // typedRpc gets ownership
++ typedRpc->setInvalidResponseHandler([this](const QJsonRpcProtocol::Response &response) {
++ handleResponseError(ResponseError { response.errorCode.toInt(),
++ response.errorMessage.toUtf8(), response.data });
++ });
++ }
++
++ void ProtocolBase::defaultUndispatchedRequestHandler(const QJsonRpc::IdType &id,
++ const QByteArray &method,
++ QJsonRpc::TypedResponse &&response)
++ {
++ Q_UNUSED(id);
++ QByteArray msg;
++ QByteArray cppBaseName = requestMethodToBaseCppName(method);
++ if (cppBaseName.isEmpty()) {
++ msg.append("Ignoring unknown request with method ");
++ msg.append(method);
++ } else {
++ msg.append("There was no handler registered with register");
++ msg.append(cppBaseName);
++ msg.append("Handler to handle a requests with method ");
++ msg.append(method);
++ }
++ response.sendErrorResponse(int(QJsonRpcProtocol::ErrorCode::MethodNotFound), msg);
++ qCWarning(lspLog) << QString::fromUtf8(msg);
++ }
++
++ void ProtocolBase::defaultUndispatchedNotificationHandler(const QByteArray &method)
++ {
++ QByteArray msg;
++ QByteArray cppBaseName = notificationMethodToBaseCppName(method);
++ if (cppBaseName.isEmpty()) {
++ msg.append("Unknown notification with method ");
++ msg.append(method);
++ } else {
++ msg.append("There was no handler registered with register");
++ msg.append(cppBaseName);
++ msg.append("NotificationHandler to handle the \"");
++ msg.append(method);
++ msg.append("\" notification");
++ }
++ if (method.startsWith("$"))
++ qCDebug(lspLog) << QString::fromUtf8(msg);
++ else
++ qCWarning(lspLog) << QString::fromUtf8(msg);
++ }
++
++ void ProtocolBase::defaultResponseErrorHandler(const QLspSpecification::ResponseError &err)
++ {
++ qCWarning(lspLog) << u"ERROR" << err.code << u":" << QString::fromUtf8(err.message)
++ << ((!err.data) ? QString()
++ : (err.data->isObject())
++ ? QString::fromUtf8(QJsonDocument(err.data->toObject()).toJson())
++ : (err.data->isArray())
++ ? QString::fromUtf8(QJsonDocument(err.data->toArray()).toJson())
++ : (err.data->isDouble()) ? QString::number(err.data->toDouble())
++ : (err.data->isString()) ? err.data->toString()
++ : (err.data->isNull()) ? u"null"_s
++ : QString());
++ }
++
++ void ProtocolBase::registerResponseErrorHandler(const ResponseErrorHandler &handler)
++ {
++ Q_D(ProtocolBase);
++ Q_ASSERT(!d->errorHandler || !handler);
++ d->errorHandler = handler;
++ }
++
++ void ProtocolBase::handleUndispatchedRequest(const QJsonRpc::IdType &id, const QByteArray &method,
++ QJsonRpc::TypedResponse &&response)
++ {
++ defaultUndispatchedRequestHandler(id, method, std::move(response));
++ }
++
++ void ProtocolBase::handleUndispatchedNotification(const QByteArray &method)
++ {
++ defaultUndispatchedNotificationHandler(method);
++ }
++
++ void ProtocolBase::handleResponseError(const ResponseError &err)
++ {
++ Q_D(ProtocolBase);
++ if (d->errorHandler)
++ d->errorHandler(err);
++ else
++ defaultResponseErrorHandler(err);
++ }
++
++ QJsonRpc::TypedRpc *ProtocolBase::typedRpc()
++ {
++ Q_D(ProtocolBase);
++ return &d->typedRpc;
++ }
++
++ QJsonRpcTransport *ProtocolBase::transport()
++ {
++ Q_D(ProtocolBase);
++ return &d->transport;
++ }
++
++ } // namespace QLspSpecification
++ QT_END_NAMESPACE