From 1d7243e72481478c8ce97dd0b5900661af0cab8d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 30 Nov 2015 14:15:54 +0100 Subject: [PATCH] Qml Debugger: Support "evaluate" while engine is running Newer versions of Qt can evaluate expressions without pausing the QML engine. We can take advantage of that. At the same time we can remove the crutch of using QQmlEngineDebugService for this. The latter produces inconsistent and generally worse results than the V4 debug service. Task-number: QTCREATORBUG-14931 Change-Id: Ic78d08a0b00cf7de3911b7b672ce229c6d779363 Reviewed-by: hjk --- src/plugins/debugger/console/console.h | 2 +- src/plugins/debugger/debuggerengine.cpp | 6 --- src/plugins/debugger/debuggerengine.h | 1 - src/plugins/debugger/qml/qmlengine.cpp | 55 ++++++++++--------------- src/plugins/debugger/qml/qmlengine.h | 1 - 5 files changed, 22 insertions(+), 43 deletions(-) diff --git a/src/plugins/debugger/console/console.h b/src/plugins/debugger/console/console.h index d9bd48289d0..89bd50e5ed7 100644 --- a/src/plugins/debugger/console/console.h +++ b/src/plugins/debugger/console/console.h @@ -49,7 +49,7 @@ namespace Utils { class SavedAction; } namespace Debugger { namespace Internal { -typedef std::function ScriptEvaluator; +typedef std::function ScriptEvaluator; class ConsoleItemModel; class ConsoleView; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index b9b8de63fe2..88b7a12b244 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1743,12 +1743,6 @@ void DebuggerEngine::executeDebuggerCommand(const QString &, DebuggerLanguages) showStatusMessage(tr("This debugger cannot handle user input.")); } -bool DebuggerEngine::evaluateScript(const QString &) -{ - showStatusMessage(tr("This debugger cannot handle user scripts.")); - return false; -} - BreakHandler *DebuggerEngine::breakHandler() const { return Internal::breakHandler(); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 09f4595e0b7..b48c5aa44cc 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -262,7 +262,6 @@ public: virtual bool acceptsDebuggerCommands() const { return true; } virtual void executeDebuggerCommand(const QString &command, DebuggerLanguages languages); - virtual bool evaluateScript(const QString &expression); virtual void assignValueInDebugger(WatchItem *item, const QString &expr, const QVariant &value); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index d642c49c396..32d6bd2bfca 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -213,6 +213,7 @@ public: QList queryIds; bool retryOnConnectFail = false; bool automaticConnect = false; + bool unpausedEvaluate = false; QTimer connectionTimer; QmlDebug::QmlDebugConnection *connection; @@ -282,8 +283,8 @@ QmlEngine::QmlEngine(const DebuggerRunParameters &startParameters, DebuggerEngin d->automaticConnect = true; } - debuggerConsole()->setScriptEvaluator([this](const QString &expr) -> bool { - return evaluateScript(expr); + debuggerConsole()->setScriptEvaluator([this](const QString &expr) { + executeDebuggerCommand(expr, QmlLanguage); }); d->connectionTimer.setInterval(4000); @@ -1116,37 +1117,23 @@ void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages if (!(languages & QmlLanguage)) return; - StackHandler *handler = stackHandler(); - if (handler->isContentsValid() && handler->currentFrame().isUsable()) { + if (state() == InferiorStopOk) { + StackHandler *handler = stackHandler(); + if (handler->isContentsValid() && handler->currentFrame().isUsable()) { + d->evaluate(command, CB(d->handleExecuteDebuggerCommand)); + } else { + // Paused but no stack? Something is wrong + d->engine->showMessage(_("Cannot evaluate %1. The stack trace is broken.").arg(command), + ConsoleOutput); + } + } else if (d->unpausedEvaluate) { d->evaluate(command, CB(d->handleExecuteDebuggerCommand)); } else { - //Currently cannot evaluate if not in a javascript break - d->engine->showMessage(QString(_("Cannot evaluate %1 in current stack frame")).arg( - command), ConsoleOutput); + d->engine->showMessage(_("The application has to be paused in order to evaluate " + "expressions").arg(command), ConsoleOutput); } } -bool QmlEngine::evaluateScript(const QString &expression) -{ - bool didEvaluate = true; - // Evaluate expression based on engine state - // When engine->state() == InferiorStopOk, the expression is sent to debuggerClient. - if (state() != InferiorStopOk) { - QModelIndex currentIndex = inspectorView()->currentIndex(); - quint32 queryId = d->inspectorAgent.queryExpressionResult - (watchHandler()->watchItem(currentIndex)->id, expression); - if (queryId) { - d->queryIds.append(queryId); - } else { - didEvaluate = false; - debuggerConsole()->printItem(ConsoleItem::ErrorType, _("Error evaluating expression.")); - } - } else { - executeDebuggerCommand(expression, QmlLanguage); - } - return didEvaluate; -} - void QmlEnginePrivate::updateScriptSource(const QString &fileName, int lineOffset, int columnOffset, const QString &source) { @@ -1330,12 +1317,14 @@ void QmlEnginePrivate::evaluate(const QString expr, const QmlCallback &cb) // The Qt side Q_ASSERTs otherwise. So ignore the request and hope // it will be repeated soon enough (which it will, e.g. in updateLocals) - QTC_ASSERT(engine->state() == InferiorStopOk, return); + QTC_ASSERT(unpausedEvaluate || engine->state() == InferiorStopOk, return); DebuggerCommand cmd(EVALUATE); cmd.arg(EXPRESSION, expr); - cmd.arg(FRAME, engine->stackHandler()->currentIndex()); + StackHandler *handler = engine->stackHandler(); + if (handler->currentFrame().isUsable()) + cmd.arg(FRAME, handler->currentIndex()); runCommand(cmd, cb); } @@ -2497,15 +2486,13 @@ void QmlEnginePrivate::stateChanged(State state) /// Start session. flushSendBuffer(); runDirectCommand(CONNECT); - runCommand({VERSION}); // Only used for logging. + runCommand({VERSION}, CB(handleVersion)); } } void QmlEnginePrivate::handleVersion(const QVariantMap &response) { - engine->showMessage(QString(_("Using V8 Version: %1")).arg( - response.value(_(BODY)).toMap(). - value(_("V8Version")).toString()), LogOutput); + unpausedEvaluate = response.value(_(BODY)).toMap().value(_("UnpausedEvaluate"), false).toBool(); } void QmlEnginePrivate::flushSendBuffer() diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 0fdccd5c52b..c0294939d0d 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -130,7 +130,6 @@ private: void expandItem(const QByteArray &iname) override; void selectWatchData(const QByteArray &iname) override; void executeDebuggerCommand(const QString &command, DebuggerLanguages languages) override; - bool evaluateScript(const QString &expression) override; bool hasCapability(unsigned) const override; void quitDebugger() override;