aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qmlls/qlanguageserver.cpp31
-rw-r--r--src/qmlls/qlanguageserver_p.h1
-rw-r--r--src/qmlls/qlanguageserver_p_p.h1
-rw-r--r--tests/auto/qmlls/CMakeLists.txt1
-rw-r--r--tests/auto/qmlls/qqmllanguageserver/CMakeLists.txt18
-rw-r--r--tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.cpp67
-rw-r--r--tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.h20
7 files changed, 110 insertions, 29 deletions
diff --git a/src/qmlls/qlanguageserver.cpp b/src/qmlls/qlanguageserver.cpp
index e6812e6f3b..6525044b80 100644
--- a/src/qmlls/qlanguageserver.cpp
+++ b/src/qmlls/qlanguageserver.cpp
@@ -109,13 +109,9 @@ void QLanguageServer::registerMethods(QJsonRpc::TypedRpc &typedRpc)
}
}
}
- if (!sendErrorResponse) {
- if (id.isString() || id.isDouble()) {
- QMutexLocker l(&d->mutex);
- d->requestsInProgress.insert(id, QRequestInProgress {});
- }
+ if (!sendErrorResponse)
return QJsonRpcProtocol::Processing::Continue;
- }
+
if (rState == RunStatus::NotInitialized)
responder(QJsonRpcProtocol::MessageHandler::error(
int(QLspSpecification::ErrorCodes::ServerNotInitialized),
@@ -129,21 +125,6 @@ void QLanguageServer::registerMethods(QJsonRpc::TypedRpc &typedRpc)
int(rState))));
return QJsonRpcProtocol::Processing::Stop;
});
- typedRpc.installOnCloseAction([this](QJsonRpc::TypedResponse::Status,
- const QJsonRpc::IdType &id, QJsonRpc::TypedRpc &) {
- Q_D(QLanguageServer);
- QJsonValue idValue = QTypedJson::toJsonValue(id);
- bool lastReq;
- {
- QMutexLocker l(&d->mutex);
- d->requestsInProgress.remove(idValue);
- lastReq = d->runStatus == RunStatus::WaitPending && d->requestsInProgress.size() <= 1;
- if (lastReq)
- d->runStatus = RunStatus::Stopping;
- }
- if (lastReq)
- executeShutdown();
- });
}
const QLspSpecification::InitializeParams &QLanguageServer::clientInfo() const
@@ -207,12 +188,8 @@ void QLanguageServer::registerHandlers(QLanguageServerProtocol *protocol)
rStatus = d->runStatus;
if (rStatus == RunStatus::Initialized) {
d->shutdownResponse = std::move(response);
- if (d->requestsInProgress.size() <= 1) {
- d->runStatus = RunStatus::Stopping;
- shouldExecuteShutdown = true;
- } else {
- d->runStatus = RunStatus::WaitPending;
- }
+ d->runStatus = RunStatus::Stopping;
+ shouldExecuteShutdown = true;
}
}
if (rStatus != RunStatus::Initialized)
diff --git a/src/qmlls/qlanguageserver_p.h b/src/qmlls/qlanguageserver_p.h
index 2e50506927..48a48f61e6 100644
--- a/src/qmlls/qlanguageserver_p.h
+++ b/src/qmlls/qlanguageserver_p.h
@@ -44,7 +44,6 @@ public:
enum class RunStatus {
NotInitialized,
Initialized, // normal state of execution
- WaitPending,
Stopping,
WaitingForExit,
Stopped
diff --git a/src/qmlls/qlanguageserver_p_p.h b/src/qmlls/qlanguageserver_p_p.h
index 55a312ecf0..55c61e8889 100644
--- a/src/qmlls/qlanguageserver_p_p.h
+++ b/src/qmlls/qlanguageserver_p_p.h
@@ -47,7 +47,6 @@ public:
mutable QMutex mutex;
// mutex gated, monotonically increasing
QLanguageServer::RunStatus runStatus = QLanguageServer::RunStatus::NotInitialized;
- QHash<QJsonValue, QRequestInProgress> requestsInProgress; // mutex gated
QLspSpecification::InitializeParams clientInfo; // immutable after runStatus > Initialized
QLspSpecification::InitializeResult serverInfo; // immutable after runStatus > Initialized
QLspSpecification::Responses::ShutdownResponseType shutdownResponse;
diff --git a/tests/auto/qmlls/CMakeLists.txt b/tests/auto/qmlls/CMakeLists.txt
index daf7d64cd4..92e70aae0c 100644
--- a/tests/auto/qmlls/CMakeLists.txt
+++ b/tests/auto/qmlls/CMakeLists.txt
@@ -8,5 +8,6 @@ if (TARGET Qt::QmlLSPrivate)
add_subdirectory(qmlls)
add_subdirectory(modules)
add_subdirectory(cli)
+ add_subdirectory(qqmllanguageserver)
endif()
diff --git a/tests/auto/qmlls/qqmllanguageserver/CMakeLists.txt b/tests/auto/qmlls/qqmllanguageserver/CMakeLists.txt
new file mode 100644
index 0000000000..7aecc9005c
--- /dev/null
+++ b/tests/auto/qmlls/qqmllanguageserver/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2026 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qqmllanguageserver LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qqmllanguageserver
+ SOURCES
+ tst_qqmllanguageserver.cpp tst_qqmllanguageserver.h
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::LanguageServerPrivate
+ Qt::Test
+ Qt::QmlLSPrivate
+)
diff --git a/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.cpp b/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.cpp
new file mode 100644
index 0000000000..0847a57ddb
--- /dev/null
+++ b/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <private/qlanguageserver_p.h>
+#include <private/qqmllanguageserver_p.h>
+#include <QtTest/qtest.h>
+
+#include "tst_qqmllanguageserver.h"
+
+using namespace Qt::StringLiterals;
+using namespace QLspSpecification;
+using namespace QmlLsp;
+
+tst_qqmllanguageserver::tst_qqmllanguageserver() { }
+
+struct ClientAndServer
+{
+ std::unique_ptr<QLanguageServerProtocol> client;
+ std::unique_ptr<QQmlLanguageServer> server;
+
+ ClientAndServer()
+ {
+ client = std::make_unique<QLanguageServerProtocol>(
+ [this](const QByteArray &data) { server->receiveData(data, true); });
+ server = std::make_unique<QQmlLanguageServer>(
+ [this](const QByteArray &data) { client->receiveData(data); });
+ }
+
+ static ClientAndServer createAndInitialize()
+ {
+ ClientAndServer result;
+
+ bool initializedOk = false;
+ InitializeParams initializeParams;
+ initializeParams.capabilities.window.emplace().workDoneProgress = true;
+ result.client->requestInitialize(
+ initializeParams,
+ [&initializedOk](const InitializeResult &) { initializedOk = true; });
+ [&initializedOk] { QTRY_VERIFY_WITH_TIMEOUT(initializedOk, 3000); }();
+ result.client->notifyInitialized({ });
+
+ return result;
+ }
+};
+
+void tst_qqmllanguageserver::noFreezeAfterRequestToClient()
+{
+ auto [client, server] = ClientAndServer::createAndInitialize();
+
+ client->registerWorkspaceSemanticTokensRefreshRequestHandler(
+ [](const QByteArray, const std::nullptr_t &, auto &&response) {
+ response.sendResponse({ });
+ });
+
+ bool ok = false;
+ server->protocol()->requestWorkspaceSemanticTokensRefresh({ }, [&ok]() { ok = true; });
+ QTRY_VERIFY_WITH_TIMEOUT(ok, 5000);
+
+ ok = false;
+ client->requestShutdown({ }, [&ok, &c = client]() {
+ c->notifyExit({ });
+ ok = true;
+ });
+ QTRY_VERIFY_WITH_TIMEOUT(ok, 5000);
+}
+
+QTEST_MAIN(tst_qqmllanguageserver)
diff --git a/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.h b/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.h
new file mode 100644
index 0000000000..b555b3d77c
--- /dev/null
+++ b/tests/auto/qmlls/qqmllanguageserver/tst_qqmllanguageserver.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2026 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TST_QQMLLANGUAGESERVER_H
+#define TST_QQMLLANGUAGESERVER_H
+
+#include <QtCore/qobject.h>
+#include <QtTest/qtest.h>
+
+class tst_qqmllanguageserver : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qqmllanguageserver();
+
+private slots:
+ void noFreezeAfterRequestToClient();
+};
+
+#endif // TST_QQMLLANGUAGESERVER_H