summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2020-08-22 17:21:36 +0200
committerLars Knoll <lars.knoll@qt.io>2020-09-02 22:44:29 +0200
commitad32ac5b4f05c9eed1fb7a93ee7947050d840a19 (patch)
tree5f14ae7a6a588ad3c9400058943f675556a403a9 /src/tools/moc
parent3e6c09279304fbde1860288717958e28377b9a9c (diff)
Make bindings introspectable through moc
Add a new BINDABLE declaration to the Q_PROPERTY() macro that tells moc where to find the QBindable for the property. Add a QUntypedBindable base class to QBindable<T> that gives access to generic functionality and checks argument compatibility at runtime. QBindable<T> will still do static checking at compile time. Add QMetaProperty::isBindable() and QMetaProperty::bindable() to be able to dynamically access the binding functionality. Change-Id: Ic7b08ae2cde83fd43e627d813a886e1de01fa3dc Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/generator.cpp59
-rw-r--r--src/tools/moc/moc.cpp29
-rw-r--r--src/tools/moc/moc.h3
3 files changed, 23 insertions, 68 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 1d2fa5d1d7..155a98209d 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -906,8 +906,8 @@ void Generator::generateProperties()
if (p.required)
flags |= Required;
- if (p.isQProperty)
- flags |= IsQProperty;
+ if (!p.bind.isEmpty())
+ flags |= Bindable;
fprintf(out, " %4d, ", stridx(p.name));
generateTypeInfo(p.type);
@@ -1025,9 +1025,8 @@ void Generator::generateMetacall()
fprintf(out, "else ");
fprintf(out,
"if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n"
- " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType\n"
- " || _c == QMetaObject::RegisterQPropertyObserver\n"
- " || _c == QMetaObject::SetQPropertyBinding) {\n"
+ " || _c == QMetaObject::ResetProperty || _c == QMetaObject::BindableProperty\n"
+ " || _c == QMetaObject::RegisterPropertyMetaType) {\n"
" qt_static_metacall(this, _c, _id, _a);\n"
" _id -= %d;\n }", int(cdef->propertyList.count()));
fprintf(out, "\n#endif // QT_NO_PROPERTIES");
@@ -1268,7 +1267,7 @@ void Generator::generateStaticMetacall()
bool needTempVarForGet = false;
bool needSet = false;
bool needReset = false;
- bool haveQProperties = false;
+ bool hasBindableProperties = false;
for (int i = 0; i < cdef->propertyList.size(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
needGet |= !p.read.isEmpty() || !p.member.isEmpty();
@@ -1278,7 +1277,7 @@ void Generator::generateStaticMetacall()
needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant);
needReset |= !p.reset.isEmpty();
- haveQProperties |= p.isQProperty;
+ hasBindableProperties |= !p.bind.isEmpty();
}
fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
@@ -1404,59 +1403,21 @@ void Generator::generateStaticMetacall()
}
fprintf(out, " }");
-#if 0
fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::RegisterQPropertyObserver) {\n");
- if (haveQProperties) {
+ fprintf(out, "if (_c == QMetaObject::BindableProperty) {\n");
+ if (hasBindableProperties) {
setupMemberAccess();
- fprintf(out, " QPropertyObserver *observer = reinterpret_cast<QPropertyObserver *>(_a[0]);\n");
fprintf(out, " switch (_id) {\n");
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.isQProperty)
+ if (p.bind.isEmpty())
continue;
- QByteArray prefix = "_t->";
- if (p.qpropertyname.isEmpty() || p.stored == "true") {
- fprintf(out, " case %d: observer->setSource(%s%s); break;\n",
- propindex, prefix.constData(), p.bindingAccessor.constData());
- } else {
- fprintf(out, " case %d: if (auto *source = %s%s) observer->setSource(*source); break; \n",
- propindex, prefix.constData(), p.bindingAccessor.constData());
- }
+ fprintf(out, " case %d: *static_cast<QUntypedBindable *>(_a[0]) = _t->%s(); break;\n", propindex, p.bind.constData());
}
fprintf(out, " default: break;\n");
fprintf(out, " }\n");
}
fprintf(out, " }");
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::SetQPropertyBinding) {\n");
- if (haveQProperties) {
- setupMemberAccess();
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.isQProperty)
- continue;
- QByteArray prefix = "_t->";
-
- if (p.qpropertyname.isEmpty() || p.stored == "true") {
- fprintf(out, " case %d: %s%s.setBinding(*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
- propindex, prefix.constData(),
- p.bindingAccessor.constData(),
- p.type.constData());
- } else {
- fprintf(out, " case %d: if (auto *source = %s%s) source->setBinding(*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n",
- propindex, prefix.constData(), p.bindingAccessor.constData(),
- p.type.constData());
- }
-
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out, " }");
-#endif
fprintf(out, "\n#endif // QT_NO_PROPERTIES");
needElse = true;
}
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 1a20d32d7c..516b231cd5 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -1022,7 +1022,7 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
for (const auto &c : classes) {
for (const auto &p : c.propertyList)
- needsQProperty |= p.isQProperty;
+ needsQProperty |= !p.bind.isEmpty();
if (any_type_contains(c.propertyList, pattern) ||
any_arg_contains(c.slotList, pattern) ||
any_arg_contains(c.signalList, pattern) ||
@@ -1219,23 +1219,9 @@ void Moc::createPropertyDef(PropertyDef &propDef)
{
propDef.location = index;
- const bool isPrivateProperty = !propDef.inPrivateClass.isEmpty();
- bool typeWrappedInQProperty = false;
- if (isPrivateProperty) {
- const int rewind = index;
- if (test(IDENTIFIER) && lexem() == "QProperty" && test(LANGLE)) {
- typeWrappedInQProperty = true;
- propDef.isQProperty = true;
- } else {
- index = rewind;
- }
- }
-
QByteArray type = parseType().name;
if (type.isEmpty())
error();
- if (typeWrappedInQProperty)
- next(RANGLE);
propDef.designable = propDef.scriptable = propDef.stored = "true";
propDef.user = "false";
/*
@@ -1346,6 +1332,9 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
case 'W': if (l != "WRITE") error(2);
propDef.write = v;
break;
+ case 'B': if (l != "BINDABLE") error(2);
+ propDef.bind = v;
+ break;
case 'D': if (l != "DESIGNABLE") error(2);
propDef.designable = v + v2;
checkIsFunction(propDef.designable, "DESIGNABLE");
@@ -1373,6 +1362,12 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
propDef.constant = false;
warning(msg.constData());
}
+ if (propDef.constant && !propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is both BINDable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
}
void Moc::parseProperty(ClassDef *def)
@@ -1808,7 +1803,7 @@ void Moc::checkProperties(ClassDef *cdef)
warning(msg.constData());
}
- if (p.read.isEmpty() && p.member.isEmpty() && !p.isQProperty) {
+ if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
const int rewind = index;
if (p.location >= 0)
index = p.location;
@@ -2012,6 +2007,7 @@ QJsonObject PropertyDef::toJson() const
jsonify("member", member);
jsonify("read", read);
jsonify("write", write);
+ jsonify("bindable", bind);
jsonify("reset", reset);
jsonify("notify", notify);
jsonify("privateClass", inPrivateClass);
@@ -2035,7 +2031,6 @@ QJsonObject PropertyDef::toJson() const
prop[QLatin1String("constant")] = constant;
prop[QLatin1String("final")] = final;
prop[QLatin1String("required")] = required;
- prop[QLatin1String("isQProperty")] = isQProperty;
if (revision > 0)
prop[QLatin1String("revision")] = revision;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index def5a8e82d..7f63402aca 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -132,7 +132,7 @@ struct PropertyDef
return (s == write);
}
- QByteArray name, type, member, read, write, reset, designable, scriptable, stored, user, notify, inPrivateClass;
+ QByteArray name, type, member, read, write, bind, reset, designable, scriptable, stored, user, notify, inPrivateClass;
int notifyId = -1; // -1 means no notifyId, >= 0 means signal defined in this class, < -1 means signal not defined in this class
enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
Specification gspec = ValueSpec;
@@ -140,7 +140,6 @@ struct PropertyDef
bool constant = false;
bool final = false;
bool required = false;
- bool isQProperty = false;
int location = -1; // token index, used for error reporting