diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-03-19 10:47:29 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2020-06-02 22:42:15 +0200 |
commit | fa987d44417528856d5e80ed7b48ba99e19fa307 (patch) | |
tree | 50cd74c1a9dd3c2197f7de2ac0d431a5b16b0a42 /src/tools/moc | |
parent | 5306fdabc1ceb09875f791526553b3665017f7ce (diff) |
MetaObject: Store the QMetaType of the methods
This does the analog of 46f407126ef3e94d59254012cdc34d6a4ad2faf2 for the
methods we care about (signals, slots, Q_INVOKABLEs). In addition to the
actual QMetaType, we store an array with offsets so that we later can do
a mapping from methodIndex to metatype.
The newly added QMetaMethod::{return,parameter}MetaType methods can then
be used to retrieve the metatypes.
This does however require that all involved types are complete. This is
unfortunately not a feasible requirement. Thus, we only populate the
metatype array on a best effort basis. For any incomplete type, we store
QMetaType::Unknown. Then, when accessing the metatype, we fall back to
the old string based code base if it's Unknown.
Squashes "moc: support incomplete types" and "Fix compile failures
after QMetaMethod change"
Fixes: QTBUG-82932
Change-Id: I6b7a587cc364b7cad0c158d6de54e8a204289ad4
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/tools/moc')
-rw-r--r-- | src/tools/moc/generator.cpp | 67 | ||||
-rw-r--r-- | src/tools/moc/generator.h | 5 | ||||
-rw-r--r-- | src/tools/moc/main.cpp | 6 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 2 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 3 |
5 files changed, 65 insertions, 18 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 976d49ad20..849e25b76d 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -80,9 +80,9 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) return nullptr; } -Generator::Generator(ClassDef *classDef, const QVector<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile) +Generator::Generator(ClassDef *classDef, const QVector<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile, bool requireCompleteTypes) : out(outfile), cdef(classDef), metaTypes(metaTypes), knownQObjectClasses(knownQObjectClasses) - , knownGadgets(knownGadgets) + , knownGadgets(knownGadgets), requireCompleteTypes(requireCompleteTypes) { if (cdef->superclassList.size()) purestSuperClass = cdef->superclassList.constFirst().first; @@ -350,7 +350,7 @@ void Generator::generateCode() int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count(); fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0); - index += methodCount * 5; + index += methodCount * QMetaObjectPrivate::IntsPerMethod; if (cdef->revisionedMethods) index += methodCount; int paramsIndex = index; @@ -391,20 +391,22 @@ void Generator::generateCode() // generateClassInfos(); + int initialMetaTypeOffset = cdef->propertyList.count(); + // // Build signals array first, otherwise the signal indices would be wrong // - generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex); + generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex, initialMetaTypeOffset); // // Build slots array // - generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex); + generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex, initialMetaTypeOffset); // // Build method array // - generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex); + generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex, initialMetaTypeOffset); // // Build method version arrays @@ -438,7 +440,7 @@ void Generator::generateCode() // Build constructors array // if (isConstructible) - generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex); + generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex, initialMetaTypeOffset); // // Terminate data array @@ -553,14 +555,48 @@ void Generator::generateCode() else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); - if (cdef->propertyList.isEmpty()) { + 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"); } else { - fprintf(out, "qt_metaTypeArray<\n"); + bool needsComma = false; + if (!requireCompleteTypes) { + fprintf(out, "qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t\n", qualifiedClassNameIdentifier.constData()); + needsComma = true; + } else { + fprintf(out, "qt_metaTypeArray<\n"); + } for (int i = 0; i < cdef->propertyList.count(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); - fprintf(out, "%s%s", i == 0 ? "" : ", ", p.type.data()); + fprintf(out, "%s%s", needsComma ? ", " : "", p.type.data()); + needsComma = true; + } + for (const QVector<FunctionDef> &methodContainer: {cdef->signalList, cdef->slotList, cdef->methodList} ) { + for (int i = 0; i< methodContainer.count(); ++i) { + const FunctionDef& fdef = methodContainer.at(i); + fprintf(out, "%s%s", needsComma ? ", " : "", fdef.type.name.data()); + needsComma = true; + for (const auto &argument: fdef.arguments) { + fprintf(out, ", %s", argument.type.name.data()); + } + } + 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) { + fprintf(out, "%s%s", needsComma ? ", " : "", argument.type.name.data()); + needsComma = true; + } } + fprintf(out, "\n"); fprintf(out, ">,\n"); } @@ -572,6 +608,7 @@ void Generator::generateCode() fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;\n}\n", cdef->qualified.constData()); + // // Generate smart cast function // @@ -688,11 +725,11 @@ void Generator::registerByteArrayVector(const QVector<QByteArray> &list) strreg(ba); } -void Generator::generateFunctions(const QVector<FunctionDef>& list, const char *functype, int type, int ¶msIndex) +void Generator::generateFunctions(const QVector<FunctionDef>& list, const char *functype, int type, int ¶msIndex, int &initialMetatypeOffset) { if (list.isEmpty()) return; - fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype); + fprintf(out, "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype); for (int i = 0; i < list.count(); ++i) { const FunctionDef &f = list.at(i); @@ -727,10 +764,12 @@ void Generator::generateFunctions(const QVector<FunctionDef>& list, const char * } int argc = f.arguments.count(); - fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x /* %s */,\n", - stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, comment.constData()); + fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n", + stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, initialMetatypeOffset, comment.constData()); paramsIndex += 1 + argc * 2; + // constructors don't have a return type + initialMetatypeOffset += (f.isConstructor ? 0 : 1) + argc; } } diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index e92b9d1208..f3d3b40349 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -39,7 +39,7 @@ class Generator ClassDef *cdef; QVector<uint> meta_data; public: - Generator(ClassDef *classDef, const QVector<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr); + Generator(ClassDef *classDef, const QVector<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr, bool requireCompleteTypes = false); void generateCode(); private: bool registerableMetaType(const QByteArray &propertyType); @@ -47,7 +47,7 @@ private: void generateClassInfos(); void registerFunctionStrings(const QVector<FunctionDef> &list); void registerByteArrayVector(const QVector<QByteArray> &list); - void generateFunctions(const QVector<FunctionDef> &list, const char *functype, int type, int ¶msIndex); + void generateFunctions(const QVector<FunctionDef> &list, const char *functype, int type, int ¶msIndex, int &initialMetatypeOffset); void generateFunctionRevisions(const QVector<FunctionDef> &list, const char *functype); void generateFunctionParameters(const QVector<FunctionDef> &list, const char *functype); void generateTypeInfo(const QByteArray &typeName, bool allowEmptyName = false); @@ -70,6 +70,7 @@ private: QVector<QByteArray> metaTypes; QHash<QByteArray, QByteArray> knownQObjectClasses; QHash<QByteArray, QByteArray> knownGadgets; + bool requireCompleteTypes; }; QT_END_NAMESPACE diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index b8c2d7f594..61f3666b16 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -367,6 +367,10 @@ int runMoc(int argc, char **argv) depFileRuleNameOption.setValueName(QStringLiteral("rule name")); parser.addOption(depFileRuleNameOption); + QCommandLineOption requireCompleTypesOption(QStringLiteral("require-complete-types")); + requireCompleTypesOption.setDescription(QStringLiteral("Require complete types for better performance")); + parser.addOption(requireCompleTypesOption); + parser.addPositionalArgument(QStringLiteral("[header-file]"), QStringLiteral("Header file to read from, otherwise stdin.")); parser.addPositionalArgument(QStringLiteral("[@option-file]"), @@ -398,6 +402,8 @@ int runMoc(int argc, char **argv) moc.noInclude = true; autoInclude = false; } + if (parser.isSet(requireCompleTypesOption)) + moc.requireCompleteTypes = true; if (!ignoreConflictingOptions) { if (parser.isSet(forceIncludeOption)) { moc.noInclude = false; diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index f04f4c5d0d..0ffbe7bb13 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -1125,7 +1125,7 @@ void Moc::generate(FILE *out, FILE *jsonOutput) fputs("", out); for (i = 0; i < classList.size(); ++i) { - Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out); + Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out, requireCompleteTypes); generator.generateCode(); } fputs("", out); diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 486d033049..84ddf47a89 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -224,13 +224,14 @@ class Moc : public Parser { public: Moc() - : noInclude(false), mustIncludeQPluginH(false) + : noInclude(false), mustIncludeQPluginH(false), requireCompleteTypes(false) {} QByteArray filename; bool noInclude; bool mustIncludeQPluginH; + bool requireCompleteTypes; QByteArray includePath; QVector<QByteArray> includeFiles; QVector<ClassDef> classList; |