moc: For non-STORED QProperties, expect a pointer
This way we can return a nullptr for cases where the class does not want to provide a property at all. For example outside of bindings when reading the default value. The moc-generated code can check for such nullptrs and handle them. Change-Id: I7ff478cb254012147bb7aed3feb160e3e679cb6d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
577558daf5
commit
f9e1674094
@ -1304,21 +1304,47 @@ void Generator::generateStaticMetacall()
|
||||
if (p.inPrivateClass.size()) {
|
||||
prefix += p.inPrivateClass + "->";
|
||||
}
|
||||
if (p.gspec == PropertyDef::PointerSpec)
|
||||
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s%s())); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (p.gspec == PropertyDef::ReferenceSpec)
|
||||
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s%s())); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (cdef->enumDeclarations.value(p.type, false))
|
||||
fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (!p.read.isEmpty())
|
||||
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
|
||||
propindex, p.type.constData(), prefix.constData(), p.read.constData());
|
||||
else
|
||||
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
|
||||
propindex, p.type.constData(), prefix.constData(), p.member.constData());
|
||||
|
||||
if (!p.qpropertyname.isEmpty() && p.stored != "true") {
|
||||
// nullptr checks needed.
|
||||
fprintf(out, " case %d:\n", propindex);
|
||||
if (p.gspec == PropertyDef::PointerSpec || p.gspec == PropertyDef::ReferenceSpec) {
|
||||
fprintf(out, " if (auto *source = %s%s)\n", prefix.constData(), p.qpropertyname.constData());
|
||||
fprintf(out, " _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%ssource->value()));\n", p.gspec == PropertyDef::ReferenceSpec ? "&" : "");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " _a[0] = nullptr;\n");
|
||||
} else if (cdef->enumDeclarations.value(p.type, false)) {
|
||||
fprintf(out, " if (auto *source = %s%s)\n", prefix.constData(), p.qpropertyname.constData());
|
||||
fprintf(out, " *reinterpret_cast<int*>(_v) = QFlag(source->value()));\n");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " *reinterpret_cast<int*>(_v) = QFlag(%s())\n;", p.type.constData());
|
||||
} else if (!p.read.isEmpty()) {
|
||||
fprintf(out, " if (auto *source = %s%s)\n", prefix.constData(), p.qpropertyname.constData());
|
||||
fprintf(out, " *reinterpret_cast<%s*>(_v) = source->value();\n", p.type.constData());
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " *reinterpret_cast<%s*>(_v) = %s()\n;", p.type.constData(), p.type.constData());
|
||||
} else {
|
||||
fprintf(out, " *reinterpret_cast< %s*>(_v) = %s%s;\n",
|
||||
p.type.constData(), prefix.constData(), p.member.constData());
|
||||
}
|
||||
fprintf(out, " break;\n");
|
||||
} else {
|
||||
if (p.gspec == PropertyDef::PointerSpec)
|
||||
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s%s())); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (p.gspec == PropertyDef::ReferenceSpec)
|
||||
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s%s())); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (cdef->enumDeclarations.value(p.type, false))
|
||||
fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
|
||||
propindex, prefix.constData(), p.read.constData());
|
||||
else if (!p.read.isEmpty())
|
||||
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
|
||||
propindex, p.type.constData(), prefix.constData(), p.read.constData());
|
||||
else
|
||||
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
|
||||
propindex, p.type.constData(), prefix.constData(), p.member.constData());
|
||||
}
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
@ -1344,8 +1370,15 @@ void Generator::generateStaticMetacall()
|
||||
prefix += p.inPrivateClass + "->";
|
||||
}
|
||||
if (cdef->enumDeclarations.value(p.type, false)) {
|
||||
fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
|
||||
propindex, prefix.constData(), p.write.constData());
|
||||
if (!p.qpropertyname.isEmpty() && p.stored != "true") {
|
||||
fprintf(out, " case %d:\n", propindex);
|
||||
fprintf(out, " if (auto *destination = %s%s)\n", prefix.constData(), p.qpropertyname.constData());
|
||||
fprintf(out, " destination->setValue(QFlag(*reinterpret_cast<int*>(_v)));");
|
||||
fprintf(out, " break;");
|
||||
} else {
|
||||
fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
|
||||
propindex, prefix.constData(), p.write.constData());
|
||||
}
|
||||
} else if (!p.write.isEmpty()) {
|
||||
QByteArray optionalQPropertyOwner;
|
||||
if (p.isQPropertyWithNotifier) {
|
||||
@ -1357,8 +1390,15 @@ void Generator::generateStaticMetacall()
|
||||
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());
|
||||
if (!p.qpropertyname.isEmpty() && p.stored != "true") {
|
||||
fprintf(out, " case %d:\n", propindex);
|
||||
fprintf(out, " if (auto *destination = %s%s)\n", prefix.constData(), p.qpropertyname.constData());
|
||||
fprintf(out, " destination->setValue(%s*reinterpret_cast<%s*>(_v));\n", optionalQPropertyOwner.constData(), p.type.constData());
|
||||
fprintf(out, " break;\n");
|
||||
} else {
|
||||
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",
|
||||
@ -1420,8 +1460,14 @@ void Generator::generateStaticMetacall()
|
||||
if (p.inPrivateClass.size()) {
|
||||
prefix += p.inPrivateClass + "->";
|
||||
}
|
||||
fprintf(out, " case %d: observer->setSource(%s%s); break;\n",
|
||||
propindex, prefix.constData(), p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData());
|
||||
if (p.qpropertyname.isEmpty() || p.stored == "true") {
|
||||
fprintf(out, " case %d: observer->setSource(%s%s); break;\n",
|
||||
propindex, prefix.constData(),
|
||||
p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData());
|
||||
} else {
|
||||
fprintf(out, " case %d: if (auto *source = %s%s) observer->setSource(*source); break; \n",
|
||||
propindex, prefix.constData(), p.qpropertyname.constData());
|
||||
}
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
@ -1448,8 +1494,18 @@ void Generator::generateStaticMetacall()
|
||||
objectAccessor += ", ";
|
||||
else
|
||||
objectAccessor.clear();
|
||||
fprintf(out, " case %d: %s%s.setBinding(%s*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
|
||||
propindex, prefix.constData(), p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData(), objectAccessor.constData(), p.type.constData());
|
||||
|
||||
if (p.qpropertyname.isEmpty() || p.stored == "true") {
|
||||
fprintf(out, " case %d: %s%s.setBinding(%s*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
|
||||
propindex, prefix.constData(),
|
||||
p.qpropertyname.isEmpty() ? p.name.constData() : p.qpropertyname.constData(),
|
||||
objectAccessor.constData(), p.type.constData());
|
||||
} else {
|
||||
fprintf(out, " case %d: if (auto *source = %s%s) source->setBinding(%s*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
|
||||
propindex, prefix.constData(), p.qpropertyname.constData(),
|
||||
objectAccessor.constData(), p.type.constData());
|
||||
}
|
||||
|
||||
}
|
||||
fprintf(out, " default: break;\n");
|
||||
fprintf(out, " }\n");
|
||||
@ -1549,13 +1605,22 @@ void Generator::generateQPropertyApi()
|
||||
fprintf(out, " %sauto *thisPtr = reinterpret_cast<%s%s *>(reinterpret_cast<%schar *>(this) - propertyMemberOffset);\n", constOrNot, constOrNot, cdef->qualified.constData(), constOrNot);
|
||||
};
|
||||
|
||||
const bool stored = (property.name == property.storage);
|
||||
|
||||
// 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.storage.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.value();\n", property.accessor.constData(), property.storage.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *source = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return source->value();\n");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return %s();\n", property.type.name.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property value setter
|
||||
@ -1564,7 +1629,12 @@ void Generator::generateQPropertyApi()
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setValue(thisPtr->%s, value);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " thisPtr->%s->%s.setValue(thisPtr->%s, value);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *target = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " target->setValue(thisPtr->%s, value);\n", property.accessor.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property value move setter
|
||||
@ -1573,7 +1643,12 @@ void Generator::generateQPropertyApi()
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setValue(thisPtr->%s, std::move(value));\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " thisPtr->%s->%s.setValue(thisPtr->%s, std::move(value));\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *target = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " target->setValue(thisPtr->%s, std::move(value));\n", property.accessor.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding setter
|
||||
@ -1583,7 +1658,14 @@ void Generator::generateQPropertyApi()
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *target = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return target->setBinding(thisPtr->%s, binding);\n", property.accessor.constData());
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return QPropertyBinding<%s>();\n", property.type.name.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding move setter
|
||||
@ -1593,7 +1675,14 @@ void Generator::generateQPropertyApi()
|
||||
property.name.constData(),
|
||||
property.type.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, std::move(binding));\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, std::move(binding));\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *target = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return target->setBinding(thisPtr->%s, std::move(binding));\n", property.accessor.constData());
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return QPropertyBinding<%s>();\n", property.type.name.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// untyped binding setter
|
||||
@ -1601,7 +1690,15 @@ void Generator::generateQPropertyApi()
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.setBinding(thisPtr->%s, binding);\n", property.accessor.constData(), property.storage.constData(), property.accessor.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *target = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return target->setBinding(thisPtr->%s, binding);\n", property.accessor.constData());
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return false;\n");
|
||||
}
|
||||
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding bool getter
|
||||
@ -1609,7 +1706,14 @@ void Generator::generateQPropertyApi()
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor(/*const*/true);
|
||||
fprintf(out, " return thisPtr->%s->%s.hasBinding();\n", property.accessor.constData(), property.storage.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.hasBinding();\n", property.accessor.constData(), property.storage.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *source = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return source->hasBinding();\n");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return false;\n");
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding getter
|
||||
@ -1618,7 +1722,14 @@ void Generator::generateQPropertyApi()
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor(/*const*/true);
|
||||
fprintf(out, " return thisPtr->%s->%s.binding();\n", property.accessor.constData(), property.storage.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.binding();\n", property.accessor.constData(), property.storage.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *source = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return source->binding();\n");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return QPropertyBinding<%s>();\n", property.type.name.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// binding taker
|
||||
@ -1627,7 +1738,14 @@ void Generator::generateQPropertyApi()
|
||||
cdef->qualified.constData(),
|
||||
property.name.constData());
|
||||
printAccessor();
|
||||
fprintf(out, " return thisPtr->%s->%s.takeBinding();\n", property.accessor.constData(), property.storage.constData());
|
||||
if (stored) {
|
||||
fprintf(out, " return thisPtr->%s->%s.takeBinding();\n", property.accessor.constData(), property.storage.constData());
|
||||
} else {
|
||||
fprintf(out, " if (auto *source = thisPtr->%s->%s)\n", property.accessor.constData(), property.storage.constData());
|
||||
fprintf(out, " return source->takeBinding();\n");
|
||||
fprintf(out, " else\n");
|
||||
fprintf(out, " return QPropertyBinding<%s>();\n", property.type.name.constData());
|
||||
}
|
||||
fprintf(out, "}\n");
|
||||
|
||||
// property setter function
|
||||
|
@ -1539,16 +1539,17 @@ void Moc::parsePrivateQProperty(ClassDef *def)
|
||||
if (test(COMMA))
|
||||
parsePropertyAttributes(propDef);
|
||||
|
||||
propDef.qpropertyname = (propDef.stored == "true") ? name : (name + "()");
|
||||
const bool stored = propDef.stored == "true";
|
||||
propDef.qpropertyname = stored ? name : (name + "()");
|
||||
|
||||
def->privateQProperties += PrivateQPropertyDef {
|
||||
type, name, setter, accessor, propDef.qpropertyname
|
||||
};
|
||||
|
||||
if (propDef.read.isEmpty())
|
||||
propDef.read = propDef.qpropertyname + ".value";
|
||||
propDef.read = propDef.qpropertyname + (stored ? ".value" : "->value");
|
||||
if (propDef.write.isEmpty())
|
||||
propDef.write = propDef.qpropertyname + ".setValue";
|
||||
propDef.write = propDef.qpropertyname + (stored ? ".setValue" : "->setValue");
|
||||
|
||||
next(RPAREN);
|
||||
|
||||
@ -1903,8 +1904,10 @@ void Moc::checkProperties(ClassDef *cdef)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
p.read = p.name + ".value";
|
||||
p.write = p.name + ".setValue";
|
||||
const bool stored = p.stored == "true";
|
||||
p.qpropertyname = stored ? p.name : (p.name + "()");
|
||||
p.read = p.qpropertyname + (stored ? ".value" : "->value");
|
||||
p.write = p.qpropertyname + (stored ? ".setValue" : "->setValue");;
|
||||
p.isQProperty = true;
|
||||
const bool hasNotifier = knownQPropertyMember && qPropertyMemberIt.value();
|
||||
p.isQPropertyWithNotifier = hasNotifier;
|
||||
|
@ -4195,19 +4195,19 @@ public:
|
||||
|
||||
void onLazyTestPropertyChanged() { q->lazyTestPropertyChanged(); }
|
||||
|
||||
QNotifiedProperty<int, &Private::onLazyTestPropertyChanged> &lazyTestProperty() {
|
||||
if (!lazyTestPropertyStorage)
|
||||
lazyTestPropertyStorage.reset(new QNotifiedProperty<int, &Private::onLazyTestPropertyChanged>);
|
||||
return *lazyTestPropertyStorage;
|
||||
const QNotifiedProperty<int, &Private::onLazyTestPropertyChanged> *lazyTestProperty() const {
|
||||
// Mind that this prevents the property read from being recorded.
|
||||
// For real-world use cases some more logic is necessary here.
|
||||
return lazyTestPropertyStorage.data();
|
||||
}
|
||||
|
||||
const QNotifiedProperty<int, &Private::onLazyTestPropertyChanged> &lazyTestProperty() const {
|
||||
QNotifiedProperty<int, &Private::onLazyTestPropertyChanged> *lazyTestProperty() {
|
||||
if (!lazyTestPropertyStorage)
|
||||
lazyTestPropertyStorage.reset(new QNotifiedProperty<int, &Private::onLazyTestPropertyChanged>);
|
||||
return *lazyTestPropertyStorage;
|
||||
return lazyTestPropertyStorage.data();
|
||||
}
|
||||
|
||||
mutable QScopedPointer<QNotifiedProperty<int, &Private::onLazyTestPropertyChanged>> lazyTestPropertyStorage;
|
||||
QScopedPointer<QNotifiedProperty<int, &Private::onLazyTestPropertyChanged>> lazyTestPropertyStorage;
|
||||
};
|
||||
Private priv{this};
|
||||
|
||||
@ -4245,7 +4245,7 @@ void tst_Moc::privateQPropertyShim()
|
||||
QCOMPARE(testObject.lazyTestProperty(), 0);
|
||||
|
||||
// Explicitly set to something
|
||||
testObject.priv.lazyTestProperty().setValue(&testObject.priv, 42);
|
||||
testObject.priv.lazyTestProperty()->setValue(&testObject.priv, 42);
|
||||
QCOMPARE(testObject.property("lazyTestProperty").toInt(), 42);
|
||||
|
||||
// Behave like a QProperty
|
||||
|
Loading…
x
Reference in New Issue
Block a user