diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2020-04-15 20:23:28 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2020-04-30 19:39:25 +0200 |
commit | 3d7265db9075db7b22b241b659f23d392d62d804 (patch) | |
tree | 902bb831d91f39b89d4481dca9381a18abb5dac3 /src/tools/moc | |
parent | b480acb3720c0d61c5c69a2b861af63b9d7c9f86 (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.cpp | 105 | ||||
-rw-r--r-- | src/tools/moc/generator.h | 1 | ||||
-rw-r--r-- | src/tools/moc/keywords.cpp | 61 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 78 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 12 | ||||
-rw-r--r-- | src/tools/moc/token.h | 1 | ||||
-rw-r--r-- | src/tools/moc/util/generate_keywords.cpp | 1 |
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" }, |