Long live Qt5 meta-object method/property descriptors

This commit introduces two significant changes to the meta-object
data format:

1) Meta-type information (QMetaType type/name) information is
stored directly in the meta-data for both properties and methods;
2) The original signature (string) of a method is no longer stored
in the meta-data, since it can be reconstructed from the method
name and parameter type info.

The motivation for this change is to enable direct access to method
names and type information (avoiding string-based lookup for types
if possible), since that's typically the information language
bindings (e.g. QML) need. (moc already had all the desired
information about methods, but it threw it away!)

This change keeps support for the older (6 and below) meta-object
revisions, but the support will be removed after a short grace
period.

The following public QMetaMethod functions have been added:

name() : QByteArray
returnType() : int
parameterCount() : int
parameterType(int index) : int

The following internal QMetaMethod function has been added:

getParameterTypes(int *types) : void

This commit extends the meta-method data to include explicit
type/name data for methods. The new data follows the existing
(5-word) method descriptors in the meta-data. The method descriptor
format was modified to enable this. First, the descriptor now
contains the meta-data index where the method's type/name information
can be found. Second, the descriptor contains the number of
parameters. Third, the descriptor has a reference to the name of the
method, not the full signature.

Each entry of a method's type/name array contains either the type id
(if it could be determined at meta-object definition time), or a
reference to the name of the type (so that the type id can be
resolved at runtime).

Lastly, instead of storing the method parameter names as a
comma-separated list that needs to be parsed at runtime (which was
how it was done prior to this commit), the names are now stored as
separate entries in the meta-object string table, and their indexes
are stored immediately after the method type info array. Hence,
parameter names can be queried through the public API without
parsing/allocating/copying, too.

Task-number: QTBUG-24154
Change-Id: Idb7ab81f12d4bfd658b74e18a0fce594f580cba3
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
This commit is contained in:
Kent Hansen 2012-02-19 00:15:00 +01:00 committed by Qt by Nokia
parent 96f2365cf4
commit f95181c7bb
10 changed files with 1065 additions and 172 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;
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;
smeta = sender->metaObject();
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, true);
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);
}
}
}
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 (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();
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();
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);

View File

@ -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);

View File

@ -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
@ -313,6 +340,15 @@ void Generator::generateCode()
generateFunctionRevisions(cdef->methodList, "method");
}
//
// 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
//
@ -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) {

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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()