Introduce Q_PROPERTY attribute REQUIRED

This is meant to correspond to required properties in QML.

Change-Id: I2645981e13f7423bc86b48370c165b3cfe2aaa62
Task-number: QTBUG-81561
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
Fabian Kosmale 2020-01-21 15:33:11 +01:00
parent 49f143e19c
commit cb3152086c
10 changed files with 69 additions and 1 deletions

View File

@ -61,6 +61,7 @@ Q_PROPERTY(type name
[USER bool] [USER bool]
[CONSTANT] [CONSTANT]
[FINAL]) [FINAL])
[REQUIRED]
//! [0] //! [0]

View File

@ -144,6 +144,12 @@
optimizations in some cases, but is not enforced by moc. Care must be taken optimizations in some cases, but is not enforced by moc. Care must be taken
never to override a \c FINAL property. never to override a \c FINAL property.
\li The presence of the \c REQUIRED attribute indicates that the property
should be set by a user of the class. This is not enforced by moc, and is
mostly useful for classes exposed to QML. In QML, classes with REQUIRED
properties cannot be instantiated unless all REQUIRED properties have
been set.
\endlist \endlist
The \c READ, \c WRITE, and \c RESET functions can be inherited. The \c READ, \c WRITE, and \c RESET functions can be inherited.

View File

@ -3572,6 +3572,21 @@ bool QMetaProperty::isFinal() const
return flags & Final; return flags & Final;
} }
/*!
\since 5.15
Returns \c true if the property is required; otherwise returns \c false.
A property is final if the \c{Q_PROPERTY()}'s \c REQUIRED attribute
is set.
*/
bool QMetaProperty::isRequired() const
{
if (!mobj)
return false;
int flags = mobj->d.data[handle + 2];
return flags & Required;
}
/*! /*!
\obsolete \obsolete

View File

@ -266,6 +266,7 @@ public:
bool isUser(const QObject *obj = nullptr) const; bool isUser(const QObject *obj = nullptr) const;
bool isConstant() const; bool isConstant() const;
bool isFinal() const; bool isFinal() const;
bool isRequired() const;
bool isFlagType() const; bool isFlagType() const;
bool isEnumType() const; bool isEnumType() const;

View File

@ -85,7 +85,8 @@ enum PropertyFlags {
User = 0x00100000, User = 0x00100000,
ResolveUser = 0x00200000, ResolveUser = 0x00200000,
Notify = 0x00400000, Notify = 0x00400000,
Revisioned = 0x00800000 Revisioned = 0x00800000,
Required = 0x01000000,
}; };
enum MethodFlags { enum MethodFlags {

View File

@ -864,6 +864,8 @@ void Generator::generateProperties()
flags |= Constant; flags |= Constant;
if (p.final) if (p.final)
flags |= Final; flags |= Final;
if (p.required)
flags |= Required;
fprintf(out, " %4d, ", stridx(p.name)); fprintf(out, " %4d, ", stridx(p.name));
generateTypeInfo(p.type); generateTypeInfo(p.type);

View File

@ -1238,6 +1238,9 @@ void Moc::createPropertyDef(PropertyDef &propDef)
} else if(l[0] == 'F' && l == "FINAL") { } else if(l[0] == 'F' && l == "FINAL") {
propDef.final = true; propDef.final = true;
continue; continue;
} else if (l[0] == 'R' && l == "REQUIRED") {
propDef.required = true;
continue;
} }
QByteArray v, v2; QByteArray v, v2;
@ -1960,6 +1963,7 @@ QJsonObject PropertyDef::toJson() const
prop[QLatin1String("constant")] = constant; prop[QLatin1String("constant")] = constant;
prop[QLatin1String("final")] = final; prop[QLatin1String("final")] = final;
prop[QLatin1String("required")] = required;
if (revision > 0) if (revision > 0)
prop[QLatin1String("revision")] = revision; prop[QLatin1String("revision")] = revision;

View File

@ -137,6 +137,7 @@ struct PropertyDef
int revision = 0; int revision = 0;
bool constant = false; bool constant = false;
bool final = false; bool final = false;
bool required = false;
QJsonObject toJson() const; QJsonObject toJson() const;
}; };

View File

@ -275,6 +275,7 @@
"final": false, "final": false,
"name": "flags", "name": "flags",
"read": "flags", "read": "flags",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Flags", "type": "Flags",
@ -299,6 +300,7 @@
"final": false, "final": false,
"name": "flags", "name": "flags",
"read": "flags", "read": "flags",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Foo::Bar::Flags", "type": "Foo::Bar::Flags",
@ -311,6 +313,7 @@
"final": false, "final": false,
"name": "flagsList", "name": "flagsList",
"read": "flagsList", "read": "flagsList",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "QList<Foo::Bar::Flags>", "type": "QList<Foo::Bar::Flags>",
@ -1988,6 +1991,7 @@
"final": false, "final": false,
"name": "blah", "name": "blah",
"read": "blah", "read": "blah",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "A::SomeEnum", "type": "A::SomeEnum",
@ -2088,6 +2092,7 @@
"final": false, "final": false,
"name": "blah", "name": "blah",
"read": "blah", "read": "blah",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "A::SomeEnum", "type": "A::SomeEnum",
@ -2257,6 +2262,7 @@
"final": false, "final": false,
"name": "gadgetPoperty", "name": "gadgetPoperty",
"read": "gadgetPoperty", "read": "gadgetPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Gadget::SomeEnum", "type": "Gadget::SomeEnum",
@ -2268,6 +2274,7 @@
"final": false, "final": false,
"name": "objectPoperty", "name": "objectPoperty",
"read": "objectPoperty", "read": "objectPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Object::SomeEnum", "type": "Object::SomeEnum",
@ -2291,6 +2298,7 @@
"final": false, "final": false,
"name": "nestedGadgetPoperty", "name": "nestedGadgetPoperty",
"read": "nestedGadgetPoperty", "read": "nestedGadgetPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Nested::Gadget::SomeEnum", "type": "Nested::Gadget::SomeEnum",
@ -2314,6 +2322,7 @@
"final": false, "final": false,
"name": "nestedObjectPoperty", "name": "nestedObjectPoperty",
"read": "nestedObjectPoperty", "read": "nestedObjectPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Nested::Object::SomeEnum", "type": "Nested::Object::SomeEnum",
@ -2442,6 +2451,7 @@
"final": false, "final": false,
"name": "gadgetPoperty", "name": "gadgetPoperty",
"read": "gadgetPoperty", "read": "gadgetPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Gadget::SomeEnum", "type": "Gadget::SomeEnum",
@ -2453,6 +2463,7 @@
"final": false, "final": false,
"name": "objectPoperty", "name": "objectPoperty",
"read": "objectPoperty", "read": "objectPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Object::SomeEnum", "type": "Object::SomeEnum",
@ -2476,6 +2487,7 @@
"final": false, "final": false,
"name": "nestedGadgetPoperty", "name": "nestedGadgetPoperty",
"read": "nestedGadgetPoperty", "read": "nestedGadgetPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Nested::Gadget::SomeEnum", "type": "Nested::Gadget::SomeEnum",
@ -2499,6 +2511,7 @@
"final": false, "final": false,
"name": "nestedObjectPoperty", "name": "nestedObjectPoperty",
"read": "nestedObjectPoperty", "read": "nestedObjectPoperty",
"required": false,
"scriptable": true, "scriptable": true,
"stored": true, "stored": true,
"type": "Nested::Object::SomeEnum", "type": "Nested::Object::SomeEnum",

View File

@ -719,6 +719,7 @@ private slots:
void cxx17Namespaces(); void cxx17Namespaces();
void cxxAttributes(); void cxxAttributes();
void mocJsonOutput(); void mocJsonOutput();
void requiredProperties();
signals: signals:
void sigWithUnsignedArg(unsigned foo); void sigWithUnsignedArg(unsigned foo);
@ -4025,6 +4026,29 @@ void tst_Moc::mocJsonOutput()
QVERIFY2(actualOutput == expectedOutput, showPotentialDiff(actualOutput, expectedOutput).constData()); QVERIFY2(actualOutput == expectedOutput, showPotentialDiff(actualOutput, expectedOutput).constData());
} }
class RequiredTest :public QObject
{
Q_OBJECT
Q_PROPERTY(int required MEMBER m_required REQUIRED)
Q_PROPERTY(int notRequired MEMBER m_notRequired)
private:
int m_required;
int m_notRequired;
};
void tst_Moc::requiredProperties()
{
QMetaObject mo = RequiredTest::staticMetaObject;
QMetaProperty required = mo.property(mo.indexOfProperty("required"));
QVERIFY(required.isValid());
QVERIFY(required.isRequired());
QMetaProperty notRequired = mo.property(mo.indexOfProperty("notRequired"));
QVERIFY(notRequired.isValid());
QVERIFY(!notRequired.isRequired());
}
QTEST_MAIN(tst_Moc) QTEST_MAIN(tst_Moc)
// the generated code must compile with QT_NO_KEYWORDS // the generated code must compile with QT_NO_KEYWORDS