Skip to content

Commit

Permalink
Fix QMetaObject naming of class enum flag
Browse files Browse the repository at this point in the history
Adds an enumName to QMetaEnum to carry the name of the enum since for
flags that doesn't match the name of the Qt type, but is needed if the
flag is scoped.

Change-Id: I1c0f77eb9e40e6fd1eb6a59bea77caf0f33fcf43
Reviewed-by: Olivier Goffart (Woboq GmbH) <[email protected]>
  • Loading branch information
Allan Sandfeld Jensen committed Aug 11, 2018
1 parent 8f58e13 commit 1c623bc
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 61 deletions.
4 changes: 2 additions & 2 deletions src/corelib/io/qdebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ QDebug qt_QMetaEnum_debugOperator(QDebug &dbg, int value, const QMetaObject *met
if (const char *scope = me.scope())
dbg << scope << "::";
if (me.isScoped())
dbg << name << "::";
dbg << me.enumName() << "::";
dbg << key;
} else {
dbg << meta->className() << "::" << name << "(" << value << ")";
Expand All @@ -964,7 +964,7 @@ QDebug qt_QMetaEnum_flagDebugOperator(QDebug &debug, quint64 value, const QMetaO
const QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
if (const char *scope = me.scope())
debug << scope << "::";
debug << me.name() << ">(" << me.valueToKeys(value) << ')';
debug << me.enumName() << ">(" << me.valueToKeys(value) << ')';
return debug;
}
#endif // !QT_NO_QOBJECT
Expand Down
92 changes: 70 additions & 22 deletions src/corelib/kernel/qmetaobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,24 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co
int QMetaObject::indexOfEnumerator(const char *name) const
{
const QMetaObject *m = this;
const int intsPerEnum = priv(m->d.data)->revision >= 8 ? 5 : 4;
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->enumeratorCount - 1; i >= 0; --i) {
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + 4*i]);
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + intsPerEnum * i]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->enumeratorOffset();
return i;
}
}
m = m->d.superdata;
}
// Check alias names:
m = this;
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = d->enumeratorCount - 1; i >= 0; --i) {
const char *prop = rawStringData(m, m->d.data[d->enumeratorData + intsPerEnum * i + 1]);
if (name[0] == prop[0] && strcmp(name + 1, prop + 1) == 0) {
i += m->enumeratorOffset();
return i;
Expand Down Expand Up @@ -1086,10 +1100,11 @@ QMetaEnum QMetaObject::enumerator(int index) const
if (i < 0 && d.superdata)
return d.superdata->enumerator(index);

const int intsPerEnum = priv(d.data)->revision >= 8 ? 5 : 4;
QMetaEnum result;
if (i >= 0 && i < priv(d.data)->enumeratorCount) {
result.mobj = this;
result.handle = priv(d.data)->enumeratorData + 4*i;
result.handle = priv(d.data)->enumeratorData + intsPerEnum * i;
}
return result;
}
Expand Down Expand Up @@ -2552,12 +2567,15 @@ bool QMetaMethod::invokeOnGadget(void* gadget, QGenericReturnArgument returnValu
*/

/*!
Returns the name of the enumerator (without the scope).
Returns the name of the type (without the scope).
For example, the Qt::Key enumeration has \c
Key as the type name and \l Qt as the scope.
For example, the Qt::AlignmentFlag enumeration has \c
AlignmentFlag as the name and \l Qt as the scope.
For flags this returns the name of the flag type, not the
name of the enum type.
\sa isValid(), scope()
\sa isValid(), scope(), enumName()
*/
const char *QMetaEnum::name() const
{
Expand All @@ -2566,6 +2584,28 @@ const char *QMetaEnum::name() const
return rawStringData(mobj, mobj->d.data[handle]);
}

/*!
Returns the enum name of the flag (without the scope).
For example, the Qt::AlignmentFlag flag has \c
AlignmentFlag as the enum name, but \c Alignment as as the type name.
Non flag enums has the same type and enum names.
Enum names have the same scope as the type name.
\since 5.12
\sa isValid(), name()
*/
const char *QMetaEnum::enumName() const
{
if (!mobj)
return 0;
const bool rev8p = priv(mobj->d.data)->revision >= 8;
if (rev8p)
return rawStringData(mobj, mobj->d.data[handle + 1]);
return name();
}

/*!
Returns the number of keys.
Expand All @@ -2575,10 +2615,10 @@ int QMetaEnum::keyCount() const
{
if (!mobj)
return 0;
return mobj->d.data[handle + 2];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
return mobj->d.data[handle + offset];
}


/*!
Returns the key with the given \a index, or 0 if no such key exists.
Expand All @@ -2588,8 +2628,9 @@ const char *QMetaEnum::key(int index) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
if (index >= 0 && index < count)
return rawStringData(mobj, mobj->d.data[data + 2*index]);
return 0;
Expand All @@ -2605,8 +2646,9 @@ int QMetaEnum::value(int index) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
if (index >= 0 && index < count)
return mobj->d.data[data + 2*index + 1];
return -1;
Expand All @@ -2624,7 +2666,8 @@ int QMetaEnum::value(int index) const
*/
bool QMetaEnum::isFlag() const
{
return mobj && mobj->d.data[handle + 1] & EnumIsFlag;
const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1;
return mobj && mobj->d.data[handle + offset] & EnumIsFlag;
}

/*!
Expand All @@ -2635,7 +2678,8 @@ bool QMetaEnum::isFlag() const
*/
bool QMetaEnum::isScoped() const
{
return mobj && mobj->d.data[handle + 1] & EnumIsScoped;
const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1;
return mobj && mobj->d.data[handle + offset] & EnumIsScoped;
}

/*!
Expand Down Expand Up @@ -2677,8 +2721,9 @@ int QMetaEnum::keyToValue(const char *key, bool *ok) const
scope = s - key - 1;
key += scope + 2;
}
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (int i = 0; i < count; ++i) {
const QByteArray className = stringData(mobj, priv(mobj->d.data)->className);
if ((!scope || (className.size() == int(scope) && strncmp(qualified_key, className.constData(), scope) == 0))
Expand All @@ -2703,8 +2748,9 @@ const char* QMetaEnum::valueToKey(int value) const
{
if (!mobj)
return 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (int i = 0; i < count; ++i)
if (value == (int)mobj->d.data[data + 2*i + 1])
return rawStringData(mobj, mobj->d.data[data + 2*i]);
Expand Down Expand Up @@ -2735,8 +2781,9 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
return 0;
// ### TODO write proper code: do not allocate memory, so we can go nothrow
int value = 0;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
for (const QStringRef &untrimmed : splitKeys) {
const QStringRef trimmed = untrimmed.trimmed();
QByteArray qualified_key = trimmed.toLatin1();
Expand Down Expand Up @@ -2778,8 +2825,9 @@ QByteArray QMetaEnum::valueToKeys(int value) const
QByteArray keys;
if (!mobj)
return keys;
int count = mobj->d.data[handle + 2];
int data = mobj->d.data[handle + 3];
const int offset = priv(mobj->d.data)->revision >= 8 ? 3 : 2;
int count = mobj->d.data[handle + offset];
int data = mobj->d.data[handle + offset + 1];
int v = value;
// reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
for (int i = count - 1; i >= 0; --i) {
Expand Down
1 change: 1 addition & 0 deletions src/corelib/kernel/qmetaobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class Q_CORE_EXPORT QMetaEnum
Q_DECL_CONSTEXPR inline QMetaEnum() : mobj(nullptr), handle(0) {}

const char *name() const;
const char *enumName() const;
bool isFlag() const;
bool isScoped() const;

Expand Down
3 changes: 2 additions & 1 deletion src/corelib/kernel/qmetaobject_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ class QMutex;
struct QMetaObjectPrivate
{
// revision 7 is Qt 5.0 everything lower is not supported
enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
// revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus

int revision;
int className;
Expand Down
49 changes: 40 additions & 9 deletions src/corelib/kernel/qmetaobjectbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,12 @@ class QMetaEnumBuilderPrivate
{
public:
QMetaEnumBuilderPrivate(const QByteArray& _name)
: name(_name), isFlag(false), isScoped(false)
: name(_name), enumName(_name), isFlag(false), isScoped(false)
{
}

QByteArray name;
QByteArray enumName;
bool isFlag;
bool isScoped;
QList<QByteArray> keys;
Expand Down Expand Up @@ -637,6 +638,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name)
QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
{
QMetaEnumBuilder en = addEnumerator(prototype.name());
en.setEnumName(prototype.enumName());
en.setIsFlag(prototype.isFlag());
en.setIsScoped(prototype.isScoped());
int count = prototype.keyCount();
Expand Down Expand Up @@ -1216,7 +1218,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
- int(d->methods.size()) // return "parameters" don't have names
- int(d->constructors.size()); // "this" parameters don't have names
if (buf) {
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QMetaObjectBuilder should generate the same version as moc");
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "QMetaObjectBuilder should generate the same version as moc");
pmeta->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags;
pmeta->className = 0; // Class name is always the first string.
Expand Down Expand Up @@ -1244,7 +1246,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,

pmeta->enumeratorCount = int(d->enumerators.size());
pmeta->enumeratorData = dataIndex;
dataIndex += 4 * int(d->enumerators.size());
dataIndex += 5 * int(d->enumerators.size());

pmeta->constructorCount = int(d->constructors.size());
pmeta->constructorData = dataIndex;
Expand All @@ -1261,7 +1263,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
dataIndex += int(d->properties.size());
if (hasRevisionedProperties)
dataIndex += int(d->properties.size());
dataIndex += 4 * int(d->enumerators.size());
dataIndex += 5 * int(d->enumerators.size());
dataIndex += 5 * int(d->constructors.size());
}

Expand Down Expand Up @@ -1410,15 +1412,17 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
Q_ASSERT(!buf || dataIndex == pmeta->enumeratorData);
for (const auto &enumerator : d->enumerators) {
int name = strings.enter(enumerator.name);
int enumName = strings.enter(enumerator.enumName);
int isFlag = enumerator.isFlag ? EnumIsFlag : 0;
int isScoped = enumerator.isScoped ? EnumIsScoped : 0;
int count = enumerator.keys.size();
int enumOffset = enumIndex;
if (buf) {
data[dataIndex] = name;
data[dataIndex + 1] = isFlag | isScoped;
data[dataIndex + 2] = count;
data[dataIndex + 3] = enumOffset;
data[dataIndex + 1] = enumName;
data[dataIndex + 2] = isFlag | isScoped;
data[dataIndex + 3] = count;
data[dataIndex + 4] = enumOffset;
}
for (int key = 0; key < count; ++key) {
int keyIndex = strings.enter(enumerator.keys[key]);
Expand All @@ -1427,7 +1431,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
data[enumOffset++] = enumerator.values[key];
}
}
dataIndex += 4;
dataIndex += 5;
enumIndex += 2 * count;
}

Expand Down Expand Up @@ -2599,7 +2603,7 @@ QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const
*/

/*!
Returns the name of the enumerator (without the scope).
Returns the type name of the enumerator (without the scope).
*/
QByteArray QMetaEnumBuilder::name() const
{
Expand All @@ -2610,6 +2614,33 @@ QByteArray QMetaEnumBuilder::name() const
return QByteArray();
}

/*!
Returns the enum name of the enumerator (without the scope).
\since 5.12
*/
QByteArray QMetaEnumBuilder::enumName() const
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
return d->enumName;
else
return QByteArray();
}

/*!
Sets this enumerator to have the enum name \c alias.
\since 5.12
\sa isFlag(), enumName()
*/
void QMetaEnumBuilder::setEnumName(const QByteArray &alias)
{
QMetaEnumBuilderPrivate *d = d_func();
if (d)
d->enumName = alias;
}

/*!
Returns \c true if this enumerator is used as a flag; otherwise returns
false.
Expand Down
3 changes: 3 additions & 0 deletions src/corelib/kernel/qmetaobjectbuilder_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ class Q_CORE_EXPORT QMetaEnumBuilder

QByteArray name() const;

QByteArray enumName() const;
void setEnumName(const QByteArray &alias);

bool isFlag() const;
void setIsFlag(bool value);

Expand Down
2 changes: 1 addition & 1 deletion src/dbus/qdbusmetaobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
- methods.count(); // ditto

QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 7, "QtDBus meta-object generator should generate the same version as moc");
Q_STATIC_ASSERT_X(QMetaObjectPrivate::OutputRevision == 8, "QtDBus meta-object generator should generate the same version as moc");
header->revision = QMetaObjectPrivate::OutputRevision;
header->className = 0;
header->classInfoCount = 0;
Expand Down
Loading

0 comments on commit 1c623bc

Please sign in to comment.