diff options
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 72 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.h | 3 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.cpp | 53 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.h | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 3 | ||||
-rw-r--r-- | tests/auto/qml/qjsengine/tst_qjsengine.cpp | 63 |
7 files changed, 217 insertions, 4 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 69e1436c0a..3bde6a60c4 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -45,6 +45,7 @@ #include "private/qv4engine_p.h" #include "private/qv4mm_p.h" +#include "private/qv4errorobject_p.h" #include "private/qv4globalobject_p.h" #include "private/qv4script_p.h" #include "private/qv4runtime_p.h" @@ -583,6 +584,46 @@ QJSValue QJSEngine::newObject() } /*! + \since 5.12 + Creates a JavaScript object of class Error. + + The prototype of the created object will be \a errorType. + + \sa newObject(), throwError(), QJSValue::isError() +*/ +QJSValue QJSEngine::newErrorObject(QJSValue::ErrorType errorType, const QString &message) +{ + QV4::Scope scope(m_v4Engine); + QV4::ScopedObject error(scope); + switch (errorType) { + case QJSValue::RangeError: + error = m_v4Engine->newRangeErrorObject(message); + break; + case QJSValue::SyntaxError: + error = m_v4Engine->newSyntaxErrorObject(message); + break; + case QJSValue::TypeError: + error = m_v4Engine->newTypeErrorObject(message); + break; + case QJSValue::URIError: + error = m_v4Engine->newURIErrorObject(message); + break; + case QJSValue::ReferenceError: + error = m_v4Engine->newReferenceErrorObject(message); + break; + case QJSValue::EvalError: + error = m_v4Engine->newEvalErrorObject(message); + break; + case QJSValue::GenericError: + error = m_v4Engine->newErrorObject(message); + break; + case QJSValue::NoError: + return QJSValue::UndefinedValue; + } + return QJSValue(m_v4Engine, error->asReturnedValue()); +} + +/*! Creates a JavaScript object of class Array with the given \a length. \sa newObject() @@ -894,6 +935,37 @@ void QJSEngine::throwError(const QString &message) m_v4Engine->throwError(message); } +/*! + Throws a run-time error (exception) with the given \a errorType and + \a message. + + \code + // Assuming that DataEntry is a QObject-derived class that has been + // registered as a singleton type and provides an invokable method + // setAge(). + + void DataEntry::setAge(int age) { + if (age < 0 || age > 200) { + jsEngine->throwError(QJSValue::RangeError, + "Age must be between 0 and 200"); + } + ... + } + \endcode + + \since Qt 5.12 + \sa {Script Exceptions}, newErrorObject() +*/ +void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message) +{ + QV4::Scope scope(m_v4Engine); + QJSValue error = newErrorObject(errorType, message); + QV4::ScopedObject e(scope, QJSValuePrivate::getValue(&error)); + if (!e) + return; + m_v4Engine->throwError(e); +} + QJSEnginePrivate *QJSEnginePrivate::get(QV4::ExecutionEngine *e) { return e->jsEngine()->d_func(); diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 5c8613ffd6..6300842341 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -84,6 +84,8 @@ public: return newQMetaObject(&T::staticMetaObject); } + QJSValue newErrorObject(QJSValue::ErrorType errorType, const QString &message = QString()); + template <typename T> inline QJSValue toScriptValue(const T &value) { @@ -114,6 +116,7 @@ public: QV4::ExecutionEngine *handle() const { return m_v4Engine; } void throwError(const QString &message); + void throwError(QJSValue::ErrorType errorType, const QString &message = QString()); private: QJSValue create(int type, const void *ptr); diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 9671e82187..14baf0ac10 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -159,6 +159,22 @@ This is a typedef for a QList<QJSValue>. */ +/*! + \enum QJSValue::ErrorType + \since 5.12 + + This enum is used to specify a type of Error object. + + \value NoError Not an Error object. + \value GenericError A generic Error object, but not of a specific sub-type. + \value EvalError An error regarding the global eval() function. + \value RangeError A value did not match the expected set or range. + \value ReferenceError A non-existing variable referenced. + \value SyntaxError Invalid syntax. + \value TypeError A value did not match the expected type. + \value URIError A URI handling function was used incorrectly. +*/ + QT_BEGIN_NAMESPACE using namespace QV4; @@ -371,7 +387,7 @@ bool QJSValue::isUndefined() const Returns true if this QJSValue is an object of the Error class; otherwise returns false. - \sa {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} + \sa errorType(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} */ bool QJSValue::isError() const { @@ -382,6 +398,41 @@ bool QJSValue::isError() const } /*! + \since 5.12 + Returns the error type this QJSValue represents if it is an Error object. + Otherwise, returns \c NoError." + + \sa isError(), {QJSEngine#Script Exceptions}{QJSEngine - Script Exceptions} +*/ +QJSValue::ErrorType QJSValue::errorType() const +{ + QV4::Value *val = QJSValuePrivate::getValue(this); + if (!val) + return NoError; + QV4::ErrorObject *error = val->as<ErrorObject>(); + if (!error) + return NoError; + switch (error->d()->errorType) { + case QV4::Heap::ErrorObject::Error: + return GenericError; + case QV4::Heap::ErrorObject::EvalError: + return EvalError; + case QV4::Heap::ErrorObject::RangeError: + return RangeError; + case QV4::Heap::ErrorObject::ReferenceError: + return ReferenceError; + case QV4::Heap::ErrorObject::SyntaxError: + return SyntaxError; + case QV4::Heap::ErrorObject::TypeError: + return TypeError; + case QV4::Heap::ErrorObject::URIError: + return URIError; + } + Q_UNREACHABLE(); + return NoError; +} + +/*! Returns true if this QJSValue is an object of the Array class; otherwise returns false. diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h index 56bd64eec1..2f95e0ff31 100644 --- a/src/qml/jsapi/qjsvalue.h +++ b/src/qml/jsapi/qjsvalue.h @@ -68,6 +68,17 @@ public: UndefinedValue }; + enum ErrorType { + NoError, + GenericError, + EvalError, + RangeError, + ReferenceError, + SyntaxError, + TypeError, + URIError + }; + public: QJSValue(SpecialValue value = UndefinedValue); ~QJSValue(); @@ -137,6 +148,7 @@ public: QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const + ErrorType errorType() const; #ifdef QT_DEPRECATED QT_DEPRECATED QJSEngine *engine() const; #endif diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 129bb20019..169ab0a4a4 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -849,6 +849,11 @@ Heap::Object *ExecutionEngine::newErrorObject(const Value &value) return ErrorObject::create<ErrorObject>(this, value, errorCtor()); } +Heap::Object *ExecutionEngine::newErrorObject(const QString &message) +{ + return ErrorObject::create<ErrorObject>(this, message); +} + Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message) { return ErrorObject::create<SyntaxErrorObject>(this, message); @@ -918,6 +923,16 @@ Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler() return m_reactionHandler.data(); } +Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message) +{ + return ErrorObject::create<URIErrorObject>(this, message); +} + +Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message) +{ + return ErrorObject::create<EvalErrorObject>(this, message); +} + Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v) { return memoryManager->allocate<VariantObject>(v); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 928c9f4947..64c7e2f32b 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -522,13 +522,16 @@ public: Heap::RegExpObject *newRegExpObject(const QRegExp &re); Heap::Object *newErrorObject(const Value &value); + Heap::Object *newErrorObject(const QString &message); Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newSyntaxErrorObject(const QString &message); Heap::Object *newReferenceErrorObject(const QString &message); Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column); Heap::Object *newTypeErrorObject(const QString &message); Heap::Object *newRangeErrorObject(const QString &message); + Heap::Object *newURIErrorObject(const QString &message); Heap::Object *newURIErrorObject(const Value &message); + Heap::Object *newEvalErrorObject(const QString &message); Heap::PromiseObject *newPromiseObject(); Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index a38224ef81..00c631141b 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -224,6 +224,8 @@ private slots: void multilineStrings(); void throwError(); + void throwErrorObject(); + void returnError(); void mathMinMax(); void importModule(); @@ -232,7 +234,9 @@ private slots: void importExportErrors(); public: - Q_INVOKABLE QJSValue throwingCppMethod(); + Q_INVOKABLE QJSValue throwingCppMethod1(); + Q_INVOKABLE void throwingCppMethod2(); + Q_INVOKABLE QJSValue throwingCppMethod3(); signals: void testSignal(); @@ -4384,7 +4388,7 @@ void tst_QJSEngine::throwError() QJSValue result = engine.evaluate( "function test(){\n" "try {\n" - " return testCase.throwingCppMethod();\n" + " return testCase.throwingCppMethod1();\n" "} catch (error) {\n" " return error;\n" "}\n" @@ -4393,17 +4397,70 @@ void tst_QJSEngine::throwError() "test();" ); QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::GenericError); QCOMPARE(result.property("lineNumber").toString(), "3"); QCOMPARE(result.property("message").toString(), "blub"); QVERIFY(!result.property("stack").isUndefined()); } -QJSValue tst_QJSEngine::throwingCppMethod() +void tst_QJSEngine::throwErrorObject() +{ + QJSEngine engine; + QJSValue wrappedThis = engine.newQObject(this); + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); + engine.globalObject().setProperty("testCase", wrappedThis); + + QJSValue result = engine.evaluate( + "function test(){\n" + " try {\n" + " testCase.throwingCppMethod2();\n" + " } catch (error) {\n" + " if (error instanceof TypeError) {\n" + " return error;\n" + " }\n" + " }\n" + " return null;\n" + "}\n" + "test();" + ); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::TypeError); + QCOMPARE(result.property("lineNumber").toString(), "3"); + QCOMPARE(result.property("message").toString(), "Wrong type"); + QVERIFY(!result.property("stack").isUndefined()); +} + +void tst_QJSEngine::returnError() +{ + QJSEngine engine; + QJSValue wrappedThis = engine.newQObject(this); + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); + engine.globalObject().setProperty("testCase", wrappedThis); + + QJSValue result = engine.evaluate("testCase.throwingCppMethod3()"); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::EvalError); + QCOMPARE(result.property("lineNumber").toString(), "1"); + QCOMPARE(result.property("message").toString(), "Something is wrong"); + QVERIFY(!result.property("stack").isUndefined()); +} + +QJSValue tst_QJSEngine::throwingCppMethod1() { qjsEngine(this)->throwError("blub"); return QJSValue(47); } +void tst_QJSEngine::throwingCppMethod2() +{ + qjsEngine(this)->throwError(QJSValue::TypeError, "Wrong type"); +} + +QJSValue tst_QJSEngine::throwingCppMethod3() +{ + return qjsEngine(this)->newErrorObject(QJSValue::EvalError, "Something is wrong"); +} + void tst_QJSEngine::mathMinMax() { QJSEngine engine; |