diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger')
13 files changed, 79 insertions, 1162 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp deleted file mode 100644 index b0f59717ac..0000000000 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdebugmessageservice.h" -#include "qqmldebugpacket.h" -#include <private/qqmldebugconnector_p.h> - -QT_BEGIN_NAMESPACE - -void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf) -{ - QQmlDebugConnector::service<QDebugMessageServiceImpl>()->sendDebugMessage(type, ctxt, buf); -} - -QDebugMessageServiceImpl::QDebugMessageServiceImpl(QObject *parent) : - QDebugMessageService(2, parent), oldMsgHandler(0), - prevState(QQmlDebugService::NotConnected) -{ - // don't execute stateChanged() in parallel - QMutexLocker lock(&initMutex); - timer.start(); - if (state() == Enabled) { - oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); - prevState = Enabled; - } -} - -void QDebugMessageServiceImpl::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. - QQmlDebugPacket ws; - ws << QByteArray("MESSAGE") << int(type) << buf.toUtf8(); - ws << QByteArray(ctxt.file) << ctxt.line << QByteArray(ctxt.function); - ws << QByteArray(ctxt.category) << timer.nsecsElapsed(); - - emit messageToClient(name(), ws.data()); - if (oldMsgHandler) - (*oldMsgHandler)(type, ctxt, buf); -} - -void QDebugMessageServiceImpl::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; -} - -void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer) -{ - QMutexLocker lock(&initMutex); - timer = otherTimer; -} - -QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h deleted file mode 100644 index c25e756c2d..0000000000 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDEBUGMESSAGESERVICE_H -#define QDEBUGMESSAGESERVICE_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/qqmldebugserviceinterfaces_p.h> - -#include <QtCore/qlogging.h> -#include <QtCore/qmutex.h> -#include <QtCore/qelapsedtimer.h> - -QT_BEGIN_NAMESPACE - -class QDebugMessageServicePrivate; - -class QDebugMessageServiceImpl : public QDebugMessageService -{ - Q_OBJECT -public: - QDebugMessageServiceImpl(QObject *parent = 0); - - void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf); - void synchronizeTime(const QElapsedTimer &otherTimer); - -protected: - void stateChanged(State); - -private: - friend class QQmlDebuggerServiceFactory; - - QtMessageHandler oldMsgHandler; - QQmlDebugService::State prevState; - QMutex initMutex; - QElapsedTimer timer; -}; - -QT_END_NAMESPACE - -#endif // QDEBUGMESSAGESERVICE_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index 27b3a5b513..f3f8a21ff8 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -2,10 +2,8 @@ TARGET = qmldbg_debugger QT = qml-private core-private packetprotocol-private SOURCES += \ - $$PWD/qdebugmessageservice.cpp \ $$PWD/qqmldebuggerservicefactory.cpp \ $$PWD/qqmlenginedebugservice.cpp \ - $$PWD/qqmlnativedebugservice.cpp \ $$PWD/qqmlwatcher.cpp \ $$PWD/qv4debugservice.cpp \ $$PWD/qv4debugger.cpp \ @@ -16,10 +14,8 @@ SOURCES += \ HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ $$PWD/../shared/qqmldebugpacket.h \ - $$PWD/qdebugmessageservice.h \ $$PWD/qqmldebuggerservicefactory.h \ $$PWD/qqmlenginedebugservice.h \ - $$PWD/qqmlnativedebugservice.h \ $$PWD/qqmlwatcher.h \ $$PWD/qv4debugservice.h \ $$PWD/qv4debugger.h \ diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json index 967a725903..442d7781a1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json @@ -1,3 +1,3 @@ { - "Keys": [ "DebugMessages", "QmlDebugger", "V8Debugger", "NativeQmlDebugger" ] + "Keys": [ "QmlDebugger", "V8Debugger" ] } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index ca3f07323d..9315adf4ce 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -39,27 +39,19 @@ #include "qqmldebuggerservicefactory.h" #include "qqmlenginedebugservice.h" -#include "qdebugmessageservice.h" #include "qv4debugservice.h" -#include "qqmlnativedebugservice.h" #include <private/qqmldebugserviceinterfaces_p.h> QT_BEGIN_NAMESPACE QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) { - if (key == QDebugMessageServiceImpl::s_key) - return new QDebugMessageServiceImpl(this); - if (key == QQmlEngineDebugServiceImpl::s_key) return new QQmlEngineDebugServiceImpl(this); if (key == QV4DebugServiceImpl::s_key) return new QV4DebugServiceImpl(this); - if (key == QQmlNativeDebugServiceImpl::s_key) - return new QQmlNativeDebugServiceImpl(this); - return 0; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h index 99d6679833..50eed2369c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h @@ -49,7 +49,7 @@ class QQmlDebuggerServiceFactory : public QQmlDebugServiceFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmldebuggerservice.json") public: - QQmlDebugService *create(const QString &key); + QQmlDebugService *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 2b8dcc19ee..151e44c4d4 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -289,10 +289,12 @@ void QQmlEngineDebugServiceImpl::buildObjectDump(QDataStream &message, 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); + const QByteArray methodName = QMetaObjectPrivate::signal(scope->metaObject(), + signalHandler->signalIndex()).name(); + const QLatin1String methodNameStr(methodName); + if (methodNameStr.size() != 0) { + prop.name = QLatin1String("on") + QChar(methodNameStr.at(0)).toUpper() + + methodNameStr.mid(1); } } } @@ -520,12 +522,12 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) ds >> file >> lineNumber >> columnNumber >> recurse >> dumpProperties; - QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber); + const QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber); rs << QByteArray("FETCH_OBJECTS_FOR_LOCATION_R") << queryId << objects.count(); - foreach (QObject *object, objects) { + for (QObject *object : objects) { if (recurse) prepareDeferredObjects(object); buildObjectDump(rs, object, recurse, dumpProperties); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp deleted file mode 100644 index 14dfc5356e..0000000000 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ /dev/null @@ -1,800 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlnativedebugservice.h" -#include "qqmldebugpacket.h" - -#include <private/qqmldebugconnector_p.h> -#include <private/qv4debugging_p.h> -#include <private/qv8engine_p.h> -#include <private/qv4engine_p.h> -#include <private/qv4debugging_p.h> -#include <private/qv4script_p.h> -#include <private/qv4string_p.h> -#include <private/qv4objectiterator_p.h> -#include <private/qv4identifier_p.h> -#include <private/qv4runtime_p.h> -#include <private/qv4isel_moth_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> - -#include <QtQml/qjsengine.h> -#include <QtCore/qjsonarray.h> -#include <QtCore/qjsondocument.h> -#include <QtCore/qjsonobject.h> -#include <QtCore/qjsonvalue.h> -#include <QtCore/qvector.h> -#include <QtCore/qpointer.h> - -//#define TRACE_PROTOCOL(s) qDebug() << s -#define TRACE_PROTOCOL(s) - -QT_BEGIN_NAMESPACE - -class BreakPoint -{ -public: - BreakPoint() : id(-1), lineNumber(-1), enabled(false), ignoreCount(0), hitCount(0) {} - bool isValid() const { return lineNumber >= 0 && !fileName.isEmpty(); } - - int id; - int lineNumber; - QString fileName; - bool enabled; - QString condition; - int ignoreCount; - - int hitCount; -}; - -inline uint qHash(const BreakPoint &b, uint seed = 0) Q_DECL_NOTHROW -{ - return qHash(b.fileName, seed) ^ b.lineNumber; -} - -inline bool operator==(const BreakPoint &a, const BreakPoint &b) -{ - return a.lineNumber == b.lineNumber && a.fileName == b.fileName - && a.enabled == b.enabled && a.condition == b.condition - && a.ignoreCount == b.ignoreCount; -} - -static void setError(QJsonObject *response, const QString &msg) -{ - response->insert(QStringLiteral("type"), QStringLiteral("error")); - response->insert(QStringLiteral("msg"), msg); -} - -class NativeDebugger; - -class Collector -{ -public: - Collector(QV4::ExecutionEngine *engine) - : m_engine(engine), m_anonCount(0) - {} - - void collect(QJsonArray *output, const QString &parentIName, const QString &name, - const QV4::Value &value); - - bool isExpanded(const QString &iname) const { return m_expanded.contains(iname); } - -public: - QV4::ExecutionEngine *m_engine; - int m_anonCount; - QStringList m_expanded; -}; - -// Encapsulate Breakpoint handling -// Could be made per-NativeDebugger (i.e. per execution engine, if needed) -class BreakPointHandler -{ -public: - BreakPointHandler() : m_haveBreakPoints(false), m_breakOnThrow(true), m_lastBreakpoint(1) {} - - void handleSetBreakpoint(QJsonObject *response, const QJsonObject &arguments); - void handleRemoveBreakpoint(QJsonObject *response, const QJsonObject &arguments); - - void removeBreakPoint(int id); - void enableBreakPoint(int id, bool onoff); - - void setBreakOnThrow(bool onoff); - bool m_haveBreakPoints; - bool m_breakOnThrow; - int m_lastBreakpoint; - QVector<BreakPoint> m_breakPoints; -}; - -void BreakPointHandler::handleSetBreakpoint(QJsonObject *response, const QJsonObject &arguments) -{ - TRACE_PROTOCOL("SET BREAKPOINT" << arguments); - QString type = arguments.value(QLatin1String("type")).toString(); - - QString fileName = arguments.value(QLatin1String("file")).toString(); - if (fileName.isEmpty()) { - setError(response, QStringLiteral("breakpoint has no file name")); - return; - } - - int line = arguments.value(QLatin1String("line")).toInt(-1); - if (line < 0) { - setError(response, QStringLiteral("breakpoint has an invalid line number")); - return; - } - - BreakPoint bp; - bp.id = m_lastBreakpoint++; - bp.fileName = fileName.mid(fileName.lastIndexOf('/') + 1); - bp.lineNumber = line; - bp.enabled = arguments.value(QLatin1String("enabled")).toBool(true); - bp.condition = arguments.value(QLatin1String("condition")).toString(); - bp.ignoreCount = arguments.value(QLatin1String("ignorecount")).toInt(); - m_breakPoints.append(bp); - - m_haveBreakPoints = true; - - response->insert(QStringLiteral("type"), type); - response->insert(QStringLiteral("breakpoint"), bp.id); -} - -void BreakPointHandler::handleRemoveBreakpoint(QJsonObject *response, const QJsonObject &arguments) -{ - int id = arguments.value(QLatin1String("id")).toInt(); - removeBreakPoint(id); - response->insert(QStringLiteral("id"), id); -} - -class NativeDebugger : public QV4::Debugging::Debugger -{ -public: - NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine); - - void signalEmitted(const QString &signal); - - QV4::ExecutionEngine *engine() const { return m_engine; } - - bool pauseAtNextOpportunity() const Q_DECL_OVERRIDE { - return m_pauseRequested - || m_service->m_breakHandler->m_haveBreakPoints - || m_stepping >= StepOver; - } - - void maybeBreakAtInstruction() Q_DECL_OVERRIDE; - void enteringFunction() Q_DECL_OVERRIDE; - void leavingFunction(const QV4::ReturnedValue &retVal) Q_DECL_OVERRIDE; - void aboutToThrow() Q_DECL_OVERRIDE; - - void handleCommand(QJsonObject *response, const QString &cmd, const QJsonObject &arguments); - -private: - void handleBacktrace(QJsonObject *response, const QJsonObject &arguments); - void handleVariables(QJsonObject *response, const QJsonObject &arguments); - void handleExpressions(QJsonObject *response, const QJsonObject &arguments); - - void handleDebuggerDeleted(QObject *debugger); - - void evaluateExpression(QV4::Scope &scope, const QString &expression); - bool checkCondition(const QString &expression); - - QStringList breakOnSignals; - - enum Speed { - NotStepping = 0, - StepOut, - StepOver, - StepIn, - }; - - void pauseAndWait(); - void pause(); - void handleContinue(QJsonObject *reponse, Speed speed); - - QV4::Function *getFunction() const; - - bool reallyHitTheBreakPoint(const QV4::Function *function, int lineNumber); - - QV4::ExecutionEngine *m_engine; - QQmlNativeDebugServiceImpl *m_service; - QV4::PersistentValue m_currentContext; - Speed m_stepping; - bool m_pauseRequested; - bool m_runningJob; - - QV4::PersistentValue m_returnedValue; -}; - -bool NativeDebugger::checkCondition(const QString &expression) -{ - QV4::Scope scope(m_engine); - evaluateExpression(scope, expression); - return scope.result.booleanValue(); -} - -void NativeDebugger::evaluateExpression(QV4::Scope &scope, const QString &expression) -{ - m_runningJob = true; - - QV4::ExecutionContextSaver saver(scope); - - QV4::ExecutionContext *ctx = m_engine->currentContext; - m_engine->pushContext(ctx); - - QV4::Script script(ctx, expression); - script.strictMode = ctx->d()->strictMode; - // In order for property lookups in QML to work, we need to disable fast v4 lookups. - // That is a side-effect of inheritContext. - script.inheritContext = true; - script.parse(); - if (!m_engine->hasException) - scope.result = script.run(); - - m_runningJob = false; -} - -NativeDebugger::NativeDebugger(QQmlNativeDebugServiceImpl *service, QV4::ExecutionEngine *engine) - : m_returnedValue(engine, QV4::Primitive::undefinedValue()) -{ - m_stepping = NotStepping; - m_pauseRequested = false; - m_runningJob = false; - m_service = service; - m_engine = engine; - TRACE_PROTOCOL("Creating native debugger"); -} - -void NativeDebugger::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 NativeDebugger::handleCommand(QJsonObject *response, const QString &cmd, - const QJsonObject &arguments) -{ - if (cmd == QLatin1String("backtrace")) - handleBacktrace(response, arguments); - else if (cmd == QLatin1String("variables")) - handleVariables(response, arguments); - else if (cmd == QLatin1String("expressions")) - handleExpressions(response, arguments); - else if (cmd == QLatin1String("stepin")) - handleContinue(response, StepIn); - else if (cmd == QLatin1String("stepout")) - handleContinue(response, StepOut); - else if (cmd == QLatin1String("stepover")) - handleContinue(response, StepOver); - else if (cmd == QLatin1String("continue")) - handleContinue(response, NotStepping); -} - -static QString encodeContext(QV4::ExecutionContext *executionContext) -{ - QQmlDebugPacket ds; - ds << quintptr(executionContext); - return QString::fromLatin1(ds.data().toHex()); -} - -static void decodeContext(const QString &context, QV4::ExecutionContext **executionContext) -{ - quintptr rawContext; - QQmlDebugPacket ds(QByteArray::fromHex(context.toLatin1())); - ds >> rawContext; - *executionContext = reinterpret_cast<QV4::ExecutionContext *>(rawContext); -} - -void NativeDebugger::handleBacktrace(QJsonObject *response, const QJsonObject &arguments) -{ - int limit = arguments.value(QLatin1String("limit")).toInt(0); - - QJsonArray frameArray; - QV4::ExecutionContext *executionContext = m_engine->currentContext; - for (int i = 0; i < limit && executionContext; ++i) { - if (QV4::Function *function = executionContext->getFunction()) { - - QJsonObject frame; - frame[QStringLiteral("language")] = QStringLiteral("js"); - frame[QStringLiteral("context")] = encodeContext(executionContext); - - if (QV4::Heap::String *functionName = function->name()) - frame[QStringLiteral("function")] = functionName->toQString(); - frame[QStringLiteral("file")] = function->sourceFile(); - - int line = executionContext->d()->lineNumber; - frame[QStringLiteral("line")] = (line < 0 ? -line : line); - - frameArray.push_back(frame); - } - - executionContext = m_engine->parentContext(executionContext); - } - - response->insert(QStringLiteral("frames"), frameArray); -} - -void Collector::collect(QJsonArray *out, const QString &parentIName, const QString &name, - const QV4::Value &value) -{ - QJsonObject dict; - QV4::Scope scope(m_engine); - - QString nonEmptyName = name.isEmpty() ? QString::fromLatin1("@%1").arg(m_anonCount++) : name; - QString iname = parentIName + QLatin1Char('.') + nonEmptyName; - dict.insert(QStringLiteral("iname"), iname); - dict.insert(QStringLiteral("name"), nonEmptyName); - - QV4::ScopedValue typeString(scope, QV4::Runtime::method_typeofValue(m_engine, value)); - dict.insert(QStringLiteral("type"), typeString->toQStringNoThrow()); - - switch (value.type()) { - case QV4::Value::Empty_Type: - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("empty")); - dict.insert(QStringLiteral("haschild"), false); - break; - case QV4::Value::Undefined_Type: - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("undefined")); - dict.insert(QStringLiteral("haschild"), false); - break; - case QV4::Value::Null_Type: - dict.insert(QStringLiteral("type"), QStringLiteral("object")); - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("null")); - dict.insert(QStringLiteral("haschild"), false); - break; - case QV4::Value::Boolean_Type: - dict.insert(QStringLiteral("value"), value.booleanValue()); - dict.insert(QStringLiteral("haschild"), false); - break; - case QV4::Value::Managed_Type: - if (const QV4::String *string = value.as<QV4::String>()) { - dict.insert(QStringLiteral("value"), string->toQStringNoThrow()); - dict.insert(QStringLiteral("haschild"), false); - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("utf16")); - dict.insert(QStringLiteral("quoted"), true); - } else if (const QV4::ArrayObject *array = value.as<QV4::ArrayObject>()) { - // The size of an array is number of its numerical properties. - // We don't consider free form object properties here. - const uint n = array->getLength(); - dict.insert(QStringLiteral("value"), qint64(n)); - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("itemcount")); - dict.insert(QStringLiteral("haschild"), qint64(n)); - if (isExpanded(iname)) { - QJsonArray children; - for (uint i = 0; i < n; ++i) { - QV4::ReturnedValue v = array->getIndexed(i); - QV4::ScopedValue sval(scope, v); - collect(&children, iname, QString::number(i), *sval); - } - dict.insert(QStringLiteral("children"), children); - } - } else if (const QV4::Object *object = value.as<QV4::Object>()) { - QJsonArray children; - bool expanded = isExpanded(iname); - qint64 numProperties = 0; - QV4::ObjectIterator it(scope, object, QV4::ObjectIterator::EnumerableOnly); - QV4::ScopedProperty p(scope); - QV4::ScopedString name(scope); - while (true) { - QV4::PropertyAttributes attrs; - uint index; - it.next(name.getRef(), &index, p, &attrs); - if (attrs.isEmpty()) - break; - if (name.getPointer()) { - ++numProperties; - if (expanded) { - if (name.getPointer()) { - QV4::Value v = p.property->value; - collect(&children, iname, name->toQStringNoThrow(), v); - } - } - } - } - dict.insert(QStringLiteral("value"), numProperties); - dict.insert(QStringLiteral("valueencoded"), QStringLiteral("itemcount")); - dict.insert(QStringLiteral("haschild"), numProperties > 0); - if (expanded) - dict.insert(QStringLiteral("children"), children); - } - break; - case QV4::Value::Integer_Type: - dict.insert(QStringLiteral("value"), value.integerValue()); - dict.insert(QStringLiteral("haschild"), false); - break; - default: // double - dict.insert(QStringLiteral("value"), value.doubleValue()); - dict.insert(QStringLiteral("haschild"), false); - } - - out->append(dict); -} - -void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &arguments) -{ - TRACE_PROTOCOL("Build variables"); - QV4::ExecutionContext *executionContext = 0; - decodeContext(arguments.value(QLatin1String("context")).toString(), &executionContext); - if (!executionContext) { - setError(response, QStringLiteral("No execution context passed")); - return; - } - TRACE_PROTOCOL("Context: " << executionContext); - - QV4::ExecutionEngine *engine = executionContext->d()->engine; - if (!engine) { - setError(response, QStringLiteral("No execution engine passed")); - return; - } - TRACE_PROTOCOL("Engine: " << engine); - - Collector collector(engine); - QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); - foreach (const QJsonValue &ex, expanded) - collector.m_expanded.append(ex.toString()); - TRACE_PROTOCOL("Expanded: " << collector.m_expanded); - - QJsonArray output; - QV4::Scope scope(engine); - - if (QV4::CallContext *callContext = executionContext->asCallContext()) { - QV4::Value thisObject = callContext->thisObject(); - collector.collect(&output, QString(), QStringLiteral("this"), thisObject); - QV4::Identifier *const *variables = callContext->variables(); - QV4::Identifier *const *formals = callContext->formals(); - for (unsigned i = 0, ei = callContext->variableCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = variables[i]) - qName = name->string; - QV4::Value val = callContext->d()->locals[i]; - collector.collect(&output, QString(), qName, val); - } - for (unsigned i = 0, ei = callContext->formalCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = formals[i]) - qName = name->string; - QV4::ReturnedValue rval = callContext->argument(i); - QV4::ScopedValue sval(scope, rval); - collector.collect(&output, QString(), qName, *sval); - } - } - - response->insert(QStringLiteral("variables"), output); -} - -void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject &arguments) -{ - TRACE_PROTOCOL("Evaluate expressions"); - QV4::ExecutionContext *executionContext = 0; - decodeContext(arguments.value(QLatin1String("context")).toString(), &executionContext); - if (!executionContext) { - setError(response, QStringLiteral("No execution context passed")); - return; - } - TRACE_PROTOCOL("Context: " << executionContext); - - QV4::ExecutionEngine *engine = executionContext->d()->engine; - if (!engine) { - setError(response, QStringLiteral("No execution engine passed")); - return; - } - TRACE_PROTOCOL("Engines: " << engine << m_engine); - - Collector collector(engine); - QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); - foreach (const QJsonValue &ex, expanded) - collector.m_expanded.append(ex.toString()); - TRACE_PROTOCOL("Expanded: " << collector.m_expanded); - - QJsonArray output; - QV4::Scope scope(engine); - - QJsonArray expressions = arguments.value(QLatin1String("expressions")).toArray(); - foreach (const QJsonValue &expr, expressions) { - QString expression = expr.toObject().value(QLatin1String("expression")).toString(); - QString name = expr.toObject().value(QLatin1String("name")).toString(); - TRACE_PROTOCOL("Evaluate expression: " << expression); - m_runningJob = true; - - evaluateExpression(scope, expression); - QV4::ScopedValue result(scope, scope.result); - - m_runningJob = false; - if (result->isUndefined()) { - QJsonObject dict; - dict[QStringLiteral("name")] = name; - dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined"); - output.append(dict); - } else if (result.ptr && result.ptr->rawValue()) { - collector.collect(&output, QString(), name, *result); - } else { - QJsonObject dict; - dict[QStringLiteral("name")] = name; - dict[QStringLiteral("valueencoded")] = QStringLiteral("notaccessible"); - output.append(dict); - } - TRACE_PROTOCOL("EXCEPTION: " << engine->hasException); - engine->hasException = false; - } - - response->insert(QStringLiteral("expressions"), output); -} - -void BreakPointHandler::removeBreakPoint(int id) -{ - for (int i = 0; i != m_breakPoints.size(); ++i) { - if (m_breakPoints.at(i).id == id) { - m_breakPoints.remove(i); - m_haveBreakPoints = !m_breakPoints.isEmpty(); - return; - } - } -} - -void BreakPointHandler::enableBreakPoint(int id, bool enabled) -{ - m_breakPoints[id].enabled = enabled; -} - -void NativeDebugger::pause() -{ - m_pauseRequested = true; -} - -void NativeDebugger::handleContinue(QJsonObject *response, Speed speed) -{ - Q_UNUSED(response); - - if (!m_returnedValue.isUndefined()) - m_returnedValue.set(m_engine, QV4::Encode::undefined()); - - m_currentContext.set(m_engine, *m_engine->currentContext); - m_stepping = speed; -} - -void NativeDebugger::maybeBreakAtInstruction() -{ - if (m_runningJob) // do not re-enter when we're doing a job for the debugger. - return; - - if (m_stepping == StepOver) { - if (m_currentContext.asManaged()->d() == m_engine->current) - pauseAndWait(); - return; - } - - if (m_stepping == StepIn) { - pauseAndWait(); - return; - } - - if (m_pauseRequested) { // Serve debugging requests from the agent - m_pauseRequested = false; - pauseAndWait(); - return; - } - - if (m_service->m_breakHandler->m_haveBreakPoints) { - if (QV4::Function *function = getFunction()) { - const int lineNumber = m_engine->current->lineNumber; - if (reallyHitTheBreakPoint(function, lineNumber)) - pauseAndWait(); - } - } -} - -void NativeDebugger::enteringFunction() -{ - if (m_runningJob) - return; - - if (m_stepping == StepIn) { - m_currentContext.set(m_engine, *m_engine->currentContext); - } -} - -void NativeDebugger::leavingFunction(const QV4::ReturnedValue &retVal) -{ - if (m_runningJob) - return; - - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { - m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); - m_stepping = StepOver; - m_returnedValue.set(m_engine, retVal); - } -} - -void NativeDebugger::aboutToThrow() -{ - if (!m_service->m_breakHandler->m_breakOnThrow) - return; - - if (m_runningJob) // do not re-enter when we're doing a job for the debugger. - return; - - QJsonObject event; - // TODO: complete this! - event.insert(QStringLiteral("event"), QStringLiteral("exception")); - m_service->emitAsynchronousMessageToClient(event); -} - -QV4::Function *NativeDebugger::getFunction() const -{ - QV4::ExecutionContext *context = m_engine->currentContext; - if (QV4::Function *function = context->getFunction()) - return function; - else - return context->d()->engine->globalCode; -} - -void NativeDebugger::pauseAndWait() -{ - QJsonObject event; - - event.insert(QStringLiteral("event"), QStringLiteral("break")); - event.insert(QStringLiteral("language"), QStringLiteral("js")); - if (QV4::ExecutionContext *executionContext = m_engine->currentContext) { - if (QV4::Function *function = executionContext->getFunction()) { - event.insert(QStringLiteral("file"), function->sourceFile()); - int line = executionContext->d()->lineNumber; - event.insert(QStringLiteral("line"), (line < 0 ? -line : line)); - } - } - - m_service->emitAsynchronousMessageToClient(event); -} - -bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int lineNumber) -{ - for (int i = 0, n = m_service->m_breakHandler->m_breakPoints.size(); i != n; ++i) { - const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i); - if (bp.lineNumber == lineNumber) { - const QString fileName = function->sourceFile(); - const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1); - if (bp.fileName.endsWith(base)) { - if (bp.condition.isEmpty() || checkCondition(bp.condition)) { - BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i]; - ++mbp.hitCount; - if (mbp.hitCount > mbp.ignoreCount) - return true; - } - } - } - } - return false; -} - -QQmlNativeDebugServiceImpl::QQmlNativeDebugServiceImpl(QObject *parent) - : QQmlNativeDebugService(1.0, parent) -{ - m_breakHandler = new BreakPointHandler; -} - -QQmlNativeDebugServiceImpl::~QQmlNativeDebugServiceImpl() -{ - delete m_breakHandler; -} - -void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QJSEngine *engine) -{ - TRACE_PROTOCOL("Adding engine" << engine); - if (engine) { - QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); - TRACE_PROTOCOL("Adding execution engine" << ee); - if (ee) { - NativeDebugger *debugger = new NativeDebugger(this, ee); - ee->iselFactory.reset(new QV4::Moth::ISelFactory); - if (state() == Enabled) - ee->setDebugger(debugger); - m_debuggers.append(QPointer<NativeDebugger>(debugger)); - } - } - QQmlDebugService::engineAboutToBeAdded(engine); -} - -void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) -{ - TRACE_PROTOCOL("Removing engine" << engine); - if (engine) { - QV4::ExecutionEngine *executionEngine = QV8Engine::getV4(engine->handle()); - foreach (NativeDebugger *debugger, m_debuggers) { - if (debugger->engine() == executionEngine) - m_debuggers.removeAll(debugger); - } - } - QQmlDebugService::engineAboutToBeRemoved(engine); -} - -void QQmlNativeDebugServiceImpl::stateAboutToBeChanged(QQmlDebugService::State state) -{ - if (state == Enabled) { - foreach (NativeDebugger *debugger, m_debuggers) { - QV4::ExecutionEngine *engine = debugger->engine(); - if (!engine->debugger()) - engine->setDebugger(debugger); - } - } - QQmlDebugService::stateAboutToBeChanged(state); -} - -void QQmlNativeDebugServiceImpl::messageReceived(const QByteArray &message) -{ - TRACE_PROTOCOL("Native message received: " << message); - QJsonObject request = QJsonDocument::fromJson(message).object(); - QJsonObject response; - QJsonObject arguments = request.value(QLatin1String("arguments")).toObject(); - QString cmd = request.value(QLatin1String("command")).toString(); - - if (cmd == QLatin1String("setbreakpoint")) { - m_breakHandler->handleSetBreakpoint(&response, arguments); - } else if (cmd == QLatin1String("removebreakpoint")) { - m_breakHandler->handleRemoveBreakpoint(&response, arguments); - } else if (cmd == QLatin1String("echo")) { - response.insert(QStringLiteral("result"), arguments); - } else { - foreach (NativeDebugger *debugger, m_debuggers) - if (debugger) - debugger->handleCommand(&response, cmd, arguments); - } - QJsonDocument doc; - doc.setObject(response); - QByteArray ba = doc.toJson(QJsonDocument::Compact); - TRACE_PROTOCOL("Sending synchronous response:" << ba.constData() << endl); - emit messageToClient(s_key, ba); -} - -void QQmlNativeDebugServiceImpl::emitAsynchronousMessageToClient(const QJsonObject &message) -{ - QJsonDocument doc; - doc.setObject(message); - QByteArray ba = doc.toJson(QJsonDocument::Compact); - TRACE_PROTOCOL("Sending asynchronous message:" << ba.constData() << endl); - emit messageToClient(s_key, ba); -} - -QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h deleted file mode 100644 index 8015513f9e..0000000000 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQML_NATIVE_DEBUG_SERVICE_H -#define QQML_NATIVE_DEBUG_SERVICE_H - -#include <private/qqmldebugconnector_p.h> -#include <private/qv4debugging_p.h> -#include <private/qv8engine_p.h> -#include <private/qv4engine_p.h> -#include <private/qv4debugging_p.h> -#include <private/qv4script_p.h> -#include <private/qv4string_p.h> -#include <private/qv4objectiterator_p.h> -#include <private/qv4identifier_p.h> -#include <private/qv4runtime_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> - -#include <QtCore/qjsonarray.h> - -#include <qqmlengine.h> - -#include <QJsonArray> -#include <QJsonDocument> -#include <QJsonObject> -#include <QJsonValue> -#include <QVector> -#include <QPointer> - -QT_BEGIN_NAMESPACE - -class NativeDebugger; -class BreakPointHandler; -class QQmlDebuggerServiceFactory; - -class QQmlNativeDebugServiceImpl : public QQmlNativeDebugService -{ -public: - QQmlNativeDebugServiceImpl(QObject *parent); - - ~QQmlNativeDebugServiceImpl() Q_DECL_OVERRIDE; - - void engineAboutToBeAdded(QJSEngine *engine) Q_DECL_OVERRIDE; - void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - - void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; - - void messageReceived(const QByteArray &message) Q_DECL_OVERRIDE; - - void emitAsynchronousMessageToClient(const QJsonObject &message); - -private: - friend class QQmlDebuggerServiceFactory; - friend class NativeDebugger; - - QList<QPointer<NativeDebugger> > m_debuggers; - BreakPointHandler *m_breakHandler; -}; - -QT_END_NAMESPACE - -#endif // QQML_NATIVE_DEBUG_SERVICE_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index 756b6b28be..773bc937f5 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -52,7 +52,7 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService) QV4Debugger *QV4DebuggerAgent::pausedDebugger() const { - foreach (QV4Debugger *debugger, m_debuggers) { + for (QV4Debugger *debugger : m_debuggers) { if (debugger->state() == QV4Debugger::Paused) return debugger; } @@ -147,13 +147,13 @@ void QV4DebuggerAgent::pause(QV4Debugger *debugger) const void QV4DebuggerAgent::pauseAll() const { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : m_debuggers) pause(debugger); } void QV4DebuggerAgent::resumeAll() const { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : m_debuggers) if (debugger->state() == QV4Debugger::Paused) debugger->resume(QV4Debugger::FullThrottle); } @@ -161,7 +161,7 @@ void QV4DebuggerAgent::resumeAll() const int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition) { if (enabled) - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->addBreakPoint(fileName, lineNumber, condition); int id = m_breakPoints.size(); @@ -178,7 +178,7 @@ void QV4DebuggerAgent::removeBreakPoint(int id) m_breakPoints.remove(id); if (breakPoint.enabled) - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); } @@ -195,7 +195,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff) return; breakPoint.enabled = onoff; - foreach (QV4Debugger *debugger, m_debuggers) { + for (QV4Debugger *debugger : qAsConst(m_debuggers)) { if (onoff) debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); else @@ -218,14 +218,14 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff) { if (onoff != m_breakOnThrow) { m_breakOnThrow = onoff; - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->setBreakOnThrow(onoff); } } void QV4DebuggerAgent::clearAllPauseRequests() { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->clearPauseRequest(); } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index d5cc765ea8..df316c1ae6 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -43,6 +43,7 @@ #include <private/qqmlcontext_p.h> #include <private/qv4qmlcontext_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qqmldebugservice_p.h> #include <QtQml/qqmlengine.h> @@ -52,9 +53,10 @@ QV4DebugJob::~QV4DebugJob() { } -JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &script) : - engine(engine), frameNr(frameNr), script(script), resultIsException(false) +JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context, + const QString &script) : + engine(engine), frameNr(frameNr), context(context), script(script), + resultIsException(false) {} void JavaScriptJob::run() @@ -65,7 +67,23 @@ void JavaScriptJob::run() QV4::ExecutionContext *ctx = engine->currentContext; QObject scopeObject; - if (frameNr < 0) { // Use QML context if available + + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + ctx = engine->parentContext(ctx); + } + engine->pushContext(ctx); + ctx = engine->currentContext; + } + + if (context >= 0) { + QQmlContext *extraContext = qmlContext(QQmlDebugService::objectForId(context)); + if (extraContext) { + engine->pushContext(QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), + &scopeObject)); + ctx = engine->currentContext; + } + } else if (frameNr < 0) { // Use QML context if available QQmlEngine *qmlEngine = engine->qmlEngine(); if (qmlEngine) { QQmlContext *qmlRootContext = qmlEngine->rootContext(); @@ -89,13 +107,6 @@ void JavaScriptJob::run() engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); ctx = engine->currentContext; } - } else { - if (frameNr > 0) { - for (int i = 0; i < frameNr; ++i) { - ctx = engine->parentContext(ctx); - } - engine->pushContext(ctx); - } } QV4::Script script(ctx, this->script); @@ -206,7 +217,7 @@ void ValueLookupJob::run() QQmlContextData::get(engine->qmlEngine()->rootContext()), scopeObject.data())); } - foreach (const QJsonValue &handle, handles) { + for (const QJsonValue &handle : handles) { QV4DataCollector::Ref ref = handle.toInt(); if (!collector->isValidRef(ref)) { exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); @@ -225,8 +236,9 @@ const QString &ValueLookupJob::exceptionMessage() const } ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &expression, QV4DataCollector *collector) : - JavaScriptJob(engine, frameNr, expression), collector(collector) + int context, const QString &expression, + QV4DataCollector *collector) : + JavaScriptJob(engine, frameNr, context, expression), collector(collector) { } @@ -259,7 +271,7 @@ GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) void GatherSourcesJob::run() { - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + for (QV4::CompiledData::CompilationUnit *unit : qAsConst(engine->compilationUnits)) { QString fileName = unit->fileName(); if (!fileName.isEmpty()) sources.append(fileName); @@ -272,7 +284,7 @@ const QStringList &GatherSourcesJob::result() const } EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) : - JavaScriptJob(engine, /*frameNr*/-1, script), result(false) + JavaScriptJob(engine, /*frameNr*/-1, /*context*/ -1, script), result(false) {} void EvalJob::handleResult(QV4::ScopedValue &result) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h index 721f42b7c2..00d3e6206a 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -60,12 +60,13 @@ class JavaScriptJob : public QV4DebugJob { QV4::ExecutionEngine *engine; int frameNr; + int context; const QString &script; bool resultIsException; public: - JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); - void run(); + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context, const QString &script); + void run() override; bool hasExeption() const; protected: @@ -90,7 +91,7 @@ class BacktraceJob: public CollectJob int toFrame; public: BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); - void run(); + void run() override; }; class FrameJob: public CollectJob @@ -100,7 +101,7 @@ class FrameJob: public CollectJob public: FrameJob(QV4DataCollector *collector, int frameNr); - void run(); + void run() override; bool wasSuccessful() const; }; @@ -112,7 +113,7 @@ class ScopeJob: public CollectJob public: ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); - void run(); + void run() override; bool wasSuccessful() const; }; @@ -123,7 +124,7 @@ class ValueLookupJob: public CollectJob public: ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); - void run(); + void run() override; const QString &exceptionMessage() const; }; @@ -135,9 +136,9 @@ class ExpressionEvalJob: public JavaScriptJob QJsonArray collectedRefs; public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &value); + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context, + const QString &expression, QV4DataCollector *collector); + void handleResult(QV4::ScopedValue &value) override; const QString &exceptionMessage() const; const QJsonObject &returnValue() const; const QJsonArray &refs() const; @@ -150,7 +151,7 @@ class GatherSourcesJob: public QV4DebugJob public: GatherSourcesJob(QV4::ExecutionEngine *engine); - void run(); + void run() override; const QStringList &result() const; }; @@ -161,7 +162,7 @@ class EvalJob: public JavaScriptJob public: EvalJob(QV4::ExecutionEngine *engine, const QString &script); - virtual void handleResult(QV4::ScopedValue &result); + void handleResult(QV4::ScopedValue &result) override; bool resultAsBoolean() const; }; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 00c5c1ad77..1d2cc092dc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -152,7 +152,7 @@ class UnknownV8CommandHandler: public V8CommandHandler public: UnknownV8CommandHandler(): V8CommandHandler(QString()) {} - virtual void handleRequest() + void handleRequest() override { QString msg = QLatin1String("unimplemented command \"") + req.value(QLatin1String("command")).toString() @@ -167,7 +167,7 @@ class V8VersionRequest: public V8CommandHandler public: V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {} - virtual void handleRequest() + void handleRequest() override { addCommand(); addRequestSequence(); @@ -177,6 +177,7 @@ public: body.insert(QStringLiteral("V8Version"), QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); body.insert(QStringLiteral("UnpausedEvaluate"), true); + body.insert(QStringLiteral("ContextEvaluate"), true); addBody(body); } }; @@ -186,7 +187,7 @@ class V8SetBreakPointRequest: public V8CommandHandler public: V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject args = req.value(QLatin1String("arguments")).toObject(); @@ -237,7 +238,7 @@ class V8ClearBreakPointRequest: public V8CommandHandler public: V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject args = req.value(QLatin1String("arguments")).toObject(); @@ -270,7 +271,7 @@ class V8BacktraceRequest: public V8CommandHandler public: V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: @@ -303,7 +304,7 @@ class V8FrameRequest: public V8CommandHandler public: V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -345,7 +346,7 @@ class V8ScopeRequest: public V8CommandHandler public: V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -390,7 +391,7 @@ class V8LookupRequest: public V8CommandHandler public: V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -430,7 +431,7 @@ class V8ContinueRequest: public V8CommandHandler public: V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -476,7 +477,7 @@ class V8DisconnectRequest: public V8CommandHandler public: V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} - virtual void handleRequest() + void handleRequest() override { debugService->debuggerAgent.removeAllBreakPoints(); debugService->debuggerAgent.resumeAll(); @@ -494,7 +495,7 @@ class V8SetExceptionBreakRequest: public V8CommandHandler public: V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} - virtual void handleRequest() + void handleRequest() override { bool wasEnabled = debugService->debuggerAgent.breakOnThrow(); @@ -534,7 +535,7 @@ class V8ScriptsRequest: public V8CommandHandler public: V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} - virtual void handleRequest() + void handleRequest() override { //decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -558,7 +559,7 @@ public: debugger->runInEngine(&job); QJsonArray body; - foreach (const QString &source, job.result()) { + for (const QString &source : job.result()) { QJsonObject src; src[QLatin1String("name")] = source; src[QLatin1String("scriptType")] = 4; @@ -606,10 +607,11 @@ class V8EvaluateRequest: public V8CommandHandler public: V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {} - virtual void handleRequest() + void handleRequest() override { QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); QString expression = arguments.value(QLatin1String("expression")).toString(); + int context = arguments.value(QLatin1String("context")).toInt(-1); int frame = -1; QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); @@ -627,7 +629,8 @@ public: frame = arguments.value(QLatin1String("frame")).toInt(0); } - ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector()); + ExpressionEvalJob job(debugger->engine(), frame, context, expression, + debugger->collector()); debugger->runInEngine(&job); if (job.hasExeption()) { createErrorResponse(job.exceptionMessage()); @@ -718,7 +721,8 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state) { QMutexLocker lock(&m_configMutex); if (state == Enabled) { - foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) { + const auto debuggers = debuggerAgent.debuggers(); + for (QV4Debugger *debugger : debuggers) { QV4::ExecutionEngine *ee = debugger->engine(); if (!ee->debugger()) ee->setDebugger(debugger); @@ -737,7 +741,7 @@ void QV4DebugServiceImpl::signalEmitted(const QString &signal) //Normalize to Lower case. QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower(); - foreach (const QString &signal, breakOnSignals) { + for (const QString &signal : qAsConst(breakOnSignals)) { if (signal == signalName) { // TODO: pause debugger break; |