diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-04-01 14:11:00 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-04-08 11:52:02 +0200 |
commit | b4d965231e4aa22b625997e8d4271f3c6f872696 (patch) | |
tree | 6567c6be580a8c2129f3455fa14756128d8e92c6 /tools/dumpcpp/main.cpp | |
parent | 37d19e4b5eda47c145eeeac884d0b558acddb19d (diff) |
dumpcpp: Use moc to generate metaobject code
dumpcpp contained an old version of moc code, which is now out
of date. Write out the interface as C++ code and run the real
moc on it to generate this. Some modifications are required.
Remove some asserts that checked on an empty meta object
created in the fallback path of QAxBasePrivate::metaObject()
which was removed by
0bcdc74f55574e1a45bef8728bd5093cf1acfc33.
Task-number: QTBUG-82945
Change-Id: Ide58bae1440331ea4d5da0fcc74b41f49f09599a
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tools/dumpcpp/main.cpp')
-rw-r--r-- | tools/dumpcpp/main.cpp | 521 |
1 files changed, 36 insertions, 485 deletions
diff --git a/tools/dumpcpp/main.cpp b/tools/dumpcpp/main.cpp index 1545a39..d50c65d 100644 --- a/tools/dumpcpp/main.cpp +++ b/tools/dumpcpp/main.cpp @@ -26,10 +26,13 @@ ** ****************************************************************************/ +#include "moc.h" + #include <QAxObject> #include <QFile> #include <QMetaObject> #include <QMetaEnum> +#include <QDebug> #include <QTextStream> #include <QSettings> #include <QStringList> @@ -85,17 +88,8 @@ void writeEnums(QTextStream &out, const QMetaObject *mo) { // enums for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) { - QMetaEnum metaEnum = mo->enumerator(ienum); - out << " enum " << metaEnum.name() << " {" << Qt::endl; - for (int k = 0; k < metaEnum.keyCount(); ++k) { - QByteArray key(metaEnum.key(k)); - out << " " << key.leftJustified(24) << "= " << metaEnum.value(k); - if (k < metaEnum.keyCount() - 1) - out << ','; - out << Qt::endl; - } - out << " };" << Qt::endl; - out << Qt::endl; + formatCppEnum(out, mo->enumerator(ienum)); + out << '\n'; } } @@ -184,9 +178,12 @@ static void formatConstructorSignature(QTextStream &out, ObjectCategories catego out << ')'; } -static void formatConstructorBody(QTextStream &out, const QByteArray &className, +static void formatConstructorBody(QTextStream &out, const QByteArray &nameSpace, + const QByteArray &className, const QString &controlID, ObjectCategories category) { + if (!nameSpace.isEmpty()) + out << nameSpace << "::"; out << className << "::" << className; formatConstructorSignature(out, category, false); out << " :" << Qt::endl << " "; @@ -258,21 +255,8 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo, functions << className; // enums - if (nameSpace.isEmpty() && !(category & OnlyInlines)) { - for (int ienum = mo->enumeratorOffset(); ienum < mo->enumeratorCount(); ++ienum) { - QMetaEnum metaEnum = mo->enumerator(ienum); - out << " enum " << metaEnum.name() << " {" << Qt::endl; - for (int k = 0; k < metaEnum.keyCount(); ++k) { - QByteArray key(metaEnum.key(k)); - out << " " << key.leftJustified(24) << "= " << metaEnum.value(k); - if (k < metaEnum.keyCount() - 1) - out << ','; - out << Qt::endl; - } - out << " };" << Qt::endl; - out << Qt::endl; - } - } + if (nameSpace.isEmpty() && !(category & OnlyInlines)) + writeEnums(out, mo); // QAxBase public virtual functions. QByteArrayList axBase_vfuncs; axBase_vfuncs.append("metaObject"); @@ -366,13 +350,7 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo, functions << propertyName; if (property.isWritable()) { - QByteArray setter(propertyName); - if (isupper(setter.at(0))) { - setter = "Set" + setter; - } else { - setter[0] = char(toupper(setter[0])); - setter = "set" + setter; - } + const QByteArray setter = setterName(propertyName); out << indent << "inline " << "void "; if (category & OnlyInlines) @@ -558,168 +536,10 @@ void generateClassDecl(QTextStream &out, const QMetaObject *mo, } } -#define addStringIdx(string) \ - out << stridx(string) << ", "; - -// The following functions were copied from moc generator with only some minor changes -void strreg(const QByteArray &s) -{ - if (!stringIndex.contains(s)) { - stringIndex.insert(s, strings.size()); - strings.append(s); - } -} - -void strDetachAndRegister(QByteArray s) -{ - s.detach(); - strreg(s); -} - -int stridx(const QByteArray &s) -{ - int i = stringIndex.value(s); - Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings"); - return i; -} - -const char *metaTypeEnumValueString(int type) -{ -#define RETURN_METATYPENAME_STRING(MetaTypeName, MetaTypeId, RealType) \ - case QMetaType::MetaTypeName: return #MetaTypeName; - - switch (type) { -QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) - } -#undef RETURN_METATYPENAME_STRING - return nullptr; -} - -int nameToBuiltinType(const QByteArray &name) -{ - if (name.isEmpty()) - return 0; - - const int tp = QMetaType::type(name.constData()); - return tp < QMetaType::User ? tp : QMetaType::UnknownType; -} - -void copyFileToStream(QFile *file, QTextStream *stream) -{ - file->seek(0); - QByteArray buffer; - const int bufferSize = 4096 * 1024; - buffer.resize(bufferSize); - while (!file->atEnd()) { - const int bytesRead = static_cast<int>(file->read(buffer.data(), bufferSize)); - if (bytesRead < bufferSize) { - buffer.resize(bytesRead); - *stream << buffer; - buffer.resize(bufferSize); - } else { - *stream << buffer; - } - } -} - -void generateTypeInfo(QTextStream &out, const QByteArray &typeName) -{ - if (QtPrivate::isBuiltinType(typeName)) { - int type; - QByteArray valueString; - if (typeName == "qreal") { - type = QMetaType::UnknownType; - valueString = "QReal"; - } else { - type = nameToBuiltinType(typeName); - valueString = metaTypeEnumValueString(type); - } - if (!valueString.isEmpty()) { - out << "QMetaType::" << valueString; - } else { - Q_ASSERT(type != QMetaType::UnknownType); - out << type; - } - } else { - Q_ASSERT(!typeName.isEmpty()); - out << "0x80000000 | " << stridx(typeName); - } -} -// End functions copied from moc generator - -void generateMethods(QTextStream &out, const QMetaObject *mo, const QMetaMethod::MethodType funcType, int ¶msIndex) -{ - out << "// "; - MethodFlags funcTypeFlag; - if (funcType == QMetaMethod::Signal) { - out << "signal"; - funcTypeFlag = MethodSignal; - } else { - out << "slot"; - funcTypeFlag = MethodSlot; - } - out << ": name, argc, parameters, tag, flags" << Qt::endl; - - int methodCount = mo->methodCount(); - for (int i = mo->methodOffset(); i < methodCount; ++i) { - const QMetaMethod method(mo->method(i)); - if (method.methodType() != funcType) - continue; - out << " "; - addStringIdx(method.name()); - out << method.parameterCount() << ", "; - out << paramsIndex << ", "; - addStringIdx(method.tag()); - out << (AccessProtected | method.attributes() | funcTypeFlag) << ',' << Qt::endl; - paramsIndex += 1 + method.parameterCount() * 2; - } - out << Qt::endl; -} - -void generateMethodParameters(QTextStream &out, const QMetaObject *mo, const QMetaMethod::MethodType funcType) -{ - out << "// "; - if (funcType == QMetaMethod::Signal) - out << "signal"; - else if (funcType == QMetaMethod::Slot) - out << "slot"; - out << ": parameters" << Qt::endl; - - int methodCount = mo->methodCount(); - for (int i = mo->methodOffset(); i < methodCount; ++i) { - const QMetaMethod method(mo->method(i)); - if (method.methodType() != funcType) - continue; - - out << " "; - - int argsCount = method.parameterCount(); - - // Return type - generateTypeInfo(out, method.typeName()); - out << ','; - - // Parameter types - const auto parameterTypes = method.parameterTypes(); - for (int j = 0; j < argsCount; ++j) { - out << ' '; - generateTypeInfo(out, parameterTypes.at(j)); - out << ','; - } - - // Parameter names - const auto parameterNames = method.parameterNames(); - for (int j = 0; j < argsCount; ++j) - out << ' ' << stridx(parameterNames.at(j)) << ','; - - out << Qt::endl; - } - out << Qt::endl; -} - -void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className, +bool generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className, const QString &controlID, - const QByteArray &nameSpace, ObjectCategories category) + const QByteArray &nameSpace, ObjectCategories category, + QString *errorString) { Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "dumpcpp should generate the same version as moc"); @@ -727,203 +547,20 @@ void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray if (!nameSpace.isEmpty()) qualifiedClassName = nameSpace + "::"; qualifiedClassName += className; - QByteArray qualifiedClassNameIdentifier = qualifiedClassName; - qualifiedClassNameIdentifier.replace(':', '_'); - - int allClassInfoCount = mo->classInfoCount(); - int allMethodCount = mo->methodCount(); - int allPropertyCount = mo->propertyCount(); - int allEnumCount = mo->enumeratorCount(); - - int thisClassInfoCount = allClassInfoCount - mo->classInfoOffset(); - int thisEnumCount = allEnumCount - mo->enumeratorOffset(); - int thisMethodCount = allMethodCount - mo->methodOffset(); - int thisPropertyCount = allPropertyCount - mo->propertyOffset(); - - int signalCount = 0; - int slotCount = 0; - int combinedParameterCount = 0; - int enumStart = MetaObjectPrivateFieldCount; - - // Register strings - strreg(qualifiedClassName); - for (int i = mo->classInfoOffset(); i < allClassInfoCount; ++i) { - const QMetaClassInfo classInfo = mo->classInfo(i); - strreg(classInfo.name()); - strreg(classInfo.value()); - } - for (int i = mo->methodOffset(); i < allMethodCount; ++i) { - const QMetaMethod method(mo->method(i)); - if (method.methodType() == QMetaMethod::Signal) - signalCount++; - if (method.methodType() == QMetaMethod::Slot) - slotCount++; - int argsCount = method.parameterCount(); - combinedParameterCount += argsCount; - - strDetachAndRegister(method.name()); - QByteArray typeName = method.typeName(); - if (!QtPrivate::isBuiltinType(typeName)) - strreg(typeName); - strreg(method.tag()); - - const auto parameterNames = method.parameterNames(); - const auto parameterTypes = method.parameterTypes(); - for (int j = 0; j < argsCount; ++j) { - if (!QtPrivate::isBuiltinType(parameterTypes.at(j))) - strDetachAndRegister(parameterTypes.at(j)); - strDetachAndRegister(parameterNames.at(j)); - } - } - for (int i = mo->propertyOffset(); i < allPropertyCount; ++i) { - const QMetaProperty property = mo->property(i); - strreg(property.name()); - if (!QtPrivate::isBuiltinType(property.typeName())) - strreg(property.typeName()); - } - for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) { - const QMetaEnum enumerator = mo->enumerator(i); - strreg(enumerator.name()); - for (int j = 0; j < enumerator.keyCount(); ++j) - strreg(enumerator.key(j)); - } - - // Build data array - out << "static const uint qt_meta_data_" << qualifiedClassNameIdentifier << "[] = {" << Qt::endl; - out << Qt::endl; - out << " // content:" << Qt::endl; - out << " 7, // revision" << Qt::endl; - out << " "; - addStringIdx(qualifiedClassName); - out << " // classname" << Qt::endl; - out << " " << thisClassInfoCount << ", " << (thisClassInfoCount ? enumStart : 0) << ", // classinfo" << Qt::endl; - enumStart += thisClassInfoCount * 2; - out << " " << thisMethodCount << ", " << (thisMethodCount ? enumStart : 0) << ", // methods" << Qt::endl; - enumStart += thisMethodCount * 5; - int paramsIndex = enumStart; - enumStart += (combinedParameterCount * 2); // parameter types + names - enumStart += thisMethodCount; // return types - out << " " << thisPropertyCount << ", " << (thisPropertyCount ? enumStart : 0) << ", // properties" << Qt::endl; - enumStart += thisPropertyCount * 3; - out << " " << thisEnumCount << ", " << (thisEnumCount ? enumStart : 0) << ", // enums/sets" << Qt::endl; - out << " 0, 0, // constructors" << Qt::endl; - out << " 0, // flags" << Qt::endl; - out << " " << signalCount << ", // signal count" << Qt::endl; - out << Qt::endl; - - if (thisClassInfoCount) { - out << " // classinfo: key, value" << Qt::endl; - for (int i = mo->classInfoOffset(); i < allClassInfoCount; ++i) { - QMetaClassInfo classInfo = mo->classInfo(i); - out << " "; - addStringIdx(classInfo.name()); - addStringIdx(classInfo.value()); - out << Qt::endl; - } - out << Qt::endl; - } - - // Signal/Slot arrays - if (signalCount) - generateMethods(out, mo, QMetaMethod::Signal, paramsIndex); - if (slotCount) - generateMethods(out, mo, QMetaMethod::Slot, paramsIndex); - - // Method parameter arrays - if (signalCount) - generateMethodParameters(out, mo, QMetaMethod::Signal); - if (slotCount) - generateMethodParameters(out, mo, QMetaMethod::Slot); - - if (thisPropertyCount) { - out << " // properties: name, type, flags" << Qt::endl; - for (int i = mo->propertyOffset(); i < allPropertyCount; ++i) { - QMetaProperty property = mo->property(i); - out << " "; - addStringIdx(property.name()); - generateTypeInfo(out, property.typeName()); - out << ", "; - - uint flags = 0; - const auto vartype = property.type(); - if (vartype != QVariant::Invalid && vartype != QVariant::UserType) - flags = uint(vartype) << 24; - - if (property.isReadable()) - flags |= Readable; - if (property.isWritable()) - flags |= Writable; - if (property.isEnumType()) - flags |= EnumOrFlag; - if (property.isDesignable()) - flags |= Designable; - if (property.isScriptable()) - flags |= Scriptable; - if (property.isStored()) - flags |= Stored; - if (property.isEditable()) - flags |= Editable; - - out << "0x" << QString::number(flags, 16).rightJustified(8, QLatin1Char('0')) - << ", \t\t // " << property.typeName() << ' ' << property.name() - << Qt::endl; - } - out << Qt::endl; - } - - if (thisEnumCount) { - out << " // enums: name, flags, count, data" << Qt::endl; - enumStart += thisEnumCount * 4; - for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) { - QMetaEnum enumerator = mo->enumerator(i); - out << " "; - addStringIdx(enumerator.name()); - out << (enumerator.isFlag() ? "0x1" : "0x0") << ", " << enumerator.keyCount() << ", " << enumStart << ", " << Qt::endl; - enumStart += enumerator.keyCount() * 2; - } - out << Qt::endl; - out << " // enum data: key, value" << Qt::endl; - for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) { - QMetaEnum enumerator = mo->enumerator(i); - for (int j = 0; j < enumerator.keyCount(); ++j) { - out << " "; - addStringIdx(enumerator.key(j)); - out << "uint("; - if (nameSpace.isEmpty()) - out << className << "::"; - else - out << nameSpace << "::"; - out << enumerator.key(j) << ")," << Qt::endl; - } - } + const QString moCode = mocCode(mo, QLatin1String(qualifiedClassName), + category.testFlag(ActiveX) ? QLatin1String("QWidget") : QLatin1String("QObject"), + errorString); + if (moCode.isEmpty()) { + out << "#error moc error\n"; + return false; } - out << " 0 // eod" << Qt::endl; - out << "};" << Qt::endl; - out << Qt::endl; - formatConstructorBody(out, className, controlID, category); + out << moCode << "\n\n"; - out << "const QMetaObject " << className << "::staticMetaObject = {" << Qt::endl; - if (category & ActiveX) - out << "{ &QWidget::staticMetaObject," << Qt::endl; - else - out << "{ &QObject::staticMetaObject," << Qt::endl; - out << "qt_meta_stringdata_all.data," << Qt::endl; - out << "qt_meta_data_" << qualifiedClassNameIdentifier << ", nullptr, nullptr, nullptr }" << Qt::endl; - out << "};" << Qt::endl; - out << Qt::endl; + formatConstructorBody(out, nameSpace, className, controlID, category); - out << "void *" << className << "::qt_metacast(const char *_clname)" << Qt::endl; - out << '{' << Qt::endl; - out << " if (!_clname) return nullptr;" << Qt::endl; - out << " if (!strcmp(_clname, \"" << qualifiedClassName << "\"))" << Qt::endl; - out << " return static_cast<void*>(const_cast<" << className << "*>(this));" << Qt::endl; - if (category & ActiveX) - out << " return QAxWidget::qt_metacast(_clname);" << Qt::endl; - else - out << " return QAxObject::qt_metacast(_clname);" << Qt::endl; - out << '}' << Qt::endl; + return true; } static void formatCommentBlockFooter(const QString &typeLibFile, QTextStream &str) @@ -1020,12 +657,8 @@ bool generateTypeLibrary(QString typeLibFile, QString outname, QMetaObject *namespaceObject = qax_readEnumInfo(typelib, nullptr); - QTemporaryFile classImplFile; - if (!classImplFile.open()) { - qWarning("dumpcpp: Cannot open temporary file."); - return false; - } - QTextStream classImplOut(&classImplFile); + QString classImpl; + QTextStream classImplOut(&classImpl); QFile implFile(outname + QLatin1String(".cpp")); QTextStream implOut(&implFile); if (!(category & (NoMetaObject|NoImplementation))) { @@ -1043,8 +676,6 @@ bool generateTypeLibrary(QString typeLibFile, QString outname, implOut << "#include \"" << outname << ".h\"" << Qt::endl; implOut << "#include <OAIdl.h>" << Qt::endl; // For IDispatch implOut << Qt::endl; - implOut << "using namespace " << libName << ';' << Qt::endl; - implOut << Qt::endl; } QFile declFile(outname + QLatin1String(".h")); @@ -1129,7 +760,6 @@ bool generateTypeLibrary(QString typeLibFile, QString outname, default: break; } - qax_deleteMetaObject(metaObject); typeinfo->ReleaseTypeAttr(typeattr); typeinfo->Release(); @@ -1282,9 +912,14 @@ bool generateTypeLibrary(QString typeLibFile, QString outname, object_category | OnlyInlines); inlinesOut << Qt::endl; } - if (implFile.isOpen()) - generateClassImpl(classImplOut, metaObject, className, guid.toString(), libNameBa, - object_category); + if (implFile.isOpen()) { + QString errorString; + if (!generateClassImpl(classImplOut, metaObject, className, guid.toString(), libNameBa, + object_category, &errorString)) { + qWarning("%s", qPrintable(errorString)); + return false; + } + } } currentTypeInfo = nullptr; } @@ -1297,93 +932,9 @@ bool generateTypeLibrary(QString typeLibFile, QString outname, // String table generation logic was ported from moc generator, with some modifications // required to split large stringdata arrays. - if (!strings.isEmpty() && implFile.isOpen()) { - // - // Build stringdata struct - // - implOut << "struct qt_meta_stringdata_all_t {" << Qt::endl; - implOut << " uint data[" << strings.size() * 2 << "];" << Qt::endl; - - QVector<QByteArrayList> listVector; - QByteArrayList currentList; - - int currentTableLen = 0; - for (const auto &s : strings) { - currentTableLen += s.length() + 1; - currentList.append(s); - // Split strings into chunks less than 64k to work around compiler limits. - if (currentTableLen > 60000) { - implOut << " char stringdata" << listVector.size() << '[' << currentTableLen + 1 << "];" << Qt::endl; - listVector.append(currentList); - currentList.clear(); - currentTableLen = 0; - } - } - implOut << " char stringdata" << listVector.size() << '[' << currentTableLen + 1 << "];" << Qt::endl; - implOut << "};" << Qt::endl; - listVector.append(currentList); - - implOut << "#define QT_MOC_LITERAL(ofs, len, table) \\" << Qt::endl - << " uint(offsetof(qt_meta_stringdata_all_t, stringdata##table) + ofs), len," << Qt::endl; - - implOut << "static const qt_meta_stringdata_all_t qt_meta_stringdata_all = {" << Qt::endl; - implOut << " {" << Qt::endl; - - int totalStringCount = 0; - for (int i = 0; i < listVector.size(); ++i) { - int idx = 0; - for (int j = 0; j < listVector[i].size(); j++) { - if (totalStringCount) - implOut << ',' << Qt::endl; - const QByteArray &str = listVector[i].at(j); - implOut << "QT_MOC_LITERAL(" << idx << ", " << str.length() << ", " << i << ')'; - idx += str.length() + 1; - } - } - implOut << Qt::endl << " }"; - - // - // Build stringdata arrays - // - for (const auto &l : listVector) { - int col = 0; - int len = 0; - implOut << ',' << Qt::endl; - implOut << " \""; - for (const auto &s : l) { - len = s.length(); - if (col && col + len >= 150) { - implOut << '"' << Qt::endl << " \""; - col = 0; - } else if (len && s.at(0) >= '0' && s.at(0) <= '9') { - implOut << "\"\""; - len += 2; - } - int idx = 0; - while (idx < s.length()) { - if (idx > 0) { - col = 0; - implOut << '"' << Qt::endl << " \""; - } - int spanLen = qMin(150, s.length() - idx); - implOut << s.mid(idx, spanLen); - idx += spanLen; - col += spanLen; - } - - implOut << "\\0"; - col += len + 2; - } - implOut << '"'; - } - // Terminate stringdata struct - implOut << Qt::endl << "};" << Qt::endl; - - implOut << "#undef QT_MOC_LITERAL" << Qt::endl << Qt::endl; - + if (implFile.isOpen()) { classImplOut.flush(); - copyFileToStream(&classImplFile, &implOut); - implOut << Qt::endl; + implOut << classImpl << Qt::endl; } qax_deleteMetaObject(namespaceObject); |