diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2018-10-30 00:49:43 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2018-10-30 00:49:43 +0100 |
commit | 708e4f7e626468f53636b7d2ef7c6a99c129751f (patch) | |
tree | 18e983f3aa8cc15c73a24ededc1eabdbb4c6d800 | |
parent | 4207940684b578469f7ec6b428403af85e579b2c (diff) | |
parent | 475c74a9926efcd968572563e678988e53804603 (diff) |
Merge 5.12 into 5.12.0
Change-Id: I9c455be35c18031c1eb4e8ca8d4b85183f72a051
27 files changed, 308 insertions, 37 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 883b21ab07..9021fd0284 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1947,11 +1947,7 @@ QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache { QQmlPropertyData *pd = cache->property(name, /*object*/nullptr, /*context*/nullptr); - // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time - if (!pd || pd->isFunction()) - return nullptr; - - if (!cache->isAllowedInRevision(pd)) + if (pd && !cache->isAllowedInRevision(pd)) return nullptr; return pd; @@ -2280,6 +2276,10 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n if (_scopeObject) { QQmlPropertyData *data = lookupQmlCompliantProperty(_scopeObject, name); if (data) { + // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time + if (data->isFunction()) + return Reference::fromName(this, name); + Reference base = Reference::fromStackSlot(this, _qmlContextSlot); Reference::PropertyCapturePolicy capturePolicy; if (!data->isConstant() && !data->isQmlBinding()) @@ -2293,6 +2293,10 @@ QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &n if (_contextObject) { QQmlPropertyData *data = lookupQmlCompliantProperty(_contextObject, name); if (data) { + // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time + if (data->isFunction()) + return Reference::fromName(this, name); + Reference base = Reference::fromStackSlot(this, _qmlContextSlot); Reference::PropertyCapturePolicy capturePolicy; if (!data->isConstant() && !data->isQmlBinding()) diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h index 80f7183074..bce59b19a7 100644 --- a/src/qml/jsruntime/qv4promiseobject_p.h +++ b/src/qml/jsruntime/qv4promiseobject_p.h @@ -39,6 +39,17 @@ #ifndef QV4PROMISEOBJECT_H #define QV4PROMISEOBJECT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qv4object_p.h" #include "qv4functionobject_p.h" diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 2e4223de7d..8cdec2f6ee 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -764,11 +764,11 @@ struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator { int propertyIndex = 0; ~QObjectWrapperOwnPropertyKeyIterator() override = default; - PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; }; -PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs) { // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 634fbcbd97..4ef4fa2c9e 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -238,20 +238,20 @@ void Heap::RegExpCtor::clearLastMatch() lastMatchEnd = 0; } -static bool isRegExp(ExecutionEngine *e, const Value *arg) +static bool isRegExp(ExecutionEngine *e, const QV4::Value *arg) { - const Object *o = arg->objectValue(); + const QV4::Object *o = arg->objectValue(); if (!o) return false; - Value isRegExp = Value::fromReturnedValue(o->get(e->symbol_match())); + QV4::Value isRegExp = QV4::Value::fromReturnedValue(o->get(e->symbol_match())); if (!isRegExp.isUndefined()) return isRegExp.toBoolean(); const RegExpObject *re = o->as<RegExpObject>(); return re ? true : false; } -uint parseFlags(Scope &scope, const Value *f) +uint parseFlags(Scope &scope, const QV4::Value *f) { uint flags = CompiledData::RegExp::RegExp_NoFlags; if (!f->isUndefined()) { @@ -546,13 +546,13 @@ static int advanceStringIndex(int index, const QString &str, bool unicode) return index; } -static void advanceLastIndexOnEmptyMatch(ExecutionEngine *e, bool unicode, Object *rx, const String *matchString, const QString &str) +static void advanceLastIndexOnEmptyMatch(ExecutionEngine *e, bool unicode, QV4::Object *rx, const String *matchString, const QString &str) { Scope scope(e); if (matchString->d()->length() == 0) { - ScopedValue v(scope, rx->get(scope.engine->id_lastIndex())); + QV4::ScopedValue v(scope, rx->get(scope.engine->id_lastIndex())); int lastIndex = advanceStringIndex(v->toLength(), str, unicode); - if (!rx->put(scope.engine->id_lastIndex(), Value::fromInt32(lastIndex))) + if (!rx->put(scope.engine->id_lastIndex(), QV4::Value::fromInt32(lastIndex))) scope.engine->throwTypeError(); } } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index f6b9c5ba94..03f351b9e4 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -112,11 +112,11 @@ bool StringObject::virtualDeleteProperty(Managed *m, PropertyKey id) struct StringObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator { ~StringObjectOwnPropertyKeyIterator() override = default; - PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; + PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; }; -PropertyKey StringObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs) +PropertyKey StringObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs) { const StringObject *s = static_cast<const StringObject *>(o); uint slen = s->d()->string->toQString().length(); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 29814246db..1cca50f6c1 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -377,7 +377,7 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs) if (lhs.m()->internalClass->vtable->isString) return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs; accumulator = lhs; - lhs = Value::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT)); + lhs = QV4::Value::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT)); goto redo; case QV4::Value::QT_Empty: Q_UNREACHABLE(); diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a67c5c4a2b..5ed3cc5d6a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1132,22 +1132,23 @@ class QQmlComponentIncubator : public QQmlIncubator public: QQmlComponentIncubator(QV4::Heap::QmlIncubatorObject *inc, IncubationMode mode) : QQmlIncubator(mode) - , incubatorObject(inc) - {} + { + incubatorObject.set(inc->internalClass->engine, inc); + } void statusChanged(Status s) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>()); i->statusChanged(s); } void setInitialState(QObject *o) override { - QV4::Scope scope(incubatorObject->internalClass->engine); - QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject); + QV4::Scope scope(incubatorObject.engine()); + QV4::Scoped<QV4::QmlIncubatorObject> i(scope, incubatorObject.as<QV4::QmlIncubatorObject>()); i->setInitialState(o); } - QV4::Heap::QmlIncubatorObject *incubatorObject; + QV4::PersistentValue incubatorObject; // keep a strong internal reference while incubating }; @@ -1571,6 +1572,9 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); } } + + if (s != QQmlIncubator::Loading) + d()->incubator->incubatorObject.clear(); } #undef INITIALPROPERTIES_SOURCE diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index ea4a69f05d..ba8d5831ad 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -847,21 +847,40 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const } } + QSet<QString> localEnums; + const QMetaObject *localMetaObject = nullptr; + // Add any enum values defined by this class, overwriting any inherited values for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { QMetaEnum e = metaObject->enumerator(ii); const bool isScoped = e.isScoped(); QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : nullptr; + // We allow enums in sub-classes to overwrite enums from base-classes, such as + // ListView.Center (from enum PositionMode) overwriting Item.Center (from enum TransformOrigin). + // This is acceptable because the _use_ of the enum from the QML side requires qualification + // anyway, i.e. ListView.Center vs. Item.Center. + // However if a class defines two enums with the same value, then that must produce a warning + // because it represents a valid conflict. + if (e.enclosingMetaObject() != localMetaObject) { + localEnums.clear(); + localMetaObject = e.enclosingMetaObject(); + } + for (int jj = 0; jj < e.keyCount(); ++jj) { const QString key = QString::fromUtf8(e.key(jj)); const int value = e.value(jj); if (!isScoped || (regType == QQmlType::CppType && extraData.cd->registerEnumClassesUnscoped)) { - if (enums.contains(key)) { - qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData()); - createEnumConflictReport(metaObject, key); - } - enums.insert(key, value); + if (localEnums.contains(key)) { + auto existingEntry = enums.find(key); + if (existingEntry != enums.end() && existingEntry.value() != value) { + qWarning("Previously registered enum will be overwritten due to name clash: %s.%s", metaObject->className(), key.toUtf8().constData()); + createEnumConflictReport(metaObject, key); + } + } else { + localEnums.insert(key); + } + enums.insert(key, value); } if (isScoped) scoped->insert(key, value); diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 1bd8fc1020..b7c4fa5b67 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -267,10 +267,11 @@ Q_SIGNALS: Q_REVISION(9) void horizontalOvershootChanged(); Q_REVISION(9) void verticalOvershootChanged(); - Q_REVISION(12) void atXEndChanged(); - Q_REVISION(12) void atYEndChanged(); - Q_REVISION(12) void atXBeginningChanged(); - Q_REVISION(12) void atYBeginningChanged(); + // The next four signals should be marked as Q_REVISION(12). See QTBUG-71243 + void atXEndChanged(); + void atYEndChanged(); + void atXBeginningChanged(); + void atYBeginningChanged(); protected: bool childMouseEventFilter(QQuickItem *, QEvent *) override; diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index f4e7fa7046..1af60051fb 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -272,8 +272,10 @@ Q_SIGNALS: void textFormatChanged(QQuickText::TextFormat textFormat); void elideModeChanged(QQuickText::TextElideMode mode); void contentSizeChanged(); - Q_REVISION(12) void contentWidthChanged(qreal contentWidth); - Q_REVISION(12) void contentHeightChanged(qreal contentHeight); + // The next two signals should be marked as Q_REVISION(12). See QTBUG-71247 + void contentWidthChanged(qreal contentWidth); + void contentHeightChanged(qreal contentHeight); + void lineHeightChanged(qreal lineHeight); void lineHeightModeChanged(LineHeightMode mode); void fontSizeModeChanged(); diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index c852c16509..d8daec2f07 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -302,10 +302,19 @@ void QQuickStateGroup::componentComplete() Q_D(QQuickStateGroup); d->componentComplete = true; + QVarLengthArray<QString, 4> names; + names.reserve(d->states.count()); for (int ii = 0; ii < d->states.count(); ++ii) { QQuickState *state = d->states.at(ii); if (!state->isNamed()) state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount)); + + const QString stateName = state->name(); + if (names.contains(stateName)) { + qmlWarning(state->parent()) << "Found duplicate state name: " << stateName; + } else { + names.append(std::move(stateName)); + } } if (d->updateAutoState()) { diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs new file mode 100644 index 0000000000..19c012d19b --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables.mjs @@ -0,0 +1,31 @@ +export function runTest(libraryUnderTest) { + let state1 = state(libraryUnderTest); + try { modifyFromOutside(libraryUnderTest); } catch (e) {} + let state2 = state(libraryUnderTest); + try { modifyFromInside(libraryUnderTest); } catch (e) {} + let state3 = state(libraryUnderTest); + return state1 + " " + state2 + " " + state3; +} + +function stringify(value) { + let s = "?"; + if (value !== undefined) + s = value.toString(); + return s; +} + +function state(libraryUnderTest) { + return (stringify(libraryUnderTest.varValue) + + stringify(libraryUnderTest.letValue) + + stringify(libraryUnderTest.constValue)); +} + +function modifyFromOutside(libraryUnderTest) { + ++libraryUnderTest.varValue; + ++libraryUnderTest.letValue; + ++libraryUnderTest.constValue; +} + +function modifyFromInside(libraryUnderTest) { + libraryUnderTest.incrementAll(); +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs new file mode 100644 index 0000000000..b6eb1a2623 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.mjs @@ -0,0 +1,8 @@ +export var varValue = 0; +export let letValue = 0; +export const constValue = 0; +export function incrementAll() { + ++varValue; + ++letValue; + ++constValue; +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml new file mode 100644 index 0000000000..bb4e759cbf --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_module.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import "importLexicalVariables.mjs" as TestRunner +import "importLexicalVariables_module.mjs" as LibraryUnderTest + +QtObject { + id: root + function runTest() { + return TestRunner.runTest(LibraryUnderTest); + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js new file mode 100644 index 0000000000..f8c215a5e7 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.js @@ -0,0 +1,9 @@ +.pragma library +var varValue = 0; +let letValue = 0; +const constValue = 0; +function incrementAll() { + ++varValue; + ++letValue; + ++constValue; +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml new file mode 100644 index 0000000000..1b3fe7fa2e --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_pragmaLibrary.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import "importLexicalVariables.mjs" as TestRunner +import "importLexicalVariables_pragmaLibrary.js" as LibraryUnderTest + +QtObject { + id: root + function runTest() { + return TestRunner.runTest(LibraryUnderTest); + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js new file mode 100644 index 0000000000..4fb68abc87 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.js @@ -0,0 +1,8 @@ +var varValue = 0; +let letValue = 0; +const constValue = 0; +function incrementAll() { + ++varValue; + ++letValue; + ++constValue; +} diff --git a/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml new file mode 100644 index 0000000000..263511e802 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/importLexicalVariables_script.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import "importLexicalVariables.mjs" as TestRunner +import "importLexicalVariables_script.js" as LibraryUnderTest + +QtObject { + id: root + function runTest() { + return TestRunner.runTest(LibraryUnderTest); + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index cf3eecff6d..8f388fcac6 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -357,6 +357,8 @@ private slots: void jumpStrictNotEqualUndefined(); void removeBindingsWithNoDependencies(); void temporaryDeadZone(); + void importLexicalVariables_data(); + void importLexicalVariables(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -8812,6 +8814,38 @@ void tst_qqmlecmascript::temporaryDeadZone() QVERIFY(v.isError()); } +void tst_qqmlecmascript::importLexicalVariables_data() +{ + QTest::addColumn<QUrl>("testFile"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("script") + << testFileUrl("importLexicalVariables_script.qml") + << QStringLiteral("0?? 1?? 2??"); + QTest::newRow("pragmaLibrary") + << testFileUrl("importLexicalVariables_pragmaLibrary.qml") + << QStringLiteral("0?? 1?? 2??"); + QTest::newRow("module") + << testFileUrl("importLexicalVariables_module.qml") + << QStringLiteral("000 000 110"); +} + +void tst_qqmlecmascript::importLexicalVariables() +{ + QFETCH(QUrl, testFile); + QFETCH(QString, expected); + + QQmlEngine engine; + QQmlComponent component(&engine, testFile); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); + QVERIFY(!component.isError()); + + QVariant result; + QMetaObject::invokeMethod(object.data(), "runTest", Qt::DirectConnection, Q_RETURN_ARG(QVariant, result)); + QCOMPARE(result, QVariant(expected)); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlincubator/data/garbageCollection.qml b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml new file mode 100644 index 0000000000..6866a02a00 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/garbageCollection.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property var incubator + + function getAndClearIncubator() { + var result = incubator + incubator = null + return result + } + + Component.onCompleted: { + var c = Qt.createComponent("statusChanged.qml"); // use existing simple type for convenience + var incubator = c.incubateObject(root); + incubator.onStatusChanged = function(status) { if (status === 1) root.incubator = incubator } + } +} diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index 8f0e04e12e..8e25079703 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -39,6 +39,7 @@ #include <QQmlComponent> #include <QQmlIncubator> #include "../../shared/util.h" +#include <private/qjsvalue_p.h> #include <private/qqmlincubator_p.h> #include <private/qqmlobjectcreator_p.h> @@ -68,6 +69,7 @@ private slots: void chainedAsynchronousClear(); void selfDelete(); void contextDelete(); + void garbageCollection(); private: QQmlIncubationController controller; @@ -1144,6 +1146,34 @@ void tst_qqmlincubator::contextDelete() } } +// QTBUG-53111 +void tst_qqmlincubator::garbageCollection() +{ + QQmlComponent component(&engine, testFileUrl("garbageCollection.qml")); + QScopedPointer<QObject> obj(component.create()); + + engine.collectGarbage(); + + bool b = true; + controller.incubateWhile(&b); + + // verify incubation completed (the incubator was not prematurely collected) + QVariant incubatorVariant; + QMetaObject::invokeMethod(obj.data(), "getAndClearIncubator", Q_RETURN_ARG(QVariant, incubatorVariant)); + QJSValue strongRef = incubatorVariant.value<QJSValue>(); + QVERIFY(!strongRef.isNull() && !strongRef.isUndefined()); + + // turn the last strong reference to the incubator into a weak one and collect + QV4::WeakValue weakIncubatorRef; + weakIncubatorRef.set(QQmlEnginePrivate::getV4Engine(&engine), *QJSValuePrivate::getValue(&strongRef)); + strongRef = QJSValue(); + incubatorVariant.clear(); + + // verify incubator is correctly collected now that incubation is complete and all references are gone + engine.collectGarbage(); + QVERIFY(weakIncubatorRef.isNullOrUndefined()); +} + QTEST_MAIN(tst_qqmlincubator) #include "tst_qqmlincubator.moc" diff --git a/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml b/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml new file mode 100644 index 0000000000..4a3cc52793 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/polymorphicFunctionLookup.qml @@ -0,0 +1,14 @@ +import QtQml 2.0 +QtObject { + id: root + property bool testFunc; + property bool ok: false + property QtObject subObject: QtObject { + function testFunc() + { + root.ok = true + } + + Component.onCompleted: testFunc() + } +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index d890668655..bb6e9582c2 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1392,7 +1392,7 @@ class ScopedEnumsWithNameClash public: enum class ScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3, OtherScopedEnum }; - enum class OtherScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3 }; + enum class OtherScopedEnum : int { ScopedVal1 = 10, ScopedVal2 = 11, ScopedVal3 = 12 }; }; class ScopedEnumsWithResolvedNameClash diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 157fd500ad..7a8de739f4 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -298,6 +298,8 @@ private slots: void retrieveQmlTypeId(); + void polymorphicFunctionLookup(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -5049,6 +5051,17 @@ void tst_qqmllanguage::retrieveQmlTypeId() QVERIFY(qmlTypeId("Test", 1, 0, "MyTypeObjectSingleton") >= 0); } +void tst_qqmllanguage::polymorphicFunctionLookup() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("polymorphicFunctionLookup.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); + + QVERIFY(o->property("ok").toBool()); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index ae02352293..ff796a5bd8 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -2676,7 +2676,7 @@ void tst_QQuickListView::sectionsSnap_data() QTest::addColumn<int>("duration"); QTest::newRow("drag") << QQuickListView::NoSnap << QPoint(100, 45) << 500; - QTest::newRow("flick") << QQuickListView::SnapOneItem << QPoint(100, 75) << 50; + QTest::newRow("flick") << QQuickListView::SnapOneItem << QPoint(100, 60) << 100; } void tst_QQuickListView::sectionsSnap() diff --git a/tests/auto/quick/qquickstates/data/duplicateStateName.qml b/tests/auto/quick/qquickstates/data/duplicateStateName.qml new file mode 100644 index 0000000000..7bfafbef1b --- /dev/null +++ b/tests/auto/quick/qquickstates/data/duplicateStateName.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + property bool condition1: false + property bool condition2: false + property bool condition3: false + + states: [ + State { name: "state1"; when: condition1 }, + State { name: "state2"; when: condition2 }, + State { name: "state1"; when: condition3 } + ] +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 073fe33e20..50554f6333 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -137,6 +137,7 @@ private slots: void revertListBug(); void QTBUG_38492(); void revertListMemoryLeak(); + void duplicateStateName(); }; void tst_qquickstates::initTestCase() @@ -1654,6 +1655,17 @@ void tst_qquickstates::revertListMemoryLeak() QVERIFY(bindingPtr->ref == 1); } +void tst_qquickstates::duplicateStateName() +{ + QQmlEngine engine; + + QQmlComponent c(&engine, testFileUrl("duplicateStateName.qml")); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("duplicateStateName.qml") + ":3:1: QML Rectangle: Found duplicate state name: state1"); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem *>(c.create())); + QVERIFY(!item.isNull()); +} + + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" |