diff options
-rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 706 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobject.h | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobject_p.h | 74 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 215 | ||||
-rw-r--r-- | src/corelib/kernel/qobjectdefs.h | 2 | ||||
-rw-r--r-- | src/tools/moc/generator.cpp | 183 | ||||
-rw-r--r-- | src/tools/moc/generator.h | 3 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 5 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qmetamethod/tst_qmetamethod.cpp | 44 |
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 ¶msIndex) { 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 ¶msIndex); 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() |