From 3d7265db9075db7b22b241b659f23d392d62d804 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 15 Apr 2020 20:23:28 +0200 Subject: 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 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 --- src/tools/moc/generator.cpp | 105 +++++++++++++++++++++++++++++++ src/tools/moc/generator.h | 1 + src/tools/moc/keywords.cpp | 61 ++++++++++-------- src/tools/moc/moc.cpp | 78 ++++++++++++++++++++--- src/tools/moc/moc.h | 12 ++++ src/tools/moc/token.h | 1 + src/tools/moc/util/generate_keywords.cpp | 1 + 7 files changed, 223 insertions(+), 36 deletions(-) (limited to 'src/tools/moc') 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 @@ -615,6 +615,11 @@ void Generator::generateCode() for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex) generateSignal(&cdef->signalList[signalindex], signalindex); +// +// Generate QProperty forwarding API +// + generateQPropertyApi(); + // // Generate plugin meta data // @@ -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(&(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 automaticPropertyMetaTypesHelper(); QMap > methodsWithAutomaticTypesHelper(const QVector &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 &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 &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 signalList, slotList, methodList, publicList; QVector nonClassSignalList; QVector propertyList; + QVector privateQProperties; QSet 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" }, -- cgit v1.2.3