summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2012-09-03 15:38:39 +0300
committerQt by Nokia <qt-info@nokia.com>2012-09-12 10:35:00 +0200
commit827a616c3a357ddd79b4e59848c57fcc6f82fa18 (patch)
tree56fc9808668d44e8d8d96840739a3a29cfd4e272
parent8d379ad2a08a782fd5cf3c63436e8e49484df63c (diff)
downloadqtactiveqt-827a616c3a357ddd79b4e59848c57fcc6f82fa18.tar.gz
Fix dumpcpp tool to work with revision 7 metaobject format.
Dumpcpp tool still generated revision 1 moc format, so generated code would no longer compile. Ported relevant revision 7 generation code from moc tool to dumpcpp tool. Also squashed multiple generated string tables into a single string table. QVariant::nameToType(typeName) no longer returns UserType for QVariant, so fixed few comparisons to take this into account. Removed warning print from MetaObjectGenerator::addProperty(), as this just spams warnings unnecessarily when generating properties. Normally the required metatypes are not registered at time of generation (e.g. when running dumpcpp tool). Note that the check for this warning was buggy in Qt4, so it already never printed there. Added a simple autotest to verify dumpcpp generates working code. Task-number: QTBUG-26587 Change-Id: If12d2301890c209e7fbcb3bc054791a1c9d492c3 Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
-rw-r--r--src/activeqt/container/qaxbase.cpp33
-rw-r--r--src/activeqt/shared/qaxtypes.cpp7
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/dumpcpp/dumpcpp.pro11
-rw-r--r--tests/auto/dumpcpp/tst_dumpcpp.cpp67
-rw-r--r--tools/dumpcpp/dumpcpp.pro9
-rw-r--r--tools/dumpcpp/main.cpp653
7 files changed, 492 insertions, 291 deletions
diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp
index b8809cc..6785716 100644
--- a/src/activeqt/container/qaxbase.cpp
+++ b/src/activeqt/container/qaxbase.cpp
@@ -1564,15 +1564,19 @@ private:
inline QByteArray replaceType(const QByteArray &type)
{
int i = 0;
- while (type_conversion[i][0]) {
- int len = int(strlen(type_conversion[i][0]));
- int ti;
- if ((ti = type.indexOf(type_conversion[i][0])) != -1) {
- QByteArray rtype(type);
- rtype.replace(ti, len, type_conversion[i][1]);
- return rtype;
+ if (type.isEmpty()) {
+ return QByteArray("void");
+ } else {
+ while (type_conversion[i][0]) {
+ int len = int(strlen(type_conversion[i][0]));
+ int ti;
+ if ((ti = type.indexOf(type_conversion[i][0])) != -1) {
+ QByteArray rtype(type);
+ rtype.replace(ti, len, type_conversion[i][1]);
+ return rtype;
+ }
+ ++i;
}
- ++i;
}
return type;
}
@@ -1681,17 +1685,6 @@ private:
if (flags & Writable)
flags |= Stored;
prop.flags = flags;
- QVariant::Type vartype = QVariant::nameToType(prop.type);
- switch(vartype) {
- case QVariant::Invalid:
- case QVariant::UserType:
- if (QMetaType::type(prop.type) == QMetaType::UnknownType)
- qWarning("QAxBase: Unsupported property '%s' type: %s (%d)",
- name.constData(), prop.type.data(), vartype);
- break;
- default:
- break;
- }
}
inline bool hasProperty(const QByteArray &name)
@@ -3673,7 +3666,7 @@ int QAxBase::internalInvoke(QMetaObject::Call call, int index, void **v)
QByteArray type = d->metaobj->paramType(signature, p, &out);
QVariant::Type vt = QVariant::nameToType(type);
QVariant qvar;
- if (vt != QVariant::UserType)
+ if (vt != QVariant::UserType && vt != QMetaType::QVariant)
qvar = QVariant(vt, v[p + 1]);
if (!qvar.isValid()) {
diff --git a/src/activeqt/shared/qaxtypes.cpp b/src/activeqt/shared/qaxtypes.cpp
index b1ffa91..b51311c 100644
--- a/src/activeqt/shared/qaxtypes.cpp
+++ b/src/activeqt/shared/qaxtypes.cpp
@@ -244,13 +244,16 @@ bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &type
QVariant qvar = var;
// "type" is the expected type, so coerce if necessary
QVariant::Type proptype = typeName.isEmpty() ? QVariant::Invalid : QVariant::nameToType(typeName);
- if (proptype == QVariant::UserType && !typeName.isEmpty()) {
+ if ((proptype == QVariant::UserType || proptype == QMetaType::QVariant) && !typeName.isEmpty()) {
if (typeName == "short" || typeName == "char")
proptype = QVariant::Int;
else if (typeName == "float")
proptype = QVariant::Double;
}
- if (proptype != QVariant::Invalid && proptype != QVariant::UserType && proptype != qvar.type()) {
+ if (proptype != QVariant::Invalid
+ && proptype != QVariant::UserType
+ && proptype != QMetaType::QVariant
+ && proptype != qvar.type()) {
if (qvar.canConvert(proptype))
qvar.convert(proptype);
else
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 8e3a63f..82cce69 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,3 +1,4 @@
TEMPLATE = subdirs
SUBDIRS += \
- qaxobject
+ qaxobject \
+ dumpcpp
diff --git a/tests/auto/dumpcpp/dumpcpp.pro b/tests/auto/dumpcpp/dumpcpp.pro
new file mode 100644
index 0000000..776aa32
--- /dev/null
+++ b/tests/auto/dumpcpp/dumpcpp.pro
@@ -0,0 +1,11 @@
+CONFIG += testcase qaxcontainer
+QT += widgets testlib
+SOURCES += tst_dumpcpp.cpp
+TARGET = tst_dumpcpp
+
+# Assume Web Browser type library is available in all windows installations
+TYPELIBS = $$(SystemRoot)\\system32\\ieframe.dll
+
+!exists($$TYPELIBS) {
+ message("Web Browser type library for test not found!")
+} \ No newline at end of file
diff --git a/tests/auto/dumpcpp/tst_dumpcpp.cpp b/tests/auto/dumpcpp/tst_dumpcpp.cpp
new file mode 100644
index 0000000..191f079
--- /dev/null
+++ b/tests/auto/dumpcpp/tst_dumpcpp.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include "ieframe.h" // generated header
+#include <QApplication>
+
+class tst_dumpcpp : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void toggleAddressBar();
+};
+
+// A simple test to verify that an object can be instantiated and interacted with
+void tst_dumpcpp::toggleAddressBar()
+{
+ SHDocVw::WebBrowser* webBrowser = new SHDocVw::WebBrowser;
+ QVERIFY(webBrowser);
+ bool addressBar = webBrowser->AddressBar();
+ addressBar = !addressBar;
+ webBrowser->SetAddressBar(addressBar);
+ QVERIFY(webBrowser->AddressBar() == addressBar);
+ delete webBrowser;
+}
+
+QTEST_MAIN(tst_dumpcpp)
+#include "tst_dumpcpp.moc"
diff --git a/tools/dumpcpp/dumpcpp.pro b/tools/dumpcpp/dumpcpp.pro
index 240ae74..27ea7d5 100644
--- a/tools/dumpcpp/dumpcpp.pro
+++ b/tools/dumpcpp/dumpcpp.pro
@@ -1,9 +1,8 @@
-TEMPLATE = app
+DESTDIR = $$QT.activeqt.bins
CONFIG += console qaxcontainer
-QT += widgets
+QT += widgets core-private
-SOURCES += main.cpp
+SOURCES = main.cpp
-target.path = $$[QT_INSTALL_BINS]
-INSTALLS += target
+load(qt_tool)
diff --git a/tools/dumpcpp/main.cpp b/tools/dumpcpp/main.cpp
index 1eee3cd..4c1cd85 100644
--- a/tools/dumpcpp/main.cpp
+++ b/tools/dumpcpp/main.cpp
@@ -51,7 +51,7 @@
#include <QFileInfo>
#include <qt_windows.h>
#include <ocidl.h>
-
+#include <private/qmetaobject_p.h>
QT_BEGIN_NAMESPACE
static ITypeInfo *currentTypeInfo = 0;
@@ -71,37 +71,6 @@ enum ObjectCategory
TypeLibID = 0x101
};
-// this comes from moc/qmetaobject.cpp
-enum ProperyFlags {
- Invalid = 0x00000000,
- Readable = 0x00000001,
- Writable = 0x00000002,
- Resetable = 0x00000004,
- EnumOrFlag = 0x00000008,
- StdCppSet = 0x00000100,
- Override = 0x00000200,
- Designable = 0x00001000,
- ResolveDesignable = 0x00002000,
- Scriptable = 0x00004000,
- ResolveScriptable = 0x00008000,
- Stored = 0x00010000,
- ResolveStored = 0x00020000,
- Editable = 0x00040000,
- ResolveEditable = 0x00080000
-};
-
-enum MemberFlags {
- AccessPrivate = 0x00,
- AccessProtected = 0x01,
- AccessPublic = 0x02,
- MemberMethod = 0x00,
- MemberSignal = 0x04,
- MemberSlot = 0x08,
- MemberCompatibility = 0x10,
- MemberCloned = 0x20,
- MemberScriptable = 0x40,
-};
-
extern QMetaObject *qax_readEnumInfo(ITypeLib *typeLib, const QMetaObject *parentObject);
extern QMetaObject *qax_readClassInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
extern QMetaObject *qax_readInterfaceInfo(ITypeLib *typeLib, ITypeInfo *typeInfo, const QMetaObject *parentObject);
@@ -111,6 +80,8 @@ extern bool qax_dispatchEqualsIDispatch;
QByteArray nameSpace;
QMap<QByteArray, QByteArray> namespaceForType;
+QVector<QByteArray> strings;
+QHash<QByteArray, int> stringIndex; // Optimization, speeds up generation
void writeEnums(QTextStream &out, const QMetaObject *mo)
{
@@ -335,13 +306,13 @@ void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaOb
if (!(category & NoInlines)) {
out << endl << indent << "{" << endl;
if (qax_qualified_usertypes.contains(simplePropType)) {
- out << indent << " " << propertyType << " qax_pointer = 0;" << endl;
- out << indent << " qRegisterMetaType(\"" << property.typeName() << "\", &qax_pointer);" << endl;
if (foreignNamespace)
out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl;
- out << indent << " qRegisterMetaType(\"" << simplePropType << "\", qax_pointer);" << endl;
- if (foreignNamespace)
- out << "#endif" << endl;
+ out << indent << " " << propertyType << " qax_pointer = 0;" << endl;
+ QByteArray simplePropTypeWithNamespace = propertyType;
+ simplePropTypeWithNamespace.replace('*', "");
+ out << indent << " qRegisterMetaType<" << propertyType << ">(\"" << property.typeName() << "\", &qax_pointer);" << endl;
+ out << indent << " qRegisterMetaType<" << simplePropTypeWithNamespace << ">(\"" << simplePropType << "\", qax_pointer);" << endl;
}
out << indent << " QVariant qax_result = property(\"" << propertyName << "\");" << endl;
if (propertyType.length() && propertyType.at(propertyType.length()-1) == '*')
@@ -350,8 +321,6 @@ void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaOb
if (qax_qualified_usertypes.contains(simplePropType)) {
simplePropType = propertyType;
simplePropType.replace('*', "");
- if (foreignNamespace)
- out << "#ifdef QAX_DUMPCPP_" << propertyType.left(propertyType.indexOf("::")).toUpper() << "_H" << endl;
out << indent << " return *(" << propertyType << "*)qax_result.constData();" << endl;
if (foreignNamespace) {
out << "#else" << endl;
@@ -386,7 +355,7 @@ void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaOb
if (!(category & NoInlines)) {
if (propertyType.endsWith('*')) {
out << "{" << endl;
- out << " int typeId = qRegisterMetaType(\"" << propertyType << "\", &value);" << endl;
+ out << " int typeId = qRegisterMetaType<" << propertyType << ">(\"" << propertyType << "\", &value);" << endl;
out << " setProperty(\"" << propertyName << "\", QVariant(typeId, &value));" << endl;
out << "}" << endl;
} else {
@@ -510,11 +479,13 @@ void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaOb
out << " = 0";
out << ";" << endl;
if (qax_qualified_usertypes.contains(simpleSlotType)) {
- out << indent << " qRegisterMetaType(\"" << simpleSlotType << "*\", &qax_result);" << endl;
bool foreignNamespace = simpleSlotType.contains("::");
if (foreignNamespace)
out << "#ifdef QAX_DUMPCPP_" << simpleSlotType.left(simpleSlotType.indexOf(':')).toUpper() << "_H" << endl;
- out << indent << " qRegisterMetaType(\"" << simpleSlotType << "\", qax_result);" << endl;
+ QByteArray simpleSlotTypeWithNamespace = slotType;
+ simpleSlotTypeWithNamespace.replace('*', "");
+ out << indent << " qRegisterMetaType<" << simpleSlotTypeWithNamespace << "*>(\"" << simpleSlotType << "*\", &qax_result);" << endl;
+ out << indent << " qRegisterMetaType<" << simpleSlotTypeWithNamespace << ">(\"" << simpleSlotType << "\", qax_result);" << endl;
if (foreignNamespace)
out << "#endif" << endl;
}
@@ -552,103 +523,273 @@ void generateClassDecl(QTextStream &out, const QString &controlID, const QMetaOb
}
}
-#define addString(string, stringData) \
- out << stringDataLength << ", "; \
- stringData += string; \
- stringDataLength += qstrlen(string); \
- stringData += "\\0"; \
- lineLength += qstrlen(string) + 1; \
- if (lineLength > 200) { stringData += "\"\n \""; lineLength = 0; } \
- ++stringDataLength;
+#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);
+ }
+}
+
+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;
+}
+
+bool isBuiltinType(const QByteArray &type)
+{
+ int id = QMetaType::type(type.constData());
+ if (id == QMetaType::UnknownType)
+ return false;
+ return (id < QMetaType::User);
+}
+
+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 0;
+}
+
+uint nameToBuiltinType(const QByteArray &name)
+{
+ if (name.isEmpty())
+ return 0;
+
+ uint tp = QMetaType::type(name.constData());
+ return tp < uint(QMetaType::User) ? tp : uint(QMetaType::UnknownType);
+}
+
+void generateTypeInfo(QTextStream &out, const QByteArray &typeName)
+{
+ if (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" << 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) << "," << endl;
+ paramsIndex += 1 + method.parameterCount() * 2;
+ }
+ out << 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" << 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 QList<QByteArray> parameterTypes = method.parameterTypes();
+ for (int j = 0; j < argsCount; ++j) {
+ out << " ";
+ generateTypeInfo(out, parameterTypes.at(j));
+ out << ",";
+ }
+
+ // Parameter names
+ const QList<QByteArray> parameterNames = method.parameterNames();
+ for (int j = 0; j < argsCount; ++j)
+ out << " " << stridx(parameterNames.at(j)) << ",";
+
+ out << endl;
+ }
+ out << endl;
+}
void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray &className, const QByteArray &nameSpace, ObjectCategory category)
{
+ Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "dumpcpp should generate the same version as moc");
+
QByteArray qualifiedClassName;
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;
+
+ strreg(method.name());
+ QByteArray typeName = method.typeName();
+ if (!isBuiltinType(typeName))
+ strreg(typeName);
+ strreg(method.tag());
+
+ const QList<QByteArray> parameterNames = method.parameterNames();
+ const QList<QByteArray> parameterTypes = method.parameterTypes();
+ for (int j = 0; j < argsCount; ++j) {
+ if (!isBuiltinType(parameterTypes.at(j)))
+ strreg(parameterTypes.at(j));
+ strreg(parameterNames.at(j));
+ }
+ }
+ for (int i = mo->propertyOffset(); i < allPropertyCount; ++i) {
+ const QMetaProperty property = mo->property(i);
+ strreg(property.name());
+ if (!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));
+ }
- QByteArray stringData(qualifiedClassName);
- int stringDataLength = stringData.length();
- stringData += "\\0\"\n";
- ++stringDataLength;
- int lineLength = 0;
-
- int classInfoCount = mo->classInfoCount() - mo->classInfoOffset();
- int enumCount = mo->enumeratorCount() - mo->enumeratorOffset();
- int methodCount = mo->methodCount() - mo->methodOffset();
- int propertyCount = mo->propertyCount() - mo->propertyOffset();
- int enumStart = 10;
-
- out << "static const uint qt_meta_data_" << qualifiedClassName.replace(':', '_') << "[] = {" << endl;
+ // Build data array
+ out << "static const uint qt_meta_data_" << qualifiedClassNameIdentifier << "[] = {" << endl;
out << endl;
out << " // content:" << endl;
- out << " 1, // revision" << endl;
- out << " 0, // classname" << endl;
- out << " " << classInfoCount << ", " << (classInfoCount ? enumStart : 0) << ", // classinfo" << endl;
- enumStart += classInfoCount * 2;
- out << " " << methodCount << ", " << (methodCount ? enumStart : 0) << ", // methods" << endl;
- enumStart += methodCount * 5;
- out << " " << propertyCount << ", " << (propertyCount ? enumStart : 0) << ", // properties" << endl;
- enumStart += propertyCount * 3;
- out << " " << enumCount << ", " << (enumCount ? enumStart : 0)
- << ", // enums/sets" << endl;
+ out << " 7, // revision" << endl;
+ out << " ";
+ addStringIdx(qualifiedClassName);
+ out << " // classname" << endl;
+ out << " " << thisClassInfoCount << ", " << (thisClassInfoCount ? enumStart : 0) << ", // classinfo" << endl;
+ enumStart += thisClassInfoCount * 2;
+ out << " " << thisMethodCount << ", " << (thisMethodCount ? enumStart : 0) << ", // methods" << endl;
+ enumStart += thisMethodCount * 5;
+ int paramsIndex = enumStart;
+ enumStart += (combinedParameterCount * 2); // parameter types + names
+ enumStart += thisMethodCount; // return types
+ out << " " << thisPropertyCount << ", " << (thisPropertyCount ? enumStart : 0) << ", // properties" << endl;
+ enumStart += thisPropertyCount * 3;
+ out << " " << thisEnumCount << ", " << (thisEnumCount ? enumStart : 0) << ", // enums/sets" << endl;
+ out << " 0, 0, // constructors" << endl;
+ out << " 0, // flags" << endl;
+ out << " " << signalCount << ", // signal count" << endl;
out << endl;
- if (classInfoCount) {
+ if (thisClassInfoCount) {
out << " // classinfo: key, value" << endl;
- stringData += " \"";
- for (int i = 0; i < classInfoCount; ++i) {
- QMetaClassInfo classInfo = mo->classInfo(i + mo->classInfoOffset());
- out << " ";
- addString(classInfo.name(), stringData);
- addString(classInfo.value(), stringData);
+ for (int i = mo->classInfoOffset(); i < allClassInfoCount; ++i) {
+ QMetaClassInfo classInfo = mo->classInfo(i);
+ out << " ";
+ addStringIdx(classInfo.name());
+ addStringIdx(classInfo.value());
out << endl;
}
- stringData += "\"\n";
out << endl;
}
- if (methodCount) {
- out << " // signals: signature, parameters, type, tag, flags" << endl;
- stringData += " \"";
- for (int i = 0; i < methodCount; ++i) {
- const QMetaMethod signal(mo->method(i + mo->methodOffset()));
- if (signal.methodType() != QMetaMethod::Signal)
- continue;
- out << " ";
- addString(signal.methodSignature().constData(), stringData);
- addString(joinParameterNames(signal.parameterNames()), stringData);
- addString(signal.typeName(), stringData);
- addString(signal.tag(), stringData);
- out << (AccessProtected | signal.attributes() | MemberSignal) << "," << endl;
- }
- stringData += "\"\n";
- out << endl;
- out << " // slots: signature, parameters, type, tag, flags" << endl;
- stringData += " \"";
- for (int i = 0; i < methodCount; ++i) {
- const QMetaMethod slot(mo->method(i + mo->methodOffset()));
- if (slot.methodType() != QMetaMethod::Slot)
- continue;
- out << " ";
- addString(slot.methodSignature().constData(), stringData);
- addString(joinParameterNames(slot.parameterNames()), stringData);
- addString(slot.typeName(), stringData);
- addString(slot.tag(), stringData);
- out << (0x01 | slot.attributes() | MemberSlot) << "," << endl;
- }
- stringData += "\"\n";
- out << endl;
- }
- if (propertyCount) {
+ // 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" << endl;
- stringData += " \"";
- for (int i = 0; i < propertyCount; ++i) {
- QMetaProperty property = mo->property(i + mo->propertyOffset());
- out << " ";
- addString(property.name(), stringData);
- addString(property.typeName(), stringData);
+ 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;
uint vartype = property.type();
@@ -673,175 +814,55 @@ void generateClassImpl(QTextStream &out, const QMetaObject *mo, const QByteArray
out << "0x" << QString::number(flags, 16).rightJustified(8, '0') << ", \t\t // " << property.typeName() << " " << property.name();
out << endl;
}
- stringData += "\"\n";
out << endl;
}
- QByteArray enumStringData;
- if (enumCount) {
+ if (thisEnumCount) {
out << " // enums: name, flags, count, data" << endl;
- enumStringData += " \"";
- enumStart += enumCount * 4;
- for (int i = 0; i < enumCount; ++i) {
- QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset());
- out << " ";
- addString(enumerator.name(), enumStringData);
+ 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 << ", " << endl;
enumStart += enumerator.keyCount() * 2;
}
- enumStringData += "\"\n";
out << endl;
out << " // enum data: key, value" << endl;
- for (int i = 0; i < enumCount; ++i) {
- enumStringData += " \"";
- QMetaEnum enumerator = mo->enumerator(i + mo->enumeratorOffset());
+ for (int i = mo->enumeratorOffset(); i < allEnumCount; ++i) {
+ QMetaEnum enumerator = mo->enumerator(i);
for (int j = 0; j < enumerator.keyCount(); ++j) {
- out << " ";
- addString(enumerator.key(j), enumStringData);
+ out << " ";
+ addStringIdx(enumerator.key(j));
+ out << "uint(";
if (nameSpace.isEmpty())
out << className << "::";
else
out << nameSpace << "::";
- out << enumerator.key(j) << "," << endl;
+ out << enumerator.key(j) << ")," << endl;
}
- enumStringData += "\"\n";
}
- out << endl;
}
- out << " 0 // eod" << endl;
+ out << " 0 // eod" << endl;
out << "};" << endl;
out << endl;
- QByteArray stringGenerator;
-
- if (!nameSpace.isEmpty()) {
- static bool firstStringData = true;
- if (firstStringData) { // print enums only once
- firstStringData = false;
- if (!enumStringData.isEmpty()) {
- // Maximum string length supported is 64K
- int maxStringLength = 65535;
- if (enumStringData.size() < maxStringLength) {
- out << "static const char qt_meta_enumstringdata_" << nameSpace << "[] = {" << endl;
- out << enumStringData << endl;
- out << "};" << endl;
- out << endl;
- } else {
- // split the string into fragments of 64k
- int fragments = (enumStringData.size() / maxStringLength);
- fragments += (enumStringData.size() % maxStringLength) ? 1 : 0;
- int i, index;
- // define the fragments (qt_meta_enumstringdata_<nameSpace>fragment#)
- for (i = 0 , index = 0; i < fragments; i++, index += maxStringLength) {
- out << "static const char qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) << "[] = {" << endl;
- QByteArray fragment = enumStringData.mid(index, maxStringLength);
- if (!(fragment[0] == ' ' || fragment[0] == '\n' || fragment[0] == '\"'))
- out << "\"";
- out << fragment;
- int endIx = fragment.size() - 1;
- if (!(fragment[endIx] == ' ' || fragment[endIx] == '\n' || fragment[endIx] == '\"' || fragment[endIx] == '\0'))
- out << "\"" << endl;
- else
- out << endl;
- out << "};" << endl;
- }
- // original array definition, size will be the combined size of the arrays defined above
- out << "static char qt_meta_enumstringdata_" << nameSpace << "[" << endl;
- for (i = 0; i < fragments; i++, index += maxStringLength) {
- out << " ";
- if (i)
- out << "+ ";
- out << "sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<")" << endl;
- }
- out << "] = {0};" << endl << endl;
- // this class will initializes the original array in constructor
- out << "class qt_meta_enumstringdata_" << nameSpace << "_init " << endl <<"{" <<endl;
- out << "public:"<<endl;
- out << " qt_meta_enumstringdata_" << nameSpace << "_init() " << endl <<" {" <<endl;
- out << " int index = 0;" << endl;
- for (i = 0; i < fragments; i++, index += maxStringLength) {
- out << " memcpy(qt_meta_enumstringdata_" << nameSpace << " + index, " <<"qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i);
- out << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1);" << endl;
- out << " index += sizeof(qt_meta_enumstringdata_" << nameSpace << "fragment"<< QString::number(i) <<") - 1;" << endl;
- }
- out << " }" << endl << "};" << endl;
- // a global variable of the class
- out << "static qt_meta_enumstringdata_" << nameSpace << "_init qt_meta_enumstringdata_" << nameSpace << "_init_instance;" << endl << endl;
- }
- }
- }
- stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_') + "()";
- out << "static const char *" << stringGenerator << " {" << endl;
- QList<QByteArray> splitStrings;
-
- // workaround for compilers that can't handle string literals longer than 64k
- int splitCount = 0;
- do {
- int lastNewline = stringData.lastIndexOf('\n', 64000);
- QByteArray splitString = stringData.left(lastNewline);
-
- splitStrings << splitString;
- out << " static const char stringdata" << splitCount << "[] = {" << endl;
- out << " \"" << splitString << endl;
- out << " };" << endl;
- stringData = stringData.mid(lastNewline + 1);
- if (stringData.startsWith(" \""))
- stringData = stringData.mid(5);
- ++splitCount;
- } while (!stringData.isEmpty());
-
- out << " static char data[";
- for (int i = 0; i < splitCount; ++i) {
- out << "sizeof(stringdata" << i << ") + ";
- }
- if (!enumStringData.isEmpty()) {
- out << "sizeof(qt_meta_enumstringdata_" << nameSpace << ")";
- } else {
- out << "0";
- }
- out << "];" << endl;
- out << " if (!data[0]) {" << endl;
- out << " int index = 0;" << endl;
-
- int dataIndex = 0;
- for (int i = 0; i < splitCount; ++i) {
- out << " memcpy(data + index";
- out << ", stringdata" << i << ", sizeof(stringdata" << i << ") - 1);" << endl;
- out << " index += sizeof(stringdata" << i << ") - 1;" << endl;
- dataIndex += splitStrings.at(i).length();
- }
- if (!enumStringData.isEmpty()) {
- out << " memcpy(data + index, qt_meta_enumstringdata_" << nameSpace << ", sizeof(qt_meta_enumstringdata_" << nameSpace << "));" << endl;
- }
- out << " }" << endl;
- out << endl;
- out << " return data;" << endl;
- out << "};" << endl;
- out << endl;
- } else {
- stringData += enumStringData;
- stringGenerator = "qt_meta_stringdata_" + qualifiedClassName.replace(':','_');
- out << "static const char qt_meta_stringdata_" << stringGenerator << "[] = {" << endl;
- out << " \"" << stringData << endl;
- out << "};" << endl;
- out << endl;
- }
out << "const QMetaObject " << className << "::staticMetaObject = {" << endl;
if (category & ActiveX)
out << "{ &QWidget::staticMetaObject," << endl;
else
out << "{ &QObject::staticMetaObject," << endl;
- out << stringGenerator << "," << endl;
- out << "qt_meta_data_" << qualifiedClassName.replace(':','_') << " }" << endl;
+ out << "qt_meta_stringdata_all.data," << endl;
+ out << "qt_meta_data_" << qualifiedClassNameIdentifier << ", 0, 0, 0 }" << endl;
out << "};" << endl;
out << endl;
out << "void *" << className << "::qt_metacast(const char *_clname)" << endl;
out << "{" << endl;
out << " if (!_clname) return 0;" << endl;
- out << " if (!strcmp(_clname, " << stringGenerator << "))" << endl;
+ out << " if (!strcmp(_clname, \"" << qualifiedClassName << "\"))" << endl;
out << " return static_cast<void*>(const_cast<" << className << "*>(this));" << endl;
if (category & ActiveX)
out << " return QAxWidget::qt_metacast(_clname);" << endl;
@@ -989,6 +1010,8 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O
QMetaObject *namespaceObject = qax_readEnumInfo(typelib, 0);
+ QByteArray classImplBuffer;
+ QTextStream classImplOut(&classImplBuffer, QIODevice::WriteOnly);
QFile implFile(cppFile + QLatin1String(".cpp"));
QTextStream implOut(&implFile);
if (!(category & (NoMetaObject|NoImplementation))) {
@@ -1257,10 +1280,8 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O
generateClassDecl(inlinesOut, guid.toString(), metaObject, className, libName.toLatin1(), (ObjectCategory)(object_category|OnlyInlines));
inlinesOut << endl;
}
- if (implFile.isOpen()) {
- generateClassImpl(implOut, metaObject, className, libName.toLatin1(), (ObjectCategory)object_category);
- implOut << endl;
- }
+ if (implFile.isOpen())
+ generateClassImpl(classImplOut, metaObject, className, libName.toLatin1(), (ObjectCategory)object_category);
}
currentTypeInfo = 0;
}
@@ -1271,6 +1292,104 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O
typeinfo->Release();
}
+ // 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 {" << endl;
+ implOut << " QByteArrayData data[" << strings.size() << "];" << endl;
+
+ QVector<QList<QByteArray> > listVector;
+ QList<QByteArray> currentList;
+
+ int currentTableLen = 0;
+ for (int i = 0; i < strings.size(); ++i) {
+ currentTableLen += strings.at(i).length() + 1;
+ currentList.append(strings.at(i));
+ // Split strings into chunks less than 64k to work around compiler limits.
+ if (currentTableLen > 60000) {
+ implOut << " char stringdata" << listVector.size() << "[" << currentTableLen + 1 << "];" << endl;
+ listVector.append(currentList);
+ currentList.clear();
+ currentTableLen = 0;
+ }
+ }
+ implOut << " char stringdata" << listVector.size() << "[" << currentTableLen + 1 << "];" << endl;
+ implOut << "};" << endl;
+ listVector.append(currentList);
+
+ // Macro that expands into a QByteArrayData. The offset member is
+ // calculated from 1) the offset of the actual characters in the
+ // stringdata.stringdata member, and 2) the stringdata.data index of the
+ // QByteArrayData being defined. This calculation relies on the
+ // QByteArrayData::data() implementation returning simply "this + offset".
+ implOut << "#define QT_MOC_LITERAL(idx, ofs, len, table) \\" << endl
+ << " Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\" << endl
+ << " offsetof(qt_meta_stringdata_all_t, stringdata##table) + ofs \\" << endl
+ << " - idx * sizeof(QByteArrayData) \\" << endl
+ << " )" << endl;
+
+ implOut << "static const qt_meta_stringdata_all_t qt_meta_stringdata_all = {" << endl;
+ implOut << " {" << 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 << "," << endl;
+ const QByteArray &str = listVector[i].at(j);
+ implOut << "QT_MOC_LITERAL(" << totalStringCount++ << ", " << idx << ", " << str.length() << ", " << i << ")";
+ idx += str.length() + 1;
+ }
+ }
+ implOut << endl << " }";
+
+ //
+ // Build stringdata arrays
+ //
+ for (int i = 0; i < listVector.size(); ++i) {
+ int col = 0;
+ int len = 0;
+ implOut << "," << endl;
+ implOut << " \"";
+ for (int j = 0; j < listVector[i].size(); ++j) {
+ QByteArray s = listVector[i].at(j);
+ len = s.length();
+ if (col && col + len >= 150) {
+ implOut << "\"" << 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 << "\"" << 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 << endl << "};" << endl;
+
+ implOut << "#undef QT_MOC_LITERAL" << endl << endl;
+
+ implOut << classImplBuffer << endl;
+ }
+
delete namespaceObject;
classesOut.flush();
@@ -1291,15 +1410,23 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O
declOut << "}" << endl;
declOut << endl;
- // partial template specialization for qMetaTypeCreateHelper
+ // partial template specialization for qMetaTypeCreateHelper and qMetaTypeConstructHelper
+ declOut << "QT_BEGIN_NAMESPACE" << endl << endl;
for (int t = 0; t < subtypes.count(); ++t) {
QByteArray subType(subtypes.at(t));
declOut << "template<>" << endl;
declOut << "inline void *qMetaTypeCreateHelper<" << libName << "::" << subType << " >(const void *t)" << endl;
- declOut << "{ Q_ASSERT(!t); return new " << libName << "::" << subType << "; }" << endl;
+ declOut << "{ Q_ASSERT(!t); Q_UNUSED(t); return new " << libName << "::" << subType << "; }" << endl;
declOut << endl;
- }
+ // qMetaTypeConstructHelper is required to make generated files compile,
+ // though it doesn't seem to be used in practice.
+ declOut << "template<>" << endl;
+ declOut << "inline void *qMetaTypeConstructHelper<" << libName << "::" << subType << " >(void *where, const void *t)" << endl;
+ declOut << "{ Q_ASSERT(!t); Q_UNUSED(t); return new (where) " << libName << "::" << subType << "; }" << endl;
+ declOut << endl;
+ }
+ declOut << "QT_END_NAMESPACE" << endl << endl;
declOut << "#endif" << endl;
declOut << endl;
}