V4 debugger: Fix expression evaluation
authorUlf Hermann <ulf.hermann@theqtcompany.com>
Tue, 18 Aug 2015 09:14:56 +0000 (11:14 +0200)
committerUlf Hermann <ulf.hermann@theqtcompany.com>
Wed, 19 Aug 2015 11:28:27 +0000 (11:28 +0000)
We need to collect the refs in the debugService's list in order for
them to show up on addRefs() and we need to generate proper error
responses if either the debugger is not stopped or the evaluation
throws an exception.

Task-number: QTBUG-47797
Task-number: QTBUG-47816
Change-Id: I98f17c1f3976859ee50b9bfac41091276ff60982
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
src/qml/jsruntime/qv4debugging.cpp
src/qml/jsruntime/qv4debugging_p.h

index a44acdd37071cd9130ed5b2d7ec3e56245dd6353..01d2a98a74b7172d4bc0f7822c41ab76f0365299 100644 (file)
@@ -317,9 +317,16 @@ ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr,
 
 void ExpressionEvalJob::handleResult(QV4::ScopedValue &result)
 {
+    if (hasExeption())
+        exception = result->toQStringNoThrow();
     collector->collect(result);
 }
 
+const QString &ExpressionEvalJob::exceptionMessage() const
+{
+    return exception;
+}
+
 GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq)
     : engine(engine)
     , seq(seq)
index c91b77cb9379620c612c9e82d967dcace4a41fd8..ebdde8f968518c7e7dec4a652b53161844edd87e 100644 (file)
@@ -104,11 +104,13 @@ private:
 class ExpressionEvalJob: public QV4::Debugging::Debugger::JavaScriptJob
 {
     QV4DataCollector *collector;
+    QString exception;
 
 public:
     ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
                       QV4DataCollector *collector);
     virtual void handleResult(QV4::ScopedValue &result);
+    const QString &exceptionMessage() const;
 };
 
 class GatherSourcesJob: public QV4::Debugging::Debugger::Job
index 6b68f9518efa07c71c6288ab87a570b3d0885c7f..89820c9f561e9d7431ba967f722e80cf2a4d7188 100644 (file)
@@ -549,31 +549,29 @@ public:
 
     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);
-
-        QV4DataCollector *collector = debugService->collector();
-        QV4DataCollector::Refs refs;
-        RefHolder holder(collector, &refs);
-        Q_ASSERT(debugger->state() == QV4::Debugging::Debugger::Paused);
-
-        ExpressionEvalJob job(debugger->engine(), frame, expression, collector);
-        debugger->runInEngine(&job);
-
-        Q_ASSERT(refs.size() == 1);
-
-        // response:
-        addCommand();
-        addRequestSequence();
-        addSuccess(true);
-        addRunning();
-        addBody(collector->lookupRef(refs.first()));
-        addRefs();
+        if (debugger->state() == QV4::Debugging::Debugger::Paused) {
+            QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+            QString expression = arguments.value(QStringLiteral("expression")).toString();
+            const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
+
+            QV4DataCollector *collector = debugService->collector();
+            RefHolder holder(collector, debugService->refs());
+            ExpressionEvalJob job(debugger->engine(), frame, expression, collector);
+            debugger->runInEngine(&job);
+            if (job.hasExeption()) {
+                createErrorResponse(job.exceptionMessage());
+            } else {
+                addCommand();
+                addRequestSequence();
+                addSuccess(true);
+                addRunning();
+                addBody(collector->lookupRef(debugService->refs()->last()));
+                addRefs();
+            }
+        } else {
+            createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work."));
+        }
     }
 };
 } // anonymous namespace
@@ -894,6 +892,11 @@ QV4DataCollector *QV4DebugServiceImpl::collector() const
     return theCollector.data();
 }
 
+QV4DataCollector::Refs *QV4DebugServiceImpl::refs()
+{
+    return &collectedRefs;
+}
+
 void QV4DebugServiceImpl::selectFrame(int frameNr)
 {
     theSelectedFrame = frameNr;
index c80ad78cc8992f60c93825ed52be3a5204c1b799..6c2950de8c0f047b6c3f770ab6220f5b09564ab1 100644 (file)
@@ -90,6 +90,7 @@ public:
 
     QV4DataCollector *collector() const;
     QV4DebuggerAgent debuggerAgent;
+    QV4DataCollector::Refs *refs();
 
 protected:
     void messageReceived(const QByteArray &);
index ceeef80b9fb5eb439230159969aa8d026f39ac42..6efc3793ce1809223502edc8a5cba01eadde24f7 100644 (file)
@@ -59,6 +59,7 @@ Debugger::JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr
     : engine(engine)
     , frameNr(frameNr)
     , script(script)
+    , resultIsException(false)
 {}
 
 void Debugger::JavaScriptJob::run()
@@ -85,11 +86,18 @@ void Debugger::JavaScriptJob::run()
     QV4::ScopedValue result(scope);
     if (!scope.engine->hasException)
         result = script.run();
-    if (scope.engine->hasException)
+    if (scope.engine->hasException) {
         result = scope.engine->catchException();
+        resultIsException = true;
+    }
     handleResult(result);
 }
 
+bool Debugger::JavaScriptJob::hasExeption() const
+{
+    return resultIsException;
+}
+
 class EvalJob: public Debugger::JavaScriptJob
 {
     bool result;
index ac0c934d42c7e6885b201455965e087deaa62185..86faba45f7ca0a782b62d5a332e8d74c9d629e50 100644 (file)
@@ -95,10 +95,12 @@ public:
         QV4::ExecutionEngine *engine;
         int frameNr;
         const QString &script;
+        bool resultIsException;
 
     public:
         JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script);
         void run();
+        bool hasExeption() const;
 
     protected:
         virtual void handleResult(QV4::ScopedValue &result) = 0;