diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-07-21 16:11:16 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-08-04 13:35:25 +0000 |
commit | 5652c4163f94aaf4bd9cef994be2ae8e7f4096c5 (patch) | |
tree | a42e882963b3e7b328dfd23da275c4e825bfb544 /src/qml/debugger | |
parent | f8e5cfcfc26499eef30fc222e24957a753651cbc (diff) |
Move debugger-specific services into a common plugin
Change-Id: Icd4e6a6c57bc3ac65cb43d2329d236012b988678
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src/qml/debugger')
-rw-r--r-- | src/qml/debugger/debugger.pri | 6 | ||||
-rw-r--r-- | src/qml/debugger/qdebugmessageservice.cpp | 103 | ||||
-rw-r--r-- | src/qml/debugger/qdebugmessageservice_p.h | 83 | ||||
-rw-r--r-- | src/qml/debugger/qqmldebugconnector.cpp | 8 | ||||
-rw-r--r-- | src/qml/debugger/qqmlenginedebugservice.cpp | 827 | ||||
-rw-r--r-- | src/qml/debugger/qqmlenginedebugservice_p.h | 135 | ||||
-rw-r--r-- | src/qml/debugger/qv4debugservice.cpp | 1207 | ||||
-rw-r--r-- | src/qml/debugger/qv4debugservice_p.h | 138 |
8 files changed, 1 insertions, 2506 deletions
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri index 9734e07a1d..728394916c 100644 --- a/src/qml/debugger/debugger.pri +++ b/src/qml/debugger/debugger.pri @@ -5,9 +5,6 @@ SOURCES += \ $$PWD/qqmldebugconnector.cpp \ $$PWD/qqmldebugservice.cpp \ $$PWD/qqmldebugserviceinterfaces.cpp \ - $$PWD/qqmlenginedebugservice.cpp \ - $$PWD/qdebugmessageservice.cpp \ - $$PWD/qv4debugservice.cpp \ $$PWD/qqmlabstractprofileradapter.cpp \ $$PWD/qqmlprofiler.cpp @@ -18,10 +15,7 @@ HEADERS += \ $$PWD/qqmldebugservicefactory_p.h \ $$PWD/qqmldebugserviceinterfaces_p.h \ $$PWD/qqmldebugstatesdelegate_p.h \ - $$PWD/qqmlenginedebugservice_p.h \ $$PWD/qqmldebug.h \ - $$PWD/qdebugmessageservice_p.h \ - $$PWD/qv4debugservice_p.h \ $$PWD/qqmlconfigurabledebugservice_p.h \ $$PWD/qqmlprofilerdefinitions_p.h \ $$PWD/qqmlabstractprofileradapter_p.h \ diff --git a/src/qml/debugger/qdebugmessageservice.cpp b/src/qml/debugger/qdebugmessageservice.cpp deleted file mode 100644 index 6b0f184951..0000000000 --- a/src/qml/debugger/qdebugmessageservice.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdebugmessageservice_p.h" -#include <private/qqmldebugconnector_p.h> - -#include <QDataStream> - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QDebugMessageService, qmlDebugMessageService) - -const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages"); - -void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf) -{ - QQmlDebugConnector::service<QDebugMessageService>()->sendDebugMessage(type, ctxt, buf); -} - -QDebugMessageService::QDebugMessageService(QObject *parent) : - QQmlDebugService(s_key, 2, parent), oldMsgHandler(0), - prevState(QQmlDebugService::NotConnected) -{ - // don't execute stateChanged() in parallel - QMutexLocker lock(&initMutex); - if (state() == Enabled) { - oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); - prevState = Enabled; - } -} - -QDebugMessageService *QDebugMessageService::instance() -{ - return qmlDebugMessageService(); -} - -void QDebugMessageService::sendDebugMessage(QtMsgType type, - const QMessageLogContext &ctxt, - const QString &buf) -{ - //We do not want to alter the message handling mechanism - //We just eavesdrop and forward the messages to a port - //only if a client is connected to it. - QByteArray message; - QQmlDebugStream ws(&message, QIODevice::WriteOnly); - ws << QByteArray("MESSAGE") << type << buf.toUtf8(); - ws << QString::fromLatin1(ctxt.file).toUtf8(); - ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8(); - - emit messageToClient(name(), message); - if (oldMsgHandler) - (*oldMsgHandler)(type, ctxt, buf); -} - -void QDebugMessageService::stateChanged(State state) -{ - QMutexLocker lock(&initMutex); - - if (state != Enabled && prevState == Enabled) { - QtMessageHandler handler = qInstallMessageHandler(oldMsgHandler); - // has our handler been overwritten in between? - if (handler != DebugMessageHandler) - qInstallMessageHandler(handler); - - } else if (state == Enabled && prevState != Enabled) { - oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); - } - - prevState = state; -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qdebugmessageservice_p.h b/src/qml/debugger/qdebugmessageservice_p.h deleted file mode 100644 index 3d0d8a79a5..0000000000 --- a/src/qml/debugger/qdebugmessageservice_p.h +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDEBUGMESSAGESERVICE_P_H -#define QDEBUGMESSAGESERVICE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qqmldebugservice_p.h" - -#include <QtCore/qlogging.h> -#include <QtCore/qmutex.h> - -QT_BEGIN_NAMESPACE - -class QDebugMessageServicePrivate; - -class QDebugMessageService : public QQmlDebugService -{ - Q_OBJECT -public: - QDebugMessageService(QObject *parent = 0); - - static QDebugMessageService *instance(); - - void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf); - -protected: - static const QString s_key; - - void stateChanged(State); - -private: - friend class QQmlDebugConnector; - - QtMessageHandler oldMsgHandler; - QQmlDebugService::State prevState; - QMutex initMutex; -}; - -QT_END_NAMESPACE - -#endif // QDEBUGMESSAGESERVICE_P_H diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index 9565f19563..393185bf0d 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -33,9 +33,6 @@ #include "qqmldebugpluginmanager_p.h" #include "qqmldebugconnector_p.h" -#include "qdebugmessageservice_p.h" -#include "qqmlenginedebugservice_p.h" -#include "qv4debugservice_p.h" #include "qqmldebugservicefactory_p.h" #include <QtCore/QPluginLoader> #include <QtCore/QCoreApplication> @@ -55,6 +52,7 @@ Q_QML_IMPORT_DEBUG_PLUGIN(QQmlDebugServerFactory) Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugService) Q_QML_IMPORT_DEBUG_PLUGIN(QQmlInspectorServiceFactory) Q_QML_IMPORT_DEBUG_PLUGIN(QQmlProfilerServiceFactory) +Q_QML_IMPORT_DEBUG_PLUGIN(QQmlDebuggerServiceFactory) struct QQmlDebugConnectorParams { QString pluginKey; @@ -118,10 +116,6 @@ QQmlDebugConnector *QQmlDebugConnector::instance() } params->instance = loadQQmlDebugConnector(QLatin1String("QQmlDebugServer")); if (params->instance) { - QQmlEngineDebugServiceImpl::instance(); - QV4DebugServiceImpl::instance(); - QDebugMessageService::instance(); - foreach (const QJsonObject &object, metaDataForQQmlDebugService()) { foreach (const QJsonValue &key, object.value(QLatin1String("MetaData")).toObject() .value(QLatin1String("Keys")).toArray()) { diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp deleted file mode 100644 index 30d2f32e2c..0000000000 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ /dev/null @@ -1,827 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlenginedebugservice_p.h" - -#include "qqmldebugstatesdelegate_p.h" -#include <private/qqmlboundsignal_p.h> -#include <qqmlengine.h> -#include <private/qqmlmetatype_p.h> -#include <qqmlproperty.h> -#include <private/qqmlproperty_p.h> -#include <private/qqmlbinding_p.h> -#include <private/qqmlcontext_p.h> -#include <private/qqmlwatcher_p.h> -#include <private/qqmlvaluetype_p.h> -#include <private/qqmlvmemetaobject_p.h> -#include <private/qqmlexpression_p.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qmetaobject.h> -#include <QtCore/qfileinfo.h> -#include <private/qmetaobject_p.h> - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QQmlEngineDebugServiceImpl, qmlEngineDebugService) - -QQmlEngineDebugServiceImpl *QQmlEngineDebugServiceImpl::instance() -{ - return qmlEngineDebugService(); -} - -QQmlEngineDebugServiceImpl::QQmlEngineDebugServiceImpl(QObject *parent) : - QQmlEngineDebugService(2, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(0) -{ - QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)), - this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant))); -} - -QQmlEngineDebugServiceImpl::~QQmlEngineDebugServiceImpl() -{ - delete m_statesDelegate; -} - -QDataStream &operator<<(QDataStream &ds, - const QQmlEngineDebugServiceImpl::QQmlObjectData &data) -{ - ds << data.url << data.lineNumber << data.columnNumber << data.idString - << data.objectName << data.objectType << data.objectId << data.contextId - << data.parentId; - return ds; -} - -QDataStream &operator>>(QDataStream &ds, - QQmlEngineDebugServiceImpl::QQmlObjectData &data) -{ - ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString - >> data.objectName >> data.objectType >> data.objectId >> data.contextId - >> data.parentId; - return ds; -} - -QDataStream &operator<<(QDataStream &ds, - const QQmlEngineDebugServiceImpl::QQmlObjectProperty &data) -{ - ds << (int)data.type << data.name; - // check first whether the data can be saved - // (otherwise we assert in QVariant::operator<<) - QByteArray buffer; - QDataStream fakeStream(&buffer, QIODevice::WriteOnly); - if (QMetaType::save(fakeStream, data.value.type(), data.value.constData())) - ds << data.value; - else - ds << QVariant(); - ds << data.valueTypeName << data.binding << data.hasNotifySignal; - return ds; -} - -QDataStream &operator>>(QDataStream &ds, - QQmlEngineDebugServiceImpl::QQmlObjectProperty &data) -{ - int type; - ds >> type >> data.name >> data.value >> data.valueTypeName - >> data.binding >> data.hasNotifySignal; - data.type = (QQmlEngineDebugServiceImpl::QQmlObjectProperty::Type)type; - return ds; -} - -static inline bool isSignalPropertyName(const QString &signalName) -{ - // see QmlCompiler::isSignalPropertyName - return signalName.length() >= 3 && signalName.startsWith(QLatin1String("on")) && - signalName.at(2).isLetter() && signalName.at(2).isUpper(); -} - -static bool hasValidSignal(QObject *object, const QString &propertyName) -{ - if (!isSignalPropertyName(propertyName)) - return false; - - QString signalName = propertyName.mid(2); - signalName[0] = signalName.at(0).toLower(); - - int sigIdx = QQmlPropertyPrivate::findSignalByName(object->metaObject(), signalName.toLatin1()).methodIndex(); - - if (sigIdx == -1) - return false; - - return true; -} - -QQmlEngineDebugServiceImpl::QQmlObjectProperty -QQmlEngineDebugServiceImpl::propertyData(QObject *obj, int propIdx) -{ - QQmlObjectProperty rv; - - QMetaProperty prop = obj->metaObject()->property(propIdx); - - rv.type = QQmlObjectProperty::Unknown; - rv.valueTypeName = QString::fromUtf8(prop.typeName()); - rv.name = QString::fromUtf8(prop.name()); - rv.hasNotifySignal = prop.hasNotifySignal(); - QQmlAbstractBinding *binding = - QQmlPropertyPrivate::binding(QQmlProperty(obj, rv.name)); - if (binding) - rv.binding = binding->expression(); - - if (QQmlValueTypeFactory::isValueType(prop.userType())) { - rv.type = QQmlObjectProperty::Basic; - } else if (QQmlMetaType::isQObject(prop.userType())) { - rv.type = QQmlObjectProperty::Object; - } else if (QQmlMetaType::isList(prop.userType())) { - rv.type = QQmlObjectProperty::List; - } else if (prop.userType() == QMetaType::QVariant) { - rv.type = QQmlObjectProperty::Variant; - } - - QVariant value; - if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) { - value = prop.read(obj); - } - rv.value = valueContents(value); - - return rv; -} - -QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const -{ - // We can't send JS objects across the wire, so transform them to variant - // maps for serialization. - if (value.userType() == qMetaTypeId<QJSValue>()) - value = value.value<QJSValue>().toVariant(); - const int userType = value.userType(); - - //QObject * is not streamable. - //Convert all such instances to a String value - - if (value.type() == QVariant::List) { - QVariantList contents; - QVariantList list = value.toList(); - int count = list.size(); - contents.reserve(count); - for (int i = 0; i < count; i++) - contents << valueContents(list.at(i)); - return contents; - } - - if (value.type() == QVariant::Map) { - QVariantMap contents; - QMapIterator<QString, QVariant> i(value.toMap()); - while (i.hasNext()) { - i.next(); - contents.insert(i.key(), valueContents(i.value())); - } - return contents; - } - - 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); - QMetaType info(userType); - QString s; - if (info.flags() & QMetaType::IsGadget - && mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) - return s; - } - } - - return value; - } - - if (QQmlMetaType::isQObject(userType)) { - QObject *o = QQmlMetaType::toQObject(value); - if (o) { - QString name = o->objectName(); - if (name.isEmpty()) - name = QStringLiteral("<unnamed object>"); - return name; - } - } - - return QString(QStringLiteral("<unknown value>")); -} - -void QQmlEngineDebugServiceImpl::buildObjectDump(QDataStream &message, - QObject *object, bool recur, bool dumpProperties) -{ - message << objectData(object); - - QObjectList children = object->children(); - - int childrenCount = children.count(); - for (int ii = 0; ii < children.count(); ++ii) { - if (qobject_cast<QQmlContext*>(children[ii])) - --childrenCount; - } - - message << childrenCount << recur; - - QList<QQmlObjectProperty> fakeProperties; - - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); - if (qobject_cast<QQmlContext*>(child)) - continue; - if (recur) - buildObjectDump(message, child, recur, dumpProperties); - else - message << objectData(child); - } - - if (!dumpProperties) { - message << 0; - return; - } - - QList<int> propertyIndexes; - for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) { - if (object->metaObject()->property(ii).isScriptable()) - propertyIndexes << ii; - } - - QQmlData *ddata = QQmlData::get(object); - if (ddata && ddata->signalHandlers) { - QQmlBoundSignal *signalHandler = ddata->signalHandlers; - - while (signalHandler) { - QQmlObjectProperty prop; - prop.type = QQmlObjectProperty::SignalProperty; - prop.hasNotifySignal = false; - QQmlBoundSignalExpression *expr = signalHandler->expression(); - if (expr) { - prop.value = expr->expression(); - QObject *scope = expr->scopeObject(); - if (scope) { - QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->signalIndex()).name()); - if (!methodName.isEmpty()) { - prop.name = QLatin1String("on") + methodName[0].toUpper() - + methodName.mid(1); - } - } - } - fakeProperties << prop; - - signalHandler = nextSignal(signalHandler); - } - } - - message << propertyIndexes.size() + fakeProperties.count(); - - for (int ii = 0; ii < propertyIndexes.size(); ++ii) - message << propertyData(object, propertyIndexes.at(ii)); - - for (int ii = 0; ii < fakeProperties.count(); ++ii) - message << fakeProperties[ii]; -} - -void QQmlEngineDebugServiceImpl::prepareDeferredObjects(QObject *obj) -{ - qmlExecuteDeferred(obj); - - QObjectList children = obj->children(); - for (int ii = 0; ii < children.count(); ++ii) { - QObject *child = children.at(ii); - prepareDeferredObjects(child); - } - -} - -void QQmlEngineDebugServiceImpl::storeObjectIds(QObject *co) -{ - QQmlDebugService::idForObject(co); - QObjectList children = co->children(); - for (int ii = 0; ii < children.count(); ++ii) - storeObjectIds(children.at(ii)); -} - -void QQmlEngineDebugServiceImpl::buildObjectList(QDataStream &message, - QQmlContext *ctxt, - const QList<QPointer<QObject> > &instances) -{ - QQmlContextData *p = QQmlContextData::get(ctxt); - - QString ctxtName = ctxt->objectName(); - int ctxtId = QQmlDebugService::idForObject(ctxt); - if (ctxt->contextObject()) - storeObjectIds(ctxt->contextObject()); - - message << ctxtName << ctxtId; - - int count = 0; - - QQmlContextData *child = p->childContexts; - while (child) { - ++count; - child = child->nextChild; - } - - message << count; - - child = p->childContexts; - while (child) { - buildObjectList(message, child->asQQmlContext(), instances); - child = child->nextChild; - } - - count = 0; - for (int ii = 0; ii < instances.count(); ++ii) { - QQmlData *data = QQmlData::get(instances.at(ii)); - if (data->context == p) - count ++; - } - message << count; - - for (int ii = 0; ii < instances.count(); ++ii) { - QQmlData *data = QQmlData::get(instances.at(ii)); - if (data->context == p) - message << objectData(instances.at(ii)); - } -} - -void QQmlEngineDebugServiceImpl::buildStatesList(bool cleanList, - const QList<QPointer<QObject> > &instances) -{ - if (m_statesDelegate) - m_statesDelegate->buildStatesList(cleanList, instances); -} - -QQmlEngineDebugServiceImpl::QQmlObjectData -QQmlEngineDebugServiceImpl::objectData(QObject *object) -{ - QQmlData *ddata = QQmlData::get(object); - QQmlObjectData rv; - if (ddata && ddata->outerContext) { - rv.url = ddata->outerContext->url(); - rv.lineNumber = ddata->lineNumber; - rv.columnNumber = ddata->columnNumber; - } else { - rv.lineNumber = -1; - rv.columnNumber = -1; - } - - QQmlContext *context = qmlContext(object); - if (context) { - QQmlContextData *cdata = QQmlContextData::get(context); - if (cdata) - rv.idString = cdata->findObjectId(object); - } - - rv.objectName = object->objectName(); - rv.objectId = QQmlDebugService::idForObject(object); - rv.contextId = QQmlDebugService::idForObject(qmlContext(object)); - rv.parentId = QQmlDebugService::idForObject(object->parent()); - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - QString typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); - } else { - rv.objectType = QString::fromUtf8(object->metaObject()->className()); - int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); - if (marker != -1) - rv.objectType = rv.objectType.left(marker); - } - - return rv; -} - -void QQmlEngineDebugServiceImpl::messageReceived(const QByteArray &message) -{ - QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); -} - -/*! - Returns a list of objects matching the given filename, line and column. -*/ -QList<QObject*> QQmlEngineDebugServiceImpl::objectForLocationInfo(const QString &filename, - int lineNumber, int columnNumber) -{ - QList<QObject *> objects; - const QHash<int, QObject *> &hash = objectsForIds(); - for (QHash<int, QObject *>::ConstIterator i = hash.constBegin(); i != hash.constEnd(); ++i) { - QQmlData *ddata = QQmlData::get(i.value()); - if (ddata && ddata->outerContext) { - if (QFileInfo(ddata->outerContext->urlString()).fileName() == filename && - ddata->lineNumber == lineNumber && - ddata->columnNumber >= columnNumber) { - objects << i.value(); - } - } - } - return objects; -} - -void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) -{ - QQmlDebugStream ds(message); - - QByteArray type; - int queryId; - ds >> type >> queryId; - - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - if (type == "LIST_ENGINES") { - rs << QByteArray("LIST_ENGINES_R"); - rs << queryId << m_engines.count(); - - for (int ii = 0; ii < m_engines.count(); ++ii) { - QQmlEngine *engine = m_engines.at(ii); - - QString engineName = engine->objectName(); - int engineId = QQmlDebugService::idForObject(engine); - - rs << engineName << engineId; - } - - } else if (type == "LIST_OBJECTS") { - int engineId = -1; - ds >> engineId; - - QQmlEngine *engine = - qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId)); - - rs << QByteArray("LIST_OBJECTS_R") << queryId; - - if (engine) { - QQmlContext *rootContext = engine->rootContext(); - // Clean deleted objects - QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(rootContext); - for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { - if (!ctxtPriv->instances.at(ii)) { - ctxtPriv->instances.removeAt(ii); - --ii; - } - } - buildObjectList(rs, rootContext, ctxtPriv->instances); - buildStatesList(true, ctxtPriv->instances); - } - - } else if (type == "FETCH_OBJECT") { - int objectId; - bool recurse; - bool dumpProperties = true; - - ds >> objectId >> recurse >> dumpProperties; - - QObject *object = QQmlDebugService::objectForId(objectId); - - rs << QByteArray("FETCH_OBJECT_R") << queryId; - - if (object) { - if (recurse) - prepareDeferredObjects(object); - buildObjectDump(rs, object, recurse, dumpProperties); - } - - } else if (type == "FETCH_OBJECTS_FOR_LOCATION") { - QString file; - int lineNumber; - int columnNumber; - bool recurse; - bool dumpProperties = true; - - ds >> file >> lineNumber >> columnNumber >> recurse >> dumpProperties; - - QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber); - - rs << QByteArray("FETCH_OBJECTS_FOR_LOCATION_R") << queryId - << objects.count(); - - foreach (QObject *object, objects) { - if (recurse) - prepareDeferredObjects(object); - buildObjectDump(rs, object, recurse, dumpProperties); - } - - } else if (type == "WATCH_OBJECT") { - int objectId; - - ds >> objectId; - bool ok = m_watch->addWatch(queryId, objectId); - - rs << QByteArray("WATCH_OBJECT_R") << queryId << ok; - - } else if (type == "WATCH_PROPERTY") { - int objectId; - QByteArray property; - - ds >> objectId >> property; - bool ok = m_watch->addWatch(queryId, objectId, property); - - rs << QByteArray("WATCH_PROPERTY_R") << queryId << ok; - - } else if (type == "WATCH_EXPR_OBJECT") { - int debugId; - QString expr; - - ds >> debugId >> expr; - bool ok = m_watch->addWatch(queryId, debugId, expr); - - rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok; - - } else if (type == "NO_WATCH") { - bool ok = m_watch->removeWatch(queryId); - - rs << QByteArray("NO_WATCH_R") << queryId << ok; - - } else if (type == "EVAL_EXPRESSION") { - int objectId; - QString expr; - - ds >> objectId >> expr; - int engineId = -1; - if (!ds.atEnd()) - ds >> engineId; - - QObject *object = QQmlDebugService::objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (!context) { - QQmlEngine *engine = qobject_cast<QQmlEngine *>( - QQmlDebugService::objectForId(engineId)); - if (engine && m_engines.contains(engine)) - context = engine->rootContext(); - } - QVariant result; - if (context) { - QQmlExpression exprObj(context, object, expr); - bool undefined = false; - QVariant value = exprObj.evaluate(&undefined); - if (undefined) - result = QString(QStringLiteral("<undefined>")); - else - result = valueContents(value); - } else { - result = QString(QStringLiteral("<unknown context>")); - } - - rs << QByteArray("EVAL_EXPRESSION_R") << queryId << result; - - } else if (type == "SET_BINDING") { - int objectId; - QString propertyName; - QVariant expr; - bool isLiteralValue; - QString filename; - int line; - ds >> objectId >> propertyName >> expr >> isLiteralValue >> - filename >> line; - bool ok = setBinding(objectId, propertyName, expr, isLiteralValue, - filename, line); - - rs << QByteArray("SET_BINDING_R") << queryId << ok; - - } else if (type == "RESET_BINDING") { - int objectId; - QString propertyName; - ds >> objectId >> propertyName; - bool ok = resetBinding(objectId, propertyName); - - rs << QByteArray("RESET_BINDING_R") << queryId << ok; - - } else if (type == "SET_METHOD_BODY") { - int objectId; - QString methodName; - QString methodBody; - ds >> objectId >> methodName >> methodBody; - bool ok = setMethodBody(objectId, methodName, methodBody); - - rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok; - - } - emit messageToClient(name(), reply); -} - -bool QQmlEngineDebugServiceImpl::setBinding(int objectId, - const QString &propertyName, - const QVariant &expression, - bool isLiteralValue, - QString filename, - int line, - int column) -{ - bool ok = true; - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - - if (object && context) { - QQmlProperty property(object, propertyName, context); - if (property.isValid()) { - - bool inBaseState = true; - if (m_statesDelegate) { - m_statesDelegate->updateBinding(context, property, expression, isLiteralValue, - filename, line, column, &inBaseState); - } - - if (inBaseState) { - if (isLiteralValue) { - property.write(expression); - } else if (hasValidSignal(object, propertyName)) { - QQmlBoundSignalExpression *qmlExpression = new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(property)->signalIndex(), - QQmlContextData::get(context), object, expression.toString(), - filename, line, column); - QQmlPropertyPrivate::takeSignalExpression(property, qmlExpression); - } else if (property.isProperty()) { - QQmlBinding *binding = new QQmlBinding(expression.toString(), object, QQmlContextData::get(context), filename, line, column); - binding->setTarget(property); - QQmlPropertyPrivate::setBinding(binding); - binding->update(); - } else { - ok = false; - qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; - } - } - - } else { - // not a valid property - if (m_statesDelegate) - ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue); - if (!ok) - qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; - } - } - return ok; -} - -bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &propertyName) -{ - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - - if (object && context) { - QString parentProperty = propertyName; - if (propertyName.indexOf(QLatin1Char('.')) != -1) - parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.'))); - - if (object->property(parentProperty.toLatin1()).isValid()) { - QQmlProperty property(object, propertyName); - QQmlPropertyPrivate::removeBinding(property); - if (property.isResettable()) { - // Note: this will reset the property in any case, without regard to states - // Right now almost no QQuickItem has reset methods for its properties (with the - // notable exception of QQuickAnchors), so this is not a big issue - // later on, setBinding does take states into account - property.reset(); - } else { - // overwrite with default value - if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { - if (QObject *emptyObject = objType->create()) { - if (emptyObject->property(parentProperty.toLatin1()).isValid()) { - QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); - if (defaultValue.isValid()) { - setBinding(objectId, propertyName, defaultValue, true); - } - } - delete emptyObject; - } - } - } - return true; - } - - if (hasValidSignal(object, propertyName)) { - QQmlProperty property(object, propertyName, context); - QQmlPropertyPrivate::setSignalExpression(property, 0); - return true; - } - - if (m_statesDelegate) { - m_statesDelegate->resetBindingForInvalidProperty(object, propertyName); - return true; - } - - return false; - } - // object or context null. - return false; -} - -bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &method, const QString &body) -{ - QObject *object = objectForId(objectId); - QQmlContext *context = qmlContext(object); - if (!object || !context || !context->engine()) - return false; - QQmlContextData *contextData = QQmlContextData::get(context); - if (!contextData) - return false; - - QQmlPropertyData dummy; - QQmlPropertyData *prop = - QQmlPropertyCache::property(context->engine(), object, method, contextData, dummy); - - if (!prop || !prop->isVMEFunction()) - return false; - - QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex); - QList<QByteArray> paramNames = metaMethod.parameterNames(); - - QString paramStr; - for (int ii = 0; ii < paramNames.count(); ++ii) { - if (ii != 0) paramStr.append(QLatin1Char(',')); - paramStr.append(QString::fromUtf8(paramNames.at(ii))); - } - - QString jsfunction = QLatin1String("(function ") + method + QLatin1Char('(') + paramStr + - QLatin1String(") {"); - jsfunction += body; - jsfunction += QLatin1String("\n})"); - - QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this - - int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle()); - QV4::Scope scope(v4); - QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber)); - vmeMetaObject->setVmeMethod(prop->coreIndex, v); - return true; -} - -void QQmlEngineDebugServiceImpl::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) -{ - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value); - - emit messageToClient(name(), reply); -} - -void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(!m_engines.contains(engine)); - - m_engines.append(engine); - emit attachedToEngine(engine); -} - -void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) -{ - Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); - - m_engines.removeAll(engine); - emit detachedFromEngine(engine); -} - -void QQmlEngineDebugServiceImpl::objectCreated(QQmlEngine *engine, QObject *object) -{ - Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); - - int engineId = QQmlDebugService::idForObject(engine); - int objectId = QQmlDebugService::idForObject(object); - int parentId = QQmlDebugService::idForObject(object->parent()); - - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - - //unique queryId -1 - rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId << parentId; - emit messageToClient(name(), reply); -} - -void QQmlEngineDebugServiceImpl::setStatesDelegate(QQmlDebugStatesDelegate *delegate) -{ - m_statesDelegate = delegate; -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h deleted file mode 100644 index 99a98e1f12..0000000000 --- a/src/qml/debugger/qqmlenginedebugservice_p.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLENGINEDEBUGSERVICE_P_H -#define QQMLENGINEDEBUGSERVICE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qqmldebugservice_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> - -#include <QtCore/qurl.h> -#include <QtCore/qvariant.h> -#include <QtCore/QPointer> - -QT_BEGIN_NAMESPACE - -class QQmlEngine; -class QQmlContext; -class QQmlWatcher; -class QDataStream; -class QQmlDebugStatesDelegate; - -class Q_QML_PRIVATE_EXPORT QQmlEngineDebugServiceImpl : public QQmlEngineDebugService -{ - Q_OBJECT -public: - QQmlEngineDebugServiceImpl(QObject * = 0); - ~QQmlEngineDebugServiceImpl(); - - struct QQmlObjectData { - QUrl url; - int lineNumber; - int columnNumber; - QString idString; - QString objectName; - QString objectType; - int objectId; - int contextId; - int parentId; - }; - - struct QQmlObjectProperty { - enum Type { Unknown, Basic, Object, List, SignalProperty, Variant }; - Type type; - QString name; - QVariant value; - QString valueTypeName; - QString binding; - bool hasNotifySignal; - }; - - void engineAboutToBeAdded(QQmlEngine *); - void engineAboutToBeRemoved(QQmlEngine *); - void objectCreated(QQmlEngine *, QObject *); - - void setStatesDelegate(QQmlDebugStatesDelegate *); - - static QQmlEngineDebugServiceImpl *instance(); - -protected: - virtual void messageReceived(const QByteArray &); - -private Q_SLOTS: - void processMessage(const QByteArray &msg); - void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); - -private: - void prepareDeferredObjects(QObject *); - void buildObjectList(QDataStream &, QQmlContext *, - const QList<QPointer<QObject> > &instances); - void buildObjectDump(QDataStream &, QObject *, bool, bool); - void buildStatesList(bool cleanList, const QList<QPointer<QObject> > &instances); - QQmlObjectData objectData(QObject *); - QQmlObjectProperty propertyData(QObject *, int); - QVariant valueContents(QVariant defaultValue) const; - bool setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0); - bool resetBinding(int objectId, const QString &propertyName); - bool setMethodBody(int objectId, const QString &method, const QString &body); - void storeObjectIds(QObject *co); - QList<QObject *> objectForLocationInfo(const QString &filename, int lineNumber, - int columnNumber); - - QList<QQmlEngine *> m_engines; - QQmlWatcher *m_watch; - QQmlDebugStatesDelegate *m_statesDelegate; -}; -Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugServiceImpl::QQmlObjectData &); -Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugServiceImpl::QQmlObjectData &); -Q_QML_PRIVATE_EXPORT QDataStream &operator<<(QDataStream &, const QQmlEngineDebugServiceImpl::QQmlObjectProperty &); -Q_QML_PRIVATE_EXPORT QDataStream &operator>>(QDataStream &, QQmlEngineDebugServiceImpl::QQmlObjectProperty &); - -QT_END_NAMESPACE - -#endif // QQMLENGINEDEBUGSERVICE_P_H - diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp deleted file mode 100644 index 94755bd35e..0000000000 --- a/src/qml/debugger/qv4debugservice.cpp +++ /dev/null @@ -1,1207 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4debugservice_p.h" -#include "qqmlengine.h" -#include "qv4engine_p.h" -#include "qv4function_p.h" -#include "qqmldebugconnector_p.h" - -#include <private/qv8engine_p.h> - -#include <QtCore/QJsonArray> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> - -const char *const V4_CONNECT = "connect"; -const char *const V4_DISCONNECT = "disconnect"; -const char *const V4_BREAK_ON_SIGNAL = "breakonsignal"; -const char *const V4_PAUSE = "interrupt"; - -#define NO_PROTOCOL_TRACING -#ifdef NO_PROTOCOL_TRACING -# define TRACE_PROTOCOL(x) -#else -#include <QtCore/QDebug> -# define TRACE_PROTOCOL(x) x -#endif - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QV4DebugServiceImpl, v4ServiceInstance) - -class V8CommandHandler; -class UnknownV8CommandHandler; - -class VariableCollector: public QV4::Debugging::Debugger::Collector -{ -public: - VariableCollector(QV4::ExecutionEngine *engine) - : Collector(engine) - , destination(0) - {} - - virtual ~VariableCollector() {} - - void collectScope(QJsonArray *dest, QV4::Debugging::Debugger *debugger, int frameNr, int scopeNr) - { - qSwap(destination, dest); - bool oldIsProp = isProperty(); - setIsProperty(true); - debugger->collectArgumentsInContext(this, frameNr, scopeNr); - debugger->collectLocalsInContext(this, frameNr, scopeNr); - setIsProperty(oldIsProp); - qSwap(destination, dest); - } - - void setDestination(QJsonArray *dest) - { destination = dest; } - - QJsonArray retrieveRefsToInclude() - { - QJsonArray result; - qSwap(refsToInclude, result); - return result; - } - - QJsonValue lookup(int handle, bool addRefs = true) - { - if (handle < 0) - handle = -handle; - - if (addRefs) - foreach (int ref, refsByHandle[handle]) - refsToInclude.append(lookup(ref, false)); - return refs[handle]; - } - - QJsonObject makeRef(int refId) - { - QJsonObject ref; - ref[QLatin1String("ref")] = refId; - return ref; - } - - QJsonObject addFunctionRef(const QString &name) - { - const int refId = newRefId(); - - QJsonObject func; - func[QLatin1String("handle")] = refId; - func[QLatin1String("type")] = QStringLiteral("function"); - func[QLatin1String("className")] = QStringLiteral("Function"); - func[QLatin1String("name")] = name; - insertRef(func, refId); - - return makeRef(refId); - } - - QJsonObject addScriptRef(const QString &name) - { - const int refId = newRefId(); - - QJsonObject func; - func[QLatin1String("handle")] = refId; - func[QLatin1String("type")] = QStringLiteral("script"); - func[QLatin1String("name")] = name; - insertRef(func, refId); - - return makeRef(refId); - } - - QJsonObject addObjectRef(QJsonObject obj, bool anonymous) - { - int ref = newRefId(); - - if (anonymous) - ref = -ref; - obj[QLatin1String("handle")] = ref; - obj[QLatin1String("type")] = QStringLiteral("object"); - insertRef(obj, ref); - QSet<int> used; - qSwap(usedRefs, used); - refsByHandle.insert(ref, used); - - return makeRef(ref); - } - -protected: - virtual void addUndefined(const QString &name) - { - QJsonObject o; - addHandle(name, o, QStringLiteral("undefined")); - } - - virtual void addNull(const QString &name) - { - QJsonObject o; - addHandle(name, o, QStringLiteral("null")); - } - - virtual void addBoolean(const QString &name, bool value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("boolean")); - } - - virtual void addString(const QString &name, const QString &value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("string")); - } - - virtual void addObject(const QString &name, const QV4::Value &value) - { - QV4::Scope scope(engine()); - QV4::ScopedObject obj(scope, value.as<QV4::Object>()); - - int ref = cachedObjectRef(obj); - if (ref != -1) { - addNameRefPair(name, ref); - } else { - int ref = newRefId(); - cacheObjectRef(obj, ref); - - QJsonArray properties, *prev = &properties; - QSet<int> used; - qSwap(usedRefs, used); - qSwap(destination, prev); - collect(obj); - qSwap(destination, prev); - qSwap(usedRefs, used); - - QJsonObject o; - o[QLatin1String("properties")] = properties; - addHandle(name, o, QStringLiteral("object"), ref); - refsByHandle.insert(ref, used); - } - } - - virtual void addInteger(const QString &name, int value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("number")); - } - - virtual void addDouble(const QString &name, double value) - { - QJsonObject o; - o[QLatin1String("value")] = value; - addHandle(name, o, QStringLiteral("number")); - } - -private: - int addHandle(const QString &name, QJsonObject object, const QString &type, int suppliedRef = -1) - { - Q_ASSERT(destination); - - object[QLatin1String("type")] = type; - - QJsonDocument tmp; - tmp.setObject(object); - QByteArray key = tmp.toJson(QJsonDocument::Compact); - - int ref; - if (suppliedRef == -1) { - ref = refCache.value(key, -1); - if (ref == -1) { - ref = newRefId(); - object[QLatin1String("handle")] = ref; - insertRef(object, ref); - refCache.insert(key, ref); - } - } else { - ref = suppliedRef; - object[QLatin1String("handle")] = ref; - insertRef(object, ref); - refCache.insert(key, ref); - } - - addNameRefPair(name, ref); - return ref; - } - - void addNameRefPair(const QString &name, int ref) - { - QJsonObject nameValuePair; - nameValuePair[QLatin1String("name")] = name; - if (isProperty()) { - nameValuePair[QLatin1String("ref")] = ref; - } else { - QJsonObject refObj; - refObj[QLatin1String("ref")] = ref; - nameValuePair[QLatin1String("value")] = refObj; - } - destination->append(nameValuePair); - usedRefs.insert(ref); - } - - int newRefId() - { - int ref = refs.count(); - refs.insert(ref, QJsonValue()); - return ref; - } - - void insertRef(const QJsonValue &value, int refId) - { - if (refId < 0) - refId = -refId; - - refs.insert(refId, value); - refsToInclude.append(value); - } - - void cacheObjectRef(QV4::Object *obj, int ref) - { - objectRefs.insert(obj, ref); - } - - int cachedObjectRef(QV4::Object *obj) const - { - return objectRefs.value(obj, -1); - } - -private: - QJsonArray refsToInclude; - QHash<int, QJsonValue> refs; - QHash<QByteArray, int> refCache; - QJsonArray *destination; - QSet<int> usedRefs; - QHash<int, QSet<int> > refsByHandle; - QHash<QV4::Object *, int> objectRefs; -}; - -int QV4DebugServiceImpl::debuggerIndex = 0; -int QV4DebugServiceImpl::sequence = 0; - -class V8CommandHandler -{ -public: - V8CommandHandler(const QString &command) - : cmd(command) - {} - - virtual ~V8CommandHandler() - {} - - QString command() const { return cmd; } - - void handle(const QJsonObject &request, QV4DebugServiceImpl *s) - { - TRACE_PROTOCOL(qDebug() << "handling command" << command() << "..."); - - req = request; - seq = req.value(QStringLiteral("seq")); - debugService = s; - - handleRequest(); - if (!response.isEmpty()) { - response[QLatin1String("type")] = QStringLiteral("response"); - debugService->send(response); - } - - debugService = 0; - seq = QJsonValue(); - req = QJsonObject(); - response = QJsonObject(); - } - - virtual void handleRequest() = 0; - -protected: - void addCommand() { response.insert(QStringLiteral("command"), cmd); } - void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); } - void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); } - void addBody(const QJsonObject &body) - { - response.insert(QStringLiteral("body"), body); - } - - void addRunning() - { - response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning()); - } - - void addRefs() - { - response.insert(QStringLiteral("refs"), debugService->buildRefs()); - } - - void createErrorResponse(const QString &msg) - { - QJsonValue command = req.value(QStringLiteral("command")); - response.insert(QStringLiteral("command"), command); - addRequestSequence(); - addSuccess(false); - addRunning(); - response.insert(QStringLiteral("message"), msg); - } - - int requestSequenceNr() const - { return seq.toInt(-1); } - -protected: - QString cmd; - QJsonObject req; - QJsonValue seq; - QV4DebugServiceImpl *debugService; - QJsonObject response; -}; - -class UnknownV8CommandHandler: public V8CommandHandler -{ -public: - UnknownV8CommandHandler(): V8CommandHandler(QString()) {} - - virtual void handleRequest() - { - QString msg = QStringLiteral("unimplemented command \""); - msg += req.value(QStringLiteral("command")).toString(); - msg += QStringLiteral("\""); - createErrorResponse(msg); - } -}; - -namespace { -class V8VersionRequest: public V8CommandHandler -{ -public: - V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {} - - virtual void handleRequest() - { - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("V8Version"), - QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); - addBody(body); - } -}; - -class V8SetBreakPointRequest: public V8CommandHandler -{ -public: - V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject args = req.value(QStringLiteral("arguments")).toObject(); - if (args.isEmpty()) - return; - - QString type = args.value(QStringLiteral("type")).toString(); - if (type != QStringLiteral("scriptRegExp")) { - createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type)); - return; - } - - QString fileName = args.value(QStringLiteral("target")).toString(); - if (fileName.isEmpty()) { - createErrorResponse(QStringLiteral("breakpoint has no file name")); - return; - } - - int line = args.value(QStringLiteral("line")).toInt(-1); - if (line < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid line number")); - return; - } - - bool enabled = args.value(QStringLiteral("enabled")).toBool(true); - QString condition = args.value(QStringLiteral("condition")).toString(); - - // set the break point: - int id = debugService->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), type); - body.insert(QStringLiteral("breakpoint"), id); - // It's undocumented, but V8 sends back an actual_locations array too. However, our - // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them - // pending until the breakpoint is hit for the first time. - addBody(body); - } -}; - -class V8ClearBreakPointRequest: public V8CommandHandler -{ -public: - V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject args = req.value(QStringLiteral("arguments")).toObject(); - if (args.isEmpty()) - return; - - int id = args.value(QStringLiteral("breakpoint")).toInt(-1); - if (id < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid number")); - return; - } - - // remove the break point: - debugService->debuggerAgent.removeBreakPoint(id); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), QStringLiteral("scriptRegExp")); - body.insert(QStringLiteral("breakpoint"), id); - addBody(body); - } -}; - -class V8BacktraceRequest: public V8CommandHandler -{ -public: - V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {} - - virtual void handleRequest() - { - // decypher the payload: - - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - int fromFrame = arguments.value(QStringLiteral("fromFrame")).toInt(0); - int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10); - // no idea what the bottom property is for, so we'll ignore it. - - QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - - QJsonArray frameArray; - QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame); - for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) - frameArray.push_back(debugService->buildFrame(frames[i], i, debugger)); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - if (frameArray.isEmpty()) { - body.insert(QStringLiteral("totalFrames"), 0); - } else { - body.insert(QStringLiteral("fromFrame"), fromFrame); - body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); - body.insert(QStringLiteral("frames"), frameArray); - } - addBody(body); - addRefs(); - } -}; - -class V8FrameRequest: public V8CommandHandler -{ -public: - V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - const int frameNr = arguments.value(QStringLiteral("number")).toInt( - debugService->selectedFrame()); - - QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { - createErrorResponse(QStringLiteral("frame command has invalid frame number")); - return; - } - - debugService->selectFrame(frameNr); - QJsonObject frame = debugService->buildFrame(frames[frameNr], frameNr, debugger); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(frame); - addRefs(); - } -}; - -class V8ScopeRequest: public V8CommandHandler -{ -public: - V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - const int frameNr = arguments.value(QStringLiteral("frameNumber")).toInt( - debugService->selectedFrame()); - const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0); - - QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1); - if (frameNr < 0 || frameNr >= frames.size()) { - createErrorResponse(QStringLiteral("scope command has invalid frame number")); - return; - } - if (scopeNr < 0) { - createErrorResponse(QStringLiteral("scope command has invalid scope number")); - return; - } - - QJsonObject scope = debugService->buildScope(frameNr, scopeNr, debugger); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(scope); - addRefs(); - } -}; - -class V8LookupRequest: public V8CommandHandler -{ -public: - V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray(); - - QJsonObject body; - foreach (const QJsonValue &handle, handles) - body[QString::number(handle.toInt())] = debugService->lookup(handle.toInt()); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(body); - addRefs(); - } -}; - -class V8ContinueRequest: public V8CommandHandler -{ -public: - V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {} - - virtual void handleRequest() - { - // decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - - QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - - if (arguments.empty()) { - debugger->resume(QV4::Debugging::Debugger::FullThrottle); - } else { - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString stepAction = arguments.value(QStringLiteral("stepaction")).toString(); - const int stepcount = arguments.value(QStringLiteral("stepcount")).toInt(1); - if (stepcount != 1) - qWarning() << "Step count other than 1 is not supported."; - - if (stepAction == QStringLiteral("in")) { - debugger->resume(QV4::Debugging::Debugger::StepIn); - } else if (stepAction == QStringLiteral("out")) { - debugger->resume(QV4::Debugging::Debugger::StepOut); - } else if (stepAction == QStringLiteral("next")) { - debugger->resume(QV4::Debugging::Debugger::StepOver); - } else { - createErrorResponse(QStringLiteral("continue command has invalid stepaction")); - return; - } - } - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - } -}; - -class V8DisconnectRequest: public V8CommandHandler -{ -public: - V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} - - virtual void handleRequest() - { - debugService->debuggerAgent.removeAllBreakPoints(); - debugService->debuggerAgent.resumeAll(); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - } -}; - -class V8SetExceptionBreakRequest: public V8CommandHandler -{ -public: - V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} - - virtual void handleRequest() - { - bool wasEnabled = debugService->debuggerAgent.breakOnThrow(); - - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString type = arguments.value(QStringLiteral("type")).toString(); - bool enabled = arguments.value(QStringLiteral("number")).toBool(!wasEnabled); - - if (type == QStringLiteral("all")) { - // that's fine - } else if (type == QStringLiteral("uncaught")) { - createErrorResponse(QStringLiteral("breaking only on uncaught exceptions is not supported yet")); - return; - } else { - createErrorResponse(QStringLiteral("invalid type for break on exception")); - return; - } - - // do it: - debugService->debuggerAgent.setBreakOnThrow(enabled); - - QJsonObject body; - body[QLatin1String("type")] = type; - body[QLatin1String("enabled")] = debugService->debuggerAgent.breakOnThrow(); - - // response: - addBody(body); - addRunning(); - addSuccess(true); - addRequestSequence(); - addCommand(); - } -}; - -class V8ScriptsRequest: public V8CommandHandler -{ -public: - V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} - - virtual void handleRequest() - { - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - int types = arguments.value(QStringLiteral("types")).toInt(-1); - if (types < 0 || types > 7) { - createErrorResponse(QStringLiteral("invalid types value in scripts command")); - return; - } else if (types != 4) { - createErrorResponse(QStringLiteral("unsupported types value in scripts command")); - return; - } - - // do it: - debugService->debuggerAgent.firstDebugger()->gatherSources(requestSequenceNr()); - - // response will be send by - } -}; - -// Request: -// { -// "seq": 4, -// "type": "request", -// "command": "evaluate", -// "arguments": { -// "expression": "a", -// "frame": 0 -// } -// } -// -// Response: -// { -// "body": { -// "handle": 3, -// "type": "number", -// "value": 1 -// }, -// "command": "evaluate", -// "refs": [], -// "request_seq": 4, -// "running": false, -// "seq": 5, -// "success": true, -// "type": "response" -// } -// -// The "value" key in "body" is the result of evaluating the expression in the request. -class V8EvaluateRequest: public V8CommandHandler -{ -public: - V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {} - - virtual void handleRequest() - { - //decypher the payload: - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString expression = arguments.value(QStringLiteral("expression")).toString(); - const int frame = arguments.value(QStringLiteral("frame")).toInt(0); - - QV4::Debugging::Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused); - - VariableCollector *collector = debugService->collector(); - QJsonArray dest; - collector->setDestination(&dest); - debugger->evaluateExpression(frame, expression, collector); - - const int ref = dest.at(0).toObject().value(QStringLiteral("value")).toObject() - .value(QStringLiteral("ref")).toInt(); - - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(collector->lookup(ref).toObject()); - addRefs(); - } -}; -} // anonymous namespace - -void QV4DebugServiceImpl::addHandler(V8CommandHandler* handler) -{ - handlers[handler->command()] = handler; -} - -V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command) const -{ - V8CommandHandler *handler = handlers.value(command, 0); - if (handler) - return handler; - else - return unknownV8CommandHandler.data(); -} - -QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) : - QQmlConfigurableDebugService<QV4DebugService>(1, parent), - debuggerAgent(this), version(1), theSelectedFrame(0), - unknownV8CommandHandler(new UnknownV8CommandHandler) -{ - addHandler(new V8VersionRequest); - addHandler(new V8SetBreakPointRequest); - addHandler(new V8ClearBreakPointRequest); - addHandler(new V8BacktraceRequest); - addHandler(new V8FrameRequest); - addHandler(new V8ScopeRequest); - addHandler(new V8LookupRequest); - addHandler(new V8ContinueRequest); - addHandler(new V8DisconnectRequest); - addHandler(new V8SetExceptionBreakRequest); - addHandler(new V8ScriptsRequest); - addHandler(new V8EvaluateRequest); -} - -QV4DebugServiceImpl::~QV4DebugServiceImpl() -{ - qDeleteAll(handlers); -} - -QV4DebugServiceImpl *QV4DebugServiceImpl::instance() -{ - return v4ServiceInstance(); -} - -void QV4DebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) -{ - QMutexLocker lock(&m_configMutex); - if (engine) { - QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); - if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) { - if (ee) { - ee->enableDebugger(); - QV4::Debugging::Debugger *debugger = ee->debugger; - debuggerMap.insert(debuggerIndex++, debugger); - debuggerAgent.addDebugger(debugger); - debuggerAgent.moveToThread(server->thread()); - moveToThread(server->thread()); - } - } - } - QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeAdded(engine); -} - -void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) -{ - QMutexLocker lock(&m_configMutex); - if (engine){ - const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); - if (ee) { - QV4::Debugging::Debugger *debugger = ee->debugger; - typedef QMap<int, QV4::Debugging::Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = debuggerMap.constEnd(); - for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) { - if (i.value() == debugger) { - debuggerMap.remove(i.key()); - break; - } - } - debuggerAgent.removeDebugger(debugger); - } - } - QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine); -} - -void QV4DebugServiceImpl::signalEmitted(const QString &signal) -{ - //This function is only called by QQmlBoundSignal - //only if there is a slot connected to the signal. Hence, there - //is no need for additional check. - - //Parse just the name and remove the class info - //Normalize to Lower case. - QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower(); - - foreach (const QString &signal, breakOnSignals) { - if (signal == signalName) { - // TODO: pause debugger - break; - } - } -} - -void QV4DebugServiceImpl::messageReceived(const QByteArray &message) -{ - QMutexLocker lock(&m_configMutex); - - QQmlDebugStream ms(message); - QByteArray header; - ms >> header; - - TRACE_PROTOCOL(qDebug() << "received message with header" << header); - - if (header == "V8DEBUG") { - QByteArray type; - QByteArray payload; - ms >> type >> payload; - TRACE_PROTOCOL(qDebug() << "... type:" << type); - - if (type == V4_CONNECT) { - emit messageToClient(name(), packMessage(type)); - stopWaiting(); - } else if (type == V4_PAUSE) { - debuggerAgent.pauseAll(); - sendSomethingToSomebody(type); - } else if (type == V4_BREAK_ON_SIGNAL) { - QByteArray signal; - bool enabled; - ms >> signal >> enabled; - //Normalize to lower case. - QString signalName(QString::fromUtf8(signal).toLower()); - if (enabled) - breakOnSignals.append(signalName); - else - breakOnSignals.removeOne(signalName); - } else if (type == "v8request") { - handleV8Request(payload); - } else if (type == V4_DISCONNECT) { - TRACE_PROTOCOL(qDebug() << "... payload:" << payload.constData()); - handleV8Request(payload); - } else { - sendSomethingToSomebody(type, 0); - } - } -} - -void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNumber) -{ - QByteArray response; - QQmlDebugStream rs(&response, QIODevice::WriteOnly); - rs << QByteArray(type) - << QByteArray::number(version) << QByteArray::number(magicNumber); - emit messageToClient(name(), packMessage(type, response)); -} - -QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService) - : debugService(debugService) -{} - -QV4::Debugging::Debugger *QV4DebuggerAgent::firstDebugger() const -{ - // Currently only 1 single engine is supported, so: - if (m_debuggers.isEmpty()) - return 0; - else - return m_debuggers.first(); -} - -bool QV4DebuggerAgent::isRunning() const -{ - // Currently only 1 single engine is supported, so: - if (QV4::Debugging::Debugger *debugger = firstDebugger()) - return debugger->state() == QV4::Debugging::Debugger::Running; - else - return false; -} - -void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::Debugger *debugger, QV4::Debugging::PauseReason reason) -{ - Q_UNUSED(reason); - - debugService->clearHandles(debugger->engine()); - - QJsonObject event, body, script; - event.insert(QStringLiteral("type"), QStringLiteral("event")); - - switch (reason) { - case QV4::Debugging::Step: - case QV4::Debugging::PauseRequest: - case QV4::Debugging::BreakPoint: { - event.insert(QStringLiteral("event"), QStringLiteral("break")); - QVector<QV4::StackFrame> frames = debugger->stackTrace(1); - if (frames.isEmpty()) - break; - - const QV4::StackFrame &topFrame = frames.first(); - body.insert(QStringLiteral("invocationText"), topFrame.function); - body.insert(QStringLiteral("sourceLine"), topFrame.line - 1); - if (topFrame.column > 0) - body.insert(QStringLiteral("sourceColumn"), topFrame.column); - QJsonArray breakPoints; - foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line)) - breakPoints.push_back(breakPointId); - body.insert(QStringLiteral("breakpoints"), breakPoints); - script.insert(QStringLiteral("name"), topFrame.source); - } break; - case QV4::Debugging::Throwing: - // TODO: complete this! - event.insert(QStringLiteral("event"), QStringLiteral("exception")); - break; - } - - if (!script.isEmpty()) - body.insert(QStringLiteral("script"), script); - if (!body.isEmpty()) - event.insert(QStringLiteral("body"), body); - debugService->send(event); -} - -void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, int requestSequenceNr) -{ - QJsonArray body; - foreach (const QString &source, sources) { - QJsonObject src; - src[QLatin1String("name")] = source; - src[QLatin1String("scriptType")] = 4; - body.append(src); - } - - QJsonObject response; - response[QLatin1String("success")] = true; - response[QLatin1String("running")] = debugger->state() == QV4::Debugging::Debugger::Running; - response[QLatin1String("body")] = body; - response[QLatin1String("command")] = QStringLiteral("scripts"); - response[QLatin1String("request_seq")] = requestSequenceNr; - response[QLatin1String("type")] = QStringLiteral("response"); - debugService->send(response); -} - -void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) -{ - TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload.constData()); - - QJsonDocument request = QJsonDocument::fromJson(payload); - QJsonObject o = request.object(); - QJsonValue type = o.value(QStringLiteral("type")); - if (type.toString() == QStringLiteral("request")) { - QJsonValue command = o.value(QStringLiteral("command")); - V8CommandHandler *h = v8CommandHandler(command.toString()); - if (h) - h->handle(o, this); - } -} - -QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QByteArray &message) -{ - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - static const QByteArray cmd("V8DEBUG"); - rs << cmd << command << message; - return reply; -} - -void QV4DebugServiceImpl::send(QJsonObject v8Payload) -{ - v8Payload[QLatin1String("seq")] = sequence++; - QJsonDocument doc; - doc.setObject(v8Payload); -#ifdef NO_PROTOCOL_TRACING - QByteArray responseData = doc.toJson(QJsonDocument::Compact); -#else - QByteArray responseData = doc.toJson(QJsonDocument::Indented); -#endif - - TRACE_PROTOCOL(qDebug() << "sending response for:" << responseData.constData() << endl); - - emit messageToClient(name(), packMessage("v8message", responseData)); -} - -void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine) -{ - theCollector.reset(new VariableCollector(engine)); -} - -QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4::Debugging::Debugger *debugger) -{ - QJsonObject frame; - frame[QLatin1String("index")] = frameNr; - frame[QLatin1String("debuggerFrame")] = false; - frame[QLatin1String("func")] = theCollector->addFunctionRef(stackFrame.function); - frame[QLatin1String("script")] = theCollector->addScriptRef(stackFrame.source); - frame[QLatin1String("line")] = stackFrame.line - 1; - if (stackFrame.column >= 0) - frame[QLatin1String("column")] = stackFrame.column; - - QJsonArray properties; - theCollector->setDestination(&properties); - if (debugger->collectThisInContext(theCollector.data(), frameNr)) { - QJsonObject obj; - obj[QLatin1String("properties")] = properties; - frame[QLatin1String("receiver")] = theCollector->addObjectRef(obj, false); - } - - QJsonArray scopes; - // Only type and index are used by Qt Creator, so we keep it easy: - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) { - int type = encodeScopeType(scopeTypes[i]); - if (type == -1) - continue; - - QJsonObject scope; - scope[QLatin1String("index")] = i; - scope[QLatin1String("type")] = type; - scopes.push_back(scope); - } - frame[QLatin1String("scopes")] = scopes; - - return frame; -} - -int QV4DebugServiceImpl::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType) -{ - switch (scopeType) { - case QV4::Heap::ExecutionContext::Type_GlobalContext: - return 0; - break; - case QV4::Heap::ExecutionContext::Type_CatchContext: - return 4; - break; - case QV4::Heap::ExecutionContext::Type_WithContext: - return 2; - break; - case QV4::Heap::ExecutionContext::Type_SimpleCallContext: - case QV4::Heap::ExecutionContext::Type_CallContext: - return 1; - break; - case QV4::Heap::ExecutionContext::Type_QmlContext: - default: - return -1; - } -} - -QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, - QV4::Debugging::Debugger *debugger) -{ - QJsonObject scope; - - QJsonArray properties; - theCollector->collectScope(&properties, debugger, frameNr, scopeNr); - - QJsonObject anonymous; - anonymous[QLatin1String("properties")] = properties; - - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr); - scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]); - scope[QLatin1String("index")] = scopeNr; - scope[QLatin1String("frameIndex")] = frameNr; - scope[QLatin1String("object")] = theCollector->addObjectRef(anonymous, true); - - return scope; -} - -QJsonValue QV4DebugServiceImpl::lookup(int refId) const -{ - return theCollector->lookup(refId); -} - -QJsonArray QV4DebugServiceImpl::buildRefs() -{ - return theCollector->retrieveRefsToInclude(); -} - -VariableCollector *QV4DebugServiceImpl::collector() const -{ - return theCollector.data(); -} - -void QV4DebugServiceImpl::selectFrame(int frameNr) -{ - theSelectedFrame = frameNr; -} - -int QV4DebugServiceImpl::selectedFrame() const -{ - return theSelectedFrame; -} - -QT_END_NAMESPACE diff --git a/src/qml/debugger/qv4debugservice_p.h b/src/qml/debugger/qv4debugservice_p.h deleted file mode 100644 index fee0e0ac89..0000000000 --- a/src/qml/debugger/qv4debugservice_p.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QV4DEBUGSERVICE_P_H -#define QV4DEBUGSERVICE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qqmlconfigurabledebugservice_p.h" -#include "qqmldebugserviceinterfaces_p.h" -#include <private/qv4debugging_p.h> - -#include <QtCore/QJsonValue> - -QT_BEGIN_NAMESPACE - -namespace QV4 { struct ExecutionEngine; } - -class QQmlEngine; -class VariableCollector; -class V8CommandHandler; -class UnknownV8CommandHandler; -class QV4DebugServiceImpl; - -class QV4DebuggerAgent : public QV4::Debugging::DebuggerAgent -{ - Q_OBJECT -public: - QV4DebuggerAgent(QV4DebugServiceImpl *debugService); - QV4::Debugging::Debugger *firstDebugger() const; - bool isRunning() const; - -public slots: - virtual void debuggerPaused(QV4::Debugging::Debugger *debugger, - QV4::Debugging::PauseReason reason); - virtual void sourcesCollected(QV4::Debugging::Debugger *debugger, QStringList sources, - int requestSequenceNr); - -private: - QV4DebugServiceImpl *debugService; -}; - -class QV4DebugServiceImpl : public QQmlConfigurableDebugService<QV4DebugService> -{ - Q_OBJECT -public: - explicit QV4DebugServiceImpl(QObject *parent = 0); - ~QV4DebugServiceImpl(); - - static QV4DebugServiceImpl *instance(); - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); - - void signalEmitted(const QString &signal); - void send(QJsonObject v8Payload); - - QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::Debugger *debugger); - QJsonArray buildRefs(); - QJsonValue lookup(int refId) const; - - QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, - QV4::Debugging::Debugger *debugger); - int selectedFrame() const; - void selectFrame(int frameNr); - - void clearHandles(QV4::ExecutionEngine *engine); - - VariableCollector *collector() const; - QV4DebuggerAgent debuggerAgent; - -protected: - void messageReceived(const QByteArray &); - void sendSomethingToSomebody(const char *type, int magicNumber = 1); - -private: - void handleV8Request(const QByteArray &payload); - static QByteArray packMessage(const QByteArray &command, - const QByteArray &message = QByteArray()); - void processCommand(const QByteArray &command, const QByteArray &data); - V8CommandHandler *v8CommandHandler(const QString &command) const; - int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); - - QStringList breakOnSignals; - QMap<int, QV4::Debugging::Debugger *> debuggerMap; - static int debuggerIndex; - static int sequence; - const int version; - - QScopedPointer<VariableCollector> theCollector; - int theSelectedFrame; - - void addHandler(V8CommandHandler* handler); - QHash<QString, V8CommandHandler*> handlers; - QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler; -}; - -QT_END_NAMESPACE - -#endif // QV4DEBUGSERVICE_P_H |