diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-05-25 16:59:42 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-05-25 15:21:32 +0000 |
commit | 9a44e3b6ca81f0e84d774a95e45b449b5d4cb583 (patch) | |
tree | e57fe07bfbfc8e64fd2f9214e9ddd5d47b3d9136 | |
parent | 71688bab1b7abf64ae840dff887aa501e83d5acc (diff) |
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 <simon.hausmann@qt.io>
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp | 63 | ||||
-rw-r--r-- | tests/auto/qml/debugger/qqmlenginedebugservice/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 <QtCore/qdebug.h> #include <QtCore/qmetaobject.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qjsonvalue.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> + #include <private/qmetaobject_p.h> #include <private/qqmldebugconnector_p.h> #include <private/qversionedpacket_p.h> @@ -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 <QtCore/qdebug.h> #include <QtCore/qthread.h> #include <QtCore/qabstractitemmodel.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> #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>("JsonTest", 1, 0, "JsonTest"); + qml << "import JsonTest 1.0\n" + "JsonTest {}" + ; + for (int i=0; i<qml.count(); i++) { QQmlComponent component(m_engine); component.setData(qml[i], QUrl::fromLocalFile("")); @@ -676,7 +719,7 @@ void tst_QQmlEngineDebugService::queryRootContexts() // root context query sends only root object data - it doesn't fill in // the children or property info QCOMPARE(context.objects.count(), 0); - QCOMPARE(context.contexts.count(), 6); + QCOMPARE(context.contexts.count(), 7); QVERIFY(context.contexts[0].debugId >= 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() { |