summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2020-04-15 20:23:28 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2020-04-30 19:39:25 +0200
commit3d7265db9075db7b22b241b659f23d392d62d804 (patch)
tree902bb831d91f39b89d4481dca9381a18abb5dac3 /src/tools/moc
parentb480acb3720c0d61c5c69a2b861af63b9d7c9f86 (diff)
Provide a way of exposing private QProperties with a fake API
The API reduces the amount of manual plumbing required to offer a conceptual property through the traditional setter/getter API as well as through QProperty<T> API. Since the latter would require inlining the type and thus making it impossible to add new properties without breaking binary compatibility, this patch introduces a fake API that behaves similar but does not contain the property by value. Change-Id: Ib9bccd867f0e4e36a520e5583ba348e728284253 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/generator.cpp105
-rw-r--r--src/tools/moc/generator.h1
-rw-r--r--src/tools/moc/keywords.cpp61
-rw-r--r--src/tools/moc/moc.cpp78
-rw-r--r--src/tools/moc/moc.h12
-rw-r--r--src/tools/moc/token.h1
-rw-r--r--src/tools/moc/util/generate_keywords.cpp1
7 files changed, 223 insertions, 36 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index acb7cdffe9..976d49ad20 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -616,6 +616,11 @@ void Generator::generateCode()
generateSignal(&cdef->signalList[signalindex], signalindex);
//
+// Generate QProperty forwarding API
+//
+ generateQPropertyApi();
+
+//
// Generate plugin meta data
//
generatePluginMetaData();
@@ -1621,6 +1626,106 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "}\n");
}
+void Generator::generateQPropertyApi()
+{
+ for (const PrivateQPropertyDef &property: cdef->privateQProperties) {
+ auto printAccessor = [this, property](bool constAccessor = false) {
+ const char *constOrNot = constAccessor ? "const " : " ";
+ fprintf(out, " const size_t propertyMemberOffset = reinterpret_cast<size_t>(&(static_cast<%s *>(nullptr)->%s));\n", cdef->qualified.constData(), property.name.constData());
+ fprintf(out, " %sauto *thisPtr = reinterpret_cast<%s%s *>(reinterpret_cast<%schar *>(this) - propertyMemberOffset);\n", constOrNot, constOrNot, cdef->qualified.constData(), constOrNot);
+ };
+
+ // property accessor
+ fprintf(out, "\n%s %s::_qt_property_api_%s::value() const\n{\n",
+ property.type.name.constData(),
+ cdef->qualified.constData(),
+ property.name.constData());
+ printAccessor(/*const*/true);
+ fprintf(out, " return thisPtr->%s->%s.value();\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // property value setter
+ fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(const %s &value)\n{\n",
+ cdef->qualified.constData(),
+ property.name.constData(),
+ property.type.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.setValue(value);\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // property value move setter
+ fprintf(out, "\nvoid %s::_qt_property_api_%s::setValue(%s &&value)\n{\n",
+ cdef->qualified.constData(),
+ property.name.constData(),
+ property.type.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.setValue(std::move(value));\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // binding setter
+ fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::setBinding(const QPropertyBinding<%s> &binding)\n{\n",
+ property.type.name.constData(),
+ cdef->qualified.constData(),
+ property.name.constData(),
+ property.type.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.setBinding(binding);\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // binding move setter
+ fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::setBinding(QPropertyBinding<%s> &&binding)\n{\n",
+ property.type.name.constData(),
+ cdef->qualified.constData(),
+ property.name.constData(),
+ property.type.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.setBinding(std::move(binding));\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // untyped binding setter
+ fprintf(out, "\nbool %s::_qt_property_api_%s::setBinding(const QUntypedPropertyBinding &binding)\n{\n",
+ cdef->qualified.constData(),
+ property.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.setBinding(binding);\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // binding bool getter
+ fprintf(out, "\nbool %s::_qt_property_api_%s::hasBinding() const\n{\n",
+ cdef->qualified.constData(),
+ property.name.constData());
+ printAccessor(/*const*/true);
+ fprintf(out, " return thisPtr->%s->%s.hasBinding();\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // binding getter
+ fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::binding() const\n{\n",
+ property.type.name.constData(),
+ cdef->qualified.constData(),
+ property.name.constData());
+ printAccessor(/*const*/true);
+ fprintf(out, " return thisPtr->%s->%s.binding();\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // binding taker
+ fprintf(out, "\nQPropertyBinding<%s> %s::_qt_property_api_%s::takeBinding()\n{\n",
+ property.type.name.constData(),
+ cdef->qualified.constData(),
+ property.name.constData());
+ printAccessor();
+ fprintf(out, " return thisPtr->%s->%s.takeBinding();\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n");
+
+ // property setter function
+ fprintf(out, "\nvoid %s::%s(const %s &value)\n{\n",
+ cdef->qualified.constData(),
+ property.setter.constData(),
+ property.type.name.constData());
+ fprintf(out, " %s->%s.setValue(value);\n", property.accessor.constData(), property.name.constData());
+ fprintf(out, "}\n\n");
+ }
+}
+
static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
{
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index eae0353199..e92b9d1208 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -58,6 +58,7 @@ private:
void generateMetacall();
void generateStaticMetacall();
void generateSignal(FunctionDef *def, int index);
+ void generateQPropertyApi();
void generatePluginMetaData();
QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypesHelper(const QVector<FunctionDef> &methodList);
diff --git a/src/tools/moc/keywords.cpp b/src/tools/moc/keywords.cpp
index cc7d747f5b..6a56d2cea5 100644
--- a/src/tools/moc/keywords.cpp
+++ b/src/tools/moc/keywords.cpp
@@ -30,12 +30,12 @@
// DO NOT EDIT.
static const short keyword_trans[][128] = {
- {0,0,0,0,0,0,0,0,0,579,576,0,0,0,0,0,
+ {0,0,0,0,0,0,0,0,0,588,585,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 579,252,577,580,8,38,239,578,25,26,236,234,30,235,27,237,
+ 588,252,586,589,8,38,239,587,25,26,236,234,30,235,27,237,
22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43,
0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,21,8,8,8,8,8,8,8,8,8,31,582,32,238,8,
+ 8,21,8,8,8,8,8,8,8,8,8,31,591,32,238,8,
0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13,
14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -177,7 +177,7 @@ static const short keyword_trans[][128] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0,
- 585,585,585,585,585,585,585,585,585,585,0,0,0,0,0,0,
+ 594,594,594,594,594,594,594,594,594,594,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -336,7 +336,7 @@ static const short keyword_trans[][128] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,583,
+ 0,0,0,0,0,0,0,0,0,0,593,0,0,0,0,592,
0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -378,8 +378,8 @@ static const short keyword_trans[][128] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,475,424,408,416,380,0,484,0,0,0,565,364,358,
- 386,0,557,472,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,475,424,408,416,380,0,484,0,0,0,574,364,358,
+ 386,0,566,472,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -443,7 +443,7 @@ static const short keyword_trans[][128] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 549,0,0,517,0,0,0,0,0,0,0,0,0,0,0,0,
+ 549,557,0,517,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
@@ -1013,30 +1013,39 @@ static const struct
{CHARACTER, 0, 84, 555, CHARACTER},
{CHARACTER, 0, 89, 556, CHARACTER},
{Q_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER},
- {CHARACTER, 0, 69, 558, CHARACTER},
- {CHARACTER, 0, 86, 559, CHARACTER},
- {CHARACTER, 0, 73, 560, CHARACTER},
- {CHARACTER, 0, 83, 561, CHARACTER},
- {CHARACTER, 0, 73, 562, CHARACTER},
- {CHARACTER, 0, 79, 563, CHARACTER},
- {CHARACTER, 0, 78, 564, CHARACTER},
- {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER},
- {CHARACTER, 0, 79, 566, CHARACTER},
- {CHARACTER, 0, 67, 567, CHARACTER},
- {CHARACTER, 0, 95, 568, CHARACTER},
+ {CHARACTER, 0, 80, 558, CHARACTER},
+ {CHARACTER, 0, 82, 559, CHARACTER},
+ {CHARACTER, 0, 79, 560, CHARACTER},
+ {CHARACTER, 0, 80, 561, CHARACTER},
+ {CHARACTER, 0, 69, 562, CHARACTER},
+ {CHARACTER, 0, 82, 563, CHARACTER},
+ {CHARACTER, 0, 84, 564, CHARACTER},
+ {CHARACTER, 0, 89, 565, CHARACTER},
+ {Q_PRIVATE_QPROPERTY_TOKEN, 0, 0, 0, CHARACTER},
+ {CHARACTER, 0, 69, 567, CHARACTER},
+ {CHARACTER, 0, 86, 568, CHARACTER},
{CHARACTER, 0, 73, 569, CHARACTER},
- {CHARACTER, 0, 78, 570, CHARACTER},
- {CHARACTER, 0, 67, 571, CHARACTER},
- {CHARACTER, 0, 76, 572, CHARACTER},
- {CHARACTER, 0, 85, 573, CHARACTER},
- {CHARACTER, 0, 68, 574, CHARACTER},
- {CHARACTER, 0, 69, 575, CHARACTER},
+ {CHARACTER, 0, 83, 570, CHARACTER},
+ {CHARACTER, 0, 73, 571, CHARACTER},
+ {CHARACTER, 0, 79, 572, CHARACTER},
+ {CHARACTER, 0, 78, 573, CHARACTER},
+ {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER},
+ {CHARACTER, 0, 79, 575, CHARACTER},
+ {CHARACTER, 0, 67, 576, CHARACTER},
+ {CHARACTER, 0, 95, 577, CHARACTER},
+ {CHARACTER, 0, 73, 578, CHARACTER},
+ {CHARACTER, 0, 78, 579, CHARACTER},
+ {CHARACTER, 0, 67, 580, CHARACTER},
+ {CHARACTER, 0, 76, 581, CHARACTER},
+ {CHARACTER, 0, 85, 582, CHARACTER},
+ {CHARACTER, 0, 68, 583, CHARACTER},
+ {CHARACTER, 0, 69, 584, CHARACTER},
{Q_MOC_INCLUDE_TOKEN, 0, 0, 0, CHARACTER},
{NEWLINE, 0, 0, 0, NOTOKEN},
{QUOTE, 0, 0, 0, NOTOKEN},
{SINGLEQUOTE, 0, 0, 0, NOTOKEN},
{WHITESPACE, 0, 0, 0, NOTOKEN},
- {HASH, 0, 35, 581, HASH},
+ {HASH, 0, 35, 590, HASH},
{PP_HASHHASH, 0, 0, 0, NOTOKEN},
{BACKSLASH, 0, 0, 0, NOTOKEN},
{CPP_COMMENT, 0, 0, 0, NOTOKEN},
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 2444d0db90..949a2e075a 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -878,6 +878,9 @@ void Moc::parse()
case Q_PRIVATE_PROPERTY_TOKEN:
parsePrivateProperty(&def);
break;
+ case Q_PRIVATE_QPROPERTY_TOKEN:
+ parsePrivateQProperty(&def);
+ break;
case ENUM: {
EnumDef enumDef;
if (parseEnum(&enumDef))
@@ -1031,10 +1034,14 @@ static QByteArrayList requiredQtContainers(const QVector<ClassDef> &classes)
QByteArrayList required;
required.reserve(candidates.size());
+ bool needsQProperty = false;
+
for (const auto &candidate : candidates) {
const QByteArray pattern = candidate + '<';
for (const auto &c : classes) {
+ if (!c.privateQProperties.isEmpty())
+ needsQProperty = true;
if (any_type_contains(c.propertyList, pattern) ||
any_arg_contains(c.slotList, pattern) ||
any_arg_contains(c.signalList, pattern) ||
@@ -1045,6 +1052,9 @@ static QByteArrayList requiredQtContainers(const QVector<ClassDef> &classes)
}
}
+ if (needsQProperty)
+ required.push_back("QProperty");
+
return required;
}
@@ -1268,6 +1278,14 @@ void Moc::createPropertyDef(PropertyDef &propDef)
propDef.type = type;
+ next();
+ propDef.name = lexem();
+
+ parsePropertyAttributes(propDef);
+}
+
+void Moc::parsePropertyAttributes(PropertyDef &propDef)
+{
auto checkIsFunction = [&](const QByteArray &def, const char *name) {
if (def.endsWith(')')) {
QByteArray msg = "Providing a function for ";
@@ -1277,9 +1295,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
}
};
- next();
- propDef.name = lexem();
-
while (test(IDENTIFIER)) {
const QByteArray l = lexem();
if (l[0] == 'C' && l == "CONSTANT") {
@@ -1459,23 +1474,30 @@ void Moc::parsePluginData(ClassDef *def)
next(RPAREN);
}
-void Moc::parsePrivateProperty(ClassDef *def)
+QByteArray Moc::parsePropertyAccessor()
{
- next(LPAREN);
- PropertyDef propDef;
next(IDENTIFIER);
- propDef.inPrivateClass = lexem();
+ QByteArray accessor = lexem();
while (test(SCOPE)) {
- propDef.inPrivateClass += lexem();
+ accessor += lexem();
next(IDENTIFIER);
- propDef.inPrivateClass += lexem();
+ accessor += lexem();
}
// also allow void functions
if (test(LPAREN)) {
next(RPAREN);
- propDef.inPrivateClass += "()";
+ accessor += "()";
}
+ return accessor;
+}
+
+void Moc::parsePrivateProperty(ClassDef *def)
+{
+ next(LPAREN);
+ PropertyDef propDef;
+ propDef.inPrivateClass = parsePropertyAccessor();
+
next(COMMA);
createPropertyDef(propDef);
@@ -1488,6 +1510,42 @@ void Moc::parsePrivateProperty(ClassDef *def)
def->propertyList += propDef;
}
+void Moc::parsePrivateQProperty(ClassDef *def)
+{
+ next(LPAREN);
+ const QByteArray accessor = parsePropertyAccessor();
+ next(COMMA);
+ const Type type = parseType();
+ next(COMMA);
+ next(IDENTIFIER);
+ const QByteArray name = lexem();
+ next(COMMA);
+ next(IDENTIFIER);
+ const QByteArray setter = lexem();
+
+ def->privateQProperties += PrivateQPropertyDef{type, name, setter, accessor};
+
+ PropertyDef propDef;
+ propDef.name = name;
+ propDef.type = type.name;
+ propDef.read = name + ".value";
+ propDef.write = name + ".setValue";
+ propDef.isQProperty = true;
+ propDef.inPrivateClass = accessor;
+ propDef.designable = propDef.scriptable = propDef.stored = "true";
+ propDef.user = "false";
+
+ if (test(COMMA))
+ parsePropertyAttributes(propDef);
+
+ next(RPAREN);
+
+ if (!propDef.notify.isEmpty())
+ def->notifyableProperties++;
+
+ def->propertyList += propDef;
+}
+
void Moc::parseEnumOrFlag(BaseDef *def, bool isFlag)
{
next(LPAREN);
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 210b6c7c2a..486d033049 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -148,6 +148,14 @@ struct PropertyDef
};
Q_DECLARE_TYPEINFO(PropertyDef, Q_MOVABLE_TYPE);
+struct PrivateQPropertyDef
+{
+ Type type;
+ QByteArray name;
+ QByteArray setter;
+ QByteArray accessor;
+};
+Q_DECLARE_TYPEINFO(PrivateQPropertyDef, Q_MOVABLE_TYPE);
struct ClassInfoDef
{
@@ -191,6 +199,7 @@ struct ClassDef : BaseDef {
QVector<FunctionDef> signalList, slotList, methodList, publicList;
QVector<QByteArray> nonClassSignalList;
QVector<PropertyDef> propertyList;
+ QVector<PrivateQPropertyDef> privateQProperties;
QSet<QByteArray> qPropertyMembers;
int notifyableProperties = 0;
int revisionedMethods = 0;
@@ -258,6 +267,7 @@ public:
void parseProperty(ClassDef *def);
void parsePluginData(ClassDef *def);
void createPropertyDef(PropertyDef &def);
+ void parsePropertyAttributes(PropertyDef &propDef);
void parseEnumOrFlag(BaseDef *def, bool isFlag);
void parseFlag(BaseDef *def);
void parseClassInfo(BaseDef *def);
@@ -266,7 +276,9 @@ public:
void parseDeclareMetatype();
void parseMocInclude();
void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access);
+ QByteArray parsePropertyAccessor();
void parsePrivateProperty(ClassDef *def);
+ void parsePrivateQProperty(ClassDef *def);
void parseFunctionArguments(FunctionDef *def);
diff --git a/src/tools/moc/token.h b/src/tools/moc/token.h
index c11ec6a38c..0b6e9c4f7c 100644
--- a/src/tools/moc/token.h
+++ b/src/tools/moc/token.h
@@ -178,6 +178,7 @@ QT_BEGIN_NAMESPACE
F(Q_INVOKABLE_TOKEN) \
F(Q_SCRIPTABLE_TOKEN) \
F(Q_PRIVATE_PROPERTY_TOKEN) \
+ F(Q_PRIVATE_QPROPERTY_TOKEN) \
F(Q_REVISION_TOKEN) \
F(Q_MOC_INCLUDE_TOKEN) \
F(SPECIAL_TREATMENT_MARK) \
diff --git a/src/tools/moc/util/generate_keywords.cpp b/src/tools/moc/util/generate_keywords.cpp
index c2cfe37fab..02a36c5000 100644
--- a/src/tools/moc/util/generate_keywords.cpp
+++ b/src/tools/moc/util/generate_keywords.cpp
@@ -242,6 +242,7 @@ static const Keyword keywords[] = {
{ "Q_SLOT", "Q_SLOT_TOKEN" },
{ "Q_SCRIPTABLE", "Q_SCRIPTABLE_TOKEN" },
{ "Q_PRIVATE_PROPERTY", "Q_PRIVATE_PROPERTY_TOKEN" },
+ { "Q_PRIVATE_QPROPERTY", "Q_PRIVATE_QPROPERTY_TOKEN" },
{ "Q_REVISION", "Q_REVISION_TOKEN" },
{ "Q_MOC_INCLUDE", "Q_MOC_INCLUDE_TOKEN" },
{ "\n", "NEWLINE" },