aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlpropertyvalidator.cpp1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp34
-rw-r--r--src/qml/jsruntime/qv4engine_p.h3
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp3
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp36
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h6
-rw-r--r--src/qmltest/quicktestresult.cpp11
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp112
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp40
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.h1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/regularExpression.qml7
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.h9
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp19
-rw-r--r--tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp22
15 files changed, 282 insertions, 29 deletions
diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp
index 1beaac8095..4714f505a7 100644
--- a/src/qml/compiler/qqmlpropertyvalidator.cpp
+++ b/src/qml/compiler/qqmlpropertyvalidator.cpp
@@ -558,6 +558,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache
}
break;
case QVariant::RegExp:
+ case QVariant::RegularExpression:
return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax"));
default: {
// generate single literal value assignment to a list property if required
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8adb84719f..02cb9cae62 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -51,6 +51,9 @@
#include <QDir>
#include <QFileInfo>
#include <QLoggingCategory>
+#if QT_CONFIG(regularexpression)
+#include <QRegularExpression>
+#endif
#ifndef V4_BOOTSTRAP
@@ -854,6 +857,13 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
return memoryManager->allocate<RegExpObject>(re);
}
+#if QT_CONFIG(regularexpression)
+Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
+{
+ return memoryManager->allocate<RegExpObject>(re);
+}
+#endif
+
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
{
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
@@ -1365,8 +1375,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
QV4::ScopedObject o(scope, value);
Q_ASSERT(o);
- if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
+ if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
+#if QT_CONFIG(regularexpression)
+ if (typeHint != QMetaType::QRegExp)
+ return re->toQRegularExpression();
+#endif
return re->toQRegExp();
+ }
if (createJSValueForObjects)
return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
@@ -1455,8 +1470,6 @@ static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QV
return o.asReturnedValue();
}
-Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-
QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
{
int type = variant.userType();
@@ -1506,6 +1519,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
case QMetaType::QRegExp:
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
+#endif
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
#if QT_CONFIG(qml_sequence_object)
@@ -1713,6 +1730,10 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
case QMetaType::QRegExp:
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(data)));
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(data)));
+#endif
case QMetaType::QObjectStar:
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
case QMetaType::QVariant:
@@ -1955,6 +1976,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
*reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
return true;
} break;
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+ if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
+ *reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
+ return true;
+ } break;
+#endif
case QMetaType::QObjectStar: {
const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
if (qobjectWrapper || value->isNull()) {
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 4557f623d0..3735c24601 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -520,6 +520,9 @@ public:
Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
Heap::RegExpObject *newRegExpObject(RegExp *re);
Heap::RegExpObject *newRegExpObject(const QRegExp &re);
+#if QT_CONFIG(regularexpression)
+ Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
+#endif
Heap::Object *newErrorObject(const Value &value);
Heap::Object *newErrorObject(const QString &message);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 355dcffaf7..15f064ba7a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1317,6 +1317,9 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
} else if (actual.as<QV4::RegExpObject>()) {
switch (conversionType) {
case QMetaType::QRegExp:
+#if QT_CONFIG(regularexpression)
+ case QMetaType::QRegularExpression:
+#endif
return 0;
default:
return 10;
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 39a2e96b45..5bd25dcbec 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -50,6 +50,9 @@
#include <QtCore/QDebug>
#include <QtCore/qregexp.h>
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
#include <cassert>
#include <typeinfo>
#include <iostream>
@@ -134,6 +137,25 @@ void Heap::RegExpObject::init(const QRegExp &re)
o->initProperties();
}
+#if QT_CONFIG(regularexpression)
+// Converts a QRegularExpression to a JS RegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegularExpression
+// have different semantics/flags, but we try to do our best.
+void Heap::RegExpObject::init(const QRegularExpression &re)
+{
+ Object::init();
+
+ Scope scope(internalClass->engine);
+ Scoped<QV4::RegExpObject> o(scope, this);
+
+ const uint flags = (re.patternOptions() & QRegularExpression::CaseInsensitiveOption)
+ ? CompiledData::RegExp::RegExp_IgnoreCase
+ : CompiledData::RegExp::RegExp_NoFlags;
+ o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, re.pattern(), flags));
+ o->initProperties();
+}
+#endif
+
void RegExpObject::initProperties()
{
setProperty(Index_LastIndex, Value::fromInt32(0));
@@ -150,6 +172,20 @@ QRegExp RegExpObject::toQRegExp() const
return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2);
}
+#if QT_CONFIG(regularexpression)
+// Converts a JS RegExp to a QRegularExpression.
+// The conversion is not 100% exact since ECMA regexp and QRegularExpression
+// have different semantics/flags, but we try to do our best.
+QRegularExpression RegExpObject::toQRegularExpression() const
+{
+ QRegularExpression::PatternOptions caseSensitivity
+ = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase)
+ ? QRegularExpression::CaseInsensitiveOption
+ : QRegularExpression::NoPatternOption;
+ return QRegularExpression(*value()->pattern, caseSensitivity);
+}
+#endif
+
QString RegExpObject::toString() const
{
QString p = *value()->pattern;
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index a584404c0b..04b533e49d 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -81,6 +81,9 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
void init();
void init(QV4::RegExp *value);
void init(const QRegExp &re);
+#if QT_CONFIG(regularexpression)
+ void init(const QRegularExpression &re);
+#endif
};
#define RegExpCtorMembers(class, Member) \
@@ -138,6 +141,9 @@ struct RegExpObject: Object {
}
QRegExp toQRegExp() const;
+#if QT_CONFIG(regularexpression)
+ QRegularExpression toQRegularExpression() const;
+#endif
QString toString() const;
QString source() const;
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index 4dbec585c4..49552e1901 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -62,7 +62,9 @@
#include <QtCore/qdebug.h>
#include <QtCore/QUrl>
#include <QtCore/QDir>
+#if QT_CONFIG(regularexpression)
#include <QtCore/qregularexpression.h>
+#endif
#include <QtQuick/qquickwindow.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qimagewriter.h>
@@ -640,12 +642,9 @@ void QuickTestResult::warn(const QString &message, const QUrl &location, int lin
void QuickTestResult::ignoreWarning(const QJSValue &message)
{
if (message.isRegExp()) {
- // ### we should probably handle QRegularExpression conversion engine-side
- QRegExp re = message.toVariant().toRegExp();
- QRegularExpression::PatternOptions opts = re.caseSensitivity() ==
- Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption;
- QRegularExpression re2(re.pattern(), opts);
- QTestLog::ignoreMessage(QtWarningMsg, re2);
+#if QT_CONFIG(regularexpression)
+ QTestLog::ignoreMessage(QtWarningMsg, message.toVariant().toRegularExpression());
+#endif
} else {
QTestLog::ignoreMessage(QtWarningMsg, message.toString().toLatin1());
}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index fb9c7b0152..d2e0035b57 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -94,6 +94,7 @@ private slots:
void valueConversion_basic2();
void valueConversion_dateTime();
void valueConversion_regExp();
+ void valueConversion_RegularExpression();
void castWithMultipleInheritance();
void collectGarbage();
void gcWithNestedDataStructure();
@@ -135,6 +136,8 @@ private slots:
void qRegExpInport_data();
void qRegExpInport();
+ void qRegularExpressionImport_data();
+ void qRegularExpressionImport();
void dateRoundtripJSQtJS();
void dateRoundtripQtJSQt();
void dateConversionJSQt();
@@ -520,22 +523,27 @@ void tst_QJSEngine::newVariant_valueOfEnum()
void tst_QJSEngine::newRegExp()
{
QJSEngine eng;
- QJSValue rexp = eng.toScriptValue(QRegExp("foo"));
- QVERIFY(!rexp.isUndefined());
- QCOMPARE(rexp.isRegExp(), true);
- QCOMPARE(rexp.isObject(), true);
- QCOMPARE(rexp.isCallable(), false);
- // prototype should be RegExp.prototype
- QVERIFY(!rexp.prototype().isUndefined());
- QCOMPARE(rexp.prototype().isObject(), true);
- // Get [[Class]] internal property of RegExp Prototype Object.
- // See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
- // See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
- QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
- QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
- QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
+ QJSValue rexps[] = {
+ eng.toScriptValue(QRegularExpression("foo")),
+ eng.toScriptValue(QRegExp("foo"))
+ };
+ for (const auto &rexp : rexps) {
+ QVERIFY(!rexp.isUndefined());
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isObject(), true);
+ QCOMPARE(rexp.isCallable(), false);
+ // prototype should be RegExp.prototype
+ QVERIFY(!rexp.prototype().isUndefined());
+ QCOMPARE(rexp.prototype().isObject(), true);
+ // Get [[Class]] internal property of RegExp Prototype Object.
+ // See ECMA-262 Section 8.6.2, "Object Internal Properties and Methods".
+ // See ECMA-262 Section 15.10.6, "Properties of the RegExp Prototype Object".
+ QJSValue r = eng.evaluate("Object.prototype.toString.call(RegExp.prototype)");
+ QCOMPARE(r.toString(), QString::fromLatin1("[object Object]"));
+ QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
- QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
+ QCOMPARE(qjsvalue_cast<QRegExp>(rexp).pattern(), QRegExp("foo").pattern());
+ }
}
void tst_QJSEngine::jsRegExp()
@@ -1601,6 +1609,28 @@ void tst_QJSEngine::valueConversion_regExp()
}
}
+void tst_QJSEngine::valueConversion_RegularExpression()
+{
+ QJSEngine eng;
+ {
+ QRegularExpression in = QRegularExpression("foo");
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
+ QCOMPARE(out.pattern(), in.pattern());
+ QCOMPARE(out.patternOptions(), in.patternOptions());
+ }
+ {
+ QRegularExpression in = QRegularExpression("foo",
+ QRegularExpression::CaseInsensitiveOption);
+ QJSValue val = eng.toScriptValue(in);
+ QVERIFY(val.isRegExp());
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(val), in);
+ QRegularExpression out = qjsvalue_cast<QRegularExpression>(val);
+ QCOMPARE(out.patternOptions(), in.patternOptions());
+ }
+}
+
Q_DECLARE_METATYPE(QGradient)
Q_DECLARE_METATYPE(QGradient*)
Q_DECLARE_METATYPE(QLinearGradient)
@@ -2950,6 +2980,8 @@ void tst_QJSEngine::reentrancy_objectCreation()
QJSValue r2 = eng2.evaluate("new RegExp('foo', 'gim')");
QCOMPARE(qjsvalue_cast<QRegExp>(r1), qjsvalue_cast<QRegExp>(r2));
QCOMPARE(qjsvalue_cast<QRegExp>(r2), qjsvalue_cast<QRegExp>(r1));
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(r1), qjsvalue_cast<QRegularExpression>(r2));
+ QCOMPARE(qjsvalue_cast<QRegularExpression>(r2), qjsvalue_cast<QRegularExpression>(r1));
}
{
QJSValue o1 = eng1.newQObject(temp);
@@ -3145,6 +3177,56 @@ void tst_QJSEngine::qRegExpInport()
}
}
+void tst_QJSEngine::qRegularExpressionImport_data()
+{
+ QTest::addColumn<QRegularExpression>("rx");
+ QTest::addColumn<QString>("string");
+ QTest::addColumn<QString>("matched");
+
+ QTest::newRow("normal") << QRegularExpression("(test|foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("normal2") << QRegularExpression("(Test|Foo)") << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive") << QRegularExpression("(test|foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
+ QTest::newRow("case insensitive2") << QRegularExpression("(Test|Foo)", QRegularExpression::CaseInsensitiveOption) << "test _ foo _ test _ Foo";
+ QTest::newRow("b(a*)(b*)") << QRegularExpression("b(a*)(b*)", QRegularExpression::CaseInsensitiveOption) << "aaabbBbaAabaAaababaaabbaaab";
+ QTest::newRow("greedy") << QRegularExpression("a*(a*)", QRegularExpression::CaseInsensitiveOption) << "aaaabaaba";
+ QTest::newRow("wildcard") << QRegularExpression(".*\\.txt") << "file.txt";
+ QTest::newRow("wildcard 2") << QRegularExpression("a.b\\.txt") << "ab.txt abb.rtc acb.txt";
+ QTest::newRow("slash") << QRegularExpression("g/.*/s", QRegularExpression::CaseInsensitiveOption) << "string/string/string";
+ QTest::newRow("slash2") << QRegularExpression("g / .* / s", QRegularExpression::CaseInsensitiveOption) << "string / string / string";
+ QTest::newRow("fixed") << QRegularExpression("a\\*aa\\.a\\(ba\\)\\*a\\\\ba", QRegularExpression::CaseInsensitiveOption) << "aa*aa.a(ba)*a\\ba";
+ QTest::newRow("fixed insensitive") << QRegularExpression("A\\*A", QRegularExpression::CaseInsensitiveOption) << "a*A A*a A*A a*a";
+ QTest::newRow("fixed sensitive") << QRegularExpression("A\\*A") << "a*A A*a A*A a*a";
+ QTest::newRow("html") << QRegularExpression("<b>(.*)</b>") << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("html minimal") << QRegularExpression("^<b>(.*)</b>$") << "<b>bold</b><i>italic</i><b>bold</b>";
+ QTest::newRow("aaa") << QRegularExpression("a{2,5}") << "aAaAaaaaaAa";
+ QTest::newRow("aaa minimal") << QRegularExpression("^a{2,5}$") << "aAaAaaaaaAa";
+ QTest::newRow("minimal") << QRegularExpression("^.*\\} [*8]$") << "}?} ?} *";
+ QTest::newRow(".? minimal") << QRegularExpression("^.?$") << ".?";
+ QTest::newRow(".+ minimal") << QRegularExpression("^.+$") << ".+";
+ QTest::newRow("[.?] minimal") << QRegularExpression("^[.?]$") << ".?";
+ QTest::newRow("[.+] minimal") << QRegularExpression("^[.+]$") << ".+";
+}
+
+void tst_QJSEngine::qRegularExpressionImport()
+{
+ QFETCH(QRegularExpression, rx);
+ QFETCH(QString, string);
+
+ QJSEngine eng;
+ QJSValue rexp;
+ rexp = eng.toScriptValue(rx);
+
+ QCOMPARE(rexp.isRegExp(), true);
+ QCOMPARE(rexp.isCallable(), false);
+
+ QJSValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
+ QJSValue result = func.call(QJSValueList() << string << rexp);
+
+ const QRegularExpressionMatch match = rx.match(string);
+ for (int i = 0; i <= match.lastCapturedIndex(); i++)
+ QCOMPARE(result.property(i).toString(), match.captured(i));
+}
+
// QScriptValue::toDateTime() returns a local time, whereas JS dates
// are always stored as UTC. Qt Script must respect the current time
// zone, and correctly adjust for daylight saving time that may be in
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index b58cd98d1e..21ebf6b10b 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -1027,6 +1027,20 @@ void tst_QJSValue::toVariant()
QJSValue rxObject = eng.toScriptValue(rx);
QVERIFY(rxObject.isRegExp());
QVariant var = rxObject.toVariant();
+
+ // We can't roundtrip a QRegExp this way, as toVariant() has no information on whether we
+ // want QRegExp or QRegularExpression. It will always create a QRegularExpression.
+ QCOMPARE(var.type(), QMetaType::QRegularExpression);
+ QRegularExpression result = var.toRegularExpression();
+ QCOMPARE(result.pattern(), rx.pattern());
+ QCOMPARE(result.patternOptions() & QRegularExpression::CaseInsensitiveOption, 0);
+ }
+
+ {
+ QRegularExpression rx = QRegularExpression("[0-9a-z]+");
+ QJSValue rxObject = eng.toScriptValue(rx);
+ QVERIFY(rxObject.isRegExp());
+ QVariant var = rxObject.toVariant();
QCOMPARE(var, QVariant(rx));
}
@@ -1194,6 +1208,32 @@ void tst_QJSValue::toRegExp()
QVERIFY(qjsvalue_cast<QRegExp>(eng.toScriptValue(QVariant())).isEmpty());
}
+void tst_QJSValue::toRegularExpression()
+{
+ QJSEngine eng;
+ {
+ QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/foo/"));
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.pattern(), QString::fromLatin1("foo"));
+ QVERIFY(!(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption));
+ }
+ {
+ QRegularExpression rx = qjsvalue_cast<QRegularExpression>(eng.evaluate("/bar/gi"));
+ QVERIFY(rx.isValid());
+ QCOMPARE(rx.pattern(), QString::fromLatin1("bar"));
+ QVERIFY(rx.patternOptions() & QRegularExpression::CaseInsensitiveOption);
+ }
+
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("[]")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("{}")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.globalObject()).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue()).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(123)).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(QJSValue(false)).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.evaluate("null")).pattern().isEmpty());
+ QVERIFY(qjsvalue_cast<QRegularExpression>(eng.toScriptValue(QVariant())).pattern().isEmpty());
+}
+
void tst_QJSValue::isArray_data()
{
newEngine();
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
index b8b9f4403c..9532b1f10e 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h
@@ -76,6 +76,7 @@ private slots:
void toQObject();
void toDateTime();
void toRegExp();
+ void toRegularExpression();
void isArray_data();
void isArray();
void isDate();
diff --git a/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml b/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml
new file mode 100644
index 0000000000..b22f8ab71e
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regularExpression.2.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regularExpression: "[a-zA-z]"
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/regularExpression.qml b/tests/auto/qml/qqmlecmascript/data/regularExpression.qml
new file mode 100644
index 0000000000..6f31ffd305
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/regularExpression.qml
@@ -0,0 +1,7 @@
+import Qt.test 1.0
+
+MyQmlObject{
+ id: obj
+ objectName: "obj"
+ regularExpression: /[a-zA-z]/
+}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h
index 4547a74470..32120ee5b7 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.h
+++ b/tests/auto/qml/qqmlecmascript/testtypes.h
@@ -33,6 +33,7 @@
#include <QtQml/qqmlexpression.h>
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
+#include <QtCore/qregularexpression.h>
#include <QtQml/qqmllist.h>
#include <QtCore/qrect.h>
#include <QtGui/qmatrix.h>
@@ -101,6 +102,7 @@ class MyQmlObject : public QObject
Q_PROPERTY(QQmlListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp)
+ Q_PROPERTY(QRegularExpression regularExpression READ regularExpression WRITE setRegularExpression)
Q_PROPERTY(int nonscriptable READ nonscriptable WRITE setNonscriptable SCRIPTABLE false)
Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty NOTIFY intChanged)
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
@@ -170,6 +172,12 @@ public:
QRegExp regExp() { return m_regExp; }
void setRegExp(const QRegExp &regExp) { m_regExp = regExp; }
+ QRegularExpression regularExpression() { return m_regularExpression; }
+ void setRegularExpression(const QRegularExpression &regularExpression)
+ {
+ m_regularExpression = regularExpression;
+ }
+
int console() const { return 11; }
int nonscriptable() const { return 0; }
@@ -270,6 +278,7 @@ private:
int m_value;
int m_resetProperty;
QRegExp m_regExp;
+ QRegularExpression m_regularExpression;
QVariant m_variant;
QJSValue m_qjsvalue;
int m_intProperty;
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 48cbf02751..b4349f79ca 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -2418,6 +2418,13 @@ void tst_qqmlecmascript::regExpBug()
delete object;
}
+ {
+ QQmlComponent component(&engine, testFileUrl("regularExpression.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create()));
+ QVERIFY(!object.isNull());
+ QCOMPARE(object->regularExpression().pattern(), QLatin1String("[a-zA-z]"));
+ }
+
//QTBUG-23068
{
QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
@@ -2427,6 +2434,18 @@ void tst_qqmlecmascript::regExpBug()
QVERIFY(!object);
QCOMPARE(component.errorString(), err);
}
+
+ {
+ const QString err = QString::fromLatin1("%1:6 Invalid property assignment: "
+ "regular expression expected; "
+ "use /pattern/ syntax\n")
+ .arg(testFileUrl("regularExpression.2.qml").toString());
+ QQmlComponent component(&engine, testFileUrl("regularExpression.2.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(!object);
+ QCOMPARE(component.errorString(), err);
+ }
}
static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source)
diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
index 4ad58ba56c..dfaeca67f1 100644
--- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
+++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp
@@ -30,6 +30,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
+#include <QtCore/qregularexpression.h>
#include <QtQml/qjsengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -118,7 +119,18 @@ void tst_QQuickWorkerScript::messaging()
QVariant response = mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>();
if (response.userType() == qMetaTypeId<QJSValue>())
response = response.value<QJSValue>().toVariant();
- QCOMPARE(response, value);
+
+ if (value.type() == QMetaType::QRegExp && response.type() == QMetaType::QRegularExpression) {
+ // toVariant() doesn't know if we want QRegExp or QRegularExpression. It always creates
+ // a QRegularExpression from a JavaScript regular expression.
+ const QRegularExpression responseRegExp = response.toRegularExpression();
+ const QRegExp valueRegExp = value.toRegExp();
+ QCOMPARE(responseRegExp.pattern(), valueRegExp.pattern());
+ QCOMPARE(bool(responseRegExp.patternOptions() & QRegularExpression::CaseInsensitiveOption),
+ bool(valueRegExp.caseSensitivity() == Qt::CaseInsensitive));
+ } else {
+ QCOMPARE(response, value);
+ }
qApp->processEvents();
delete worker;
@@ -135,10 +147,10 @@ void tst_QQuickWorkerScript::messaging_data()
QTest::newRow("string") << qVariantFromValue(QString("More cheeeese, Gromit!"));
QTest::newRow("variant list") << qVariantFromValue((QVariantList() << "a" << "b" << "c"));
QTest::newRow("date time") << qVariantFromValue(QDateTime::currentDateTime());
-#ifndef QT_NO_REGEXP
- // Qt Script's QScriptValue -> QRegExp uses RegExp2 pattern syntax
- QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive, QRegExp::RegExp2));
-#endif
+ QTest::newRow("regexp") << qVariantFromValue(QRegExp("^\\d\\d?$", Qt::CaseInsensitive,
+ QRegExp::RegExp2));
+ QTest::newRow("regularexpression") << qVariantFromValue(QRegularExpression(
+ "^\\d\\d?$", QRegularExpression::CaseInsensitiveOption));
}
void tst_QQuickWorkerScript::messaging_sendQObjectList()