aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/common/qv4compileddata_p.h6
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp67
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h21
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc29
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h9
-rw-r--r--src/qml/parser/qqmljs.g10
-rw-r--r--src/qml/parser/qqmljsast_p.h5
-rw-r--r--src/qml/qml/qqmlirloader.cpp14
-rw-r--r--src/qml/qml/qqmllist.cpp3
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp6
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h1
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h12
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h10
-rw-r--r--tests/auto/qml/qqmlproperty/data/listBehaviorAppendPragma.qml39
-rw-r--r--tests/auto/qml/qqmlproperty/data/listBehaviorFail1.qml3
-rw-r--r--tests/auto/qml/qqmlproperty/data/listBehaviorFail2.qml5
-rw-r--r--tests/auto/qml/qqmlproperty/data/listBehaviorReplaceIfNotDefaultPragma.qml39
-rw-r--r--tests/auto/qml/qqmlproperty/data/listBehaviorReplacePragma.qml39
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp49
19 files changed, 342 insertions, 25 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 9530d391d6..b819681247 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -968,7 +968,11 @@ struct Unit
IsSharedLibrary = 0x8, // .pragma shared?
IsESModule = 0x10,
PendingTypeCompilation = 0x20, // the QML data structures present are incomplete and require type compilation
- IsStrict = 0x40
+ IsStrict = 0x40,
+ ListPropertyAssignReplaceIfDefault = 0x80,
+ ListPropertyAssignReplaceIfNotDefault = 0x100,
+ ListPropertyAssignReplace
+ = ListPropertyAssignReplaceIfDefault | ListPropertyAssignReplaceIfNotDefault,
};
quint32_le flags;
quint32_le stringTableSize;
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index e6efec0b16..9605eda030 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -815,19 +815,43 @@ bool IRBuilder::visit(QQmlJS::AST::UiPragma *node)
{
Pragma *pragma = New<Pragma>();
- // For now the only valid pragma is Singleton, so lets validate the input
- if (!node->name.isNull())
- {
+ if (!node->name.isNull()) {
if (node->name == QStringLiteral("Singleton")) {
- pragma->type = Pragma::PragmaSingleton;
+ pragma->type = Pragma::Singleton;
} else if (node->name == QStringLiteral("Strict")) {
- pragma->type = Pragma::PragmaStrict;
+ pragma->type = Pragma::Strict;
+ } else if (node->name == QStringLiteral("ListPropertyAssignBehavior")) {
+ for (const Pragma *prev : _pragmas) {
+ if (prev->type != Pragma::ListPropertyAssignBehavior)
+ continue;
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser",
+ "Multiple list property assign behavior pragmas found"));
+ return false;
+ }
+
+ pragma->type = Pragma::ListPropertyAssignBehavior;
+ if (node->value == QStringLiteral("Replace")) {
+ pragma->listPropertyAssignBehavior = Pragma::Replace;
+ } else if (node->value == QStringLiteral("ReplaceIfNotDefault")) {
+ pragma->listPropertyAssignBehavior = Pragma::ReplaceIfNotDefault;
+ } else if (node->value == QStringLiteral("Append")) {
+ pragma->listPropertyAssignBehavior = Pragma::Append;
+ } else {
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser",
+ "Unknown list property assign behavior '%1' in pragma")
+ .arg(node->value));
+ return false;
+ }
} else {
- recordError(node->pragmaToken, QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Unknown pragma '%1'").arg(node->name));
return false;
}
} else {
- recordError(node->pragmaToken, QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
+ recordError(node->pragmaToken, QCoreApplication::translate(
+ "QQmlParser", "Empty pragma found"));
return false;
}
@@ -1634,27 +1658,42 @@ bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *prope
void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
{
+ using namespace QV4::CompiledData;
+
output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
- QV4::CompiledData::Unit *jsUnit = nullptr;
+ Unit *jsUnit = nullptr;
// We may already have unit data if we're loading an ahead-of-time generated cache file.
if (output.javaScriptCompilationUnit.data) {
- jsUnit = const_cast<QV4::CompiledData::Unit *>(output.javaScriptCompilationUnit.data);
+ jsUnit = const_cast<Unit *>(output.javaScriptCompilationUnit.data);
output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings();
} else {
- QV4::CompiledData::Unit *createdUnit;
+ Unit *createdUnit;
jsUnit = createdUnit = output.jsGenerator.generateUnit();
// enable flag if we encountered pragma Singleton
for (Pragma *p : qAsConst(output.pragmas)) {
switch (p->type) {
- case Pragma::PragmaSingleton:
- createdUnit->flags |= QV4::CompiledData::Unit::IsSingleton;
+ case Pragma::Singleton:
+ createdUnit->flags |= Unit::IsSingleton;
break;
- case Pragma::PragmaStrict:
- createdUnit->flags |= QV4::CompiledData::Unit::IsStrict;
+ case Pragma::Strict:
+ createdUnit->flags |= Unit::IsStrict;
+ break;
+ case Pragma::ListPropertyAssignBehavior:
+ switch (p->listPropertyAssignBehavior) {
+ case Pragma::Replace:
+ createdUnit->flags |= Unit::ListPropertyAssignReplace;
+ break;
+ case Pragma::ReplaceIfNotDefault:
+ createdUnit->flags |= Unit::ListPropertyAssignReplaceIfNotDefault;
+ break;
+ case Pragma::Append:
+ // this is the default
+ break;
+ }
break;
}
}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index fe6a9db750..036da04743 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -408,11 +408,24 @@ private:
struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
{
- enum PragmaType {
- PragmaSingleton = 0x1,
- PragmaStrict = 0x2
+ enum PragmaType
+ {
+ Singleton,
+ Strict,
+ ListPropertyAssignBehavior,
+ };
+
+ enum ListPropertyAssignBehaviorValue
+ {
+ Append,
+ Replace,
+ ReplaceIfNotDefault,
};
- quint32 type;
+
+ PragmaType type;
+
+ // Could become a union with type as differentiator if necessary
+ ListPropertyAssignBehaviorValue listPropertyAssignBehavior;
QV4::CompiledData::Location location;
};
diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
index 718b0c25ac..32c2e751a5 100644
--- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
@@ -242,5 +242,34 @@ refer to the \l MouseArea child, and if it had an \c id of \c root rather than
the root object defined in \c SquareButton.qml as the two would be declared
within separate scopes.
+\section1 Pragmas
+
+You can prepend global instructions to a QML document using the \c pragma
+keyword. The following pragmas are supported:
+
+\section2 Singleton
+
+\c{pragma Singleton} declares the component defined in the QML document as
+singleton. Singletons are created only once per QML engine. In order to use
+a QML-declared singleton you also have to register it with its module. See
+\l{qt_target_qml_sources} for how to do this with CMake.
+
+\section2 ListPropertyAssignBehavior
+
+With this pragma you can define how assignments to list properties shall be
+handled in components defined in the QML document. By default, assigning to a
+list property appends to the list. You can explicitly request this behavior
+using the value \c{Append}. Alternatively, you can request the contents of list
+properties to always be replaced using \c{Replace}, or replaced if the property
+is not the default property using \c{ReplaceIfNotDefault}. For example:
+
+\qml
+pragma ListPropertyAssignBehavior: ReplaceIfNotDefault
+\endqml
+
+The same declaration can also be given for C++-defined types. See
+\l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND},
+\l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE}, and
+\l{QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT}
*/
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 9ceec1fbf7..e4670553cb 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -190,6 +190,15 @@ public:
// --- interface for QQmlPropertyCacheCreator
using CompiledObject = CompiledData::Object;
using CompiledFunction = CompiledData::Function;
+ enum class ListPropertyAssignBehavior { Append, Replace, ReplaceIfNotDefault };
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ if (data->flags & CompiledData::Unit::ListPropertyAssignReplace)
+ return ListPropertyAssignBehavior::Replace;
+ if (data->flags & CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ return ListPropertyAssignBehavior::ReplaceIfNotDefault;
+ return ListPropertyAssignBehavior::Append;
+ }
int objectCount() const { return qmlData->nObjects; }
const CompiledObject *objectAt(int index) const
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index a78dd383f3..7fd2db03a5 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -824,6 +824,16 @@ UiPragma: T_PRAGMA PragmaId Semicolon;
} break;
./
+UiPragma: T_PRAGMA PragmaId T_COLON JsIdentifier Semicolon;
+/.
+ case $rule_number: {
+ AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2), stringRef(4));
+ pragma->pragmaToken = loc(1);
+ pragma->semicolonToken = loc(5);
+ sym(1).Node = pragma;
+ } break;
+./
+
ImportId: MemberExpression;
UiImport: UiImportHead Semicolon;
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index bd4e225412..ba646919dc 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -3135,8 +3135,8 @@ class QML_PARSER_EXPORT UiPragma: public Node
public:
QQMLJS_DECLARE_AST_NODE(UiPragma)
- UiPragma(QStringView name)
- : name(name)
+ UiPragma(QStringView name, QStringView value = {})
+ : name(name), value(value)
{ kind = K; }
void accept0(BaseVisitor *visitor) override;
@@ -3149,6 +3149,7 @@ public:
// attributes
QStringView name;
+ QStringView value;
SourceLocation pragmaToken;
SourceLocation semicolonToken;
};
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index 8b700cd928..6b8be0bb74 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -58,18 +58,24 @@ void QQmlIRLoader::load()
for (quint32 i = 0; i < qmlUnit->nImports; ++i)
output->imports << qmlUnit->importAt(i);
- const auto createPragma = [&](QmlIR::Pragma::PragmaType type) {
+ const auto createPragma = [&](
+ QmlIR::Pragma::PragmaType type,
+ QmlIR::Pragma::ListPropertyAssignBehaviorValue value = QmlIR::Pragma::Append) {
QmlIR::Pragma *p = New<QmlIR::Pragma>();
p->location = QV4::CompiledData::Location();
p->type = type;
+ p->listPropertyAssignBehavior = value;
output->pragmas << p;
};
if (unit->flags & QV4::CompiledData::Unit::IsSingleton)
- createPragma(QmlIR::Pragma::PragmaSingleton);
+ createPragma(QmlIR::Pragma::Singleton);
if (unit->flags & QV4::CompiledData::Unit::IsStrict)
- createPragma(QmlIR::Pragma::PragmaStrict);
-
+ createPragma(QmlIR::Pragma::Strict);
+ if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplace)
+ createPragma(QmlIR::Pragma::ListPropertyAssignBehavior, QmlIR::Pragma::Replace);
+ else if (unit->flags & QV4::CompiledData::Unit::ListPropertyAssignReplaceIfNotDefault)
+ createPragma(QmlIR::Pragma::ListPropertyAssignBehavior, QmlIR::Pragma::ReplaceIfNotDefault);
for (uint i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i);
diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp
index 5a2cf1e455..5f2cc2d44a 100644
--- a/src/qml/qml/qqmllist.cpp
+++ b/src/qml/qml/qqmllist.cpp
@@ -476,6 +476,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -492,6 +493,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
+ \sa {Defining Object Types through QML Documents}
*/
/*!
@@ -506,6 +508,7 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
\sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
+ \sa {Defining Object Types through QML Documents}
*/
/*!
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 5ed63fb57c..f8077d559d 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -209,6 +209,7 @@ QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
cache->allowedRevisionCache = allowedRevisionCache;
cache->_metaObject = _metaObject;
cache->_defaultPropertyName = _defaultPropertyName;
+ cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
return cache;
}
@@ -424,6 +425,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
_jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
if (_jsFactoryMethodIndex != -1)
_jsFactoryMethodIndex -= metaObject->methodOffset();
+ } else if (0 == qstrcmp(name, "QML.ListPropertyAssignBehavior")) {
+ _listPropertyAssignBehavior = mci.value();
}
}
}
@@ -1106,6 +1109,9 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
}
}
+
+ if (!_listPropertyAssignBehavior.isEmpty())
+ builder.addClassInfo("QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
}
namespace {
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 1db3f0f464..0146f9d123 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -328,6 +328,7 @@ private:
RefCountedMetaObject _metaObject;
QByteArray _dynamicClassName;
QByteArray _dynamicStringData;
+ QByteArray _listPropertyAssignBehavior;
QString _defaultPropertyName;
QQmlPropertyCacheMethodArguments *argumentsCache;
QByteArray _checksum;
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 55dd6d2728..363a9ff4e2 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -433,6 +433,18 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
cache->_dynamicClassName = newClassName;
+ using ListPropertyAssignBehavior = typename ObjectContainer::ListPropertyAssignBehavior;
+ switch (objectContainer->listPropertyAssignBehavior()) {
+ case ListPropertyAssignBehavior::ReplaceIfNotDefault:
+ cache->_listPropertyAssignBehavior = "ReplaceIfNotDefault";
+ break;
+ case ListPropertyAssignBehavior::Replace:
+ cache->_listPropertyAssignBehavior = "Replace";
+ break;
+ case ListPropertyAssignBehavior::Append:
+ break;
+ }
+
QQmlPropertyResolver resolver(baseTypeCache);
auto p = obj->propertiesBegin();
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index 1a100828f8..2fe1f5242e 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -88,12 +88,22 @@ public:
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
+ using ListPropertyAssignBehavior = QmlIR::Pragma::ListPropertyAssignBehaviorValue;
+
const QmlIR::Object *objectAt(int index) const { return document->objects.at(index); }
int objectCount() const { return document->objects.count(); }
QString stringAt(int idx) const;
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); }
QmlIR::PoolList<QmlIR::Function>::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); }
QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr;
+ ListPropertyAssignBehavior listPropertyAssignBehavior() const
+ {
+ for (const QmlIR::Pragma *pragma: document->pragmas) {
+ if (pragma->type == QmlIR::Pragma::ListPropertyAssignBehavior)
+ return pragma->listPropertyAssignBehavior;
+ }
+ return ListPropertyAssignBehavior::Append;
+ }
// ---
QQmlRefPointer<QV4::ExecutableCompilationUnit> compile();
diff --git a/tests/auto/qml/qqmlproperty/data/listBehaviorAppendPragma.qml b/tests/auto/qml/qqmlproperty/data/listBehaviorAppendPragma.qml
new file mode 100644
index 0000000000..f7844564a8
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listBehaviorAppendPragma.qml
@@ -0,0 +1,39 @@
+pragma ListPropertyAssignBehavior: Append
+
+import QtQml
+
+QtObject {
+ component WithDefault: QtObject {
+ default property list<QtObject> defaultList
+ }
+
+ component MyChild: WithDefault {
+ QtObject { objectName: "default1" }
+
+ property list<QtObject> myList: [
+ QtObject { objectName: "test1" }
+ ]
+ }
+
+ property MyChild myChild1: MyChild {
+ myList: [
+ QtObject { objectName: "test2" }
+ ]
+
+ QtObject { objectName: "default2" }
+ }
+
+ property MyChild myChild2: MyChild {
+ property list<QtObject> myOwnList: [
+ QtObject { property string str: "test3" }
+ ]
+ myList: myOwnList
+ defaultList: myOwnList
+ }
+
+ property int length1: myChild1.myList.length
+ property int length2: myChild2.myList.length
+
+ property int default1: myChild1.defaultList.length
+ property int default2: myChild2.defaultList.length
+}
diff --git a/tests/auto/qml/qqmlproperty/data/listBehaviorFail1.qml b/tests/auto/qml/qqmlproperty/data/listBehaviorFail1.qml
new file mode 100644
index 0000000000..2723249e48
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listBehaviorFail1.qml
@@ -0,0 +1,3 @@
+pragma ListPropertyAssignBehavior: Foo
+import QtQml
+QtObject {}
diff --git a/tests/auto/qml/qqmlproperty/data/listBehaviorFail2.qml b/tests/auto/qml/qqmlproperty/data/listBehaviorFail2.qml
new file mode 100644
index 0000000000..63b79f85d1
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listBehaviorFail2.qml
@@ -0,0 +1,5 @@
+pragma ListPropertyAssignBehavior: Append
+pragma Singleton
+pragma ListPropertyAssignBehavior: Replace
+import QtQml
+QtObject {}
diff --git a/tests/auto/qml/qqmlproperty/data/listBehaviorReplaceIfNotDefaultPragma.qml b/tests/auto/qml/qqmlproperty/data/listBehaviorReplaceIfNotDefaultPragma.qml
new file mode 100644
index 0000000000..ea4de1d8a4
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listBehaviorReplaceIfNotDefaultPragma.qml
@@ -0,0 +1,39 @@
+pragma ListPropertyAssignBehavior: ReplaceIfNotDefault
+
+import QtQml
+
+QtObject {
+ component WithDefault: QtObject {
+ default property list<QtObject> defaultList
+ }
+
+ component MyChild: WithDefault {
+ QtObject { objectName: "default1" }
+
+ property list<QtObject> myList: [
+ QtObject { objectName: "test1" }
+ ]
+ }
+
+ property MyChild myChild1: MyChild {
+ myList: [
+ QtObject { objectName: "test2" }
+ ]
+
+ QtObject { objectName: "default2" }
+ }
+
+ property MyChild myChild2: MyChild {
+ property list<QtObject> myOwnList: [
+ QtObject { property string str: "test3" }
+ ]
+ myList: myOwnList
+ defaultList: myOwnList
+ }
+
+ property int length1: myChild1.myList.length
+ property int length2: myChild2.myList.length
+
+ property int default1: myChild1.defaultList.length
+ property int default2: myChild2.defaultList.length
+}
diff --git a/tests/auto/qml/qqmlproperty/data/listBehaviorReplacePragma.qml b/tests/auto/qml/qqmlproperty/data/listBehaviorReplacePragma.qml
new file mode 100644
index 0000000000..e960a7cac5
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listBehaviorReplacePragma.qml
@@ -0,0 +1,39 @@
+pragma ListPropertyAssignBehavior: Replace
+
+import QtQml
+
+QtObject {
+ component WithDefault: QtObject {
+ default property list<QtObject> defaultList
+ }
+
+ component MyChild: WithDefault {
+ QtObject { objectName: "default1" }
+
+ property list<QtObject> myList: [
+ QtObject { objectName: "test1" }
+ ]
+ }
+
+ property MyChild myChild1: MyChild {
+ myList: [
+ QtObject { objectName: "test2" }
+ ]
+
+ QtObject { objectName: "default2" }
+ }
+
+ property MyChild myChild2: MyChild {
+ property list<QtObject> myOwnList: [
+ QtObject { property string str: "test3" }
+ ]
+ myList: myOwnList
+ defaultList: myOwnList
+ }
+
+ property int length1: myChild1.myList.length
+ property int length2: myChild2.myList.length
+
+ property int default1: myChild1.defaultList.length
+ property int default2: myChild2.defaultList.length
+}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index fc045b777c..9cf622c2d7 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -1724,6 +1724,55 @@ void tst_qqmlproperty::listOverrideBehavior()
QVERIFY(alwaysReplaceContainer != nullptr);
QQmlListReference alwaysReplaceChildrenList(alwaysReplaceContainer, "children");
QCOMPARE(alwaysReplaceChildrenList.count(), 2);
+
+ {
+ QQmlComponent appendQml(&engine, testFileUrl("listBehaviorAppendPragma.qml"));
+ QVERIFY2(appendQml.isReady(), qPrintable(appendQml.errorString()));
+ QScopedPointer<QObject> o(appendQml.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("length1").toInt(), 2);
+ QCOMPARE(o->property("length2").toInt(), 1);
+ QCOMPARE(o->property("default1").toInt(), 2);
+ QCOMPARE(o->property("default2").toInt(), 1);
+ }
+
+ {
+ QQmlComponent replaceQml(&engine, testFileUrl("listBehaviorReplacePragma.qml"));
+ QVERIFY2(replaceQml.isReady(), qPrintable(replaceQml.errorString()));
+ QScopedPointer<QObject> o(replaceQml.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("length1").toInt(), 1);
+ QCOMPARE(o->property("length2").toInt(), 1);
+ QCOMPARE(o->property("default1").toInt(), 1);
+ QCOMPARE(o->property("default2").toInt(), 1);
+ }
+
+ {
+ QQmlComponent replaceIfNotDefaultQml(
+ &engine, testFileUrl("listBehaviorReplaceIfNotDefaultPragma.qml"));
+ QVERIFY2(replaceIfNotDefaultQml.isReady(),
+ qPrintable(replaceIfNotDefaultQml.errorString()));
+ QScopedPointer<QObject> o(replaceIfNotDefaultQml.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("length1").toInt(), 1);
+ QCOMPARE(o->property("length2").toInt(), 1);
+ QCOMPARE(o->property("default1").toInt(), 2);
+ QCOMPARE(o->property("default2").toInt(), 1);
+ }
+
+ {
+ QQmlComponent fail1(&engine, testFileUrl("listBehaviorFail1.qml"));
+ QVERIFY(fail1.isError());
+ QVERIFY(fail1.errorString().contains(
+ QStringLiteral("Unknown list property assign behavior 'Foo' in pragma")));
+ }
+
+ {
+ QQmlComponent fail2(&engine, testFileUrl("listBehaviorFail2.qml"));
+ QVERIFY(fail2.isError());
+ QVERIFY(fail2.errorString().contains(
+ QStringLiteral("Multiple list property assign behavior pragmas found")));
+ }
}
void tst_qqmlproperty::urlHandling_data()