summaryrefslogtreecommitdiffstats
path: root/tools/dumpcpp/main.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-04-01 14:11:00 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-04-08 11:52:02 +0200
commitb4d965231e4aa22b625997e8d4271f3c6f872696 (patch)
tree6567c6be580a8c2129f3455fa14756128d8e92c6 /tools/dumpcpp/main.cpp
parent37d19e4b5eda47c145eeeac884d0b558acddb19d (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.cpp521
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 &paramsIndex)
-{
- 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);