diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 650ea60617..a574bec179 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -384,6 +384,33 @@ QString QMetaObject::tr(const char *s, const char *c, int n) const { return QCoreApplication::translate(objectClassName(this), s, c, n); } + +/*! + \since 6.2 + Returns the metatype corresponding to this metaobject. + If the metaobject originates from a namespace, an invalid metatype is returned. + */ +QMetaType QMetaObject::metaType() const +{ + + const QMetaObjectPrivate *d = priv(this->d.data); + if (d->revision < 10) { + // before revision 10, we did not store the metatype in the metatype array + return QMetaType::fromName(className()); + } else { + /* in the metatype array, we store + idx: 0 propertyCount - 1 propertyCount + data:QMetaType(prop0), ..., QMetaType(propPropCount-1), QMetaType(class),... + */ + auto iface = this->d.metaTypes[d->propertyCount]; + if (iface == QtPrivate::qMetaTypeInterfaceForType()) + return QMetaType(); // return invalid meta-type for namespaces + if (iface) + return QMetaType(iface); + else // in case of a dynamic metaobject, we might have no metatype stored + return QMetaType::fromName(className()); // try lookup by name in that case + } +} #endif // QT_NO_TRANSLATION /*! diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index dbd82ba27b..c25735cb86 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -172,7 +172,7 @@ struct QMetaObjectPrivate // revision 7 is Qt 5.0 everything lower is not supported // revision 8 is Qt 5.12: It adds the enum name to QMetaEnum // revision 9 is Qt 6.0: It adds the metatype of properties and methods - enum { OutputRevision = 9 }; // Used by moc, qmetaobjectbuilder and qdbus + enum { OutputRevision = 10 }; // Used by moc, qmetaobjectbuilder and qdbus enum { IntsPerMethod = QMetaMethod::Data::Size }; enum { IntsPerEnum = QMetaEnum::Data::Size }; enum { IntsPerProperty = QMetaProperty::Data::Size }; diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 3ee7d17545..8c55bdb3ae 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1203,7 +1203,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, - int(d->methods.size()) // return "parameters" don't have names - int(d->constructors.size()); // "this" parameters don't have names if constexpr (mode == Construct) { - static_assert(QMetaObjectPrivate::OutputRevision == 9, "QMetaObjectBuilder should generate the same version as moc"); + static_assert(QMetaObjectPrivate::OutputRevision == 10, "QMetaObjectBuilder should generate the same version as moc"); pmeta->revision = QMetaObjectPrivate::OutputRevision; pmeta->flags = d->flags; pmeta->className = 0; // Class name is always the first string. @@ -1281,7 +1281,8 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, // Output the methods in the class. Q_ASSERT(!buf || dataIndex == pmeta->methodData); - int parameterMetaTypesIndex = int(d->properties.size()); + // + 1 for metatype of this metaobject + int parameterMetaTypesIndex = int(d->properties.size()) + 1; for (const auto &method : d->methods) { [[maybe_unused]] int name = strings.enter(method.name()); int argc = method.parameterCount(); @@ -1448,6 +1449,10 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, *types = reinterpret_cast(mt); types++; } + // add metatype interface for this metaobject - must be null + // as we can't know our metatype + *types = nullptr; + types++; for (const auto &method: d->methods) { QMetaType mt(QMetaType::fromName(method.returnType).id()); *types = reinterpret_cast(mt); diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 5ade222ac5..00a6b62eab 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -173,6 +173,8 @@ struct Q_CORE_EXPORT QMetaObject QString tr(const char *s, const char *c, int n = -1) const; #endif // QT_NO_TRANSLATION + QMetaType metaType() const; + int methodOffset() const; int enumeratorOffset() const; int propertyOffset() const; diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index 90a50cc600..1026f6429f 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -422,7 +422,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) - methods.count(); // ditto QDBusMetaObjectPrivate *header = reinterpret_cast(idata.data()); - static_assert(QMetaObjectPrivate::OutputRevision == 9, "QtDBus meta-object generator should generate the same version as moc"); + static_assert(QMetaObjectPrivate::OutputRevision == 10, "QtDBus meta-object generator should generate the same version as moc"); header->revision = QMetaObjectPrivate::OutputRevision; header->className = 0; header->classInfoCount = 0; @@ -459,6 +459,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) idata[typeidOffset++] = 0; // eod int totalMetaTypeCount = properties.count(); + ++totalMetaTypeCount; // + 1 for metatype of dynamic metaobject for (const auto& methodContainer: {signals_, methods}) { for (const auto& method: methodContainer) { int argc = method.inputTypes.size() + qMax(qsizetype(0), method.outputTypes.size() - 1); @@ -469,7 +470,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) int propertyId = 0; // add each method: - int currentMethodMetaTypeOffset = properties.count(); + int currentMethodMetaTypeOffset = properties.count() + 1; for (int x = 0; x < 2; ++x) { // Signals must be added before other methods, to match moc. QMap &map = (x == 0) ? signals_ : methods; @@ -559,6 +560,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) metaTypes[propertyId++] = QMetaType(mp.type); } + metaTypes[propertyId] = QMetaType(); // we can't know our own metatype Q_ASSERT(offset == header->propertyDBusData); Q_ASSERT(signatureOffset == header->methodDBusData); diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 78829ce93c..ad3df36292 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -396,7 +396,8 @@ void Generator::generateCode() // generateClassInfos(); - int initialMetaTypeOffset = cdef->propertyList.count(); + // all property metatypes, + 1 for the type of the current class itself + int initialMetaTypeOffset = cdef->propertyList.count() + 1; // // Build signals array first, otherwise the signal indices would be wrong @@ -560,64 +561,60 @@ void Generator::generateCode() else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); - bool constructorListContainsArgument = false; - for (int i = 0; i< cdef->constructorList.count(); ++i) { - const FunctionDef& fdef = cdef->constructorList.at(i); - if (fdef.arguments.count()) { - constructorListContainsArgument = true; - break; - } - } - if (cdef->propertyList.isEmpty() && cdef->signalList.isEmpty() && cdef->slotList.isEmpty() && cdef->methodList.isEmpty() && !constructorListContainsArgument) { - fprintf(out, " nullptr,\n"); + bool needsComma = false; + const bool requireCompleteness = requireCompleteTypes || cdef->requireCompleteMethodTypes; + if (!requireCompleteness) { + fprintf(out, "qt_incomplete_metaTypeArrayrequireCompleteMethodTypes; - if (!requireCompleteness) { - fprintf(out, "qt_incomplete_metaTypeArraypropertyList.count(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); + fprintf(out, "qt_metaTypeArray<\n"); + } + // metatypes for properties + for (int i = 0; i < cdef->propertyList.count(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + if (requireCompleteness) + fprintf(out, "%s%s", needsComma ? ", " : "", p.type.data()); + else + fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", p.type.data()); + needsComma = true; + } + // type name for the Q_OJBECT/GADGET itself, void for namespaces + auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void"; + if (requireCompleteness) + fprintf(out, "%s%s", needsComma ? ", " : "", ownType); + else + fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", ownType); + + // metatypes for all exposed methods + // no need to check for needsComma any longer, as we always need one due to the classname being present + for (const QList &methodContainer : + { cdef->signalList, cdef->slotList, cdef->methodList }) { + for (int i = 0; i< methodContainer.count(); ++i) { + const FunctionDef& fdef = methodContainer.at(i); if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", p.type.data()); + fprintf(out, ", %s", fdef.type.name.data()); else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", p.type.data()); - needsComma = true; - } - for (const QList &methodContainer : - { cdef->signalList, cdef->slotList, cdef->methodList }) { - for (int i = 0; i< methodContainer.count(); ++i) { - const FunctionDef& fdef = methodContainer.at(i); - if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", fdef.type.name.data()); - else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::false_type>", needsComma ? ", " : "", fdef.type.name.data()); - needsComma = true; - for (const auto &argument: fdef.arguments) { - if (requireCompleteness) - fprintf(out, ", %s", argument.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); - } - } - fprintf(out, "\n"); - } - for (int i = 0; i< cdef->constructorList.count(); ++i) { - const FunctionDef& fdef = cdef->constructorList.at(i); + fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", fdef.type.name.data()); for (const auto &argument: fdef.arguments) { if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", argument.type.name.data()); + fprintf(out, ", %s", argument.type.name.data()); else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::false_type>", needsComma ? ", " : "", argument.type.name.data()); - needsComma = true; + fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); } } fprintf(out, "\n"); - fprintf(out, ">,\n"); } + for (int i = 0; i< cdef->constructorList.count(); ++i) { + const FunctionDef& fdef = cdef->constructorList.at(i); + for (const auto &argument: fdef.arguments) { + if (requireCompleteness) + fprintf(out, ", %s", argument.type.name.data()); + else + fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); + } + } + fprintf(out, "\n"); + fprintf(out, ">,\n"); fprintf(out, " nullptr\n} };\n\n"); diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 86501b74ea..968ccee043 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -315,6 +315,8 @@ private slots: void propertyConstant(); void propertyFinal(); + void metaType(); + void stdSet(); void classInfo(); @@ -1612,6 +1614,15 @@ void tst_QMetaObject::propertyFinal() QVERIFY(!prop.isFinal()); } +void tst_QMetaObject::metaType() +{ + QCOMPARE(QObject::staticMetaObject.metaType(), QMetaType::fromType()); + QCOMPARE(MyGadget::staticMetaObject.metaType(), QMetaType::fromType()); + QCOMPARE(QAbstractProxyModel::staticMetaObject.metaType(), QMetaType::fromType()); + auto qtNameSpaceMetaType = Qt::staticMetaObject.metaType(); + QVERIFY2(!qtNameSpaceMetaType.isValid(), qtNameSpaceMetaType.name()); +} + class ClassInfoTestObjectA : public QObject { Q_OBJECT