From 61447075954aab99b3abc9c78294e5966ae3b6ce Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 16 Mar 2018 14:51:15 +0100 Subject: Pass "this" object when evaluating debug jobs We have to explicitly specify the "this" object on QV4::Function::call, otherwise it will assume undefined or the QML global object. Task-number: QTBUG-66942 Change-Id: I1af7742b4fee1b49e9760a413834daf3edb15d74 Reviewed-by: Simon Hausmann --- .../qmltooling/qmldbg_debugger/qv4debugjob.cpp | 10 +++++-- .../qqmlnativedebugservice.cpp | 10 +++++-- src/qml/jsruntime/qv4script.cpp | 7 +++-- src/qml/jsruntime/qv4script_p.h | 2 +- .../qml/debugger/qv4debugger/tst_qv4debugger.cpp | 32 ++++++++++++++++++++++ 5 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 5b049ab521..7950d21612 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -112,8 +112,14 @@ void JavaScriptJob::run() script.inheritContext = true; script.parse(); QV4::ScopedValue result(scope); - if (!scope.engine->hasException) - result = script.run(); + if (!scope.engine->hasException) { + if (frame) { + QV4::ScopedValue thisObject(scope, frame->thisObject()); + result = script.run(thisObject); + } else { + result = script.run(); + } + } if (scope.engine->hasException) { result = scope.engine->catchException(); resultIsException = true; diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 718975275a..e17fe92983 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -260,8 +260,14 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(const QString &expression) // That is a side-effect of inheritContext. script.inheritContext = true; script.parse(); - if (!m_engine->hasException) - return script.run(); + if (!m_engine->hasException) { + if (m_engine->currentStackFrame) { + QV4::ScopedValue thisObject(scope, m_engine->currentStackFrame->thisObject()); + script.run(thisObject); + } else { + script.run(); + } + } m_runningJob = false; return QV4::Encode::undefined(); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index bb6608bec0..267c93952d 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -136,7 +136,7 @@ void Script::parse() } } -ReturnedValue Script::run() +ReturnedValue Script::run(const QV4::Value *thisObject) { if (!parsed) parse(); @@ -149,10 +149,11 @@ ReturnedValue Script::run() if (qmlContext.isUndefined()) { TemporaryAssignment savedGlobalCode(engine->globalCode, vmFunction); - return vmFunction->call(engine->globalObject, nullptr, 0, context); + return vmFunction->call(thisObject ? thisObject : engine->globalObject, nullptr, 0, + context); } else { Scoped qml(valueScope, qmlContext.value()); - return vmFunction->call(nullptr, nullptr, 0, qml); + return vmFunction->call(thisObject, nullptr, 0, qml); } } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 24291b9aa6..cb03c6b064 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -93,7 +93,7 @@ struct Q_QML_EXPORT Script { bool parseAsBinding; void parse(); - ReturnedValue run(); + ReturnedValue run(const QV4::Value *thisObject = nullptr); Function *function(); diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 5dd62da15a..4ce0f9fd89 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -316,6 +316,8 @@ private slots: void lastLineOfConditional_data(); void lastLineOfConditional(); + + void readThis(); private: QV4Debugger *debugger() const { @@ -865,6 +867,36 @@ void tst_qv4debugger::lastLineOfConditional() QCOMPARE(secondState.lineNumber, lastLine); } +void tst_qv4debugger::readThis() +{ + m_debuggerAgent->m_captureContextInfo = true; + QString script = + "var x = function() {\n" + " return this.a;\n" + "}.apply({a : 5}, []);\n"; + + TestAgent::ExpressionRequest request; + request.expression = "this"; + request.frameNr = 0; + request.context = -1; // no extra context + m_debuggerAgent->m_expressionRequests << request; + + debugger()->addBreakPoint("applyThis", 2); + evaluateJavaScript(script, "applyThis"); + QVERIFY(m_debuggerAgent->m_wasPaused); + + QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 1); + QJsonObject result0 = m_debuggerAgent->m_expressionResults[0]; + QCOMPARE(result0.value("type").toString(), QStringLiteral("object")); + QCOMPARE(result0.value("value").toInt(), 1); + QJsonArray properties = result0.value("properties").toArray(); + QCOMPARE(properties.size(), 1); + QJsonObject a = properties.first().toObject(); + QCOMPARE(a.value("name").toString(), QStringLiteral("a")); + QCOMPARE(a.value("type").toString(), QStringLiteral("number")); + QCOMPARE(a.value("value").toInt(), 5); +} + void tst_qv4debugger::redundancy_data() { QTest::addColumn("redundantRefs"); -- cgit v1.2.3