diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-03-12 21:02:14 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-03-12 21:02:14 +0100 |
commit | 3f4496ecea2cb1cb773c899675a6ecd0ef6183d5 (patch) | |
tree | a55813fb4fbe24fe0b1e1446abe29fd0818df576 | |
parent | 31e64606f253663f8ee2032b94521afd1804ab11 (diff) | |
parent | 4c689ad93d06bcfff5dfc4fdc41c69767aa04bee (diff) |
Merge remote-tracking branch 'origin/5.11' into dev
Change-Id: I6b2568337c09ff98850b4ecccccc9a8fc25064cd
35 files changed, 697 insertions, 485 deletions
diff --git a/.gitmodules b/.gitmodules index c9561f396d..e6e5650150 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "tests/auto/qml/ecmascripttests/test262"] path = tests/auto/qml/ecmascripttests/test262 url = ../qtdeclarative-testsuites.git + branch = snapshot-20150317-8f6a508-based diff --git a/src/3rdparty/masm/wtf/Compiler.h b/src/3rdparty/masm/wtf/Compiler.h index da10196cc1..598d7f2c1c 100644 --- a/src/3rdparty/masm/wtf/Compiler.h +++ b/src/3rdparty/masm/wtf/Compiler.h @@ -27,13 +27,13 @@ #define WTF_Compiler_h /* COMPILER() - the compiler being used to build the project */ -#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE) +#define COMPILER(WTF_FEATURE) WTF_COMPILER_##WTF_FEATURE /* COMPILER_SUPPORTS() - whether the compiler being used to build the project supports the given feature. */ -#define COMPILER_SUPPORTS(WTF_COMPILER_FEATURE) (defined WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE && WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE) +#define COMPILER_SUPPORTS(WTF_COMPILER_FEATURE) WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE /* COMPILER_QUIRK() - whether the compiler being used to build the project requires a given quirk. */ -#define COMPILER_QUIRK(WTF_COMPILER_QUIRK) (defined WTF_COMPILER_QUIRK_##WTF_COMPILER_QUIRK && WTF_COMPILER_QUIRK_##WTF_COMPILER_QUIRK) +#define COMPILER_QUIRK(WTF_COMPILER_QUIRK) WTF_COMPILER_QUIRK_##WTF_COMPILER_QUIRK /* ==== COMPILER() - the compiler being used to build the project ==== */ diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h index 7f2023a68a..4f37245495 100644 --- a/src/3rdparty/masm/wtf/Platform.h +++ b/src/3rdparty/masm/wtf/Platform.h @@ -38,26 +38,26 @@ /* ==== PLATFORM handles OS, operating environment, graphics API, and CPU. This macro will be phased out in favor of platform adaptation macros, policy decision macros, and top-level port definitions. ==== */ -#define PLATFORM(WTF_FEATURE) (defined WTF_PLATFORM_##WTF_FEATURE && WTF_PLATFORM_##WTF_FEATURE) +#define PLATFORM(WTF_FEATURE) WTF_PLATFORM_##WTF_FEATURE /* ==== Platform adaptation macros: these describe properties of the target environment. ==== */ /* CPU() - the target CPU architecture */ -#define CPU(WTF_FEATURE) (defined WTF_CPU_##WTF_FEATURE && WTF_CPU_##WTF_FEATURE) +#define CPU(WTF_FEATURE) WTF_CPU_##WTF_FEATURE /* HAVE() - specific system features (headers, functions or similar) that are present or not */ -#define HAVE(WTF_FEATURE) (defined HAVE_##WTF_FEATURE && HAVE_##WTF_FEATURE) +#define HAVE(WTF_FEATURE) HAVE_##WTF_FEATURE /* OS() - underlying operating system; only to be used for mandated low-level services like virtual memory, not to choose a GUI toolkit */ -#define OS(WTF_FEATURE) (defined WTF_OS_##WTF_FEATURE && WTF_OS_##WTF_FEATURE) +#define OS(WTF_FEATURE) WTF_OS_##WTF_FEATURE /* ==== Policy decision macros: these define policy choices for a particular port. ==== */ /* USE() - use a particular third-party library or optional OS service */ -#define USE(WTF_FEATURE) (defined WTF_USE_##WTF_FEATURE && WTF_USE_##WTF_FEATURE) +#define USE(WTF_FEATURE) WTF_USE_##WTF_FEATURE /* ENABLE() - turn on a specific feature of WebKit */ -#define ENABLE(WTF_FEATURE) (defined ENABLE_##WTF_FEATURE && ENABLE_##WTF_FEATURE) +#define ENABLE(WTF_FEATURE) ENABLE_##WTF_FEATURE /* ==== CPU() - the target CPU architecture ==== */ diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 7f2cf40611..c2cf18e3c4 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -665,6 +665,17 @@ private: } // namespace QmlIR +struct QQmlCompileError +{ + QQmlCompileError() {} + QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) + : location(location), description(description) {} + QV4::CompiledData::Location location; + QString description; + + bool isSet() const { return !description.isEmpty(); } +}; + QT_END_NAMESPACE #endif // QQMLIRBUILDER_P_H diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp index 4f8b48f52e..fd22cd58f1 100644 --- a/src/qml/compiler/qqmlpropertycachecreator.cpp +++ b/src/qml/compiler/qqmlpropertycachecreator.cpp @@ -45,26 +45,54 @@ QT_BEGIN_NAMESPACE QAtomicInt QQmlPropertyCacheCreatorBase::classIndexCounter(0); -QQmlBindingInstantiationContext::QQmlBindingInstantiationContext() - : referencingObjectIndex(-1) - , instantiatingBinding(nullptr) - , instantiatingProperty(nullptr) +QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, + const QString &instantiatingPropertyName, QQmlPropertyCache *referencingObjectPropertyCache) + : referencingObjectIndex(referencingObjectIndex) + , instantiatingBinding(instantiatingBinding) + , instantiatingPropertyName(instantiatingPropertyName) + , referencingObjectPropertyCache(referencingObjectPropertyCache) { +} +bool QQmlBindingInstantiationContext::resolveInstantiatingProperty() +{ + if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty) + return true; + + Q_ASSERT(referencingObjectIndex >= 0); + Q_ASSERT(referencingObjectPropertyCache); + Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); + + bool notInRevision = false; + instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, ¬InRevision, QmlIR::PropertyResolver::IgnoreRevision); + return instantiatingProperty != nullptr; } -QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache) - : referencingObjectIndex(referencingObjectIndex) - , instantiatingBinding(instantiatingBinding) - , instantiatingProperty(nullptr) +QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const { - if (instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty) { - Q_ASSERT(referencingObjectIndex >= 0); - Q_ASSERT(referencingObjectPropertyCache); - Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); + if (instantiatingProperty) { + if (instantiatingProperty->isQObject()) { + return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion()); + } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) { + return enginePrivate->cache(vtmo); + } + } + return QQmlRefPointer<QQmlPropertyCache>(); +} + +void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const +{ + for (QQmlBindingInstantiationContext pendingBinding: *this) { + const int groupPropertyObjectIndex = pendingBinding.instantiatingBinding->value.objectIndex; + + if (propertyCaches->at(groupPropertyObjectIndex)) + continue; + + if (!pendingBinding.resolveInstantiatingProperty()) + continue; - bool notInRevision = false; - instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, ¬InRevision, QmlIR::PropertyResolver::IgnoreRevision); + auto cache = pendingBinding.instantiatingPropertyCache(enginePrivate); + propertyCaches->set(groupPropertyObjectIndex, cache); } } diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h index 2af0fe0036..8bbc8291b4 100644 --- a/src/qml/compiler/qqmlpropertycachecreator_p.h +++ b/src/qml/compiler/qqmlpropertycachecreator_p.h @@ -50,18 +50,31 @@ // We mean it. // -#include "qqmltypecompiler_p.h" #include <private/qqmlvaluetype_p.h> #include <private/qqmlengine_p.h> QT_BEGIN_NAMESPACE struct QQmlBindingInstantiationContext { - QQmlBindingInstantiationContext(); - QQmlBindingInstantiationContext(int referencingObjectIndex, const QV4::CompiledData::Binding *instantiatingBinding, const QString &instantiatingPropertyName, const QQmlPropertyCache *referencingObjectPropertyCache); - int referencingObjectIndex; - const QV4::CompiledData::Binding *instantiatingBinding; - QQmlPropertyData *instantiatingProperty; + QQmlBindingInstantiationContext() {} + QQmlBindingInstantiationContext(int referencingObjectIndex, + const QV4::CompiledData::Binding *instantiatingBinding, + const QString &instantiatingPropertyName, + QQmlPropertyCache *referencingObjectPropertyCache); + + bool resolveInstantiatingProperty(); + QQmlRefPointer<QQmlPropertyCache> instantiatingPropertyCache(QQmlEnginePrivate *enginePrivate) const; + + int referencingObjectIndex = -1; + const QV4::CompiledData::Binding *instantiatingBinding = nullptr; + QString instantiatingPropertyName; + QQmlRefPointer<QQmlPropertyCache> referencingObjectPropertyCache; + QQmlPropertyData *instantiatingProperty = nullptr; +}; + +struct QQmlPendingGroupPropertyBindings : public QVector<QQmlBindingInstantiationContext> +{ + void resolveMissingPropertyCaches(QQmlEnginePrivate *enginePrivate, QQmlPropertyCacheVector *propertyCaches) const; }; struct QQmlPropertyCacheCreatorBase @@ -77,7 +90,10 @@ class QQmlPropertyCacheCreator : public QQmlPropertyCacheCreatorBase public: typedef typename ObjectContainer::CompiledObject CompiledObject; - QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports); + QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, + QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, + QQmlEnginePrivate *enginePrivate, + const ObjectContainer *objectContainer, const QQmlImports *imports); QQmlCompileError buildMetaObjects(); @@ -92,14 +108,19 @@ protected: const ObjectContainer * const objectContainer; const QQmlImports * const imports; QQmlPropertyCacheVector *propertyCaches; + QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings; }; template <typename ObjectContainer> -inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, QQmlEnginePrivate *enginePrivate, const ObjectContainer *objectContainer, const QQmlImports *imports) +inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlPropertyCacheVector *propertyCaches, + QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings, + QQmlEnginePrivate *enginePrivate, + const ObjectContainer *objectContainer, const QQmlImports *imports) : enginePrivate(enginePrivate) , objectContainer(objectContainer) , imports(imports) , propertyCaches(propertyCaches) + , pendingGroupPropertyBindings(pendingGroupPropertyBindings) { propertyCaches->resize(objectContainer->objectCount()); } @@ -169,6 +190,14 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje for ( ; binding != end; ++binding) if (binding->type >= QV4::CompiledData::Binding::Type_Object) { QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache); + + // Binding to group property where we failed to look up the type of the + // property? Possibly a group property that is an alias that's not resolved yet. + // Let's attempt to resolve it after we're done with the aliases and fill in the + // propertyCaches entry then. + if (!context.resolveInstantiatingProperty()) + pendingGroupPropertyBindings->append(context); + QQmlCompileError error = buildMetaObjectRecursively(binding->value.objectIndex, context); if (error.isSet()) return error; @@ -183,11 +212,7 @@ template <typename ObjectContainer> inline QQmlPropertyCache *QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlCompileError *error) const { if (context.instantiatingProperty) { - if (context.instantiatingProperty->isQObject()) { - return enginePrivate->rawPropertyCacheForType(context.instantiatingProperty->propType(), context.instantiatingProperty->typeMinorVersion()); - } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(context.instantiatingProperty->propType())) { - return enginePrivate->cache(vtmo); - } + return context.instantiatingPropertyCache(enginePrivate); } else if (obj->inheritedTypeNameIndex != 0) { auto *typeRef = objectContainer->resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 3415e1c073..a896745b3f 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -45,7 +45,6 @@ #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlcomponent_p.h> -#include "qqmlpropertycachecreator_p.h" //#include "qv4jssimplifier_p.h" #define COMPILE_EXCEPTION(token, desc) \ @@ -79,8 +78,12 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() customParsers.insert(it.key(), customParser); } + QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings; + + { - QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, engine, this, imports()); + QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings, + engine, this, imports()); QQmlCompileError error = propertyCacheBuilder.buildMetaObjects(); if (error.isSet()) { recordError(error); @@ -122,6 +125,8 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() QQmlComponentAndAliasResolver resolver(this); if (!resolver.resolve()) return nullptr; + + pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_propertyCaches); } { diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index d905b956c7..b8eddcb9b2 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -55,6 +55,7 @@ #include <qhash.h> #include <private/qqmltypeloader_p.h> #include <private/qqmlirbuilder_p.h> +#include <private/qqmlpropertycachecreator_p.h> QT_BEGIN_NAMESPACE @@ -74,17 +75,6 @@ struct Location; } } -struct QQmlCompileError -{ - QQmlCompileError() {} - QQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) - : location(location), description(description) {} - QV4::CompiledData::Location location; - QString description; - - bool isSet() const { return !description.isEmpty(); } -}; - struct QQmlTypeCompiler { Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler) diff --git a/src/qml/compiler/qv4bytecodegenerator_p.h b/src/qml/compiler/qv4bytecodegenerator_p.h index 3b3c766bfe..e69f2cd310 100644 --- a/src/qml/compiler/qv4bytecodegenerator_p.h +++ b/src/qml/compiler/qv4bytecodegenerator_p.h @@ -102,14 +102,19 @@ public: Jump(BytecodeGenerator *generator, int instruction) : generator(generator), index(instruction) - {} + { Q_ASSERT(generator && index != -1); } + ~Jump() { - Q_ASSERT(generator->instructions[index].linkedLabel != -1); + Q_ASSERT(index == -1 || generator->instructions[index].linkedLabel != -1); // make sure link() got called } + Jump(Jump &&j) { + std::swap(generator, j.generator); + std::swap(index, j.index); + } - BytecodeGenerator *generator; - int index; + BytecodeGenerator *generator = nullptr; + int index = -1; void link() { link(generator->label()); @@ -119,6 +124,12 @@ public: Q_ASSERT(generator->instructions[index].linkedLabel == -1); generator->instructions[index].linkedLabel = l.index; } + + private: + // make this type move-only: + Q_DISABLE_COPY(Jump) + // we never move-assign this type anywhere, so disable it: + Jump &operator=(Jump &&) = delete; }; struct ExceptionHandler : public Label { diff --git a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc index 0471d7db9b..be4db4c917 100644 --- a/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc +++ b/src/qml/doc/src/javascript/dynamicobjectcreation.qdoc @@ -157,7 +157,7 @@ to inside the string literals. When managing dynamically created objects, you must ensure the creation context outlives the created object. Otherwise, if the creation context is destroyed -first, the bindings in the dynamic object will no longer work. +first, the bindings and signal handlers in the dynamic object will no longer work. The actual creation context depends on how an object is created: diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f555740455..36448638f3 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -341,6 +341,11 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje if (!ddata) return QV4::Encode::undefined(); + if (Q_UNLIKELY(!ddata->propertyCache)) { + ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + ddata->propertyCache->addref(); + } + QQmlPropertyCache *cache = ddata->propertyCache; Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index cdda0bf7ef..4e83abebdf 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -664,8 +664,21 @@ void BlockAllocator::collectGrayItems(MarkStack *markStack) } HeapItem *HugeItemAllocator::allocate(size_t size) { - Chunk *c = chunkAllocator->allocate(size); - chunks.push_back(HugeChunk{c, size}); + MemorySegment *m = nullptr; + Chunk *c = nullptr; + if (size >= MemorySegment::SegmentSize/2) { + // too large to handle through the ChunkAllocator, let's get our own memory segement + size_t segmentSize = size + Chunk::HeaderSize; // space required for the Chunk header + size_t pageSize = WTF::pageSize(); + segmentSize = (segmentSize + pageSize - 1) & ~(pageSize - 1); // align to page sizes + m = new MemorySegment(segmentSize); + size = (size + pageSize - 1) & ~(pageSize - 1); // align to page sizes + c = m->allocate(size); + } else { + c = chunkAllocator->allocate(size); + } + Q_ASSERT(c); + chunks.push_back(HugeChunk{m, c, size}); Chunk::setBit(c->objectBitmap, c->first() - c->realBase()); Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem); #ifdef V4_USE_HEAPTRACK @@ -686,7 +699,13 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato v->destroy(b); b->_checkIsDestroyed(); } - chunkAllocator->free(c.chunk, c.size); + if (c.segment) { + // own memory segment + c.segment->free(c.chunk, c.size); + delete c.segment; + } else { + chunkAllocator->free(c.chunk, c.size); + } #ifdef V4_USE_HEAPTRACK heaptrack_report_free(c.chunk); #endif diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 1ef54ffcc6..40670bcdc7 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct ChunkAllocator; +struct MemorySegment; struct BlockAllocator { BlockAllocator(ChunkAllocator *chunkAllocator, ExecutionEngine *engine) @@ -136,6 +137,7 @@ struct HugeItemAllocator { ChunkAllocator *chunkAllocator; ExecutionEngine *engine; struct HugeChunk { + MemorySegment *segment; Chunk *chunk; size_t size; }; diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index ca3bff43a4..c314833304 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -490,6 +490,7 @@ void QQmlBinding::refresh() void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags) { + const bool wasEnabled = enabledFlag(); setEnabledFlag(e); setNotifyOnValueChanged(e); @@ -499,7 +500,7 @@ void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags) m_nextBinding.clearFlag2(); } - if (e) + if (e && !wasEnabled) update(flags); } @@ -514,13 +515,13 @@ void QQmlBinding::setTarget(const QQmlProperty &prop) setTarget(prop.object(), pd->core, &pd->valueTypeData); } -void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType) +bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType) { m_target = object; if (!object) { m_targetIndex = QQmlPropertyIndex(); - return; + return false; } int coreIndex = core.coreIndex(); @@ -530,9 +531,10 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const int aValueTypeIndex; if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { + // can't resolve id (yet) m_target = nullptr; m_targetIndex = QQmlPropertyIndex(); - return; + return false; } if (valueTypeIndex == -1) valueTypeIndex = aValueTypeIndex; @@ -541,7 +543,7 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const if (!data || !data->propertyCache) { m_target = nullptr; m_targetIndex = QQmlPropertyIndex(); - return; + return false; } QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); Q_ASSERT(propertyData); @@ -557,6 +559,8 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const data->propertyCache = QQmlEnginePrivate::get(context()->engine)->cache(m_target->metaObject()); data->propertyCache->addref(); } + + return true; } void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 19ec3f5d4f..b67b02975f 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -72,6 +72,8 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, { friend class QQmlAbstractBinding; public: + typedef QExplicitlySharedDataPointer<QQmlBinding> Ptr; + static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *); static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *, const QString &url = QString(), quint16 lineNumber = 0); @@ -82,7 +84,7 @@ public: ~QQmlBinding() override; void setTarget(const QQmlProperty &); - void setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType); + bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType); void setNotifyOnValueChanged(bool); diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 061f3b54a5..3174bbecd3 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -241,6 +241,9 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); \li main.qml \li \snippet qml/component/main.qml 0 \endtable + + It is important that the lifetime of the creation context outlive any created objects. See + \l{Maintaining Dynamically Created Objects} for more details. */ /*! diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 36e56a01f8..90f3beb40b 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -780,7 +780,7 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) qSwap(_currentList, savedList); } -bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) +bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding) { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); @@ -802,7 +802,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con } // ### resolve this at compile time - if (property && property->propType() == qMetaTypeId<QQmlScriptString>()) { + if (bindingProperty && bindingProperty->propType() == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; @@ -815,7 +815,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlPropertyData::RemoveBindingOnAliasWrite; int propertyWriteStatus = -1; void *argv[] = { &ss, nullptr, &propertyWriteStatus, &propertyWriteFlags }; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv); return true; } @@ -826,7 +826,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; } - if (!property) // ### error + if (!bindingProperty) // ### error return true; if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) { @@ -838,20 +838,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con const QQmlPropertyData *valueTypeProperty = nullptr; QObject *bindingTarget = _bindingTarget; - if (QQmlValueTypeFactory::isValueType(property->propType())) { - valueType = QQmlValueTypeFactory::valueType(property->propType()); + if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) { + valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType()); if (!valueType) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; } - valueType->read(_qobject, property->coreIndex()); + valueType->read(_qobject, bindingProperty->coreIndex()); groupObject = valueType; - valueTypeProperty = property; + valueTypeProperty = bindingProperty; } else { void *argv[1] = { &groupObject }; - QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv); + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, bindingProperty->coreIndex(), argv); if (!groupObject) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; @@ -864,21 +864,21 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; if (valueType) - valueType->write(_qobject, property->coreIndex(), QQmlPropertyData::BypassInterceptor); + valueType->write(_qobject, bindingProperty->coreIndex(), QQmlPropertyData::BypassInterceptor); return true; } } - if (_ddata->hasBindingBit(property->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) + if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) - QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex())); + QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex())); if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; - int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex()); + int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, context, _scopeObject, runtimeFunction, currentQmlContext()); @@ -890,34 +890,44 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // the point property (_qobjectForBindings) and after evaluating the expression, // the result is written to a value type virtual property, that contains the sub-index // of the "x" property. - QQmlBinding *qmlBinding; - const QQmlPropertyData *prop = property; + QQmlBinding::Ptr qmlBinding; + const QQmlPropertyData *targetProperty = bindingProperty; const QQmlPropertyData *subprop = nullptr; if (_valueTypeProperty) { - prop = _valueTypeProperty; - subprop = property; + targetProperty = _valueTypeProperty; + subprop = bindingProperty; } if (binding->containsTranslations()) { qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context); } else { QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; - qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext()); + qmlBinding = QQmlBinding::create(targetProperty, runtimeFunction, _scopeObject, context, currentQmlContext()); } - qmlBinding->setTarget(_bindingTarget, *prop, subprop); - sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); + auto bindingTarget = _bindingTarget; + auto valueTypeProperty = _valueTypeProperty; + auto assignBinding = [qmlBinding, bindingTarget, targetProperty, subprop, bindingProperty, valueTypeProperty](QQmlObjectCreatorSharedState *sharedState) -> bool { + if (!qmlBinding->setTarget(bindingTarget, *targetProperty, subprop) && targetProperty->isAlias()) + return false; + + sharedState->allCreatedBindings.push(qmlBinding); - if (property->isAlias()) { - QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable); - } else { - qmlBinding->addToObject(); + if (bindingProperty->isAlias()) { + QQmlPropertyPrivate::setBinding(qmlBinding.data(), QQmlPropertyPrivate::DontEnable); + } else { + qmlBinding->addToObject(); - if (!_valueTypeProperty) { - QQmlData *targetDeclarativeData = QQmlData::get(_bindingTarget); - Q_ASSERT(targetDeclarativeData); - targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex()); + if (!valueTypeProperty) { + QQmlData *targetDeclarativeData = QQmlData::get(bindingTarget); + Q_ASSERT(targetDeclarativeData); + targetDeclarativeData->setPendingBindingBit(bindingTarget, bindingProperty->coreIndex()); + } } - } + + return true; + }; + if (!assignBinding(sharedState.data())) + pendingAliasBindings.push_back(assignBinding); } return true; } @@ -934,9 +944,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QObject *target = createdSubObject->parent(); QQmlProperty prop; if (_valueTypeProperty) - prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context); + prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context); else - prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context); + prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context); vs->setTarget(prop); return true; } @@ -946,8 +956,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QObject *target = createdSubObject->parent(); QQmlPropertyIndex propertyIndex; - if (property->isAlias()) { - QQmlPropertyIndex originalIndex(property->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1); + if (bindingProperty->isAlias()) { + QQmlPropertyIndex originalIndex(bindingProperty->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1); QQmlPropertyIndex propIndex; QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex); QQmlData *data = QQmlData::get(target); @@ -964,9 +974,9 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con } else { QQmlProperty prop; if (_valueTypeProperty) - prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context); + prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, bindingProperty, context); else - prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context); + prop = QQmlPropertyPrivate::restore(target, *bindingProperty, nullptr, context); vi->setTarget(prop); propertyIndex = QQmlPropertyPrivate::propertyIndex(prop); } @@ -982,8 +992,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con // Assigning object to signal property? if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) { - if (!property->isFunction()) { - recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(property->name(_qobject))); + if (!bindingProperty->isFunction()) { + recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject))); return false; } QMetaMethod method = QQmlMetaType::defaultMethod(createdSubObject); @@ -992,7 +1002,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; } - QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex()); + QMetaMethod signalMethod = _qobject->metaObject()->method(bindingProperty->coreIndex()); if (!QMetaObject::checkConnectArgs(signalMethod, method)) { recordError(binding->valueLocation, tr("Cannot connect mismatched signal/slot %1 %vs. %2") @@ -1001,7 +1011,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; } - QQmlPropertyPrivate::connect(_qobject, property->coreIndex(), createdSubObject, method.methodIndex()); + QQmlPropertyPrivate::connect(_qobject, bindingProperty->coreIndex(), createdSubObject, method.methodIndex()); return true; } @@ -1010,32 +1020,32 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con int propertyWriteStatus = -1; void *argv[] = { nullptr, nullptr, &propertyWriteStatus, &propertyWriteFlags }; - if (const char *iid = QQmlMetaType::interfaceIId(property->propType())) { + if (const char *iid = QQmlMetaType::interfaceIId(bindingProperty->propType())) { void *ptr = createdSubObject->qt_metacast(iid); if (ptr) { argv[0] = &ptr; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv); } else { recordError(binding->location, tr("Cannot assign object to interface property")); return false; } - } else if (property->propType() == QMetaType::QVariant) { - if (property->isVarProperty()) { + } else if (bindingProperty->propType() == QMetaType::QVariant) { + if (bindingProperty->isVarProperty()) { QV4::Scope scope(v4); QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(engine->handle(), createdSubObject)); - _vmeMetaObject->setVMEProperty(property->coreIndex(), wrappedObject); + _vmeMetaObject->setVMEProperty(bindingProperty->coreIndex(), wrappedObject); } else { QVariant value = QVariant::fromValue(createdSubObject); argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv); } - } else if (property->isQList()) { + } else if (bindingProperty->isQList()) { Q_ASSERT(_currentList.object); void *itemToAdd = createdSubObject; const char *iid = nullptr; - int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType()); + int listItemType = QQmlEnginePrivate::get(engine)->listType(bindingProperty->propType()); if (listItemType != -1) iid = QQmlMetaType::interfaceIId(listItemType); if (iid) @@ -1051,17 +1061,17 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con } else { // pointer compatibility was tested in QQmlPropertyValidator at type compile time argv[0] = &createdSubObject; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, bindingProperty->coreIndex(), argv); } return true; } - if (property->isQList()) { + if (bindingProperty->isQList()) { recordError(binding->location, tr("Cannot assign primitives to lists")); return false; } - setPropertyValue(property, binding); + setPropertyValue(bindingProperty, binding); return true; } @@ -1274,12 +1284,33 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo qSwap(_qmlContext, qmlContext); - bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr); + bool ok = populateInstance(index, instance, /*binding target*/instance, /*value type property*/nullptr); + if (ok) { + if (isContextObject && !pendingAliasBindings.empty()) { + bool processedAtLeastOneBinding = false; + do { + processedAtLeastOneBinding = false; + for (std::vector<PendingAliasBinding>::iterator it = pendingAliasBindings.begin(); + it != pendingAliasBindings.end(); ) { + if ((*it)(sharedState.data())) { + it = pendingAliasBindings.erase(it); + processedAtLeastOneBinding = true; + } else { + ++it; + } + } + } while (processedAtLeastOneBinding && pendingAliasBindings.empty()); + Q_ASSERT(pendingAliasBindings.empty()); + } + } else { + // an error occurred, so we can't setup the pending alias bindings + pendingAliasBindings.clear(); + } qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); - return result ? instance : nullptr; + return ok ? instance : nullptr; } QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 399a5f6d4a..67a5bdd827 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -161,6 +161,9 @@ private: QV4::QmlContext *_qmlContext; friend struct QQmlObjectCreatorRecursionWatcher; + + typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding; + std::vector<PendingAliasBinding> pendingAliasBindings; }; struct QQmlObjectCreatorRecursionWatcher diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 8ecd597a39..c4487f91a3 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -269,7 +269,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) for (int ii = 0; ii < path.count() - 1; ++ii) { const QStringRef &pathName = path.at(ii); - if (typeNameCache) { + // Types must begin with an uppercase letter (see checkRegistration() + // in qqmlmetatype.cpp for the enforcement of this). + if (typeNameCache && !pathName.isEmpty() && pathName.at(0).isUpper()) { QQmlTypeNameCache::Result r = typeNameCache->query(pathName); if (r.isValid()) { if (r.type.isValid()) { @@ -875,6 +877,7 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bin void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags) { Q_ASSERT(binding); + Q_ASSERT(binding->targetObject()); QObject *object = binding->targetObject(); const QQmlPropertyIndex index = binding->targetPropertyIndex(); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 51a191a41f..b78a2ddd20 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -81,6 +81,7 @@ template <typename T> class QQmlPropertyCacheAliasCreator; // We have this somewhat awful split between RawData and Data so that RawData can be // used in unions. In normal code, you should always use Data which initializes RawData // to an invalid state on construction. +// ### We should be able to remove this split nowadays class QQmlPropertyRawData { public: @@ -273,20 +274,20 @@ public: private: Flags _flags; - qint16 _coreIndex; - quint16 _propType; + qint16 _coreIndex = 0; + quint16 _propType = 0; // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). - qint16 _notifyIndex; - qint16 _overrideIndex; + qint16 _notifyIndex = 0; + qint16 _overrideIndex = 0; - quint8 _revision; - quint8 _typeMinorVersion; - qint16 _metaObjectOffset; + quint8 _revision = 0; + quint8 _typeMinorVersion = 0; + qint16 _metaObjectOffset = 0; - QQmlPropertyCacheMethodArguments *_arguments; - StaticMetaCallFunction _staticMetaCallFunction; + QQmlPropertyCacheMethodArguments *_arguments = nullptr; + StaticMetaCallFunction _staticMetaCallFunction = nullptr; friend class QQmlPropertyData; friend class QQmlPropertyCache; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index a107bb42ce..61208d1c4a 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2187,8 +2187,12 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + QQmlPendingGroupPropertyBindings pendingGroupPropertyBindings; + { - QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, engine, m_compiledData, &m_importCache); + QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, + &pendingGroupPropertyBindings, + engine, m_compiledData, &m_importCache); QQmlCompileError error = propertyCacheCreator.buildMetaObjects(); if (error.isSet()) { setError(error); @@ -2198,6 +2202,8 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeName QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData); aliasCreator.appendAliasPropertiesToMetaObjects(); + + pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches); } static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeReference> &typeRefs, QCryptographicHash *hash, QQmlEngine *engine) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 0e1d9e6fad..14ba6561d4 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1123,6 +1123,11 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va QQmlEngine *engine = scope.engine->qmlEngine(); QQmlContextData *context = scope.engine->callingQmlContext(); + if (!context) { + QQmlEngine *qmlEngine = scope.engine->qmlEngine(); + if (qmlEngine) + context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext); + } Q_ASSERT(context); QQmlContext *effectiveContext = nullptr; if (context->isPragmaLibraryContext) @@ -1250,6 +1255,11 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va QQmlEngine *engine = scope.engine->qmlEngine(); QQmlContextData *context = scope.engine->callingQmlContext(); + if (!context) { + QQmlEngine *qmlEngine = scope.engine->qmlEngine(); + if (qmlEngine) + context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext); + } Q_ASSERT(context); QQmlContextData *effectiveContext = context; if (context->isPragmaLibraryContext) diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 40d1fab3dc..1be4bafe28 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -625,8 +625,7 @@ QQuickPointerDevice *QQuickPointerDevice::touchDevice(const QTouchDevice *d) int maximumTouchPoints = 10; QQuickPointerDevice::Capabilities caps = QQuickPointerDevice::Capabilities(QTouchDevice::Position); if (d) { - QQuickPointerDevice::Capabilities caps = - static_cast<QQuickPointerDevice::Capabilities>(static_cast<int>(d->capabilities()) & 0x0F); + caps = static_cast<QQuickPointerDevice::Capabilities>(static_cast<int>(d->capabilities()) & 0xFF); if (d->type() == QTouchDevice::TouchPad) { type = QQuickPointerDevice::TouchPad; caps |= QQuickPointerDevice::Scroll; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index ea24bfcad5..3a0aea517c 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -1544,6 +1544,13 @@ QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj) mirroring is not the desired behavior, or if the child item already implements mirroring in some custom way. + To set the layout direction based on the \l {Default Layout Direction}{default layout direction} + of the application, use the following code: + + \code + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + \endcode + See \l {Right-to-left User Interfaces} for further details on using \c LayoutMirroring and other related features to implement right-to-left support for an application. */ diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262 -Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8 +Subproject 40b4f28e98c416a092e26aa17489bf94ccb8bf4 diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index bf964a5744..52e18011cb 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -76,6 +76,7 @@ private slots: void qmlContextProperties(); void testGCCorruption(); void testGroupedPropertyRevisions(); + void componentFromEval(); public slots: QObject *createAQObjectForOwnershipTest () @@ -885,6 +886,17 @@ void tst_qqmlengine::testGroupedPropertyRevisions() QVERIFY(!c2.errorString().isEmpty()); } +void tst_qqmlengine::componentFromEval() +{ + QQmlEngine engine; + const QUrl testUrl = testFileUrl("EmptyComponent.qml"); + QJSValue result = engine.evaluate("Qt.createComponent(\"" + testUrl.toString() + "\");"); + QPointer<QQmlComponent> component(qobject_cast<QQmlComponent*>(result.toQObject())); + QVERIFY(!component.isNull()); + QScopedPointer<QObject> item(component->create()); + QVERIFY(!item.isNull()); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmllanguage/data/alias.15.qml b/tests/auto/qml/qqmllanguage/data/alias.15.qml new file mode 100644 index 0000000000..5f3de9c83e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.15.qml @@ -0,0 +1,12 @@ +import QtQuick 2.6 + +Item { + id: root + + property alias symbol: symbol + symbol.y: 1 + + Item { + id: symbol + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.16.qml b/tests/auto/qml/qqmllanguage/data/alias.16.qml new file mode 100644 index 0000000000..4637aec58f --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.16.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 + +Window { + visible: true + + property alias list: repeater.model + + list: ["A", "B", "C"] + + Repeater { + id: repeater + } +} + diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml new file mode 100644 index 0000000000..ff2f0f5a2c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.2.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + property int secondVar: { + stats.increaseEvaluationCounter() + return 1 + } + property int firstVar: secondVar + 1 +} diff --git a/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml new file mode 100644 index 0000000000..0eb5e03642 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/noDoubleEvaluationForFlushedBindings.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +QtObject { + property int firstVar: secondVar + 1 + property int secondVar: { + stats.increaseEvaluationCounter() + return 1 + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 952e4a22a1..8bc631fbdd 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -125,6 +125,8 @@ private slots: void dynamicObjectProperties(); void dynamicSignalsAndSlots(); void simpleBindings(); + void noDoubleEvaluationForFlushedBindings_data(); + void noDoubleEvaluationForFlushedBindings(); void autoComponentCreation(); void autoComponentCreationInGroupProperty(); void propertyValueSource(); @@ -372,9 +374,11 @@ void tst_qqmllanguage::insertedSemicolon() QQmlComponent component(&engine, testFileUrl(file)); + QScopedPointer<QObject> object; + if(create) { - QObject *object = component.create(); - QVERIFY(!object); + object.reset(component.create()); + QVERIFY(object.isNull()); } VERIFY_ERRORS(errorFile.toLatin1().constData()); @@ -606,9 +610,11 @@ void tst_qqmllanguage::errors() QQmlComponent component(&engine, testFileUrl(file)); + QScopedPointer<QObject> object; + if (create) { - QObject *object = component.create(); - QVERIFY(!object); + object.reset(component.create()); + QVERIFY(object.isNull()); } VERIFY_ERRORS(errorFile.toLatin1().constData()); @@ -618,7 +624,7 @@ void tst_qqmllanguage::simpleObject() { QQmlComponent component(&engine, testFileUrl("simpleObject.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -626,7 +632,7 @@ void tst_qqmllanguage::simpleContainer() { QQmlComponent component(&engine, testFileUrl("simpleContainer.qml")); VERIFY_ERRORS(0); - MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getChildren()->count(),2); } @@ -635,7 +641,7 @@ void tst_qqmllanguage::interfaceProperty() { QQmlComponent component(&engine, testFileUrl("interfaceProperty.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->interface()); QCOMPARE(object->interface()->id, 913); @@ -645,7 +651,7 @@ void tst_qqmllanguage::interfaceQList() { QQmlComponent component(&engine, testFileUrl("interfaceQList.qml")); VERIFY_ERRORS(0); - MyContainer *container= qobject_cast<MyContainer*>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer*>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getQListInterfaces()->count(), 2); for(int ii = 0; ii < 2; ++ii) @@ -656,7 +662,7 @@ void tst_qqmllanguage::assignObjectToSignal() { QQmlComponent component(&engine, testFileUrl("assignObjectToSignal.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -666,7 +672,7 @@ void tst_qqmllanguage::assignObjectToVariant() { QQmlComponent component(&engine, testFileUrl("assignObjectToVariant.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVariant v = object->property("a"); QVERIFY(v.userType() == qMetaTypeId<QObject *>()); @@ -676,7 +682,7 @@ void tst_qqmllanguage::assignLiteralSignalProperty() { QQmlComponent component(&engine, testFileUrl("assignLiteralSignalProperty.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->onLiteralSignal(), 10); } @@ -686,7 +692,7 @@ void tst_qqmllanguage::assignQmlComponent() { QQmlComponent component(&engine, testFileUrl("assignQmlComponent.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 1); QObject *child = object->getChildren()->at(0); @@ -699,7 +705,7 @@ void tst_qqmllanguage::assignBasicTypes() { QQmlComponent component(&engine, testFileUrl("assignBasicTypes.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3); QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2); @@ -744,7 +750,7 @@ void tst_qqmllanguage::assignTypeExtremes() { QQmlComponent component(&engine, testFileUrl("assignTypeExtremes.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->uintProperty(), 0xEE6B2800); QCOMPARE(object->intProperty(), -0x77359400); @@ -755,7 +761,7 @@ void tst_qqmllanguage::assignCompositeToType() { QQmlComponent component(&engine, testFileUrl("assignCompositeToType.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -764,7 +770,7 @@ void tst_qqmllanguage::assignLiteralToVariant() { QQmlComponent component(&engine, testFileUrl("assignLiteralToVariant.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(isJSNumberType(object->property("test1").userType())); @@ -792,8 +798,6 @@ void tst_qqmllanguage::assignLiteralToVariant() QCOMPARE(object->property("test10"), QVariant(bool(true))); QCOMPARE(object->property("test11"), QVariant(bool(false))); QVERIFY(object->property("test12") == QVariant(QVector4D(100, 100, 100, 100))); - - delete object; } // Test that literals are stored correctly in "var" properties @@ -803,7 +807,7 @@ void tst_qqmllanguage::assignLiteralToVar() { QQmlComponent component(&engine, testFileUrl("assignLiteralToVar.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(isJSNumberType(object->property("test1").userType())); @@ -843,15 +847,13 @@ void tst_qqmllanguage::assignLiteralToVar() QCOMPARE(object->property("test16"), QVariant(QVector3D(100, 100, 100))); QCOMPARE(object->property("variantTest1Bound"), QVariant(9)); QCOMPARE(object->property("test1Bound"), QVariant(11)); - - delete object; } void tst_qqmllanguage::assignLiteralToJSValue() { QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -939,11 +941,11 @@ void tst_qqmllanguage::assignNullStrings() { QQmlComponent component(&engine, testFileUrl("assignNullStrings.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->stringProperty().isNull()); QVERIFY(object->byteArrayProperty().isNull()); - QMetaObject::invokeMethod(object, "assignNullStringsFromJs", Qt::DirectConnection); + QMetaObject::invokeMethod(object.data(), "assignNullStringsFromJs", Qt::DirectConnection); QVERIFY(object->stringProperty().isNull()); QVERIFY(object->byteArrayProperty().isNull()); } @@ -953,7 +955,7 @@ void tst_qqmllanguage::bindJSValueToVar() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); QObject *object = root->findChild<QObject *>("varProperties"); @@ -1002,7 +1004,7 @@ void tst_qqmllanguage::bindJSValueToVariant() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); QObject *object = root->findChild<QObject *>("variantProperties"); @@ -1051,7 +1053,7 @@ void tst_qqmllanguage::bindJSValueToType() QQmlComponent component(&engine, testFileUrl("assignLiteralToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -1086,7 +1088,7 @@ void tst_qqmllanguage::bindTypeToJSValue() QQmlComponent component(&engine, testFileUrl("bindTypeToJSValue.qml")); VERIFY_ERRORS(0); - QObject *root = component.create(); + QScopedPointer<QObject> root(component.create()); QVERIFY(root != nullptr); { @@ -1225,7 +1227,7 @@ void tst_qqmllanguage::customParserTypes() { QQmlComponent component(&engine, testFileUrl("customParserTypes.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("count"), QVariant(2)); } @@ -1235,7 +1237,7 @@ void tst_qqmllanguage::rootAsQmlComponent() { QQmlComponent component(&engine, testFileUrl("rootAsQmlComponent.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->property("x"), QVariant(11)); QCOMPARE(object->getChildren()->count(), 2); @@ -1259,12 +1261,12 @@ void tst_qqmllanguage::inlineQmlComponents() { QQmlComponent component(&engine, testFileUrl("inlineQmlComponents.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 1); QQmlComponent *comp = qobject_cast<QQmlComponent *>(object->getChildren()->at(0)); QVERIFY(comp != nullptr); - MyQmlObject *compObject = qobject_cast<MyQmlObject *>(comp->create()); + QScopedPointer<MyQmlObject> compObject(qobject_cast<MyQmlObject *>(comp->create())); QVERIFY(compObject != nullptr); QCOMPARE(compObject->value(), 11); } @@ -1275,7 +1277,7 @@ void tst_qqmllanguage::idProperty() { QQmlComponent component(&engine, testFileUrl("idProperty.qml")); VERIFY_ERRORS(0); - MyContainer *object = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> object(qobject_cast<MyContainer *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->getChildren()->count(), 2); MyTypeObject *child = @@ -1306,14 +1308,14 @@ void tst_qqmllanguage::autoNotifyConnection() { QQmlComponent component(&engine, testFileUrl("autoNotifyConnection.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QMetaProperty prop = object->metaObject()->property(object->metaObject()->indexOfProperty("receivedNotify")); QVERIFY(prop.isValid()); - QCOMPARE(prop.read(object), QVariant::fromValue(false)); + QCOMPARE(prop.read(object.data()), QVariant::fromValue(false)); object->setPropertyWithNotify(1); - QCOMPARE(prop.read(object), QVariant::fromValue(true)); + QCOMPARE(prop.read(object.data()), QVariant::fromValue(true)); } // Tests that signals can be assigned to @@ -1321,7 +1323,7 @@ void tst_qqmllanguage::assignSignal() { QQmlComponent component(&engine, testFileUrl("assignSignal.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -1333,7 +1335,7 @@ void tst_qqmllanguage::assignSignalFunctionExpression() { QQmlComponent component(&engine, testFileUrl("assignSignalFunctionExpression.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QTest::ignoreMessage(QtWarningMsg, "MyQmlObject::basicSlot"); emit object->basicSignal(); @@ -1362,10 +1364,9 @@ void tst_qqmllanguage::overrideSignal() QQmlComponent component(&engine, testFileUrl(file)); if (errorFile.isEmpty()) { VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->property("success").toBool()); - delete object; } else { VERIFY_ERRORS(errorFile.toLatin1().constData()); } @@ -1376,8 +1377,7 @@ void tst_qqmllanguage::dynamicProperties() { QQmlComponent component(&engine, testFileUrl("dynamicProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); - QVERIFY(object != nullptr); + QScopedPointer<QObject> object(component.create()); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); @@ -1394,15 +1394,13 @@ void tst_qqmllanguage::dynamicPropertiesNested() { QQmlComponent component(&engine, testFileUrl("dynamicPropertiesNested.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("super_a").toInt(), 11); // Overridden QCOMPARE(object->property("super_c").toInt(), 14); // Inherited QCOMPARE(object->property("a").toInt(), 13); // New QCOMPARE(object->property("b").toInt(), 12); // New - - delete object; } // Tests the creation and assignment to dynamic list properties @@ -1410,7 +1408,7 @@ void tst_qqmllanguage::listProperties() { QQmlComponent component(&engine, testFileUrl("listProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toInt(), 2); @@ -1430,7 +1428,7 @@ void tst_qqmllanguage::dynamicObjectProperties() { QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("objectProperty"), qVariantFromValue((QObject*)nullptr)); @@ -1439,7 +1437,7 @@ void tst_qqmllanguage::dynamicObjectProperties() { QQmlComponent component(&engine, testFileUrl("dynamicObjectProperties.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->property("objectProperty") != qVariantFromValue((QObject*)nullptr)); @@ -1453,7 +1451,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots() QQmlComponent component(&engine, testFileUrl("dynamicSignalsAndSlots.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(object->metaObject()->indexOfMethod("signal1()") != -1); QVERIFY(object->metaObject()->indexOfMethod("signal2()") != -1); @@ -1461,7 +1459,7 @@ void tst_qqmllanguage::dynamicSignalsAndSlots() QVERIFY(object->metaObject()->indexOfMethod("slot2()") != -1); QCOMPARE(object->property("test").toInt(), 0); - QMetaObject::invokeMethod(object, "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10))); + QMetaObject::invokeMethod(object.data(), "slot3", Qt::DirectConnection, Q_ARG(QVariant, QVariant(10))); QCOMPARE(object->property("test").toInt(), 10); } @@ -1469,13 +1467,44 @@ void tst_qqmllanguage::simpleBindings() { QQmlComponent component(&engine, testFileUrl("simpleBindings.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value1"), QVariant(10)); QCOMPARE(object->property("value2"), QVariant(10)); QCOMPARE(object->property("value3"), QVariant(21)); QCOMPARE(object->property("value4"), QVariant(10)); - QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object)); + QCOMPARE(object->property("objectProperty"), QVariant::fromValue(object.data())); +} + +class EvaluationCounter : public QObject +{ + Q_OBJECT +public: + int counter = 0; + Q_INVOKABLE void increaseEvaluationCounter() { ++counter; } +}; + +void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::newRow("order1") << QString("noDoubleEvaluationForFlushedBindings.qml"); + QTest::newRow("order2") << QString("noDoubleEvaluationForFlushedBindings.2.qml"); +} + +void tst_qqmllanguage::noDoubleEvaluationForFlushedBindings() +{ + QFETCH(QString, fileName); + QQmlEngine engine; + + EvaluationCounter stats; + engine.rootContext()->setContextProperty("stats", &stats); + + QQmlComponent component(&engine, testFileUrl(fileName)); + VERIFY_ERRORS(0); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QCOMPARE(stats.counter, 1); } void tst_qqmllanguage::autoComponentCreation() @@ -1483,20 +1512,20 @@ void tst_qqmllanguage::autoComponentCreation() { QQmlComponent component(&engine, testFileUrl("autoComponentCreation.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } { QQmlComponent component(&engine, testFileUrl("autoComponentCreation.2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } @@ -1506,10 +1535,10 @@ void tst_qqmllanguage::autoComponentCreationInGroupProperty() { QQmlComponent component(&engine, testFileUrl("autoComponentCreationInGroupProperties.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QVERIFY(object->componentProperty() != nullptr); - MyTypeObject *child = qobject_cast<MyTypeObject *>(object->componentProperty()->create()); + QScopedPointer<MyTypeObject> child(qobject_cast<MyTypeObject *>(object->componentProperty()->create())); QVERIFY(child != nullptr); QCOMPARE(child->realProperty(), qreal(9)); } @@ -1519,7 +1548,7 @@ void tst_qqmllanguage::propertyValueSource() { QQmlComponent component(&engine, testFileUrl("propertyValueSource.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QList<QObject *> valueSources; @@ -1533,14 +1562,14 @@ void tst_qqmllanguage::propertyValueSource() MyPropertyValueSource *valueSource = qobject_cast<MyPropertyValueSource *>(valueSources.at(0)); QVERIFY(valueSource != nullptr); - QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object)); + QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data())); QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty"))); } { QQmlComponent component(&engine, testFileUrl("propertyValueSource.2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QList<QObject *> valueSources; @@ -1554,7 +1583,7 @@ void tst_qqmllanguage::propertyValueSource() MyPropertyValueSource *valueSource = qobject_cast<MyPropertyValueSource *>(valueSources.at(0)); QVERIFY(valueSource != nullptr); - QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object)); + QCOMPARE(valueSource->prop.object(), qobject_cast<QObject*>(object.data())); QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty"))); } } @@ -1563,9 +1592,9 @@ void tst_qqmllanguage::attachedProperties() { QQmlComponent component(&engine, testFileUrl("attachedProperties.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object); + QObject *attached = qmlAttachedPropertiesObject<MyQmlObject>(object.data()); QVERIFY(attached != nullptr); QCOMPARE(attached->property("value"), QVariant(10)); QCOMPARE(attached->property("value2"), QVariant(13)); @@ -1576,7 +1605,7 @@ void tst_qqmllanguage::dynamicObjects() { QQmlComponent component(&engine, testFileUrl("dynamicObject.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1585,7 +1614,7 @@ void tst_qqmllanguage::customVariantTypes() { QQmlComponent component(&engine, testFileUrl("customVariantTypes.qml")); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->customType().a, 10); } @@ -1599,7 +1628,7 @@ void tst_qqmllanguage::valueTypes() QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); @@ -1630,20 +1659,17 @@ void tst_qqmllanguage::cppnamespace() { QQmlComponent component(&engine, testFileUrl("cppnamespace.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2); - - delete object; } { QQmlComponent component(&engine, testFileUrl("cppnamespace.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - delete object; } } @@ -1653,7 +1679,7 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1665,15 +1691,13 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("valueAlias", QVariant(19)); QCOMPARE(object->property("valueAlias").toInt(), 19); QCOMPARE(object->property("value").toInt(), 19); - - delete object; } // Complex object alias { QQmlComponent component(&engine, testFileUrl("alias.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1684,21 +1708,19 @@ void tst_qqmllanguage::aliasProperties() // Write through alias MyQmlObject *v2 = new MyQmlObject(); - v2->setParent(object); + v2->setParent(object.data()); object->setProperty("aliasObject", qVariantFromValue(v2)); MyQmlObject *v3 = qvariant_cast<MyQmlObject *>(object->property("aliasObject")); QVERIFY(v3 != nullptr); QCOMPARE(v3, v2); - - delete object; } // Nested aliases { QQmlComponent component(&engine, testFileUrl("alias.3.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 1892); @@ -1711,27 +1733,23 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("value2", QVariant(8080)); QCOMPARE(object->property("value").toInt(), 8080); QCOMPARE(object->property("value2").toInt(), 8080); - - delete object; } // Enum aliases { QQmlComponent component(&engine, testFileUrl("alias.4.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("enumAlias").toInt(), 1); - - delete object; } // Id aliases { QQmlComponent component(&engine, testFileUrl("alias.5.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVariant v = object->property("otherAlias"); @@ -1745,15 +1763,13 @@ void tst_qqmllanguage::aliasProperties() QCOMPARE(v.userType(), qMetaTypeId<MyQmlObject*>()); o = qvariant_cast<MyQmlObject*>(v); QVERIFY(!o); - - delete object; } // Nested aliases - this used to cause a crash { QQmlComponent component(&engine, testFileUrl("alias.6.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("a").toInt(), 1923); @@ -1765,7 +1781,7 @@ void tst_qqmllanguage::aliasProperties() QQmlComponent component(&engine, testFileUrl("alias.7.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QObject *object1 = qvariant_cast<QObject *>(object->property("object")); @@ -1778,10 +1794,10 @@ void tst_qqmllanguage::aliasProperties() delete object1; - QObject *alias2 = object; // "Random" start value + QObject *alias2 = object.data(); // "Random" start value int status = -1; void *a[] = { &alias2, nullptr, &status }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, + QMetaObject::metacall(object.data(), QMetaObject::ReadProperty, object->metaObject()->indexOfProperty("aliasedObject"), a); QVERIFY(!alias2); } @@ -1790,24 +1806,20 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.8.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 10); - - delete object; } // Complex composite type { QQmlComponent component(&engine, testFileUrl("alias.9.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toInt(), 10); - - delete object; } // Valuetype alias @@ -1815,7 +1827,7 @@ void tst_qqmllanguage::aliasProperties() { QQmlComponent component(&engine, testFileUrl("alias.10.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1827,15 +1839,13 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("valueAlias", QVariant(QRect(3, 3, 4, 9))); QCOMPARE(object->property("valueAlias").toRect(), QRect(3, 3, 4, 9)); QCOMPARE(object->property("rectProperty").toRect(), QRect(3, 3, 4, 9)); - - delete object; } // Valuetype sub-alias { QQmlComponent component(&engine, testFileUrl("alias.11.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); // Read through alias @@ -1847,8 +1857,6 @@ void tst_qqmllanguage::aliasProperties() object->setProperty("aliasProperty", QVariant(4)); QCOMPARE(object->property("aliasProperty").toInt(), 4); QCOMPARE(object->property("rectProperty").toRect(), QRect(4, 8, 102, 111)); - - delete object; } // Nested aliases with a qml file @@ -1892,6 +1900,30 @@ void tst_qqmllanguage::aliasProperties() QVERIFY(subObject->property("success").toBool()); } + + // Property bindings on group properties that are actually aliases (QTBUG-51043) + { + QQmlComponent component(&engine, testFileUrl("alias.15.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subItem = qvariant_cast<QObject*>(object->property("symbol")); + QVERIFY(!subItem.isNull()); + + QCOMPARE(subItem->property("y").toInt(), 1); + } + + // Alias to sub-object with binding (QTBUG-57041) + { + // This is shold *not* crash. + QQmlComponent component(&engine, testFileUrl("alias.16.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -1899,10 +1931,9 @@ void tst_qqmllanguage::aliasPropertiesAndSignals() { QQmlComponent component(&engine, testFileUrl("aliasPropertiesAndSignals.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("test").toBool(), true); - delete o; } // Test that the root element in a composite type can be a Component @@ -1910,7 +1941,7 @@ void tst_qqmllanguage::componentCompositeType() { QQmlComponent component(&engine, testFileUrl("componentCompositeType.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1944,11 +1975,9 @@ void tst_qqmllanguage::i18n() QFETCH(QString, stringProperty); QQmlComponent component(&engine, testFileUrl(file)); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->stringProperty(), stringProperty); - - delete object; } // Check that the Component::onCompleted attached property works @@ -1959,7 +1988,7 @@ void tst_qqmllanguage::onCompleted() QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 6 10"); QTest::ignoreMessage(QtDebugMsg, "Completed 10 11"); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); } @@ -1968,12 +1997,11 @@ void tst_qqmllanguage::onDestruction() { QQmlComponent component(&engine, testFileUrl("onDestruction.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); QTest::ignoreMessage(QtDebugMsg, "Destruction 6 10"); QTest::ignoreMessage(QtDebugMsg, "Destruction 10 11"); - delete object; } // Check that assignments to QQmlScriptString properties work @@ -1983,7 +2011,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QVERIFY(!object->scriptProperty().isEmpty()); QCOMPARE(object->scriptProperty().stringLiteral(), QString()); @@ -1994,21 +2022,21 @@ void tst_qqmllanguage::scriptString() const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(object->scriptProperty()); QVERIFY(scriptPrivate != nullptr); QCOMPARE(scriptPrivate->script, QString("foo + bar")); - QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(scriptPrivate->context, qmlContext(object)); + QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(scriptPrivate->context, qmlContext(object.data())); QVERIFY(object->grouped() != nullptr); const QQmlScriptStringPrivate *groupedPrivate = QQmlScriptStringPrivate::get(object->grouped()->script()); QCOMPARE(groupedPrivate->script, QString("console.log(1921)")); - QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(groupedPrivate->context, qmlContext(object)); + QCOMPARE(groupedPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(groupedPrivate->context, qmlContext(object.data())); } { QQmlComponent component(&engine, testFileUrl("scriptString2.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().stringLiteral(), QString("hello\\n\\\"world\\\"")); } @@ -2017,7 +2045,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString3.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); bool ok; QCOMPARE(object->scriptProperty().numberLiteral(&ok), qreal(12.345)); @@ -2029,7 +2057,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString4.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); bool ok; QCOMPARE(object->scriptProperty().booleanLiteral(&ok), true); @@ -2040,7 +2068,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString5.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().isNullLiteral(), true); } @@ -2049,7 +2077,7 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString6.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->scriptProperty().isUndefinedLiteral(), true); } @@ -2057,12 +2085,12 @@ void tst_qqmllanguage::scriptString() QQmlComponent component(&engine, testFileUrl("scriptString7.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QQmlScriptString ss = object->scriptProperty(); { - QQmlExpression expr(ss, /*context*/nullptr, object); + QQmlExpression expr(ss, /*context*/nullptr, object.data()); QCOMPARE(expr.evaluate().toInt(), int(100)); } @@ -2083,9 +2111,9 @@ void tst_qqmllanguage::scriptStringJs() QQmlComponent component(&engine, testFileUrl("scriptStringJs.qml")); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); - QQmlContext *context = QQmlEngine::contextForObject(object); + QQmlContext *context = QQmlEngine::contextForObject(object.data()); QVERIFY(context != nullptr); bool ok; @@ -2097,7 +2125,7 @@ void tst_qqmllanguage::scriptStringJs() QVERIFY(object->scriptProperty().numberLiteral(&ok) == 0.0 && !ok); QVERIFY(!object->scriptProperty().booleanLiteral(&ok) && !ok); - QJSValue inst = engine.newQObject(object); + QJSValue inst = engine.newQObject(object.data()); QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }"); func.callWithInstance(inst, QJSValueList() << "test a \"string "); @@ -2187,7 +2215,7 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() QQmlComponent component(&engine, url); VERIFY_ERRORS(0); - MyTypeObject *object = qobject_cast<MyTypeObject*>(component.create()); + QScopedPointer<MyTypeObject> object(qobject_cast<MyTypeObject*>(component.create())); QVERIFY(object != nullptr); QQmlScriptString ss = object->scriptProperty(); QVERIFY(!ss.isEmpty()); @@ -2199,11 +2227,11 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() const QQmlScriptStringPrivate *scriptPrivate = QQmlScriptStringPrivate::get(ss); QVERIFY(scriptPrivate != nullptr); QVERIFY(scriptPrivate->script.isEmpty()); - QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object)); - QCOMPARE(scriptPrivate->context, qmlContext(object)); + QCOMPARE(scriptPrivate->scope, qobject_cast<QObject*>(object.data())); + QCOMPARE(scriptPrivate->context, qmlContext(object.data())); { - QQmlExpression expr(ss, /*context*/nullptr, object); + QQmlExpression expr(ss, /*context*/nullptr, object.data()); QCOMPARE(expr.evaluate().toInt(), int(100)); } } @@ -2214,22 +2242,22 @@ void tst_qqmllanguage::scriptStringComparison() { QQmlComponent component1(&engine, testFileUrl("scriptString.qml")); QVERIFY(!component1.isError() && component1.errors().isEmpty()); - MyTypeObject *object1 = qobject_cast<MyTypeObject*>(component1.create()); + QScopedPointer<MyTypeObject> object1(qobject_cast<MyTypeObject*>(component1.create())); QVERIFY(object1 != nullptr); QQmlComponent component2(&engine, testFileUrl("scriptString2.qml")); QVERIFY(!component2.isError() && component2.errors().isEmpty()); - MyTypeObject *object2 = qobject_cast<MyTypeObject*>(component2.create()); + QScopedPointer<MyTypeObject> object2(qobject_cast<MyTypeObject*>(component2.create())); QVERIFY(object2 != nullptr); QQmlComponent component3(&engine, testFileUrl("scriptString3.qml")); QVERIFY(!component3.isError() && component3.errors().isEmpty()); - MyTypeObject *object3 = qobject_cast<MyTypeObject*>(component3.create()); + QScopedPointer<MyTypeObject> object3(qobject_cast<MyTypeObject*>(component3.create())); QVERIFY(object3 != nullptr); //QJSValue inst1 = engine.newQObject(object1); - QJSValue inst2 = engine.newQObject(object2); - QJSValue inst3 = engine.newQObject(object3); + QJSValue inst2 = engine.newQObject(object2.data()); + QJSValue inst3 = engine.newQObject(object3.data()); QJSValue func = engine.evaluate("function(value) { this.scriptProperty = value }"); const QString s = "hello\\n\\\"world\\\""; @@ -2284,7 +2312,7 @@ void tst_qqmllanguage::scriptStringComparison() // While this are two instances of the same object they are still considered different // because the (none literal) script string may access variables which have different // values in both instances and hence evaluated to different results. - MyTypeObject *object1_2 = qobject_cast<MyTypeObject*>(component1.create()); + QScopedPointer<MyTypeObject> object1_2(qobject_cast<MyTypeObject*>(component1.create())); QVERIFY(object1_2 != nullptr); QVERIFY(object1->scriptProperty() != object1_2->scriptProperty()); } @@ -2296,7 +2324,7 @@ void tst_qqmllanguage::defaultPropertyListOrder() QQmlComponent component(&engine, testFileUrl("defaultPropertyListOrder.qml")); VERIFY_ERRORS(0); - MyContainer *container = qobject_cast<MyContainer *>(component.create()); + QScopedPointer<MyContainer> container(qobject_cast<MyContainer *>(component.create())); QVERIFY(container != nullptr); QCOMPARE(container->getChildren()->count(), 6); @@ -2317,15 +2345,13 @@ void tst_qqmllanguage::declaredPropertyValues() void tst_qqmllanguage::dontDoubleCallClassBegin() { QQmlComponent component(&engine, testFileUrl("dontDoubleCallClassBegin.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); MyParserStatus *o2 = qobject_cast<MyParserStatus *>(qvariant_cast<QObject *>(o->property("object"))); QVERIFY(o2); QCOMPARE(o2->classBeginCount(), 1); QCOMPARE(o2->componentCompleteCount(), 1); - - delete o; } void tst_qqmllanguage::reservedWords_data() @@ -2425,10 +2451,9 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q QCOMPARE(actualerror.left(partialMatch ? expectederror.length(): -1),expectederror); } else { VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(QString(object->metaObject()->className()), type); - delete object; } engine.setImportPathList(defaultImportPathList); @@ -2439,10 +2464,9 @@ void tst_qqmllanguage::inlineAssignmentsOverrideBindings() { QQmlComponent component(&engine, testFileUrl("inlineAssignmentsOverrideBindings.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 11); - delete o; } // QTBUG-19354 @@ -2873,10 +2897,9 @@ void tst_qqmllanguage::importsPath() QTRY_VERIFY(component.isReady()); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toString(), value); - delete object; engine.setImportPathList(defaultImportPathList); } @@ -3084,10 +3107,9 @@ void tst_qqmllanguage::importJs() } if (performTest) { - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("test").toBool(),true); - delete object; } engine.setImportPathList(defaultImportPathList); @@ -3136,21 +3158,21 @@ void tst_qqmllanguage::qmlAttachedPropertiesObjectMethod() { QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.1.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object, false), (QObject *)nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr); + QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false), (QObject *)nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr); } { QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.2.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, false) != nullptr); - QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object, true) != nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), false) != nullptr); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(object.data(), true) != nullptr); } } @@ -3171,12 +3193,10 @@ void tst_qqmllanguage::customOnProperty() QQmlComponent component(&engine, testFileUrl("customOnProperty.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("on").toInt(), 10); - - delete object; } // QTBUG-12601 @@ -3185,12 +3205,10 @@ void tst_qqmllanguage::variantNotify() QQmlComponent component(&engine, testFileUrl("variantNotify.qml")); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("notifyCount").toInt(), 1); - - delete object; } void tst_qqmllanguage::revisions() @@ -3199,38 +3217,32 @@ void tst_qqmllanguage::revisions() QQmlComponent component(&engine, testFileUrl("revisions11.qml")); VERIFY_ERRORS(0); - MyRevisionedClass *object = qobject_cast<MyRevisionedClass*>(component.create()); + QScopedPointer<MyRevisionedClass> object(qobject_cast<MyRevisionedClass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop2(), 10.0); - - delete object; } { QQmlEngine myEngine; QQmlComponent component(&myEngine, testFileUrl("revisionssub11.qml")); VERIFY_ERRORS(0); - MyRevisionedSubclass *object = qobject_cast<MyRevisionedSubclass*>(component.create()); + QScopedPointer<MyRevisionedSubclass> object(qobject_cast<MyRevisionedSubclass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop1(), 10.0); QCOMPARE(object->prop2(), 10.0); QCOMPARE(object->prop3(), 10.0); QCOMPARE(object->prop4(), 10.0); - - delete object; } { QQmlComponent component(&engine, testFileUrl("versionedbase.qml")); VERIFY_ERRORS(0); - MySubclass *object = qobject_cast<MySubclass*>(component.create()); + QScopedPointer<MySubclass> object(qobject_cast<MySubclass*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->prop1(), 10.0); QCOMPARE(object->prop2(), 10.0); - - delete object; } } @@ -3276,8 +3288,8 @@ void tst_qqmllanguage::subclassedUncreateableRevision() QQmlComponent c(&engine); QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QScopedPointer<QObject> obj(c.create()); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); QCOMPARE(c.errors().count(), 1); QCOMPARE(c.errors().first().description(), QString("Cannot create MyUncreateableBaseClass")); } @@ -3288,17 +3300,16 @@ void tst_qqmllanguage::subclassedUncreateableRevision() if (!shouldWork) QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); + QScopedPointer<QObject> obj(c.create()); if (!shouldWork) { - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); return; } QVERIFY(obj); - MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj); + MyUncreateableBaseClass *base = qobject_cast<MyUncreateableBaseClass*>(obj.data()); QVERIFY(base); QCOMPARE(base->property(prop.toLatin1()).toBool(), true); - delete obj; } void tst_qqmllanguage::subclassedExtendedUncreateableRevision_data() @@ -3332,8 +3343,8 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision() QQmlComponent c(&engine); QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QScopedPointer<QObject> obj(c.create()); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); QCOMPARE(c.errors().count(), 1); QCOMPARE(c.errors().first().description(), QString("Cannot create MyExtendedUncreateableBaseClass")); } @@ -3344,17 +3355,16 @@ void tst_qqmllanguage::subclassedExtendedUncreateableRevision() if (!shouldWork) QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); c.setData(qml.toUtf8(), QUrl::fromLocalFile(QDir::currentPath())); - QObject *obj = c.create(); + QScopedPointer<QObject> obj(c.create()); if (!shouldWork) { - QCOMPARE(obj, static_cast<QObject*>(nullptr)); + QCOMPARE(obj.data(), static_cast<QObject*>(nullptr)); return; } QVERIFY(obj); - MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj); + MyExtendedUncreateableBaseClass *base = qobject_cast<MyExtendedUncreateableBaseClass*>(obj.data()); QVERIFY(base); QCOMPARE(base->property(prop.toLatin1()).toBool(), true); - delete obj; } void tst_qqmllanguage::uncreatableTypesAsProperties() @@ -3415,12 +3425,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals() QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toBool(), true); - - delete o; } // QTCREATORBUG-2769 @@ -3428,12 +3436,10 @@ void tst_qqmllanguage::aliasPropertyChangeSignals() QQmlComponent component(&engine, testFileUrl("aliasPropertyChangeSignals.2.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toBool(), true); - - delete o; } } @@ -3444,24 +3450,20 @@ void tst_qqmllanguage::propertyInit() QQmlComponent component(&engine, testFileUrl("propertyInit.1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 1); - - delete o; } { QQmlComponent component(&engine, testFileUrl("propertyInit.2.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test").toInt(), 123); - - delete o; } } @@ -3471,17 +3473,16 @@ void tst_qqmllanguage::registrationOrder() { QQmlComponent component(&engine, testFileUrl("registrationOrder.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->metaObject(), &MyVersion2Class::staticMetaObject); - delete o; } void tst_qqmllanguage::readonly() { QQmlComponent component(&engine, testFileUrl("readonly.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test1").toInt(), 10); @@ -3507,8 +3508,6 @@ void tst_qqmllanguage::readonly() QCOMPARE(o->property("test1").toInt(), 10); QCOMPARE(o->property("test2").toInt(), 22); QCOMPARE(o->property("test3").toInt(), 2); - - delete o; } void tst_qqmllanguage::readonlyObjectProperties() @@ -3533,7 +3532,7 @@ void tst_qqmllanguage::receivers() { QQmlComponent component(&engine, testFileUrl("receivers.qml")); - MyReceiversTestObject *o = qobject_cast<MyReceiversTestObject*>(component.create()); + QScopedPointer<MyReceiversTestObject> o(qobject_cast<MyReceiversTestObject*>(component.create())); QVERIFY(o != nullptr); QCOMPARE(o->mySignalCount(), 1); QCOMPARE(o->propChangedCount(), 2); @@ -3542,8 +3541,6 @@ void tst_qqmllanguage::receivers() QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::mySignal))); QVERIFY(o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::propChanged))); QVERIFY(!o->isSignalConnected(QMetaMethod::fromSignal(&MyReceiversTestObject::myUnconnectedSignal))); - - delete o; } void tst_qqmllanguage::registeredCompositeType() @@ -3551,10 +3548,8 @@ void tst_qqmllanguage::registeredCompositeType() QQmlComponent component(&engine, testFileUrl("registeredCompositeType.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - - delete o; } // QTBUG-43582 @@ -3563,14 +3558,12 @@ void tst_qqmllanguage::registeredCompositeTypeWithEnum() QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithEnum.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0)); QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42)); QCOMPARE(o->property("enumValue15").toInt(), static_cast<int>(MyCompositeBaseType::ScopedCompositeEnum::EnumValue15)); - - delete o; } // QTBUG-43581 @@ -3579,12 +3572,10 @@ void tst_qqmllanguage::registeredCompositeTypeWithAttachedProperty() QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeWithAttachedProperty.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("attachedProperty").toString(), QStringLiteral("test")); - - delete o; } // QTBUG-18268 @@ -3597,15 +3588,14 @@ void tst_qqmllanguage::remoteLoadCrash() while (component.isLoading()) QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50); - QObject *o = component.create(); - delete o; + QScopedPointer<QObject> o(component.create()); } void tst_qqmllanguage::signalWithDefaultArg() { QQmlComponent component(&engine, testFileUrl("signalWithDefaultArg.qml")); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->property("signalCount").toInt(), 0); @@ -3620,15 +3610,13 @@ void tst_qqmllanguage::signalWithDefaultArg() QCOMPARE(object->property("signalArg").toInt(), 15); - QMetaObject::invokeMethod(object, "emitNoArgSignal"); + QMetaObject::invokeMethod(object.data(), "emitNoArgSignal"); QCOMPARE(object->property("signalCount").toInt(), 3); QCOMPARE(object->property("signalArg").toInt(), 5); - QMetaObject::invokeMethod(object, "emitArgSignal"); + QMetaObject::invokeMethod(object.data(), "emitArgSignal"); QCOMPARE(object->property("signalCount").toInt(), 4); QCOMPARE(object->property("signalArg").toInt(), 22); - - delete object; } void tst_qqmllanguage::signalParameterTypes() @@ -3636,19 +3624,17 @@ void tst_qqmllanguage::signalParameterTypes() // bound signal handlers { QQmlComponent component(&engine, testFileUrl("signalParameterTypes.1.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); QVERIFY(obj != nullptr); QVERIFY(obj->property("success").toBool()); - delete obj; } // dynamic signal connections { QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); QVERIFY(obj != nullptr); QVERIFY(obj->property("success").toBool()); - delete obj; } } @@ -3661,7 +3647,7 @@ void tst_qqmllanguage::globalEnums() QQmlComponent component(&engine, testFileUrl("globalEnums.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); MyEnum1Class *enum1Class = o->findChild<MyEnum1Class *>(QString::fromLatin1("enum1Class")); @@ -3687,7 +3673,7 @@ void tst_qqmllanguage::globalEnums() QSignalSpy signalA(enum2Class, SIGNAL(valueAChanged(MyEnum1Class::EnumA))); QSignalSpy signalB(enum2Class, SIGNAL(valueBChanged(MyEnum2Class::EnumB))); - QMetaObject::invokeMethod(o, "setEnumValues"); + QMetaObject::invokeMethod(o.data(), "setEnumValues"); QVERIFY(enum1Class->getValue() == MyEnum1Class::A_13); QVERIFY(enum2Class->getValueA() == MyEnum1Class::A_11); @@ -3706,8 +3692,6 @@ void tst_qqmllanguage::globalEnums() QVERIFY(enum2Class->property("dValue") == 2); QVERIFY(enum2Class->property("eValue") == 14); QVERIFY(enum2Class->property("e2Value") == 76); - - delete o; } void tst_qqmllanguage::lowercaseEnumRuntime_data() @@ -3753,7 +3737,7 @@ void tst_qqmllanguage::scopedEnum() { QQmlComponent component(&engine, testFileUrl("scopedEnum.qml")); - MyTypeObject *o = qobject_cast<MyTypeObject *>(component.create()); + QScopedPointer<MyTypeObject> o(qobject_cast<MyTypeObject *>(component.create())); QVERIFY(o != nullptr); QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal1); @@ -3761,7 +3745,7 @@ void tst_qqmllanguage::scopedEnum() QCOMPARE(o->property("listValue").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal3); QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal1); - QMetaObject::invokeMethod(o, "assignNewValue"); + QMetaObject::invokeMethod(o.data(), "assignNewValue"); QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal2); QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal2); } @@ -3770,7 +3754,7 @@ void tst_qqmllanguage::qmlEnums() { { QQmlComponent component(&engine, testFileUrl("TypeWithEnum.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("enumValue").toInt(), 1); QCOMPARE(o->property("enumValue2").toInt(), 2); @@ -3785,7 +3769,7 @@ void tst_qqmllanguage::qmlEnums() { QQmlComponent component(&engine, testFileUrl("usingTypeWithEnum.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o); QCOMPARE(o->property("enumValue").toInt(), 1); QCOMPARE(o->property("enumValue2").toInt(), 0); @@ -3830,10 +3814,9 @@ void tst_qqmllanguage::literals() QQmlComponent component(&engine, testFile("literals.qml")); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property(property.toLatin1()), value); - delete object; } void tst_qqmllanguage::objectDeletionNotify_data() @@ -3852,19 +3835,17 @@ void tst_qqmllanguage::objectDeletionNotify() QQmlComponent component(&engine, testFile(file)); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("success").toBool(), true); - QMetaObject::invokeMethod(object, "destroyObject"); + QMetaObject::invokeMethod(object.data(), "destroyObject"); // Process the deletion event QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); QCOMPARE(object->property("success").toBool(), true); - - delete object; } void tst_qqmllanguage::scopedProperties() @@ -3898,7 +3879,7 @@ void tst_qqmllanguage::implicitImportsLast() QQmlComponent component(&engine, testFile("localOrderTest.qml")); VERIFY_ERRORS(0); - QObject *object = qobject_cast<QObject *>(component.create()); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QVERIFY(QString(object->metaObject()->className()).startsWith(QLatin1String("QQuickMouseArea"))); QObject* object2 = object->property("item").value<QObject*>(); @@ -3918,10 +3899,10 @@ void tst_qqmllanguage::getSingletonInstance(QQmlEngine& engine, const char* file QQmlComponent component(&engine, testFile(fileName)); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); - getSingletonInstance(object, propertyName, result); + getSingletonInstance(object.data(), propertyName, result); } void tst_qqmllanguage::getSingletonInstance(QObject* o, const char* propertyName, QObject** result /* out */) @@ -3958,10 +3939,10 @@ void tst_qqmllanguage::compositeSingletonProperties() { QQmlComponent component(&engine, testFile("singletonTest1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); } // Checks that the addresses of the composite singletons used in the same @@ -4012,15 +3993,15 @@ void tst_qqmllanguage::compositeSingletonQualifiedNamespace() { QQmlComponent component(&engine, testFile("singletonTest5.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); // lets verify that the singleton instance we are using is the same // when loaded through another file (without namespace!) QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4037,16 +4018,16 @@ void tst_qqmllanguage::compositeSingletonModule() QQmlComponent component(&engine, testFile("singletonTest6.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 125, "value2", -55); - verifyCompositeSingletonPropertyValues(o, "value3", 125, "value4", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 125, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 125, "value4", -55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4063,16 +4044,16 @@ void tst_qqmllanguage::compositeSingletonModuleVersioned() QQmlComponent component(&engine, testFile("singletonTest7.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55); - verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4089,16 +4070,16 @@ void tst_qqmllanguage::compositeSingletonModuleQualified() QQmlComponent component(&engine, testFile("singletonTest8.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 225, "value2", 55); - verifyCompositeSingletonPropertyValues(o, "value3", 225, "value4", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 225, "value2", 55); + verifyCompositeSingletonPropertyValues(o.data(), "value3", 225, "value4", 55); // lets verify that the singleton instance we are using is the same // when loaded through another file QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); QObject* s2 = nullptr; @@ -4128,10 +4109,10 @@ void tst_qqmllanguage::compositeSingletonDynamicSignal() { QQmlComponent component(&engine, testFile("singletonTest11.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", -55); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", -55); } // Use qmlRegisterType to register a qml composite type with pragma Singleton defined in it. @@ -4177,10 +4158,10 @@ void tst_qqmllanguage::compositeSingletonRemote() QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents, 50); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 525, "value2", 355); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 525, "value2", 355); } // Load a composite singleton type and a javascript file that has .pragma library @@ -4190,14 +4171,14 @@ void tst_qqmllanguage::compositeSingletonJavaScriptPragma() { QQmlComponent component(&engine, testFile("singletonTest16.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); // The value1 that is read from the SingletonType was changed from 125 to 99 // in compositeSingletonDynamicSignal() above. As the type is a singleton and // the engine has not been destroyed, we just retrieve the old instance and // the value is still 99. - verifyCompositeSingletonPropertyValues(o, "value1", 99, "value2", 333); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 99, "value2", 333); } // Reads values from a Singleton accessed through selectors. @@ -4208,10 +4189,10 @@ void tst_qqmllanguage::compositeSingletonSelectors() qmlSelector.setExtraSelectors(QStringList() << "basicSelector"); QQmlComponent component(&e2, testFile("singletonTest1.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 625, "value2", 455); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 625, "value2", 455); } // Reads values from a Singleton that was registered through the C++ API: @@ -4220,10 +4201,10 @@ void tst_qqmllanguage::compositeSingletonRegistered() { QQmlComponent component(&engine, testFile("singletonTest17.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); - verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755); + verifyCompositeSingletonPropertyValues(o.data(), "value1", 925, "value2", 755); } void tst_qqmllanguage::compositeSingletonCircular() @@ -4233,7 +4214,7 @@ void tst_qqmllanguage::compositeSingletonCircular() QQmlTestMessageHandler messageHandler; - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); // ensure we aren't hitting the recursion warning @@ -4588,7 +4569,7 @@ void tst_qqmllanguage::noChildEvents() QQmlComponent component(&engine); component.setData("import QtQml 2.0; import Test 1.0; MyQmlObject { property QtObject child: QtObject {} }", QUrl()); VERIFY_ERRORS(0); - MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create()); + QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject*>(component.create())); QVERIFY(object != nullptr); QCOMPARE(object->childAddedEventCount(), 0); } @@ -4608,10 +4589,10 @@ void tst_qqmllanguage::deleteSingletons() QQmlEngine tmpEngine; QQmlComponent component(&tmpEngine, testFile("singletonTest5.qml")); VERIFY_ERRORS(0); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QObject *s1 = nullptr; - getSingletonInstance(o, "singletonInstance", &s1); + getSingletonInstance(o.data(), "singletonInstance", &s1); QVERIFY(s1 != nullptr); singleton = s1; QVERIFY(singleton.data() != nullptr); @@ -4635,7 +4616,7 @@ void tst_qqmllanguage::arrayBuffer() QFETCH(QString, file); QQmlComponent component(&engine, testFile(file)); VERIFY_ERRORS(0); - QObject *object = component.create(); + QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); QCOMPARE(object->property("ok").toBool(), true); } diff --git a/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml b/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml new file mode 100644 index 0000000000..8cbd928f36 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/data/aliasToIdWithMatchingQmlFileName.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Item { + property alias testType: testType + + Rectangle { + id: testType + } +} diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 128dc21b9a..1e9ba80264 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -143,6 +143,7 @@ private slots: void registeredCompositeTypeProperty(); void deeplyNestedObject(); void readOnlyDynamicProperties(); + void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem(); void floatToStringPrecision_data(); void floatToStringPrecision(); @@ -2047,6 +2048,17 @@ void tst_qqmlproperty::readOnlyDynamicProperties() delete obj; } +void tst_qqmlproperty::aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem() +{ + const QUrl url = testFileUrl("aliasToIdWithMatchingQmlFileName.qml"); + QQmlEngine engine; + QQmlComponent component(&engine, url); + QScopedPointer<QObject> root(component.create()); + + QQmlProperty property(root.data(), "testType.objectName", QQmlEngine::contextForObject(root.data())); + QVERIFY(property.isValid()); +} + void tst_qqmlproperty::floatToStringPrecision_data() { QTest::addColumn<QString>("propertyName"); diff --git a/tests/auto/quick/qquickmousearea/BLACKLIST b/tests/auto/quick/qquickmousearea/BLACKLIST deleted file mode 100644 index 817eb472a4..0000000000 --- a/tests/auto/quick/qquickmousearea/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-63786 -[pressedMultipleButtons] -* diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index ea55c25761..aa379e834e 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -1578,91 +1578,85 @@ void tst_QQuickMouseArea::transformedMouseArea() } } +struct MouseEvent { + QEvent::Type type; + Qt::MouseButton button; +}; +Q_DECLARE_METATYPE(MouseEvent) + void tst_QQuickMouseArea::pressedMultipleButtons_data() { QTest::addColumn<Qt::MouseButtons>("accepted"); - QTest::addColumn<QList<Qt::MouseButtons> >("buttons"); + QTest::addColumn<QList<MouseEvent> >("mouseEvents"); QTest::addColumn<QList<bool> >("pressed"); QTest::addColumn<QList<Qt::MouseButtons> >("pressedButtons"); QTest::addColumn<int>("changeCount"); - QList<Qt::MouseButtons> buttons; + Qt::MouseButtons accepted; + QList<MouseEvent> mouseEvents; QList<bool> pressed; QList<Qt::MouseButtons> pressedButtons; - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << nullptr; - pressed << true - << true - << true - << false; - pressedButtons << Qt::LeftButton - << Qt::LeftButton - << Qt::LeftButton - << nullptr; - QTest::newRow("Accept Left - Press left, Press Right, Release Right") - << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::RightButton - << nullptr; - pressed << true - << true - << false - << false; - pressedButtons << Qt::LeftButton - << Qt::LeftButton - << nullptr - << nullptr; - QTest::newRow("Accept Left - Press left, Press Right, Release Left") - << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << nullptr; - pressed << true - << true - << true - << false; - pressedButtons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << nullptr; - QTest::newRow("Accept Left|Right - Press left, Press Right, Release Right") - << (Qt::LeftButton | Qt::RightButton) << buttons << pressed << pressedButtons << 4; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::RightButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << nullptr; - pressed << true - << true - << false - << false; - pressedButtons << Qt::RightButton - << Qt::RightButton - << nullptr - << nullptr; - QTest::newRow("Accept Right - Press Right, Press Left, Release Right") - << Qt::MouseButtons(Qt::RightButton) << buttons << pressed << pressedButtons << 2; + int changeCount; + + MouseEvent leftPress = { QEvent::MouseButtonPress, Qt::LeftButton }; + MouseEvent leftRelease = { QEvent::MouseButtonRelease, Qt::LeftButton }; + MouseEvent rightPress = { QEvent::MouseButtonPress, Qt::RightButton }; + MouseEvent rightRelease = { QEvent::MouseButtonRelease, Qt::RightButton }; + + auto addRowWithFormattedTitleAndReset = [&]() { + QByteArray title; + title.append("Accept:"); + if (accepted & Qt::LeftButton) + title.append(" LeftButton"); + if (accepted & Qt::RightButton) + title.append(" RightButton"); + title.append(" | Events:"); + for (MouseEvent event : mouseEvents) { + title.append(event.type == QEvent::MouseButtonPress ? " Press" : " Release"); + title.append(event.button == Qt::LeftButton ? " Left," : " Right,"); + } + title.chop(1); // remove last comma + QTest::newRow(title) << accepted << mouseEvents << pressed << pressedButtons << changeCount; + + mouseEvents.clear(); + pressed.clear(); + pressedButtons.clear(); + }; + + accepted = Qt::LeftButton; + changeCount = 2; + mouseEvents << leftPress << rightPress << rightRelease << leftRelease; + pressed << true << true << true << false; + pressedButtons << Qt::LeftButton << Qt::LeftButton << Qt::LeftButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::LeftButton; + changeCount = 2; + mouseEvents << leftPress << rightPress << leftRelease << rightRelease; + pressed << true << true << false << false; + pressedButtons << Qt::LeftButton << Qt::LeftButton << Qt::NoButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::LeftButton | Qt::RightButton; + changeCount = 4; + mouseEvents << leftPress << rightPress << rightRelease << leftRelease; + pressed << true << true << true << false; + pressedButtons << Qt::LeftButton << (Qt::LeftButton | Qt::RightButton) << Qt::LeftButton + << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::RightButton; + changeCount = 2; + mouseEvents << rightPress << leftPress << rightRelease << leftRelease; + pressed << true << true << false << false; + pressedButtons << Qt::RightButton << Qt::RightButton << Qt::NoButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); } void tst_QQuickMouseArea::pressedMultipleButtons() { QFETCH(Qt::MouseButtons, accepted); - QFETCH(QList<Qt::MouseButtons>, buttons); + QFETCH(QList<MouseEvent>, mouseEvents); QFETCH(QList<bool>, pressed); QFETCH(QList<Qt::MouseButtons>, pressedButtons); QFETCH(int, changeCount); @@ -1681,21 +1675,17 @@ void tst_QQuickMouseArea::pressedMultipleButtons() QSignalSpy pressedButtonsSpy(mouseArea, SIGNAL(pressedButtonsChanged())); mouseArea->setAcceptedMouseButtons(accepted); - QPoint point(10,10); - - for (int i = 0; i < buttons.count(); ++i) { - int btns = buttons.at(i); - - // The windowsysteminterface takes care of sending releases - QTest::mousePress(&view, (Qt::MouseButton)btns, Qt::NoModifier, point); - + QPoint point(10, 10); + for (int i = 0; i < mouseEvents.count(); ++i) { + const MouseEvent mouseEvent = mouseEvents.at(i); + if (mouseEvent.type == QEvent::MouseButtonPress) + QTest::mousePress(&view, mouseEvent.button, Qt::NoModifier, point); + else + QTest::mouseRelease(&view, mouseEvent.button, Qt::NoModifier, point); QCOMPARE(mouseArea->pressed(), pressed.at(i)); QCOMPARE(mouseArea->pressedButtons(), pressedButtons.at(i)); } - QTest::mousePress(&view, Qt::NoButton, Qt::NoModifier, point); - QCOMPARE(mouseArea->pressed(), false); - QCOMPARE(pressedSpy.count(), 2); QCOMPARE(pressedButtonsSpy.count(), changeCount); } |