diff options
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4errorobject.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqml.cpp | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlbuiltinfunctions.cpp | 17 | ||||
-rw-r--r-- | src/qmltest/quicktestutil.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/data/exceptionFromInner.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp | 16 |
13 files changed, 72 insertions, 22 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 904749d7f6..6aa44dda0d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -220,7 +220,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frame[QLatin1String("debuggerFrame")] = false; frame[QLatin1String("func")] = stackFrame.function; frame[QLatin1String("script")] = stackFrame.source; - frame[QLatin1String("line")] = stackFrame.line - 1; + frame[QLatin1String("line")] = qAbs(stackFrame.line) - 1; if (stackFrame.column >= 0) frame[QLatin1String("column")] = stackFrame.column; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index eda1c4c931..eca6562b90 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -530,7 +530,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in for (auto &&frame: trace) exceptionStackTrace->push_back(QString::fromLatin1("%1:%2:%3:%4").arg( frame.function, - QString::number(frame.line), + QString::number(qAbs(frame.line)), QString::number(frame.column), frame.source) ); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index d1ddde7089..f1a2bc0947 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1234,7 +1234,7 @@ StackTrace ExecutionEngine::stackTrace(int frameLimit) const QV4::StackFrame frame; frame.source = f->source(); frame.function = f->function(); - frame.line = qAbs(f->lineNumber()); + frame.line = f->lineNumber(); frame.column = -1; stack.append(frame); if (f->isJSTypesFrame()) { @@ -1272,7 +1272,7 @@ static inline char *v4StackTrace(const ExecutionContext *context) const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString(); str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function << "\",file=\"" << fileName << "\",fullname=\"" << fileName - << "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}"; + << "\",line=\"" << qAbs(stackTrace.at(i).line) << "\",language=\"js\"}"; } } str << ']'; @@ -1467,7 +1467,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError() if (!trace.isEmpty()) { QV4::StackFrame frame = trace.constFirst(); error.setUrl(QUrl(frame.source)); - error.setLine(frame.line); + error.setLine(qAbs(frame.line)); error.setColumn(frame.column); } QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception); diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 516c81864f..35b5952d38 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -56,7 +56,7 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t) e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); if (!e->d()->stackTrace->isEmpty()) { setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); - setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(qAbs(e->d()->stackTrace->at(0).line))); } if (!message.isUndefined()) @@ -84,7 +84,7 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int Q_ASSERT(!e->d()->stackTrace->isEmpty()); setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); - setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(e->d()->stackTrace->at(0).line)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Value::fromInt32(qAbs(e->d()->stackTrace->at(0).line))); if (!message.isUndefined()) setProperty(scope.engine, QV4::ErrorObject::Index_Message, message); diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp index e8ff9a89bc..5117e745a0 100644 --- a/src/qml/jsruntime/qv4stackframe.cpp +++ b/src/qml/jsruntime/qv4stackframe.cpp @@ -40,7 +40,7 @@ int CppStackFrame::lineNumber() const { if (auto *line = lineAndStatement(this)) return line->line; - return -1; + return missingLineNumber(); } int CppStackFrame::statementNumber() const @@ -50,6 +50,15 @@ int CppStackFrame::statementNumber() const return -1; } +int CppStackFrame::missingLineNumber() const +{ + // Remove the first bit so that we can cast to positive int and negate. + // Remove the last bit so that it can't be -1. + const int result = -int(quintptr(this) & 0x7ffffffe); + Q_ASSERT(result < -1); + return result; +} + ReturnedValue QV4::CppStackFrame::thisObject() const { if (isJSTypesFrame()) diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index 2777d79c31..9c3e3700ce 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -83,6 +83,8 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrame : protected CppStackFrameBase int lineNumber() const; int statementNumber() const; + int missingLineNumber() const; + CppStackFrame *parentFrame() const { return parent; } void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; } diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 4304934019..ca9c1d8e52 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1234,13 +1234,25 @@ static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *comp static void amendException(QV4::ExecutionEngine *engine) { + const int missingLineNumber = engine->currentStackFrame->missingLineNumber(); const int lineNumber = engine->currentStackFrame->lineNumber(); - engine->exceptionStackTrace.front().line = lineNumber; + Q_ASSERT(missingLineNumber != lineNumber); + + auto amendStackTrace = [&](QV4::StackTrace *stackTrace) { + for (auto it = stackTrace->begin(), end = stackTrace->end(); it != end; ++it) { + if (it->line == missingLineNumber) { + it->line = lineNumber; + break; + } + } + }; + + amendStackTrace(&engine->exceptionStackTrace); QV4::Scope scope(engine); QV4::Scoped<QV4::ErrorObject> error(scope, *engine->exceptionValue); if (error) // else some other value was thrown - error->d()->stackTrace->front().line = lineNumber; + amendStackTrace(error->d()->stackTrace); } diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp index 9d75073e84..ebb5c301db 100644 --- a/src/qml/qml/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/qqmlbuiltinfunctions.cpp @@ -1755,15 +1755,14 @@ static QString jsStack(QV4::ExecutionEngine *engine) { const QV4::StackFrame &frame = stackTrace.at(i); QString stackFrame; - if (frame.column >= 0) - stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg(frame.function, - frame.source, - QString::number(frame.line), - QString::number(frame.column)); - else - stackFrame = QStringLiteral("%1 (%2:%3)").arg(frame.function, - frame.source, - QString::number(frame.line)); + if (frame.column >= 0) { + stackFrame = QStringLiteral("%1 (%2:%3:%4)").arg( + frame.function, frame.source, + QString::number(qAbs(frame.line)), QString::number(frame.column)); + } else { + stackFrame = QStringLiteral("%1 (%2:%3)").arg( + frame.function, frame.source, QString::number(qAbs(frame.line))); + } if (i) stack += QLatin1Char('\n'); diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp index 15f530c60e..c7cac4b4b2 100644 --- a/src/qmltest/quicktestutil.cpp +++ b/src/qmltest/quicktestutil.cpp @@ -87,7 +87,7 @@ int QuickTestUtil::callerLine(int frameIndex) const QVector<QV4::StackFrame> stack = v4->stackTrace(frameIndex + 2); if (stack.size() > frameIndex + 1) - return stack.at(frameIndex + 1).line; + return qAbs(stack.at(frameIndex + 1).line); return -1; } diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 6f147446f0..f95a7ade9a 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -274,9 +274,10 @@ public: void dumpStackTrace() const { qDebug() << "Stack depth:" << m_stackTrace.size(); - foreach (const QV4::StackFrame &frame, m_stackTrace) + for (const QV4::StackFrame &frame : m_stackTrace) { qDebug("\t%s (%s:%d:%d)", qPrintable(frame.function), qPrintable(frame.source), - frame.line, frame.column); + qAbs(frame.line), frame.column); + } } }; diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt index 370ef4ac9c..363c24c648 100644 --- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt +++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt @@ -105,6 +105,7 @@ set(qml_files equalityQUrl.qml equalityVarAndNonStorable.qml equalsUndefined.qml + exceptionFromInner.qml excessiveParameters.qml extendedTypes.qml failures.qml diff --git a/tests/auto/qml/qmlcppcodegen/data/exceptionFromInner.qml b/tests/auto/qml/qmlcppcodegen/data/exceptionFromInner.qml new file mode 100644 index 0000000000..13855356f2 --- /dev/null +++ b/tests/auto/qml/qmlcppcodegen/data/exceptionFromInner.qml @@ -0,0 +1,10 @@ +pragma Strict +import QtQml + +QtObject { + property QtObject theNull: null + + function doFail() : string { return theNull.objectName } + function delegateFail() : string { doFail() } + function disbelieveFail() : string { delegateFail() } +} diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp index 20e6922dc4..f3869e6e40 100644 --- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp +++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp @@ -74,6 +74,7 @@ private slots: void equalityVarAndNonStorable(); void equalsUndefined(); void evadingAmbiguity(); + void exceptionFromInner(); void excessiveParameters(); void extendedTypes(); void failures(); @@ -1415,6 +1416,21 @@ void tst_QmlCppCodegen::evadingAmbiguity() QCOMPARE(o2->property("i").toString(), QStringLiteral("Ambiguous2")); } +void tst_QmlCppCodegen::exceptionFromInner() +{ + QQmlEngine engine; + QQmlComponent component(&engine, QUrl(u"qrc:/qt/qml/TestTypes/exceptionFromInner.qml"_s)); + QVERIFY2(!component.isError(), component.errorString().toUtf8()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QTest::ignoreMessage( + QtWarningMsg, + "qrc:/qt/qml/TestTypes/exceptionFromInner.qml:7: TypeError: " + "Cannot read property 'objectName' of null"); + QMetaObject::invokeMethod(object.data(), "disbelieveFail"); +} + void tst_QmlCppCodegen::excessiveParameters() { QQmlEngine engine; |