aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp1
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h16
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp71
10 files changed, 115 insertions, 5 deletions
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 198ce98f2d..a26cdba53a 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1515,6 +1515,14 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
}
}
+ for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) {
+ QQmlPropertyData *propertyData = _propertyCache->property(i);
+ if (propertyData && propertyData->isRequired()) {
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {propertyData->name(_qobject), compilationUnit->finalUrl(), _compiledObject->location, {}});
+ }
+ }
+
if (_compiledObject->nFunctions > 0)
setupFunctions();
setupBindings();
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 472bba0202..0604e1e981 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -75,6 +75,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
flags.setIsWritable(p.isWritable());
flags.setIsResettable(p.isResettable());
flags.setIsFinal(p.isFinal());
+ flags.setIsRequired(p.isRequired());
if (p.isEnumType())
flags.type = QQmlPropertyData::Flags::EnumType;
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index 2d9091edcd..7f70c34854 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -109,7 +109,7 @@ public:
unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
unsigned isSignalHandler : 1; // Function is a signal handler
unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
+ unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
unsigned isConstructor : 1; // The function was marked is a constructor
unsigned isDirect : 1; // Exists on a C++ QMetaObject
unsigned isOverridden : 1; // Is overridden by a extension property
@@ -159,6 +159,11 @@ public:
isDirect = b;
}
+ void setIsRequired(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isRequiredORisCloned = b;
+ }
+
void setIsVMEFunction(bool b) {
Q_ASSERT(type == FunctionType);
isConstantORisVMEFunction = b;
@@ -193,7 +198,7 @@ public:
void setIsCloned(bool b) {
Q_ASSERT(type == FunctionType);
- isCloned = b;
+ isRequiredORisCloned = b;
}
void setIsConstructor(bool b) {
@@ -224,6 +229,7 @@ public:
bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
bool isOverridden() const { return m_flags.isOverridden; }
bool isDirect() const { return m_flags.isOverload; }
+ bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
bool isFunction() const { return m_flags.type == Flags::FunctionType; }
bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
@@ -241,7 +247,7 @@ public:
bool isSignalHandler() const { return m_flags.isSignalHandler; }
bool isOverload() const { return m_flags.isOverload; }
void setOverload(bool onoff) { m_flags.isOverload = onoff; }
- bool isCloned() const { return isFunction() && m_flags.isCloned; }
+ bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
bool isConstructor() const { return m_flags.isConstructor; }
bool hasOverride() const { return overrideIndex() >= 0; }
@@ -438,7 +444,7 @@ QQmlPropertyData::Flags::Flags()
, isFinalORisV4Function(false)
, isSignalHandler(false)
, isOverload(false)
- , isCloned(false)
+ , isRequiredORisCloned(false)
, isConstructor(false)
, isOverridden(false)
, type(OtherType)
@@ -455,7 +461,7 @@ bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) c
isFinalORisV4Function == other.isFinalORisV4Function &&
isOverridden == other.isOverridden &&
isSignalHandler == other.isSignalHandler &&
- isCloned == other.isCloned &&
+ isRequiredORisCloned == other.isRequiredORisCloned &&
type == other.type &&
isConstructor == other.isConstructor &&
notFullyResolved == other.notFullyResolved &&
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml
new file mode 100644
index 0000000000..76673f6409
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredProperty.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+MyClass {test: 42}
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml
new file mode 100644
index 0000000000..d4c059581c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParent.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+Child2 {test: test2; test2: 18}
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml
new file mode 100644
index 0000000000..082e22dc3f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInChildAndParentNotSet.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+Child2 { test: 13 }
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml
new file mode 100644
index 0000000000..6602684542
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParent.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+Child {test: 42}
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml
new file mode 100644
index 0000000000..5971b0c263
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyInParentNotSet.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+Child {}
diff --git a/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml
new file mode 100644
index 0000000000..dab48a3d71
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/cppRequiredPropertyNotSet.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.15
+import example.org 1.0
+
+MyClass {}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 4d2f773dbf..64696e7f3f 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -133,6 +133,8 @@ private slots:
void autoComponentCreationInGroupProperty();
void propertyValueSource();
void requiredProperty();
+ void requiredPropertyFromCpp_data();
+ void requiredPropertyFromCpp();
void attachedProperties();
void dynamicObjects();
void customVariantTypes();
@@ -1679,6 +1681,75 @@ void tst_qqmllanguage::requiredProperty()
}
}
+class MyClassWithRequiredProperty : public QObject
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test MEMBER m_test REQUIRED NOTIFY testChanged)
+ Q_SIGNAL void testChanged();
+private:
+ int m_test;
+};
+
+class ChildClassWithoutOwnRequired : public MyClassWithRequiredProperty
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test2 MEMBER m_test2 NOTIFY test2Changed)
+ Q_SIGNAL void test2Changed();
+private:
+ int m_test2;
+};
+
+class ChildClassWithOwnRequired : public MyClassWithRequiredProperty
+{
+public:
+ Q_OBJECT
+ Q_PROPERTY(int test2 MEMBER m_test2 REQUIRED NOTIFY test2Changed)
+ Q_SIGNAL void test2Changed();
+private:
+ int m_test2;
+};
+
+void tst_qqmllanguage::requiredPropertyFromCpp_data()
+{
+ qmlRegisterType<MyClassWithRequiredProperty>("example.org", 1, 0, "MyClass");
+ qmlRegisterType<ChildClassWithoutOwnRequired>("example.org", 1, 0, "Child");
+ qmlRegisterType<ChildClassWithOwnRequired>("example.org", 1, 0, "Child2");
+
+
+ QTest::addColumn<QUrl>("setFile");
+ QTest::addColumn<QUrl>("notSetFile");
+ QTest::addColumn<QString>("errorMessage");
+ QTest::addColumn<int>("expectedValue");
+
+ QTest::addRow("direct") << testFileUrl("cppRequiredProperty.qml") << testFileUrl("cppRequiredPropertyNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42;
+ QTest::addRow("in parent") << testFileUrl("cppRequiredPropertyInParent.qml") << testFileUrl("cppRequiredPropertyInParentNotSet.qml") << QString(":4 Required property test was not initialized\n") << 42;
+ QTest::addRow("in child and parent") << testFileUrl("cppRequiredPropertyInChildAndParent.qml") << testFileUrl("cppRequiredPropertyInChildAndParentNotSet.qml") << QString(":4 Required property test2 was not initialized\n") << 18;
+}
+
+void tst_qqmllanguage::requiredPropertyFromCpp()
+{
+ QQmlEngine engine;
+ QFETCH(QUrl, setFile);
+ QFETCH(QUrl, notSetFile);
+ QFETCH(QString, errorMessage);
+ QFETCH(int, expectedValue);
+ {
+ QQmlComponent comp(&engine, notSetFile);
+ QScopedPointer<QObject> o { comp.create() };
+ QVERIFY(o.isNull());
+ QVERIFY(comp.isError());
+ QCOMPARE(comp.errorString(), notSetFile.toString() + errorMessage);
+ }
+ {
+ QQmlComponent comp(&engine, setFile);
+ QScopedPointer<QObject> o { comp.create() };
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->property("test").toInt(), expectedValue);
+ }
+}
+
void tst_qqmllanguage::attachedProperties()
{
QQmlComponent component(&engine, testFileUrl("attachedProperties.qml"));