From b0f445a1526fa43563522d865c5ad1546201003c Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 29 Apr 2020 15:08:53 +0200 Subject: Add support for QNotifiedProperty to the moc Change the meaning of Q_PRIVATE_QPROPERTY to imply that the property is implemented using a QNotifiedProperty. That requires passing the owner object instance to the value and binding setters. Similarly, detect QNotifiedProperty members like QProperty. Change-Id: If49bbb04c8ccd4a661973888c50d2d556c25034f Reviewed-by: Ulf Hermann --- src/tools/moc/generator.cpp | 37 +++++++++++++++++++++++++++---------- src/tools/moc/moc.cpp | 16 +++++++++++++--- src/tools/moc/moc.h | 3 ++- tests/auto/tools/moc/tst_moc.cpp | 20 ++++++++++---------- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 7f2dcc371d..999f86963e 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1335,8 +1335,18 @@ void Generator::generateStaticMetacall() fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast(_v))); break;\n", propindex, prefix.constData(), p.write.constData()); } else if (!p.write.isEmpty()) { - fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n", - propindex, prefix.constData(), p.write.constData(), p.type.constData()); + QByteArray optionalQPropertyOwner; + if (p.isQPropertyWithNotifier) { + optionalQPropertyOwner = "_t"; + if (p.inPrivateClass.size()) { + optionalQPropertyOwner += "->"; + optionalQPropertyOwner += p.inPrivateClass; + } + optionalQPropertyOwner += ", "; + } + + fprintf(out, " case %d: %s%s(%s*reinterpret_cast< %s*>(_v)); break;\n", + propindex, prefix.constData(), p.write.constData(), optionalQPropertyOwner.constData(), p.type.constData()); } else { fprintf(out, " case %d:\n", propindex); fprintf(out, " if (%s%s != *reinterpret_cast< %s*>(_v)) {\n", @@ -1416,11 +1426,18 @@ void Generator::generateStaticMetacall() if (!p.isQProperty) continue; QByteArray prefix = "_t->"; + QByteArray objectAccessor = "_t"; if (p.inPrivateClass.size()) { prefix += p.inPrivateClass + "->"; + objectAccessor += "->"; + objectAccessor += p.inPrivateClass; } - fprintf(out, " case %d: %s%s.setBinding(*reinterpret_cast *>(_a[0])); break;\n", - propindex, prefix.constData(), p.name.constData(), p.type.constData()); + if (p.isQPropertyWithNotifier) + objectAccessor += ", "; + else + objectAccessor.clear(); + fprintf(out, " case %d: %s%s.setBinding(%s*reinterpret_cast *>(_a[0])); break;\n", + propindex, prefix.constData(), p.name.constData(), objectAccessor.constData(), p.type.constData()); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); @@ -1535,7 +1552,7 @@ void Generator::generateQPropertyApi() 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, " return thisPtr->%s->%s.setValue(thisPtr->%s, value);\n", property.accessor.constData(), property.name.constData(), property.accessor.constData()); fprintf(out, "}\n"); // property value move setter @@ -1544,7 +1561,7 @@ void Generator::generateQPropertyApi() 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, " return thisPtr->%s->%s.setValue(thisPtr->%s, std::move(value));\n", property.accessor.constData(), property.name.constData(), property.accessor.constData()); fprintf(out, "}\n"); // binding setter @@ -1554,7 +1571,7 @@ void Generator::generateQPropertyApi() 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, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.name.constData(), property.accessor.constData()); fprintf(out, "}\n"); // binding move setter @@ -1564,7 +1581,7 @@ void Generator::generateQPropertyApi() 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, " return thisPtr->%s->%s.setBinding(thisPtr->%s, std::move(binding));\n", property.accessor.constData(), property.name.constData(), property.accessor.constData()); fprintf(out, "}\n"); // untyped binding setter @@ -1572,7 +1589,7 @@ void Generator::generateQPropertyApi() cdef->qualified.constData(), property.name.constData()); printAccessor(); - fprintf(out, " return thisPtr->%s->%s.setBinding(binding);\n", property.accessor.constData(), property.name.constData()); + fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.name.constData(), property.accessor.constData()); fprintf(out, "}\n"); // binding bool getter @@ -1606,7 +1623,7 @@ void Generator::generateQPropertyApi() 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, " this->%s.setValue(value);\n", property.name.constData()); fprintf(out, "}\n\n"); } } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 82059e340f..20ff739121 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -582,8 +582,12 @@ bool Moc::parseMaybeQProperty(ClassDef *def) if (!test(IDENTIFIER)) return false; - if (lexem() != "QProperty") + bool hasNotifier = false; + if (lexem() == "QNotifiedProperty") { + hasNotifier = true; + } else if (lexem() != "QProperty") { return false; + } if (!test(LANGLE)) return false; @@ -596,7 +600,7 @@ bool Moc::parseMaybeQProperty(ClassDef *def) if (!test(SEMIC)) return false; - def->qPropertyMembers.insert(propName); + def->qPropertyMembersMaybeWithNotifier.insert(propName, hasNotifier); return true; } @@ -1525,6 +1529,7 @@ void Moc::parsePrivateQProperty(ClassDef *def) propDef.read = name + ".value"; propDef.write = name + ".setValue"; propDef.isQProperty = true; + propDef.isQPropertyWithNotifier = true; propDef.inPrivateClass = accessor; propDef.designable = propDef.scriptable = propDef.stored = "true"; propDef.user = "false"; @@ -1868,7 +1873,10 @@ void Moc::checkProperties(ClassDef *cdef) } if (p.read.isEmpty() && p.member.isEmpty()) { - if (!cdef->qPropertyMembers.contains(p.name) && !p.isQProperty) { + + auto qPropertyMemberIt = cdef->qPropertyMembersMaybeWithNotifier.constFind(p.name); + const bool knownQPropertyMember = qPropertyMemberIt != cdef->qPropertyMembersMaybeWithNotifier.constEnd(); + if (!knownQPropertyMember && !p.isQProperty) { const int rewind = index; if (p.location >= 0) index = p.location; @@ -1885,6 +1893,8 @@ void Moc::checkProperties(ClassDef *cdef) p.read = p.name + ".value"; p.write = p.name + ".setValue"; p.isQProperty = true; + const bool hasNotifier = knownQPropertyMember && qPropertyMemberIt.value(); + p.isQPropertyWithNotifier = hasNotifier; p.designable = p.scriptable = p.stored = "true"; p.user = "false"; } diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 8043a547fc..0e1f33a804 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -141,6 +141,7 @@ struct PropertyDef bool final = false; bool required = false; bool isQProperty = false; + bool isQPropertyWithNotifier = false; int location = -1; // token index, used for error reporting @@ -200,7 +201,7 @@ struct ClassDef : BaseDef { QVector nonClassSignalList; QVector propertyList; QVector privateQProperties; - QSet qPropertyMembers; + QHash qPropertyMembersMaybeWithNotifier; int revisionedMethods = 0; bool hasQObject = false; diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 37d3cc130f..4a6d16b45a 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -4116,19 +4116,20 @@ class ClassWithQPropertyMembers : public QObject Q_PROPERTY(int privateExposedProperty) public: - QProperty publicProperty; - QProperty notExposed; - signals: void publicPropertyChanged(); +public: + QNotifiedProperty publicProperty; + QProperty notExposed; + + protected: QProperty protectedProperty; private: QProperty privateProperty; QProperty privateExposedProperty; - QPropertyMemberChangeHandler<&ClassWithQPropertyMembers::publicProperty, &ClassWithQPropertyMembers::publicPropertyChanged> connector{this}; }; void tst_Moc::qpropertyMembers() @@ -4151,7 +4152,7 @@ void tst_Moc::qpropertyMembers() QSignalSpy publicPropertySpy(&instance, SIGNAL(publicPropertyChanged())); - instance.publicProperty.setValue(100); + instance.publicProperty.setValue(&instance, 100); QCOMPARE(prop.read(&instance).toInt(), 100); QCOMPARE(publicPropertySpy.count(), 1); @@ -4182,9 +4183,9 @@ void tst_Moc::observerMetaCall() instance.qt_metacall(QMetaObject::RegisterQPropertyObserver, prop.propertyIndex(), argv); } - instance.publicProperty.setValue(100); + instance.publicProperty.setValue(&instance, 100); QCOMPARE(observerCallCount, 1); - instance.publicProperty.setValue(101); + instance.publicProperty.setValue(&instance, 101); QCOMPARE(observerCallCount, 2); } @@ -4235,9 +4236,8 @@ public: ClassWithPrivateQPropertyShim *q = nullptr; - QProperty testProperty; void onTestPropertyChanged() { q->testPropertyChanged(); } - QPropertyMemberChangeHandler<&Private::testProperty, &Private::onTestPropertyChanged> testChangeHandler{this}; + QNotifiedProperty testProperty; }; Private priv{this}; @@ -4257,7 +4257,7 @@ void tst_Moc::privateQPropertyShim() QVERIFY(prop.notifySignal().isValid()); } - testObject.priv.testProperty.setValue(42); + testObject.priv.testProperty.setValue(&testObject.priv, 42); QCOMPARE(testObject.property("testProperty").toInt(), 42); // Behave like a QProperty -- cgit v1.2.3