summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qmetaobject.cpp706
-rw-r--r--src/corelib/kernel/qmetaobject.h6
-rw-r--r--src/corelib/kernel/qmetaobject_p.h74
-rw-r--r--src/corelib/kernel/qobject.cpp215
-rw-r--r--src/corelib/kernel/qobjectdefs.h2
-rw-r--r--src/tools/moc/generator.cpp183
-rw-r--r--src/tools/moc/generator.h3
-rw-r--r--src/tools/moc/moc.cpp5
-rw-r--r--src/tools/moc/moc.h3
-rw-r--r--tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp44
10 files changed, 1067 insertions, 174 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 4d629dd933..0a1fb3daf7 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -189,6 +189,53 @@ static inline int stringSize(const QMetaObject *mo, int index)
return qstrlen(legacyString(mo, index));
}
+static inline QByteArray typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ if (typeInfo & IsUnresolvedType) {
+ return toByteArray(stringData(mo, typeInfo & TypeNameIndexMask));
+ } else {
+ // ### Use the QMetaType::typeName() that returns QByteArray
+ const char *t = QMetaType::typeName(typeInfo);
+ return QByteArray::fromRawData(t, qstrlen(t));
+ }
+}
+
+static inline const char *rawTypeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ return typeNameFromTypeInfo(mo, typeInfo).constData();
+}
+
+static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+{
+ if (!(typeInfo & IsUnresolvedType))
+ return typeInfo;
+ return QMetaType::type(toByteArray(stringData(mo, typeInfo & TypeNameIndexMask)));
+}
+
+class QMetaMethodPrivate : public QMetaMethod
+{
+public:
+ static const QMetaMethodPrivate *get(const QMetaMethod *q)
+ { return static_cast<const QMetaMethodPrivate *>(q); }
+
+ inline QByteArray signature() const;
+ inline QByteArray name() const;
+ inline int typesDataIndex() const;
+ inline const char *rawReturnTypeName() const;
+ inline int returnType() const;
+ inline int parameterCount() const;
+ inline int parametersDataIndex() const;
+ inline uint parameterTypeInfo(int index) const;
+ inline int parameterType(int index) const;
+ inline void getParameterTypes(int *types) const;
+ inline QList<QByteArray> parameterTypes() const;
+ inline QList<QByteArray> parameterNames() const;
+ inline QByteArray tag() const;
+
+private:
+ QMetaMethodPrivate();
+};
+
/*!
\since 4.5
@@ -539,7 +586,37 @@ int QMetaObject::classInfoCount() const
return n;
}
+// Returns true if the method defined by the given meta-object&handle
+// matches the given name, argument count and argument types, otherwise
+// returns false.
+static bool methodMatch(const QMetaObject *m, int handle,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ Q_ASSERT(priv(m->d.data)->revision >= 7);
+ if (int(m->d.data[handle + 1]) != argc)
+ return false;
+
+ if (toByteArray(stringData(m, m->d.data[handle])) != name)
+ return false;
+
+ int paramsIndex = m->d.data[handle + 2] + 1;
+ for (int i = 0; i < argc; ++i) {
+ uint typeInfo = m->d.data[paramsIndex + i];
+ if (types[i].type()) {
+ if (types[i].type() != typeFromTypeInfo(m, typeInfo))
+ return false;
+ } else {
+ if (types[i].name() != typeNameFromTypeInfo(m, typeInfo))
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** \internal
+* \obsolete
* helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within
* the baseObject
* \a MethodType might be MethodSignal or MethodSlot, or 0 to match everything.
@@ -550,6 +627,8 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
const char *method,
bool normalizeStringData)
{
+ QByteArray methodName;
+ QArgumentTypeArray methodArgumentTypes;
for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
int i = (MethodType == MethodSignal && priv(m->d.data)->revision >= 4)
? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
@@ -557,10 +636,21 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
? (priv(m->d.data)->signalCount) : 0;
if (!normalizeStringData) {
for (; i >= end; --i) {
- const char *stringdata = rawStringData(m, m->d.data[priv(m->d.data)->methodData + 5*i]);
- if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
- *baseObject = m;
- return i;
+ if (priv(m->d.data)->revision >= 7) {
+ if (methodName.isEmpty())
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodArgumentTypes);
+ int handle = priv(m->d.data)->methodData + 5*i;
+ if (methodMatch(m, handle, methodName, methodArgumentTypes.size(),
+ methodArgumentTypes.constData())) {
+ *baseObject = m;
+ return i;
+ }
+ } else {
+ const char *stringdata = legacyString(m, m->d.data[priv(m->d.data)->methodData + 5*i]);
+ if (method[0] == stringdata[0] && strcmp(method + 1, stringdata + 1) == 0) {
+ *baseObject = m;
+ return i;
+ }
}
}
} else if (priv(m->d.data)->revision < 5) {
@@ -577,6 +667,34 @@ static inline int indexOfMethodRelative(const QMetaObject **baseObject,
return -1;
}
+/** \internal
+* helper function for indexOf{Method,Slot,Signal}, returns the relative index of the method within
+* the baseObject
+* \a MethodType might be MethodSignal or MethodSlot, or 0 to match everything.
+*/
+template<int MethodType>
+static inline int indexOfMethodRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
+ Q_ASSERT(priv(m->d.data)->revision >= 7);
+ int i = (MethodType == MethodSignal)
+ ? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1);
+ const int end = (MethodType == MethodSlot)
+ ? (priv(m->d.data)->signalCount) : 0;
+
+ for (; i >= end; --i) {
+ int handle = priv(m->d.data)->methodData + 5*i;
+ if (methodMatch(m, handle, name, argc, types)) {
+ *baseObject = m;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
/*!
\since 4.5
@@ -592,10 +710,16 @@ int QMetaObject::indexOfConstructor(const char *constructor) const
{
if (priv(d.data)->revision < 2)
return -1;
- for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {
- const char *data = rawStringData(this, d.data[priv(d.data)->constructorData + 5*i]);
- if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
- return i;
+ else if (priv(d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(constructor, types);
+ return QMetaObjectPrivate::indexOfConstructor(this, name, types.size(), types.constData());
+ } else {
+ for (int i = priv(d.data)->constructorCount-1; i >= 0; --i) {
+ const char *data = legacyString(this, d.data[priv(d.data)->constructorData + 5*i]);
+ if (data[0] == constructor[0] && strcmp(constructor + 1, data + 1) == 0) {
+ return i;
+ }
}
}
return -1;
@@ -612,16 +736,60 @@ int QMetaObject::indexOfConstructor(const char *constructor) const
int QMetaObject::indexOfMethod(const char *method) const
{
const QMetaObject *m = this;
- int i = indexOfMethodRelative<0>(&m, method, false);
- if (i < 0) {
- m = this;
- i = indexOfMethodRelative<0>(&m, method, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(method, types);
+ i = indexOfMethodRelative<0>(&m, name, types.size(), types.constData());
+ } else {
+ i = indexOfMethodRelative<0>(&m, method, false);
+ if (i < 0) {
+ m = this;
+ i = indexOfMethodRelative<0>(&m, method, true);
+ }
}
if (i >= 0)
i += m->methodOffset();
return i;
}
+// Parses a string of comma-separated types into QArgumentTypes.
+static void argumentTypesFromString(const char *str, const char *end,
+ QArgumentTypeArray &types)
+{
+ Q_ASSERT(str <= end);
+ while (str != end) {
+ if (!types.isEmpty())
+ ++str; // Skip comma
+ const char *begin = str;
+ int level = 0;
+ while (str != end && (level > 0 || *str != ',')) {
+ if (*str == '<')
+ ++level;
+ else if (*str == '>')
+ --level;
+ ++str;
+ }
+ types += QArgumentType(QByteArray(begin, str - begin));
+ }
+}
+
+// Given a method \a signature (e.g. "foo(int,double)"), this function
+// populates the argument \a types array and returns the method name.
+QByteArray QMetaObjectPrivate::decodeMethodSignature(
+ const char *signature, QArgumentTypeArray &types)
+{
+ const char *lparens = strchr(signature, '(');
+ if (!lparens)
+ return QByteArray();
+ const char *rparens = strchr(lparens + 1, ')');
+ if (!rparens || *(rparens+1))
+ return QByteArray();
+ int nameLength = lparens - signature;
+ argumentTypesFromString(lparens + 1, rparens, types);
+ return QByteArray::fromRawData(signature, nameLength);
+}
+
/*!
Finds \a signal and returns its index; otherwise returns -1.
@@ -636,10 +804,17 @@ int QMetaObject::indexOfMethod(const char *method) const
int QMetaObject::indexOfSignal(const char *signal) const
{
const QMetaObject *m = this;
- int i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, false);
- if (i < 0) {
- m = this;
- i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signal, types);
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, name, types.size(), types.constData());
+ } else {
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, false);
+ if (i < 0) {
+ m = this;
+ i = QMetaObjectPrivate::indexOfSignalRelative(&m, signal, true);
+ }
}
if (i >= 0)
i += m->methodOffset();
@@ -647,6 +822,7 @@ int QMetaObject::indexOfSignal(const char *signal) const
}
/*! \internal
+ \obsolete
Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
\a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
@@ -668,6 +844,31 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
return i;
}
+/*! \internal
+ Same as QMetaObject::indexOfSignal, but the result is the local offset to the base object.
+
+ \a baseObject will be adjusted to the enclosing QMetaObject, or 0 if the signal is not found
+*/
+int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types);
+#ifndef QT_NO_DEBUG
+ const QMetaObject *m = *baseObject;
+ if (i >= 0 && m && m->d.superdata) {
+ int conflict = indexOfMethod(m->d.superdata, name, argc, types);
+ if (conflict >= 0) {
+ QMetaMethod conflictMethod = m->d.superdata->method(conflict);
+ qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
+ conflictMethod.methodSignature().constData(),
+ rawStringData(m->d.superdata, 0), rawStringData(m, 0));
+ }
+ }
+ #endif
+ return i;
+}
+
/*!
Finds \a slot and returns its index; otherwise returns -1.
@@ -679,9 +880,16 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
int QMetaObject::indexOfSlot(const char *slot) const
{
const QMetaObject *m = this;
- int i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, false);
- if (i < 0)
- i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, true);
+ int i;
+ if (priv(m->d.data)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(slot, types);
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, name, types.size(), types.constData());
+ } else {
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, false);
+ if (i < 0)
+ i = QMetaObjectPrivate::indexOfSlotRelative(&m, slot, true);
+ }
if (i >= 0)
i += m->methodOffset();
return i;
@@ -695,6 +903,104 @@ int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
return indexOfMethodRelative<MethodSlot>(m, slot, normalizeStringData);
}
+// same as indexOfSignalRelative but for slots.
+int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
+ const QByteArray &name, int argc,
+ const QArgumentType *types)
+{
+ return indexOfMethodRelative<MethodSlot>(m, name, argc, types);
+}
+
+int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfSignalRelative(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfSlotRelative(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ int i = indexOfMethodRelative<0>(&m, name, argc, types);
+ if (i >= 0)
+ i += m->methodOffset();
+ return i;
+}
+
+int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types)
+{
+ for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) {
+ int handle = priv(m->d.data)->constructorData + 5*i;
+ if (methodMatch(m, handle, name, argc, types))
+ return i;
+ }
+ return -1;
+}
+
+/*!
+ \internal
+
+ Returns true if the \a signalTypes and \a methodTypes are
+ compatible; otherwise returns false.
+*/
+bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
+ int methodArgc, const QArgumentType *methodTypes)
+{
+ if (signalArgc < methodArgc)
+ return false;
+ for (int i = 0; i < methodArgc; ++i) {
+ if (signalTypes[i] != methodTypes[i])
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Returns true if the \a signal and \a method arguments are
+ compatible; otherwise returns false.
+*/
+bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
+ const QMetaMethodPrivate *method)
+{
+ if (signal->methodType() != QMetaMethod::Signal)
+ return false;
+ if (signal->parameterCount() < method->parameterCount())
+ return false;
+ const QMetaObject *smeta = signal->enclosingMetaObject();
+ const QMetaObject *rmeta = method->enclosingMetaObject();
+ for (int i = 0; i < method->parameterCount(); ++i) {
+ uint sourceTypeInfo = signal->parameterTypeInfo(i);
+ uint targetTypeInfo = method->parameterTypeInfo(i);
+ if ((sourceTypeInfo & IsUnresolvedType)
+ || (targetTypeInfo & IsUnresolvedType)) {
+ QByteArray sourceName = typeNameFromTypeInfo(smeta, sourceTypeInfo);
+ QByteArray targetName = typeNameFromTypeInfo(rmeta, targetTypeInfo);
+ if (sourceName != targetName)
+ return false;
+ } else {
+ int sourceType = typeFromTypeInfo(smeta, sourceTypeInfo);
+ int targetType = typeFromTypeInfo(rmeta, targetTypeInfo);
+ if (sourceType != targetType)
+ return false;
+ }
+ }
+ return true;
+}
+
static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
{
while (self) {
@@ -872,12 +1178,16 @@ QMetaProperty QMetaObject::property(int index) const
if (i >= 0 && i < priv(d.data)->propertyCount) {
int handle = priv(d.data)->propertyData + 3*i;
int flags = d.data[handle + 2];
- const char *type = rawStringData(this, d.data[handle + 1]);
result.mobj = this;
result.handle = handle;
result.idx = i;
if (flags & EnumOrFlag) {
+ const char *type;
+ if (priv(d.data)->revision >= 7)
+ type = rawTypeNameFromTypeInfo(this, d.data[handle + 1]);
+ else
+ type = legacyString(this, d.data[handle + 1]);
result.menum = enumerator(indexOfEnumerator(type));
if (!result.menum.isValid()) {
const char *enum_name = type;
@@ -977,6 +1287,21 @@ bool QMetaObject::checkConnectArgs(const char *signal, const char *method)
return false;
}
+/*!
+ \since 5.0
+ \overload
+
+ Returns true if the \a signal and \a method arguments are
+ compatible; otherwise returns false.
+*/
+bool QMetaObject::checkConnectArgs(const QMetaMethod &signal,
+ const QMetaMethod &method)
+{
+ return QMetaObjectPrivate::checkConnectArgs(
+ QMetaMethodPrivate::get(&signal),
+ QMetaMethodPrivate::get(&method));
+}
+
static void qRemoveWhitespace(const char *s, char *d)
{
char last = 0;
@@ -1318,6 +1643,120 @@ bool QMetaObject::invokeMethod(QObject *obj,
\internal
*/
+QByteArray QMetaMethodPrivate::signature() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QByteArray result;
+ result.reserve(256);
+ result += name();
+ result += '(';
+ QList<QByteArray> argTypes = parameterTypes();
+ for (int i = 0; i < argTypes.size(); ++i) {
+ if (i)
+ result += ',';
+ result += argTypes.at(i);
+ }
+ result += ')';
+ return result;
+}
+
+QByteArray QMetaMethodPrivate::name() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return toByteArray(stringData(mobj, mobj->d.data[handle]));
+}
+
+int QMetaMethodPrivate::typesDataIndex() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[handle + 2];
+}
+
+const char *QMetaMethodPrivate::rawReturnTypeName() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ uint typeInfo = mobj->d.data[typesDataIndex()];
+ if (typeInfo & IsUnresolvedType)
+ return rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ else {
+ if (typeInfo == QMetaType::Void) {
+ // QMetaMethod::typeName() is documented to return an empty string
+ // if the return type is void, but QMetaType::typeName() returns
+ // "void".
+ return "";
+ }
+ return QMetaType::typeName(typeInfo);
+ }
+}
+
+int QMetaMethodPrivate::returnType() const
+{
+ return parameterType(-1);
+}
+
+int QMetaMethodPrivate::parameterCount() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[handle + 1];
+}
+
+int QMetaMethodPrivate::parametersDataIndex() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return typesDataIndex() + 1;
+}
+
+uint QMetaMethodPrivate::parameterTypeInfo(int index) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return mobj->d.data[parametersDataIndex() + index];
+}
+
+int QMetaMethodPrivate::parameterType(int index) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return typeFromTypeInfo(mobj, parameterTypeInfo(index));
+}
+
+void QMetaMethodPrivate::getParameterTypes(int *types) const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ int dataIndex = parametersDataIndex();
+ int argc = parameterCount();
+ for (int i = 0; i < argc; ++i) {
+ int id = typeFromTypeInfo(mobj, mobj->d.data[dataIndex++]);
+ *(types++) = id;
+ }
+}
+
+QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QList<QByteArray> list;
+ int argc = parameterCount();
+ int paramsIndex = parametersDataIndex();
+ for (int i = 0; i < argc; ++i)
+ list += typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
+ return list;
+}
+
+QList<QByteArray> QMetaMethodPrivate::parameterNames() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ QList<QByteArray> list;
+ int argc = parameterCount();
+ int namesIndex = parametersDataIndex() + argc;
+ for (int i = 0; i < argc; ++i)
+ list += toByteArray(stringData(mobj, mobj->d.data[namesIndex + i]));
+ return list;
+}
+
+QByteArray QMetaMethodPrivate::tag() const
+{
+ Q_ASSERT(priv(mobj->d.data)->revision >= 7);
+ return toByteArray(stringData(mobj, mobj->d.data[handle + 3]));
+}
+
/*!
\since 5.0
@@ -1330,7 +1769,92 @@ QByteArray QMetaMethod::methodSignature() const
{
if (!mobj)
return QByteArray();
- return toByteArray(stringData(mobj, mobj->d.data[handle]));
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->signature();
+ } else {
+ const char *sig = rawStringData(mobj, mobj->d.data[handle]);
+ return QByteArray::fromRawData(sig, qstrlen(sig));
+ }
+}
+
+/*!
+ \since 5.0
+
+ Returns the name of this method.
+
+ \sa methodSignature(), parameterCount()
+*/
+QByteArray QMetaMethod::name() const
+{
+ if (!mobj)
+ return QByteArray();
+ return QMetaMethodPrivate::get(this)->name();
+}
+
+/*!
+ \since 5.0
+
+ Returns the return type of this method.
+
+ The return value is one of the types that are registered
+ with QMetaType, or 0 if the type is not registered.
+
+ \sa parameterType(), QMetaType, typeName()
+*/
+int QMetaMethod::returnType() const
+ {
+ if (!mobj)
+ return 0;
+ return QMetaMethodPrivate::get(this)->returnType();
+}
+
+/*!
+ \since 5.0
+
+ Returns the number of parameters of this method.
+
+ \sa parameterType(), parameterNames()
+*/
+int QMetaMethod::parameterCount() const
+{
+ if (!mobj)
+ return 0;
+ return QMetaMethodPrivate::get(this)->parameterCount();
+}
+
+/*!
+ \since 5.0
+
+ Returns the type of the parameter at the given \a index.
+
+ The return value is one of the types that are registered
+ with QMetaType, or 0 if the type is not registered.
+
+ \sa parameterCount(), returnType(), QMetaType
+*/
+int QMetaMethod::parameterType(int index) const
+{
+ if (!mobj || index < 0)
+ return 0;
+ if (index >= QMetaMethodPrivate::get(this)->parameterCount())
+ return 0;
+ return QMetaMethodPrivate::get(this)->parameterType(index);
+}
+
+/*!
+ \since 5.0
+ \internal
+
+ Gets the parameter \a types of this method. The storage
+ for \a types must be able to hold parameterCount() items.
+
+ \sa parameterCount(), returnType(), parameterType()
+*/
+void QMetaMethod::getParameterTypes(int *types) const
+{
+ if (!mobj)
+ return;
+ QMetaMethodPrivate::get(this)->getParameterTypes(types);
}
/*!
@@ -1342,8 +1866,12 @@ QList<QByteArray> QMetaMethod::parameterTypes() const
{
if (!mobj)
return QList<QByteArray>();
- return QMetaObjectPrivate::parameterTypeNamesFromSignature(
- rawStringData(mobj, mobj->d.data[handle]));
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->parameterTypes();
+ } else {
+ return QMetaObjectPrivate::parameterTypeNamesFromSignature(
+ legacyString(mobj, mobj->d.data[handle]));
+ }
}
/*!
@@ -1356,36 +1884,43 @@ QList<QByteArray> QMetaMethod::parameterNames() const
QList<QByteArray> list;
if (!mobj)
return list;
- const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
- if (*names == 0) {
- // do we have one or zero arguments?
- const char *signature = rawStringData(mobj, mobj->d.data[handle]);
- while (*signature && *signature != '(')
- ++signature;
- if (*++signature != ')')
- list += QByteArray();
+ if (priv(mobj->d.data)->revision >= 7) {
+ return QMetaMethodPrivate::get(this)->parameterNames();
} else {
- --names;
- do {
- const char *begin = ++names;
- while (*names && *names != ',')
- ++names;
- list += QByteArray(begin, names - begin);
- } while (*names);
+ const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
+ if (*names == 0) {
+ // do we have one or zero arguments?
+ const char *signature = rawStringData(mobj, mobj->d.data[handle]);
+ while (*signature && *signature != '(')
+ ++signature;
+ if (*++signature != ')')
+ list += QByteArray();
+ } else {
+ --names;
+ do {
+ const char *begin = ++names;
+ while (*names && *names != ',')
+ ++names;
+ list += QByteArray(begin, names - begin);
+ } while (*names);
+ }
+ return list;
}
- return list;
}
/*!
- Returns the return type of this method, or an empty string if the
+ Returns the return type name of this method, or an empty string if the
return type is \e void.
*/
const char *QMetaMethod::typeName() const
{
if (!mobj)
return 0;
- return rawStringData(mobj, mobj->d.data[handle + 2]);
+ if (priv(mobj->d.data)->revision >= 7)
+ return QMetaMethodPrivate::get(this)->rawReturnTypeName();
+ else
+ return legacyString(mobj, mobj->d.data[handle + 2]);
}
/*!
@@ -1422,7 +1957,10 @@ const char *QMetaMethod::tag() const
{
if (!mobj)
return 0;
- return rawStringData(mobj, mobj->d.data[handle + 3]);
+ if (priv(mobj->d.data)->revision >= 7)
+ return QMetaMethodPrivate::get(this)->tag().constData();
+ else
+ return legacyString(mobj, mobj->d.data[handle + 3]);
}
@@ -1623,7 +2161,9 @@ bool QMetaMethod::invoke(QObject *object,
break;
}
int metaMethodArgumentCount = 0;
- {
+ if (priv(mobj->d.data)->revision >= 7) {
+ metaMethodArgumentCount = QMetaMethodPrivate::get(this)->parameterCount();
+ } else {
// based on QMetaObject::parameterNames()
const char *names = rawStringData(mobj, mobj->d.data[handle + 1]);
if (*names == 0) {
@@ -2058,7 +2598,10 @@ QByteArray QMetaEnum::valueToKeys(int value) const
v = v & ~k;
if (!keys.isEmpty())
keys += '|';
- keys += rawStringData(mobj, mobj->d.data[data + 2*i]);
+ if (priv(mobj->d.data)->revision >= 7)
+ keys += toByteArray(stringData(mobj, mobj->d.data[data + 2*i]));
+ else
+ keys += legacyString(mobj, mobj->d.data[data + 2*i]);
}
}
return keys;
@@ -2150,7 +2693,10 @@ const char *QMetaProperty::typeName() const
if (!mobj)
return 0;
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- return rawStringData(mobj, mobj->d.data[handle + 1]);
+ if (priv(mobj->d.data)->revision >= 7)
+ return rawTypeNameFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ else
+ return legacyString(mobj, mobj->d.data[handle + 1]);
}
/*!
@@ -2164,9 +2710,16 @@ QVariant::Type QMetaProperty::type() const
if (!mobj)
return QVariant::Invalid;
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- uint flags = mobj->d.data[handle + 2];
- uint type = flags >> 24;
+ uint type;
+ if (priv(mobj->d.data)->revision >= 7) {
+ type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ if (type >= QMetaType::User)
+ return QVariant::UserType;
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ type = flags >> 24;
+ }
if (type)
return QVariant::Type(type);
if (isEnumType()) {
@@ -2194,11 +2747,22 @@ QVariant::Type QMetaProperty::type() const
*/
int QMetaProperty::userType() const
{
- QVariant::Type tp = type();
- if (tp != QVariant::UserType)
- return tp;
+ if (!mobj)
+ return 0;
+ if (priv(mobj->d.data)->revision >= 7) {
+ int handle = priv(mobj->d.data)->propertyData + 3*idx;
+ int type = typeFromTypeInfo(mobj, mobj->d.data[handle + 1]);
+ if (type)
+ return type;
+ } else {
+ QVariant::Type tp = type();
+ if (tp != QVariant::UserType)
+ return tp;
+ }
if (isEnumType()) {
int enumMetaTypeId = QMetaType::type(qualifiedName(menum));
+ if (enumMetaTypeId == 0)
+ return QVariant::Int; // Match behavior of QMetaType::type()
return enumMetaTypeId;
}
return QMetaType::type(typeName());
@@ -2298,13 +2862,25 @@ QVariant QMetaProperty::read(const QObject *object) const
t = enumMetaTypeId;
} else {
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- uint flags = mobj->d.data[handle + 2];
- const char *typeName = rawStringData(mobj, mobj->d.data[handle + 1]);
- t = (flags >> 24);
- if (t == QVariant::Invalid)
- t = QMetaType::type(typeName);
- if (t == QVariant::Invalid)
- t = QVariant::nameToType(typeName);
+ const char *typeName = 0;
+ if (priv(mobj->d.data)->revision >= 7) {
+ uint typeInfo = mobj->d.data[handle + 1];
+ if (!(typeInfo & IsUnresolvedType))
+ t = typeInfo;
+ else {
+ typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ t = QMetaType::type(typeName);
+ }
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ t = (flags >> 24);
+ if (t == QVariant::Invalid) {
+ typeName = legacyString(mobj, mobj->d.data[handle + 1]);
+ t = QMetaType::type(typeName);
+ if (t == QVariant::Invalid)
+ t = QVariant::nameToType(typeName);
+ }
+ }
if (t == QVariant::Invalid) {
qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property '%s::%s'", typeName, mobj->className(), name());
return QVariant();
@@ -2367,8 +2943,20 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
v.convert(QVariant::Int);
} else {
int handle = priv(mobj->d.data)->propertyData + 3*idx;
- uint flags = mobj->d.data[handle + 2];
- t = flags >> 24;
+ const char *typeName = 0;
+ if (priv(mobj->d.data)->revision >= 7) {
+ uint typeInfo = mobj->d.data[handle + 1];
+ if (!(typeInfo & IsUnresolvedType))
+ t = typeInfo;
+ else {
+ typeName = rawStringData(mobj, typeInfo & TypeNameIndexMask);
+ t = QMetaType::type(typeName);
+ }
+ } else {
+ uint flags = mobj->d.data[handle + 2];
+ t = flags >> 24;
+ typeName = legacyString(mobj, mobj->d.data[handle + 1]);
+ }
if (t == QVariant::Invalid) {
const char *typeName = rawStringData(mobj, mobj->d.data[handle + 1]);
const char *vtypeName = value.typeName();
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 573e69fdb7..095b196dca 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -58,7 +58,12 @@ public:
inline QMetaMethod() : mobj(0),handle(0) {}
QByteArray methodSignature() const;
+ QByteArray name() const;
const char *typeName() const;
+ int returnType() const;
+ int parameterCount() const;
+ int parameterType(int index) const;
+ void getParameterTypes(int *types) const;
QList<QByteArray> parameterTypes() const;
QList<QByteArray> parameterNames() const;
const char *tag() const;
@@ -146,6 +151,7 @@ private:
const QMetaObject *mobj;
uint handle;
+ friend class QMetaMethodPrivate;
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
friend class QObject;
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index d789711bb4..509dede4cb 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -105,6 +105,59 @@ enum MetaObjectFlags {
RequiresVariantMetaObject = 0x02
};
+enum MetaDataFlags {
+ IsUnresolvedType = 0x80000000,
+ TypeNameIndexMask = 0x7FFFFFFF
+};
+
+class QArgumentType
+{
+public:
+ QArgumentType(int type)
+ : _type(type)
+ {}
+ QArgumentType(const QByteArray &name)
+ : _type(QMetaType::type(name.constData())), _name(name)
+ {}
+ QArgumentType()
+ : _type(0)
+ {}
+ int type() const
+ { return _type; }
+ QByteArray name() const
+ {
+ if (_type && _name.isEmpty())
+ const_cast<QArgumentType *>(this)->_name = QMetaType::typeName(_type);
+ return _name;
+ }
+ bool operator==(const QArgumentType &other) const
+ {
+ if (_type)
+ return _type == other._type;
+ else if (other._type)
+ return false;
+ else
+ return _name == other._name;
+ }
+ bool operator!=(const QArgumentType &other) const
+ {
+ if (_type)
+ return _type != other._type;
+ else if (other._type)
+ return true;
+ else
+ return _name != other._name;
+ }
+
+private:
+ int _type;
+ QByteArray _name;
+};
+
+template <class T, int> class QVarLengthArray;
+typedef QVarLengthArray<QArgumentType, 10> QArgumentTypeArray;
+
+class QMetaMethodPrivate;
class QMutex;
struct QMetaObjectPrivate
@@ -137,6 +190,27 @@ struct QMetaObjectPrivate
bool normalizeStringData);
static int originalClone(const QMetaObject *obj, int local_method_index);
+ static QByteArray decodeMethodSignature(const char *signature,
+ QArgumentTypeArray &types);
+ static int indexOfSignalRelative(const QMetaObject **baseObject,
+ const QByteArray &name, int argc,
+ const QArgumentType *types);
+ static int indexOfSlotRelative(const QMetaObject **m,
+ const QByteArray &name, int argc,
+ const QArgumentType *types);
+ static int indexOfSignal(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfSlot(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfMethod(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
+ int argc, const QArgumentType *types);
+ static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
+ int methodArgc, const QArgumentType *methodTypes);
+ static bool checkConnectArgs(const QMetaMethodPrivate *signal,
+ const QMetaMethodPrivate *method);
+
static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index f44e4c4761..9977f96f99 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -95,6 +95,30 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
return types;
}
+static int *queuedConnectionTypes(const QArgumentType *argumentTypes, int argc)
+{
+ QScopedArrayPointer<int> types(new int [argc + 1]);
+ for (int i = 0; i < argc; ++i) {
+ const QArgumentType &type = argumentTypes[i];
+ if (type.type())
+ types[i] = type.type();
+ else if (type.name().endsWith('*'))
+ types[i] = QMetaType::VoidStar;
+ else
+ types[i] = QMetaType::type(type.name());
+
+ if (!types[i]) {
+ qWarning("QObject::connect: Cannot queue arguments of type '%s'\n"
+ "(Make sure '%s' is registered using qRegisterMetaType().)",
+ type.name().constData(), type.name().constData());
+ return 0;
+ }
+ }
+ types[argc] = 0;
+
+ return types.take();
+}
+
static QBasicMutex _q_ObjectMutexPool[131];
/** \internal
@@ -2278,20 +2302,40 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
const QMetaObject *smeta = sender->metaObject();
const char *signal_arg = signal;
++signal; //skip code
- int signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- if (signal_index < 0) {
- // check for normalized signatures
- tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
- signal = tmp_signal_name.constData() + 1;
-
- smeta = sender->metaObject();
+ QByteArray signalName;
+ QArgumentTypeArray signalTypes;
+ int signal_index;
+ if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ if (signal_index < 0) {
+ // check for normalized signatures
+ tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
+ signal = tmp_signal_name.constData() + 1;
+
+ signalTypes.clear();
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ }
+ } else {
signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- }
- if (signal_index < 0) {
- // re-use tmp_signal_name and signal from above
+ if (signal_index < 0) {
+ // check for normalized signatures
+ tmp_signal_name = QMetaObject::normalizedSignature(signal - 1);
+ signal = tmp_signal_name.constData() + 1;
+
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
+ if (signal_index < 0) {
+ // re-use tmp_signal_name and signal from above
- smeta = sender->metaObject();
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ smeta = sender->metaObject();
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ }
+ }
}
if (signal_index < 0) {
err_method_notfound(sender, signal_arg, "connect");
@@ -2312,36 +2356,71 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
const char *method_arg = method;
++method; // skip code
+ QByteArray methodName;
+ QArgumentTypeArray methodTypes;
const QMetaObject *rmeta = receiver->metaObject();
int method_index_relative = -1;
- switch (membcode) {
- case QSLOT_CODE:
- method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
- break;
- case QSIGNAL_CODE:
- method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
- break;
- }
-
- if (method_index_relative < 0) {
- // check for normalized methods
- tmp_method_name = QMetaObject::normalizedSignature(method);
- method = tmp_method_name.constData();
-
- // rmeta may have been modified above
- rmeta = receiver->metaObject();
+ if (QMetaObjectPrivate::get(rmeta)->revision >= 7) {
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ }
+ if (method_index_relative < 0) {
+ // check for normalized methods
+ tmp_method_name = QMetaObject::normalizedSignature(method);
+ method = tmp_method_name.constData();
+
+ methodTypes.clear();
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
+ // rmeta may have been modified above
+ rmeta = receiver->metaObject();
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
+ &rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ break;
+ }
+ }
+ } else {
switch (membcode) {
case QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
- if (method_index_relative < 0)
- method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
break;
case QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
- if (method_index_relative < 0)
- method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
break;
}
+
+ if (method_index_relative < 0) {
+ // check for normalized methods
+ tmp_method_name = QMetaObject::normalizedSignature(method);
+ method = tmp_method_name.constData();
+
+ // rmeta may have been modified above
+ rmeta = receiver->metaObject();
+ switch (membcode) {
+ case QSLOT_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, false);
+ if (method_index_relative < 0)
+ method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(&rmeta, method, true);
+ break;
+ case QSIGNAL_CODE:
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, false);
+ if (method_index_relative < 0)
+ method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(&rmeta, method, true);
+ break;
+ }
+ }
}
if (method_index_relative < 0) {
@@ -2350,7 +2429,18 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
return QMetaObject::Connection(0);
}
- if (!QMetaObject::checkConnectArgs(signal, method)) {
+ bool compatibleArgs = true;
+ if ((QMetaObjectPrivate::get(smeta)->revision < 7) && (QMetaObjectPrivate::get(rmeta)->revision < 7)) {
+ compatibleArgs = QMetaObject::checkConnectArgs(signal, method);
+ } else {
+ if (signalName.isEmpty())
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ if (methodName.isEmpty())
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
+ compatibleArgs = QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), signalTypes.constData(),
+ methodTypes.size(), methodTypes.constData());
+ }
+ if (!compatibleArgs) {
qWarning("QObject::connect: Incompatible sender/receiver arguments"
"\n %s::%s --> %s::%s",
sender->metaObject()->className(), signal,
@@ -2360,8 +2450,11 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign
int *types = 0;
if ((type == Qt::QueuedConnection)
- && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))
+ && ((QMetaObjectPrivate::get(smeta)->revision >= 7)
+ ? !(types = queuedConnectionTypes(signalTypes.constData(), signalTypes.size()))
+ : !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes())))) {
return QMetaObject::Connection(0);
+ }
#ifndef QT_NO_DEBUG
if (warnCompat) {
@@ -2604,12 +2697,25 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
*/
bool res = false;
const QMetaObject *smeta = sender->metaObject();
+ QByteArray signalName;
+ QArgumentTypeArray signalTypes;
+ if (signal && (QMetaObjectPrivate::get(smeta)->revision >= 7))
+ signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
+ QByteArray methodName;
+ QArgumentTypeArray methodTypes;
+ if (method && (QMetaObjectPrivate::get(receiver->metaObject())->revision >= 7))
+ methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
do {
int signal_index = -1;
if (signal) {
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
- if (signal_index < 0)
- signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ if (QMetaObjectPrivate::get(smeta)->revision >= 7) {
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &smeta, signalName, signalTypes.size(), signalTypes.constData());
+ } else {
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, false);
+ if (signal_index < 0)
+ signal_index = QMetaObjectPrivate::indexOfSignalRelative(&smeta, signal, true);
+ }
if (signal_index < 0)
break;
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);
@@ -2624,7 +2730,13 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
} else {
const QMetaObject *rmeta = receiver->metaObject();
do {
- int method_index = rmeta->indexOfMethod(method);
+ int method_index;
+ if (QMetaObjectPrivate::get(rmeta)->revision >= 7) {
+ method_index = QMetaObjectPrivate::indexOfMethod(
+ rmeta, methodName, methodTypes.size(), methodTypes.constData());
+ } else {
+ method_index = rmeta->indexOfMethod(method);
+ }
if (method_index >= 0)
while (method_index < rmeta->methodOffset())
rmeta = rmeta->superClass();
@@ -3307,9 +3419,17 @@ int QObjectPrivate::signalIndex(const char *signalName) const
{
Q_Q(const QObject);
const QMetaObject *base = q->metaObject();
- int relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false);
- if (relative_index < 0)
- relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true);
+ int relative_index;
+ if (QMetaObjectPrivate::get(base)->revision >= 7) {
+ QArgumentTypeArray types;
+ QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(
+ &base, name, types.size(), types.constData());
+ } else {
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, false);
+ if (relative_index < 0)
+ relative_index = QMetaObjectPrivate::indexOfSignalRelative(&base, signalName, true);
+ }
if (relative_index < 0)
return relative_index;
relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
@@ -4037,9 +4157,16 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
locker.unlock();
// reconstruct the signature to call connectNotify
- const char *sig = QMetaObjectPrivate::rawStringData(senderMetaObject, senderMetaObject->d.data[
- reinterpret_cast<const QMetaObjectPrivate*>(senderMetaObject->d.data)->methodData
- + 5 * (signal_index - signalOffset)]);
+ QByteArray tmp_sig;
+ const char *sig;
+ if (QMetaObjectPrivate::get(senderMetaObject)->revision >= 7) {
+ tmp_sig = senderMetaObject->method(signal_index - signalOffset + methodOffset).methodSignature();
+ sig = tmp_sig.constData();
+ } else {
+ sig = reinterpret_cast<const char *>(senderMetaObject->d.stringdata)
+ + senderMetaObject->d.data[QMetaObjectPrivate::get(senderMetaObject)->methodData
+ + 5 * (signal_index - signalOffset)];
+ }
QVarLengthArray<char> signalSignature(qstrlen(sig) + 2);
signalSignature.data()[0] = char(QSIGNAL_CODE + '0');
strcpy(signalSignature.data() + 1 , sig);
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 6c40733877..8751d0f5a1 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -325,6 +325,8 @@ struct Q_CORE_EXPORT QMetaObject
QMetaProperty userProperty() const;
static bool checkConnectArgs(const char *signal, const char *method);
+ static bool checkConnectArgs(const QMetaMethod &signal,
+ const QMetaMethod &method);
static QByteArray normalizedSignature(const char *method);
static QByteArray normalizedType(const char *type);
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 9571af4bd5..73a0605028 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -54,7 +54,7 @@
QT_BEGIN_NAMESPACE
-uint qvariant_nameToType(const QByteArray &name)
+uint nameToBuiltinType(const QByteArray &name)
{
if (name.isEmpty())
return 0;
@@ -64,20 +64,27 @@ uint qvariant_nameToType(const QByteArray &name)
}
/*
- Returns true if the type is a QVariant types.
+ Returns true if the type is a built-in type.
*/
-bool isVariantType(const QByteArray &type)
-{
- return qvariant_nameToType(type) != 0;
+bool isBuiltinType(const QByteArray &type)
+ {
+ int id = QMetaType::type(type.constData());
+ if (!id && !type.isEmpty() && type != "void")
+ return false;
+ return (id < QMetaType::User);
}
-/*!
- Returns true if the type is qreal.
-*/
-static bool isQRealType(const QByteArray &type)
-{
- return (type == "qreal");
-}
+static 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;
+ }
Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile)
: out(outfile), cdef(classDef), metaTypes(metaTypes)
@@ -122,6 +129,17 @@ int Generator::stridx(const QByteArray &s)
return i;
}
+// Returns the sum of all parameters (including return type) for the given
+// \a list of methods. This is needed for calculating the size of the methods'
+// parameter type/name meta-data.
+static int aggregateParameterCount(const QList<FunctionDef> &list)
+{
+ int sum = 0;
+ for (int i = 0; i < list.count(); ++i)
+ sum += list.at(i).arguments.count() + 1; // +1 for return type
+ return sum;
+}
+
void Generator::generateCode()
{
bool isQt = (cdef->classname == "Qt");
@@ -266,6 +284,15 @@ void Generator::generateCode()
index += methodCount * 5;
if (cdef->revisionedMethods)
index += methodCount;
+ int paramsIndex = index;
+ int totalParameterCount = aggregateParameterCount(cdef->signalList)
+ + aggregateParameterCount(cdef->slotList)
+ + aggregateParameterCount(cdef->methodList)
+ + aggregateParameterCount(cdef->constructorList);
+ index += totalParameterCount * 2 // types and parameter names
+ - methodCount // return "parameters" don't have names
+ - cdef->constructorList.count(); // "this" parameters don't have names
+
fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
index += cdef->propertyList.count() * 3;
if(cdef->notifyableProperties)
@@ -292,17 +319,17 @@ void Generator::generateCode()
//
// Build signals array first, otherwise the signal indices would be wrong
//
- generateFunctions(cdef->signalList, "signal", MethodSignal);
+ generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex);
//
// Build slots array
//
- generateFunctions(cdef->slotList, "slot", MethodSlot);
+ generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex);
//
// Build method array
//
- generateFunctions(cdef->methodList, "method", MethodMethod);
+ generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex);
//
// Build method version arrays
@@ -314,6 +341,15 @@ void Generator::generateCode()
}
//
+// Build method parameters array
+//
+ generateFunctionParameters(cdef->signalList, "signal");
+ generateFunctionParameters(cdef->slotList, "slot");
+ generateFunctionParameters(cdef->methodList, "method");
+ if (isConstructible)
+ generateFunctionParameters(cdef->constructorList, "constructor");
+
+//
// Build property array
//
generateProperties();
@@ -327,7 +363,7 @@ void Generator::generateCode()
// Build constructors array
//
if (isConstructible)
- generateFunctions(cdef->constructorList, "constructor", MethodConstructor);
+ generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex);
//
// Terminate data array
@@ -346,7 +382,7 @@ void Generator::generateCode()
QList<QByteArray> extraList;
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
- if (!isVariantType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') &&
+ if (!isBuiltinType(p.type) && !metaTypes.contains(p.type) && !p.type.contains('*') &&
!p.type.contains('<') && !p.type.contains('>')) {
int s = p.type.lastIndexOf("::");
if (s > 0) {
@@ -511,50 +547,29 @@ void Generator::registerFunctionStrings(const QList<FunctionDef>& list)
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
- QByteArray sig = f.name + '(';
- QByteArray arguments;
+ strreg(f.name);
+ if (!isBuiltinType(f.normalizedType))
+ strreg(f.normalizedType);
+ strreg(f.tag);
for (int j = 0; j < f.arguments.count(); ++j) {
const ArgumentDef &a = f.arguments.at(j);
- if (j) {
- sig += ",";
- arguments += ",";
- }
- sig += a.normalizedType;
- arguments += a.name;
+ if (!isBuiltinType(a.normalizedType))
+ strreg(a.normalizedType);
+ strreg(a.name);
}
- sig += ')';
-
- strreg(sig);
- strreg(arguments);
- strreg(f.normalizedType);
- strreg(f.tag);
}
}
-void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type)
+void Generator::generateFunctions(const QList<FunctionDef>& list, const char *functype, int type, int &paramsIndex)
{
if (list.isEmpty())
return;
- fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype);
+ fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype);
for (int i = 0; i < list.count(); ++i) {
const FunctionDef &f = list.at(i);
- QByteArray sig = f.name + '(';
- QByteArray arguments;
-
- for (int j = 0; j < f.arguments.count(); ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j) {
- sig += ",";
- arguments += ",";
- }
- sig += a.normalizedType;
- arguments += a.name;
- }
- sig += ')';
-
unsigned char flags = type;
if (f.access == FunctionDef::Private)
flags |= AccessPrivate;
@@ -576,8 +591,12 @@ void Generator::generateFunctions(const QList<FunctionDef>& list, const char *fu
flags |= MethodScriptable;
if (f.revision > 0)
flags |= MethodRevisioned;
- fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", stridx(sig),
- stridx(arguments), stridx(f.normalizedType), stridx(f.tag), flags);
+
+ int argc = f.arguments.count();
+ fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n",
+ stridx(f.name), argc, paramsIndex, stridx(f.tag), flags);
+
+ paramsIndex += 1 + argc * 2;
}
}
@@ -591,12 +610,51 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef>& list, const
}
}
+void Generator::generateFunctionParameters(const QList<FunctionDef>& list, const char *functype)
+{
+ if (list.isEmpty())
+ return;
+ fprintf(out, "\n // %ss: parameters\n", functype);
+ for (int i = 0; i < list.count(); ++i) {
+ const FunctionDef &f = list.at(i);
+ fprintf(out, " ");
+
+ // Types
+ for (int j = -1; j < f.arguments.count(); ++j) {
+ if (j > -1)
+ fputc(' ', out);
+ const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
+ if (isBuiltinType(typeName)) {
+ int type = nameToBuiltinType(typeName);
+ const char *valueString = metaTypeEnumValueString(type);
+ if (valueString)
+ fprintf(out, "QMetaType::%s", valueString);
+ else
+ fprintf(out, "%4d", type);
+ } else {
+ Q_ASSERT(!typeName.isEmpty());
+ fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(typeName));
+ }
+ fputc(',', out);
+ }
+
+ // Parameter names
+ for (int j = 0; j < f.arguments.count(); ++j) {
+ const ArgumentDef &arg = f.arguments.at(j);
+ fprintf(out, " %4d,", stridx(arg.name));
+ }
+
+ fprintf(out, "\n");
+ }
+}
+
void Generator::registerPropertyStrings()
{
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
strreg(p.name);
- strreg(p.type);
+ if (!isBuiltinType(p.type))
+ strreg(p.type);
}
}
@@ -611,11 +669,8 @@ void Generator::generateProperties()
for (int i = 0; i < cdef->propertyList.count(); ++i) {
const PropertyDef &p = cdef->propertyList.at(i);
uint flags = Invalid;
- if (!isVariantType(p.type)) {
+ if (!isBuiltinType(p.type))
flags |= EnumOrFlag;
- } else if (!isQRealType(p.type)) {
- flags |= qvariant_nameToType(p.type) << 24;
- }
if (!p.read.isEmpty())
flags |= Readable;
if (!p.write.isEmpty()) {
@@ -665,12 +720,20 @@ void Generator::generateProperties()
if (p.final)
flags |= Final;
- fprintf(out, " %4d, %4d, ",
- stridx(p.name),
- stridx(p.type));
- if (!(flags >> 24) && isQRealType(p.type))
- fprintf(out, "(QMetaType::QReal << 24) | ");
- fprintf(out, "0x%.8x,\n", flags);
+ fprintf(out, " %4d, ", stridx(p.name));
+
+ if (isBuiltinType(p.type)) {
+ int type = nameToBuiltinType(p.type);
+ const char *valueString = metaTypeEnumValueString(type);
+ if (valueString)
+ fprintf(out, "QMetaType::%s", valueString);
+ else
+ fprintf(out, "%4d", type);
+ } else {
+ fprintf(out, "0x%.8x | %d", IsUnresolvedType, stridx(p.type));
+ }
+
+ fprintf(out, ", 0x%.8x,\n", flags);
}
if(cdef->notifyableProperties) {
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index c5692f25ae..c85d24fd15 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -58,8 +58,9 @@ private:
void registerClassInfoStrings();
void generateClassInfos();
void registerFunctionStrings(const QList<FunctionDef> &list);
- void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type);
+ void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type, int &paramsIndex);
void generateFunctionRevisions(const QList<FunctionDef>& list, const char *functype);
+ void generateFunctionParameters(const QList<FunctionDef> &list, const char *functype);
void registerEnumStrings();
void generateEnums(int index);
void registerPropertyStrings();
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 385390d954..49fc29592d 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -819,8 +819,7 @@ void Moc::generate(FILE *out)
fprintf(out, "#include <QtCore/qobject.h>\n");
fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
- if (mustIncludeQMetaTypeH)
- fprintf(out, "#include <QtCore/qmetatype.h>\n");
+ fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
if (mustIncludeQPluginH)
fprintf(out, "#include <QtCore/qplugin.h>\n");
@@ -977,8 +976,6 @@ void Moc::createPropertyDef(PropertyDef &propDef)
type = "qlonglong";
else if (type == "ULongLong")
type = "qulonglong";
- else if (type == "qreal")
- mustIncludeQMetaTypeH = true;
propDef.type = type;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index aedb97b234..e20e29acb8 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -198,14 +198,13 @@ class Moc : public Parser
{
public:
Moc()
- : noInclude(false), generatedCode(false), mustIncludeQMetaTypeH(false), mustIncludeQPluginH(false)
+ : noInclude(false), generatedCode(false), mustIncludeQPluginH(false)
{}
QByteArray filename;
bool noInclude;
bool generatedCode;
- bool mustIncludeQMetaTypeH;
bool mustIncludeQPluginH;
QByteArray includePath;
QList<QByteArray> includeFiles;
diff --git a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
index f653e66bfd..60c8fdb2f2 100644
--- a/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
+++ b/tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp
@@ -603,15 +603,51 @@ void tst_QMetaMethod::method()
QCOMPARE(method.methodType(), methodType);
QCOMPARE(method.access(), access);
- QCOMPARE(method.methodSignature(), signature);
+ QVERIFY(!method.methodSignature().isEmpty());
+ if (method.methodSignature() != signature) {
+ // QMetaMethod should always produce a semantically equivalent signature
+ int signatureIndex = (methodType == QMetaMethod::Constructor)
+ ? mo->indexOfConstructor(method.methodSignature())
+ : mo->indexOfMethod(method.methodSignature());
+ QCOMPARE(signatureIndex, index);
+ }
+
+ QByteArray computedName = signature.left(signature.indexOf('('));
+ QCOMPARE(method.name(), computedName);
QCOMPARE(method.tag(), "");
- QCOMPARE(method.typeName(), returnTypeName.constData());
- QCOMPARE(QMetaType::type(method.typeName()), returnType);
+ QCOMPARE(method.returnType(), returnType);
+ if (QByteArray(method.typeName()) != returnTypeName) {
+ // QMetaMethod should always produce a semantically equivalent typename
+ QCOMPARE(QMetaType::type(method.typeName()), QMetaType::type(returnTypeName));
+ }
- QCOMPARE(method.parameterTypes(), parameterTypeNames);
+ if (method.parameterTypes() != parameterTypeNames) {
+ // QMetaMethod should always produce semantically equivalent typenames
+ QList<QByteArray> actualTypeNames = method.parameterTypes();
+ QCOMPARE(actualTypeNames.size(), parameterTypeNames.size());
+ for (int i = 0; i < parameterTypeNames.size(); ++i) {
+ QCOMPARE(QMetaType::type(actualTypeNames.at(i)),
+ QMetaType::type(parameterTypeNames.at(i)));
+ }
+ }
QCOMPARE(method.parameterNames(), parameterNames);
+
+ QCOMPARE(method.parameterCount(), parameterTypes.size());
+ for (int i = 0; i < parameterTypes.size(); ++i)
+ QCOMPARE(method.parameterType(i), parameterTypes.at(i));
+
+ {
+ QVector<int> actualParameterTypes(parameterTypes.size());
+ method.getParameterTypes(actualParameterTypes.data());
+ for (int i = 0; i < parameterTypes.size(); ++i)
+ QCOMPARE(actualParameterTypes.at(i), parameterTypes.at(i));
+ }
+
+ // Bogus indexes
+ QCOMPARE(method.parameterType(-1), 0);
+ QCOMPARE(method.parameterType(parameterTypes.size()), 0);
}
void tst_QMetaMethod::invalidMethod()