From 9a44e3b6ca81f0e84d774a95e45b449b5d4cb583 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 25 May 2018 16:59:42 +0200 Subject: QML Debugger: Don't crash when encoding JSON data Apparently QVariant::save cannot deal with QJsonObject and friends. Transform them into QVariants before sending them over the wire. Task-number: QTBUG-68474 Change-Id: I8fc9fade4915c2b40f8d16aea51ea6ff65247dc1 Reviewed-by: Simon Hausmann --- .../qmldbg_debugger/qqmlenginedebugservice.cpp | 63 +++++++++++++--------- .../tst_qqmlenginedebugservice.cpp | 63 +++++++++++++++++++++- 2 files changed, 99 insertions(+), 27 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index d008b86a78..17bae6d695 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -55,6 +55,11 @@ #include #include #include +#include +#include +#include +#include + #include #include #include @@ -211,34 +216,40 @@ QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const return contents; } - if (QQmlValueTypeFactory::isValueType(userType)) { - switch (userType) { - case QMetaType::QRect: - case QMetaType::QRectF: - case QMetaType::QPoint: - case QMetaType::QPointF: - case QMetaType::QSize: - case QMetaType::QSizeF: - case QMetaType::QFont: - // Don't call the toString() method on those. The stream operators are better. - return value; - default: - break; - } - - const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType); - if (mo) { - int toStringIndex = mo->indexOfMethod("toString()"); - if (toStringIndex != -1) { - QMetaMethod mm = mo->method(toStringIndex); - QString s; - if (mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) - return s; + switch (userType) { + case QMetaType::QRect: + case QMetaType::QRectF: + case QMetaType::QPoint: + case QMetaType::QPointF: + case QMetaType::QSize: + case QMetaType::QSizeF: + case QMetaType::QFont: + // Don't call the toString() method on those. The stream operators are better. + return value; + case QMetaType::QJsonValue: + return value.toJsonValue().toVariant(); + case QMetaType::QJsonObject: + return value.toJsonObject().toVariantMap(); + case QMetaType::QJsonArray: + return value.toJsonArray().toVariantList(); + case QMetaType::QJsonDocument: + return value.toJsonDocument().toVariant(); + default: + if (QQmlValueTypeFactory::isValueType(userType)) { + const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType); + if (mo) { + int toStringIndex = mo->indexOfMethod("toString()"); + if (toStringIndex != -1) { + QMetaMethod mm = mo->method(toStringIndex); + QString s; + if (mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) + return s; + } } - } - // We expect all QML value types to either have a toString() method or stream operators - return value; + // We expect all QML value types to either have a toString() method or stream operators + return value; + } } if (QQmlMetaType::isQObject(userType)) { diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index 89217e7556..417b75e760 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -53,6 +53,9 @@ #include #include #include +#include +#include +#include #define QVERIFYOBJECT(statement) \ do {\ @@ -82,6 +85,40 @@ public: QModelIndex modelIndex() { return QModelIndex(); } }; +class JsonTest : public QObject +{ + Q_OBJECT + Q_PROPERTY(QJsonObject data READ data WRITE setData NOTIFY dataChanged) + +public: + JsonTest(QObject *parent = 0) : QObject(parent) + { + m_data["foo"] = QJsonValue(12); + m_data["ttt"] = QJsonArray({4, 5, 4, 3, 2}); + m_data["a"] = QJsonValue(QJsonValue::Null); + m_data["b"] = QJsonValue(QJsonValue::Undefined); + m_data["c"] = QJsonValue("fffff"); + } + + QJsonObject data() const { return m_data; } + +signals: + void dataChanged(const QJsonObject &data); + +public slots: + void setData(const QJsonObject &data) + { + if (data != m_data) { + m_data = data; + emit dataChanged(data); + } + } + +private: + QJsonObject m_data; +}; + + class tst_QQmlEngineDebugService : public QObject { Q_OBJECT @@ -139,6 +176,7 @@ private slots: void regression_QTCREATORBUG_7451(); void queryObjectWithNonStreamableTypes(); + void jsonData(); void asynchronousCreate(); void invalidContexts(); void createObjectOnDestruction(); @@ -363,6 +401,11 @@ void tst_QQmlEngineDebugService::initTestCase() "CustomTypes {}" ; + qmlRegisterType("JsonTest", 1, 0, "JsonTest"); + qml << "import JsonTest 1.0\n" + "JsonTest {}" + ; + for (int i=0; i= 0); QCOMPARE(context.contexts[0].name, QString("tst_QQmlDebug_childContext")); } @@ -915,6 +958,24 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes() QVariant(QLatin1String("QModelIndex()"))); } +void tst_QQmlEngineDebugService::jsonData() +{ + bool success; + + QmlDebugObjectReference rootObject = findRootObject(5, true); + QVERIFY(!rootObject.className.isEmpty()); + + m_dbg->queryObject(rootObject, &success); + QVERIFY(success); + QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result()))); + + QmlDebugObjectReference obj = m_dbg->object(); + QVERIFY(!obj.className.isEmpty()); + + QCOMPARE(findProperty(obj.properties, "data").value, + QJsonDocument::fromJson("{\"a\":null,\"c\":\"fffff\",\"foo\":12,\"ttt\":[4,5,4,3,2]}") + .toVariant()); +} void tst_QQmlEngineDebugService::queryExpressionResult() { -- cgit v1.2.3