summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Stottlemyer <bstottle@ford.com>2019-05-14 20:51:16 -0400
committerBrett Stottlemyer <bstottle@ford.com>2019-05-17 20:17:29 +0000
commit91f83125dd403878c989be4098cc3a35eb5ba06f (patch)
tree6a15a35bb32ebc745a3bd1f08b88c2c67d0496cd
parente520e4fd777350673d5022982481f82672fea6ff (diff)
More fixes for (dynamic) enums in signals and slots
This addresses two larger issues with enums and several smaller fixes. First, unlike the recent fix for properties, we need to register enums for queued connections to work and get signal/slot updates over QtRO to work. This change adds said registration. Second, enums are identified with the class they are defined in, so passing updates through a dynamic object requires converting the typenames. The templated enableRemoting methods become interesting here, as the class name depends on the type passed as a template parameter. This change also updates the repc output so enums are properly resolved via the templates. Smaller fixes include updates to some tests and several places where enums were converted to/from int. Note: we need (and have always needed) to convert enums to ints, since the class name is passed as part of the variant serialization which cannot be changed without major digging into qvariant and QDataStream serialization internals. Change-Id: I0a77f85df6a400a7a44394a05c9c2401bee4e4a8 Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/remoteobjects/qremoteobjectdynamicreplica.cpp1
-rw-r--r--src/remoteobjects/qremoteobjectnode.cpp74
-rw-r--r--src/remoteobjects/qremoteobjectpacket.cpp30
-rw-r--r--src/remoteobjects/qremoteobjectpacket_p.h9
-rw-r--r--src/remoteobjects/qremoteobjectsource.cpp4
-rw-r--r--src/remoteobjects/qremoteobjectsource.h79
-rw-r--r--src/remoteobjects/qremoteobjectsource_p.h1
-rw-r--r--src/remoteobjects/qremoteobjectsourceio.cpp13
-rw-r--r--tests/auto/integration/tst_integration.cpp5
-rw-r--r--tests/auto/integration_external/client/main.cpp4
-rw-r--r--tests/auto/integration_multiprocess/client/main.cpp4
-rw-r--r--tests/auto/proxy_multiprocess/client/main.cpp16
-rw-r--r--tests/auto/proxy_multiprocess/server/main.cpp1
-rw-r--r--tests/auto/proxy_multiprocess/server/mytestserver.cpp8
-rw-r--r--tests/auto/proxy_multiprocess/server/mytestserver.h1
-rw-r--r--tests/auto/proxy_multiprocess/subclass.rep11
-rw-r--r--tools/repc/repcodegenerator.cpp27
17 files changed, 238 insertions, 50 deletions
diff --git a/src/remoteobjects/qremoteobjectdynamicreplica.cpp b/src/remoteobjects/qremoteobjectdynamicreplica.cpp
index 58b8778..f778c3a 100644
--- a/src/remoteobjects/qremoteobjectdynamicreplica.cpp
+++ b/src/remoteobjects/qremoteobjectdynamicreplica.cpp
@@ -171,6 +171,7 @@ int QRemoteObjectDynamicReplica::qt_metacall(QMetaObject::Call call, int id, voi
id = -1;
} else if (call == QMetaObject::InvokeMetaMethod) {
if (id < impl->m_numSignals) {
+ qCDebug(QT_REMOTEOBJECT) << "DynamicReplica Activate" << impl->m_metaObject->method(saved_id).methodSignature();
// signal relay from Source world to Replica
QMetaObject::activate(this, impl->m_metaObject, id, argv);
diff --git a/src/remoteobjects/qremoteobjectnode.cpp b/src/remoteobjects/qremoteobjectnode.cpp
index d241e15..2c88983 100644
--- a/src/remoteobjects/qremoteobjectnode.cpp
+++ b/src/remoteobjects/qremoteobjectnode.cpp
@@ -118,6 +118,42 @@ static void GadgetLoadOperator(QDataStream &in, void *data)
in >> prop;
}
+// Like the Q_GADGET static methods above, we need constructor/destructor methods
+// in order to use dynamically defined enums with QVariant or as signal/slot
+// parameters (i.e., the queued connection mechanism, which QtRO leverages).
+//
+// We will need the enum methods to support different sizes when typed scope enum
+// support is added, so might as well use that now.
+template<typename T>
+static void EnumDestructor(void *ptr)
+{
+ static_cast<T*>(ptr)->~T();
+}
+
+template<typename T>
+static void *EnumConstructor(void *where, const void *copy)
+{
+ T *ret = where ? new(where) T : new T;
+ if (copy)
+ *ret = *static_cast<const T*>(copy);
+ return ret;
+}
+
+// Not used, but keeping these in case we end up with a need for save/load.
+template<typename T>
+static void EnumSaveOperator(QDataStream & out, const void *data)
+{
+ const T value = *static_cast<const T *>(data);
+ out << value;
+}
+
+template<typename T>
+static void EnumLoadOperator(QDataStream &in, void *data)
+{
+ T value = *static_cast<T *>(data);
+ in >> value;
+}
+
static QString name(const QMetaObject * const mobj)
{
const int ind = mobj->indexOfClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE);
@@ -728,16 +764,18 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec
builder.setSuperClass(&QRemoteObjectReplica::staticMetaObject);
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
- QString type;
+ QString typeString;
+ QByteArray type;
quint32 numEnums = 0;
quint32 numGadgets = 0;
quint32 numSignals = 0;
quint32 numMethods = 0;
quint32 numProperties = 0;
- in >> type;
- builder.addClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE, type.toLatin1());
- builder.setClassName(type.toLatin1());
+ in >> typeString;
+ type = typeString.toLatin1();
+ builder.addClassInfo(QCLASSINFO_REMOTEOBJECT_TYPE, type);
+ builder.setClassName(type);
in >> numEnums;
for (quint32 i = 0; i < numEnums; ++i) {
@@ -812,7 +850,28 @@ QMetaObject *QRemoteObjectMetaObjectManager::addDynamicType(IoDeviceBase *connec
}
auto meta = builder.toMetaObject();
- dynamicTypes.insert(type, meta);
+ // Our type likely has enumerations from the inherited base classes, such as the Replica State
+ // We only want to register the new enumerations, and since we just added them, we know they
+ // are the last indices. Thus a backwards count seems most efficient.
+ const int totalEnumCount = meta->enumeratorCount();
+ for (int i = numEnums; i > 0; i--) {
+ auto const enumMeta = meta->enumerator(totalEnumCount - i);
+ const QByteArray registeredName = QByteArray(type).append("::").append(enumMeta.name());
+ // When we add support for enum classes, we will need to set this to something like
+ // QByteArray(enumClass).append("::").append(enumMeta.name()) when enumMeta.isScoped() is true.
+ // That is a new feature, though.
+ if (QMetaType::isRegistered(QMetaType::type(registeredName)))
+ continue;
+ const auto flags = QMetaType::IsEnumeration | QMetaType::NeedsConstruction | QMetaType::NeedsDestruction;
+ int enumTypeId = -1;
+ int size = 4; // This could have different values once we support typed scoped enums
+ enumTypeId = QMetaType::registerType(registeredName.constData(), nullptr, nullptr,
+ &EnumDestructor<qint32>, &EnumConstructor<qint32>, size, flags, nullptr);
+ // Below line will register load/save if needed.
+ // QMetaType::registerStreamOperators(enumTypeId, &EnumSaveOperator<qint32>, &EnumLoadOperator<qint32>);
+ qCDebug(QT_REMOTEOBJECT) << "Registering new enum with id" << enumTypeId << enumMeta.enumName() << enumMeta.name() << enumMeta.scope();
+ }
+ dynamicTypes.insert(typeString, meta);
return meta;
}
@@ -1220,8 +1279,11 @@ void QRemoteObjectNodePrivate::onClientRead(QObject *obj)
for (int i = 0; i < rxArgs.size(); i++) {
if (signal.parameterType(i) == QMetaType::QVariant)
param[i + 1] = const_cast<void*>(reinterpret_cast<const void*>(&rxArgs.at(i)));
- else
+ else {
+ if (QMetaType::typeFlags(signal.parameterType(i)).testFlag(QMetaType::IsEnumeration))
+ rxArgs[i].convert(signal.parameterType(i));
param[i + 1] = const_cast<void *>(rxArgs.at(i).data());
+ }
}
} else if (propertyIndex != -1) {
param.resize(2);
diff --git a/src/remoteobjects/qremoteobjectpacket.cpp b/src/remoteobjects/qremoteobjectpacket.cpp
index 283d21b..e5c6213 100644
--- a/src/remoteobjects/qremoteobjectpacket.cpp
+++ b/src/remoteobjects/qremoteobjectpacket.cpp
@@ -286,12 +286,14 @@ void recurseForGadgets(GadgetsData &gadgets, const QRemoteObjectSourceBase *sour
void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
{
const SourceApiMap *api = source->m_api;
- bool dynamic = source->m_api->isDynamic();
- const QByteArray classname(source->m_api->typeName().toLatin1());
- const QByteArray sourcename = QByteArray(classname).append("Source");
- auto replace = [&classname, &sourcename, dynamic](QByteArray &name) {
- if (!dynamic) // Compiled classes likely have <ClassNameSource> that should be <ClassName>
- name.replace(sourcename, classname);
+ const QByteArray desiredClassName(api->typeName().toLatin1());
+ const QByteArray originalClassName = api->className();
+ // The dynamic class will be called typeName on the receiving side of this definition
+ // However, there are types like enums that have the QObject's class name. Replace()
+ // will convert a parameter such as "ParentClassSource::MyEnum" to "ParentClass::MyEnum"
+ // so the type can be properly resolved and registered.
+ auto replace = [&originalClassName, &desiredClassName](QByteArray &name) {
+ name.replace(originalClassName, desiredClassName);
};
ds << source->m_api->typeName();
@@ -370,11 +372,15 @@ void serializeDefinition(QDataStream &ds, const QRemoteObjectSourceBase *source)
for (int i = 0; i < numMethods; ++i) {
const int index = api->sourceMethodIndex(i);
Q_ASSERT(index >= 0);
+ auto signature = api->methodSignature(i);
+ replace(signature);
+ auto typeName = api->typeName(i);
+ replace(typeName);
#ifdef QTRO_VERBOSE_PROTOCOL
- qDebug() << " Slot" << i << "(signature =" << api->methodSignature(i) << "parameter names =" << api->methodParameterNames(i) << "return type =" << api->typeName(i) << ")";
+ qDebug() << " Slot" << i << "(signature =" << signature << "parameter names =" << api->methodParameterNames(i) << "return type =" << typeName << ")";
#endif
- ds << api->methodSignature(i);
- ds << api->typeName(i);
+ ds << signature;
+ ds << typeName;
ds << api->methodParameterNames(i);
}
@@ -567,8 +573,7 @@ QRO_::QRO_(const QVariant &value)
QDataStream &operator<<(QDataStream &stream, const QRO_ &info)
{
stream << info.name << info.typeName << (quint8)(info.type) << info.classDefinition << info.isNull;
- qCDebug(QT_REMOTEOBJECT) << "Serializing QRO_" << info.name << info.typeName << (info.type == ObjectType::CLASS ? "Class" : info.type == ObjectType::MODEL ? "Model" : "Gadget")
- << (info.isNull ? "nullptr" : "valid pointer") << (info.classDefinition.isEmpty() ? "no definitions" : "with definitions");
+ qCDebug(QT_REMOTEOBJECT) << "Serializing " << info;
// info.parameters will be filled in by serializeProperty
return stream;
}
@@ -578,8 +583,7 @@ QDataStream &operator>>(QDataStream &stream, QRO_ &info)
quint8 tmpType;
stream >> info.name >> info.typeName >> tmpType >> info.classDefinition >> info.isNull;
info.type = static_cast<ObjectType>(tmpType);
- qCDebug(QT_REMOTEOBJECT) << "Deserializing QRO_" << info.name << info.typeName << (info.isNull ? "nullptr" : "valid pointer")
- << (info.classDefinition.isEmpty() ? "no definitions" : "with definitions");
+ qCDebug(QT_REMOTEOBJECT) << "Deserializing " << info;
if (!info.isNull)
stream >> info.parameters;
return stream;
diff --git a/src/remoteobjects/qremoteobjectpacket_p.h b/src/remoteobjects/qremoteobjectpacket_p.h
index 542f998..d0292b4 100644
--- a/src/remoteobjects/qremoteobjectpacket_p.h
+++ b/src/remoteobjects/qremoteobjectpacket_p.h
@@ -72,6 +72,8 @@ class QRemoteObjectRootSource;
namespace QRemoteObjectPackets {
+Q_NAMESPACE
+
class DataStreamPacket;
struct ObjectInfo
@@ -100,6 +102,7 @@ inline QDataStream& operator>>(QDataStream &stream, ObjectInfo &info)
typedef QVector<ObjectInfo> ObjectInfoList;
enum class ObjectType : quint8 { CLASS, MODEL, GADGET };
+Q_ENUM_NS(ObjectType)
// Use a short name, as QVariant::save writes the name every time a qvariant of
// this type is serialized
@@ -118,9 +121,9 @@ public:
inline QDebug operator<<(QDebug dbg, const QRO_ &info)
{
- dbg.nospace() << "QRO_(name: " << info.name << "typeName: " << info.typeName << "type: " << (info.type == ObjectType::CLASS ? "Class" : "Model")
- << ", valid: " << (info.isNull ? "true" : "false")
- << ", paremeters: {" << info.parameters <<")";
+ dbg.nospace() << "QRO_(name: " << info.name << ", typeName: " << info.typeName << ", type: " << info.type
+ << ", valid: " << (info.isNull ? "true" : "false") << ", paremeters: {" << info.parameters <<")"
+ << (info.classDefinition.isEmpty() ? " no definitions)" : " with definitions)");
return dbg.space();
}
diff --git a/src/remoteobjects/qremoteobjectsource.cpp b/src/remoteobjects/qremoteobjectsource.cpp
index 8b8b280..52bd089 100644
--- a/src/remoteobjects/qremoteobjectsource.cpp
+++ b/src/remoteobjects/qremoteobjectsource.cpp
@@ -365,7 +365,9 @@ void QRemoteObjectSourceBase::handleMetaCall(int index, QMetaObject::Call call,
}
qCDebug(QT_REMOTEOBJECT) << "# Listeners" << d->m_listeners.length();
- qCDebug(QT_REMOTEOBJECT) << "Invoke args:" << m_object << call << index << *marshalArgs(index, a);
+ qCDebug(QT_REMOTEOBJECT) << "Invoke args:" << m_object
+ << (call == 0 ? QLatin1String("InvokeMetaMethod") : QStringLiteral("Non-invoked call: %d").arg(call))
+ << m_api->signalSignature(index) << *marshalArgs(index, a);
serializeInvokePacket(d->m_packet, name(), call, index, *marshalArgs(index, a), -1, propertyIndex);
d->m_packet.baseAddress = 0;
diff --git a/src/remoteobjects/qremoteobjectsource.h b/src/remoteobjects/qremoteobjectsource.h
index f2993bd..61346df 100644
--- a/src/remoteobjects/qremoteobjectsource.h
+++ b/src/remoteobjects/qremoteobjectsource.h
@@ -99,6 +99,56 @@ static inline void qtro_method_test(Func1, Func2)
"Return types are not compatible.");
}
+// The stringData, methodMatch and QMetaObjectPrivate methods are modified versions of the code
+// from qmetaobject_p.h/qmetaobject.cpp. The modifications are based on our custom need to match
+// a method name that comes from the .rep file.
+// The QMetaObjectPrivate struct should only have members appended to maintain binary compatibility,
+// so we should be fine with only the listed version with the fields we use.
+inline const QByteArray apiStringData(const QMetaObject *mo, int index)
+{
+ const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) };
+ return data;
+}
+
+inline bool apiMethodMatch(const QMetaObject *m, int handle,
+ const QByteArray &name, int argc,
+ const int *types)
+{
+ if (int(m->d.data[handle + 1]) != argc)
+ return false;
+ if (apiStringData(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 (typeInfo & 0x80000000) { // Custom/named type, compare names
+ const char *t = QMetaType::typeName(types[i]);
+ const auto type = QByteArray::fromRawData(t, qstrlen(t));
+ if (type != apiStringData(m, typeInfo & 0x7FFFFFFF))
+ return false;
+ } else if (types[i] != int(typeInfo))
+ return false;
+ }
+ return true;
+}
+
+struct QMetaObjectPrivate
+{
+ // revision 7 is Qt 5.0 everything lower is not supported
+ // 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;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+ int signalCount;
+};
+
template <class ObjectType, typename Func1, typename Func2>
static inline int qtro_method_index(Func1, Func2, const char *methodName, int *count, int const **types)
{
@@ -114,7 +164,33 @@ static inline int qtro_method_index(Func1, Func2, const char *methodName, int *c
"Return types are not compatible.");
*count = Type2::ArgumentCount;
*types = QtPrivate::ConnectionTypes<typename Type2::Arguments>::types();
- return ObjectType::staticMetaObject.indexOfMethod(methodName);
+
+ int result = ObjectType::staticMetaObject.indexOfMethod(methodName);
+ if (result >= 0)
+ return result;
+ // We can have issues, specifically with enums, since the compiler can infer the class. Since
+ // indexOfMethod() is doing string comparisons for registered types, "MyEnum" and "MyClass::MyEnum"
+ // won't match.
+ // Below is similar to QMetaObject->indexOfMethod, but template magic has already matched parameter
+ // types, so we need to find a match for the API method name + parameters. Neither approach works
+ // 100%, as the below code doesn't match a parameter of type "size_t" (which the template match
+ // identifies as "ulong"). These subtleties can cause the below string comparison fails.
+ // There is no known case that would fail both methods.
+ // TODO: is there a way to make this a constexpr so a failure is detected at compile time?
+ int nameLength = strchr(methodName, '(') - methodName;
+ const auto name = QByteArray::fromRawData(methodName, nameLength);
+ for (const QMetaObject *m = &ObjectType::staticMetaObject; m; m = m->d.superdata) {
+ const auto priv = reinterpret_cast<const QMetaObjectPrivate*>(m->d.data);
+ int i = (priv->methodCount - 1);
+ const int end = priv->signalCount;
+ for (; i >= end; --i) {
+ int handle = priv->methodData + 5*i;
+ if (apiMethodMatch(m, handle, name, *count, *types))
+ return i + m->methodOffset();
+ }
+ }
+ qWarning() << "No matching method for" << methodName << "in the provided metaclass" << ObjectType::staticMetaObject.className();
+ return -1;
}
template <class ObjectType>
@@ -146,6 +222,7 @@ public:
virtual ~SourceApiMap() {}
virtual QString name() const = 0;
virtual QString typeName() const = 0;
+ virtual QByteArray className() const { return typeName().toLatin1().append("Source"); }
virtual int enumCount() const = 0;
virtual int propertyCount() const = 0;
virtual int signalCount() const = 0;
diff --git a/src/remoteobjects/qremoteobjectsource_p.h b/src/remoteobjects/qremoteobjectsource_p.h
index 0fdd3c8..4ed4c5d 100644
--- a/src/remoteobjects/qremoteobjectsource_p.h
+++ b/src/remoteobjects/qremoteobjectsource_p.h
@@ -134,6 +134,7 @@ public:
~DynamicApiMap() override {}
QString name() const override { return m_name; }
QString typeName() const override { return m_typeName; }
+ QByteArray className() const override { return QByteArray(m_metaObject->className()); }
int enumCount() const override { return m_enumCount; }
int propertyCount() const override { return m_properties.size(); }
int signalCount() const override { return m_signals.size(); }
diff --git a/src/remoteobjects/qremoteobjectsourceio.cpp b/src/remoteobjects/qremoteobjectsourceio.cpp
index bde010b..35f3bfd 100644
--- a/src/remoteobjects/qremoteobjectsourceio.cpp
+++ b/src/remoteobjects/qremoteobjectsourceio.cpp
@@ -235,8 +235,15 @@ void QRemoteObjectSourceIo::onServerRead(QObject *conn)
}
if (source->m_api->isAdapterMethod(index))
qRODebug(this) << "Adapter (method) Invoke-->" << m_rxName << source->m_adapter->metaObject()->method(resolvedIndex).name();
- else
- qRODebug(this) << "Source (method) Invoke-->" << m_rxName << source->m_object->metaObject()->method(resolvedIndex).name();
+ else {
+ qRODebug(this) << "Source (method) Invoke-->" << m_rxName << source->m_object->metaObject()->method(resolvedIndex).methodSignature();
+ auto method = source->m_object->metaObject()->method(resolvedIndex);
+ const int parameterCount = method.parameterCount();
+ for (int i = 0; i < parameterCount; i++) {
+ if (QMetaType::typeFlags(method.parameterType(i)).testFlag(QMetaType::IsEnumeration))
+ m_rxArgs[i].convert(method.parameterType(i));
+ }
+ }
int typeId = QMetaType::type(source->m_api->typeName(index).constData());
if (!QMetaType(typeId).sizeOf())
typeId = QVariant::Invalid;
@@ -260,6 +267,8 @@ void QRemoteObjectSourceIo::onServerRead(QObject *conn)
watcher->deleteLater();
});
} else {
+ if (QMetaType::typeFlags(returnValue.userType()).testFlag(QMetaType::IsEnumeration))
+ returnValue = QVariant::fromValue<qint32>(returnValue.toInt());
serializeInvokeReplyPacket(m_packet, m_rxName, serialId, returnValue);
connection->write(m_packet.array, m_packet.size);
}
diff --git a/tests/auto/integration/tst_integration.cpp b/tests/auto/integration/tst_integration.cpp
index af5cba0..7f39381 100644
--- a/tests/auto/integration/tst_integration.cpp
+++ b/tests/auto/integration/tst_integration.cpp
@@ -345,8 +345,9 @@ private slots:
// set property on the replica (test property change packet)
{
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumChanged(TestClassReplica::ClassEnum)));
+ QVERIFY(spy.isValid());
tc_rep->pushClassEnum(TestClassReplica::Two);
- QVERIFY(spy.wait());
+ QVERIFY(spy.count() || spy.wait());
QCOMPARE((qint32)tc.classEnum(), (qint32)tc_rep->classEnum());
}
@@ -405,7 +406,7 @@ private slots:
QSignalSpy spy(tc_rep.data(), SIGNAL(classEnumChanged(TestClassReplica::ClassEnum)));
bool res = property.write(tc_repDynamic.data(), TestClassReplica::Two);
QVERIFY(!res);
- int methodIndex = metaObject->indexOfMethod("pushClassEnum(ClassEnum)");
+ int methodIndex = metaObject->indexOfMethod("pushClassEnum(TestClassReplica::ClassEnum)");
QVERIFY(methodIndex >= 0);
QMetaMethod method = metaObject->method(methodIndex);
QVERIFY(method.isValid());
diff --git a/tests/auto/integration_external/client/main.cpp b/tests/auto/integration_external/client/main.cpp
index 05f7f59..bc53333 100644
--- a/tests/auto/integration_external/client/main.cpp
+++ b/tests/auto/integration_external/client/main.cpp
@@ -129,7 +129,7 @@ private Q_SLOTS:
QCOMPARE(simm.parameterType(2), int(QMetaType::QString));
}
- int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(Enum1,bool,int)");
+ int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
QVERIFY(slotIdx != -1);
auto slmm = mo->method(slotIdx);
{
@@ -143,7 +143,7 @@ private Q_SLOTS:
int enumVal = 0;
mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
- QGenericArgument("Enum1", &enumVal),
+ QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
Q_ARG(bool, true), Q_ARG(int, 1234));
int enumIdx = mo->indexOfProperty("enum1");
diff --git a/tests/auto/integration_multiprocess/client/main.cpp b/tests/auto/integration_multiprocess/client/main.cpp
index b60a48a..87f2ad8 100644
--- a/tests/auto/integration_multiprocess/client/main.cpp
+++ b/tests/auto/integration_multiprocess/client/main.cpp
@@ -112,7 +112,7 @@ private Q_SLOTS:
QCOMPARE(simm.parameterType(2), int(QMetaType::QString));
}
- int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(Enum1,bool,int)");
+ int slotIdx = mo->indexOfSlot("testEnumParamsInSlots(MyInterfaceReplica::Enum1,bool,int)");
QVERIFY(slotIdx != -1);
auto slmm = mo->method(slotIdx);
{
@@ -126,7 +126,7 @@ private Q_SLOTS:
int enumVal = 0;
mo->invokeMethod(rep.data(), "testEnumParamsInSlots",
- QGenericArgument("Enum1", &enumVal),
+ QGenericArgument("MyInterfaceReplica::Enum1", &enumVal),
Q_ARG(bool, true), Q_ARG(int, 1234));
int enumIdx = mo->indexOfProperty("enum1");
diff --git a/tests/auto/proxy_multiprocess/client/main.cpp b/tests/auto/proxy_multiprocess/client/main.cpp
index f37821f..7657464 100644
--- a/tests/auto/proxy_multiprocess/client/main.cpp
+++ b/tests/auto/proxy_multiprocess/client/main.cpp
@@ -69,14 +69,26 @@ private Q_SLOTS:
QCOMPARE(m_rep->variant(), QVariant());
}
+ QPoint p(1, 2);
+ auto enumReply = m_rep->enumSlot(p, ParentClassReplica::bar);
+ QVERIFY(enumReply.waitForFinished());
+ QCOMPARE(enumReply.error(), QRemoteObjectPendingCall::NoError);
+ QCOMPARE(enumReply.returnValue(), QVariant::fromValue(ParentClassReplica::foobar));
+
qDebug() << "Verified expected initial states, sending start.";
+ QSignalSpy enumSpy(m_rep.data(), &ParentClassReplica::enum2);
+ QSignalSpy advanceSpy(m_rep.data(), SIGNAL(advance()));
auto reply = m_rep->start();
QVERIFY(reply.waitForFinished());
QVERIFY(reply.error() == QRemoteObjectPendingCall::NoError);
QCOMPARE(reply.returnValue(), QVariant::fromValue(true));
+ QVERIFY(enumSpy.wait());
+ QCOMPARE(enumSpy.count(), 1);
+ const auto arguments = enumSpy.takeFirst();
+ QCOMPARE(arguments.at(0), QVariant::fromValue(ParentClassReplica::foo));
+ QCOMPARE(arguments.at(1), QVariant::fromValue(ParentClassReplica::bar));
- QSignalSpy advanceSpy(m_rep.data(), SIGNAL(advance()));
- QVERIFY(advanceSpy.wait());
+ QVERIFY(advanceSpy.count() || advanceSpy.wait());
QVERIFY(m_rep->subClass() != nullptr);
QCOMPARE(m_rep->subClass()->myPOD(), updatedValue);
QCOMPARE(m_rep->subClass()->i(), updatedI);
diff --git a/tests/auto/proxy_multiprocess/server/main.cpp b/tests/auto/proxy_multiprocess/server/main.cpp
index 2e6895b..27d4336 100644
--- a/tests/auto/proxy_multiprocess/server/main.cpp
+++ b/tests/auto/proxy_multiprocess/server/main.cpp
@@ -83,6 +83,7 @@ private Q_SLOTS:
parent.setTracks(&model);
parent.setMyEnum(ParentClassSource::foobar);
parent.setVariant(QVariant::fromValue(podValue));
+ emit parent.enum2(ParentClassSource::foo, ParentClassSource::bar);
emit parent.advance();
diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.cpp b/tests/auto/proxy_multiprocess/server/mytestserver.cpp
index b0c75ab..8b15e4d 100644
--- a/tests/auto/proxy_multiprocess/server/mytestserver.cpp
+++ b/tests/auto/proxy_multiprocess/server/mytestserver.cpp
@@ -29,7 +29,6 @@
#include <qdebug.h>
#include "mytestserver.h"
-#include "rep_subclass_source.h"
MyTestServer::MyTestServer(QObject *parent)
: ParentClassSimpleSource(parent)
@@ -53,3 +52,10 @@ bool MyTestServer::quit()
emit quitApp();
return true;
}
+
+ParentClassSource::MyEnum MyTestServer::enumSlot(QPoint p, MyEnum myEnum)
+{
+ Q_UNUSED(p)
+ Q_UNUSED(myEnum)
+ return ParentClassSource::foobar;
+}
diff --git a/tests/auto/proxy_multiprocess/server/mytestserver.h b/tests/auto/proxy_multiprocess/server/mytestserver.h
index df044c1..22fce15 100644
--- a/tests/auto/proxy_multiprocess/server/mytestserver.h
+++ b/tests/auto/proxy_multiprocess/server/mytestserver.h
@@ -47,6 +47,7 @@ public:
public Q_SLOTS:
bool start() override;
bool quit() override;
+ MyEnum enumSlot(QPoint p, MyEnum myEnum) override;
Q_SIGNALS:
void quitApp();
diff --git a/tests/auto/proxy_multiprocess/subclass.rep b/tests/auto/proxy_multiprocess/subclass.rep
index 7055944..41377d0 100644
--- a/tests/auto/proxy_multiprocess/subclass.rep
+++ b/tests/auto/proxy_multiprocess/subclass.rep
@@ -1,3 +1,5 @@
+#include <QPoint>
+
POD MyPOD(int i, float f, QString s)
POD VariantPOD(int i, int j)
@@ -9,17 +11,16 @@ class SubClass
class ParentClass
{
- // We need several Enums to test dynamic registration
- ENUM MyEnumProp {foo=1, bar=3, foobar=6}
- ENUM MyEnumSignal {a=1, b, c}
+ ENUM MyEnum {foo=1, bar=3, foobar=6}
PROP(bool started = false)
- PROP(MyEnumProp myEnum=foo)
+ PROP(MyEnum myEnum=foo)
PROP(QVariant variant)
SLOT(bool start())
SLOT(bool quit())
SIGNAL(advance())
- SIGNAL(enum2(MyEnumSignal myEnumSignal, MyEnumSignal sig2))
+ SIGNAL(enum2(MyEnum myEnum1, MyEnum myEnum2))
+ SLOT(MyEnum enumSlot(QPoint point, MyEnum myEnum))
CLASS subClass(SubClass)
MODEL tracks(display)
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
index 870033c..fd208c0 100644
--- a/tools/repc/repcodegenerator.cpp
+++ b/tools/repc/repcodegenerator.cpp
@@ -859,7 +859,7 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << " void " << property.name << "Changed(" << fullyQualifiedTypeName(astClass, className, typeForMode(property, mode)) << " " << property.name << ");" << endl;
}
- QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, className);
+ const QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, className);
Q_FOREACH (const ASTFunction &signal, signalsList)
out << " void " << signal.name << "(" << signal.paramsAsString() << ");" << endl;
@@ -883,15 +883,16 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
out << "public Q_SLOTS:" << endl;
Q_FOREACH (const ASTProperty &property, astClass.properties) {
if (property.modifier == ASTProperty::ReadPush) {
+ const auto type = fullyQualifiedTypeName(astClass, className, property.type);
if (mode != REPLICA) {
- out << " virtual void push" << cap(property.name) << "(" << property.type << " " << property.name << ")" << endl;
+ out << " virtual void push" << cap(property.name) << "(" << type << " " << property.name << ")" << endl;
out << " {" << endl;
out << " set" << cap(property.name) << "(" << property.name << ");" << endl;
out << " }" << endl;
} else {
- out << " void push" << cap(property.name) << "(" << property.type << " " << property.name << ")" << endl;
+ out << " void push" << cap(property.name) << "(" << type << " " << property.name << ")" << endl;
out << " {" << endl;
- out << " static int __repc_index = " << className << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name) << "(" << property.type << ")\");" << endl;
+ out << " static int __repc_index = " << className << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name) << "(" << type << ")\");" << endl;
out << " QVariantList __repc_args;" << endl;
out << " __repc_args << QVariant::fromValue(" << property.name << ");" << endl;
out << " send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);" << endl;
@@ -899,9 +900,11 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
}
}
}
- Q_FOREACH (const ASTFunction &slot, astClass.slotsList) {
+ const QVector<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList, className);
+ Q_FOREACH (const ASTFunction &slot, slotsList) {
+ const auto returnType = fullyQualifiedTypeName(astClass, className, slot.returnType);
if (mode != REPLICA) {
- out << " virtual " << slot.returnType << " " << slot.name << "(" << slot.paramsAsString() << ") = 0;" << endl;
+ out << " virtual " << returnType << " " << slot.name << "(" << slot.paramsAsString() << ") = 0;" << endl;
} else {
// TODO: Discuss whether it is a good idea to special-case for void here,
const bool isVoid = slot.returnType == QStringLiteral("void");
@@ -909,7 +912,7 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
if (isVoid)
out << " void " << slot.name << "(" << slot.paramsAsString() << ")" << endl;
else
- out << " QRemoteObjectPendingReply<" << slot.returnType << "> " << slot.name << "(" << slot.paramsAsString()<< ")" << endl;
+ out << " QRemoteObjectPendingReply<" << returnType << "> " << slot.name << "(" << slot.paramsAsString()<< ")" << endl;
out << " {" << endl;
out << " static int __repc_index = " << className << "::staticMetaObject.indexOfSlot(\"" << slot.name << "(" << slot.paramsAsString(ASTFunction::Normalized) << ")\");" << endl;
out << " QVariantList __repc_args;" << endl;
@@ -922,7 +925,7 @@ void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass
if (isVoid)
out << " send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);" << endl;
else
- out << " return QRemoteObjectPendingReply<" << slot.returnType << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));" << endl;
+ out << " return QRemoteObjectPendingReply<" << returnType << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));" << endl;
out << " }" << endl;
}
}
@@ -1284,8 +1287,12 @@ void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astCl
for (int i = 0; i < slotCount; ++i)
{
const ASTFunction &slot = astClass.slotsList.at(i);
- out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2\");")
- .arg(QString::number(i+pushCount), slot.returnType) << endl;
+ if (isClassEnum(astClass, slot.returnType))
+ out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"$1\").replace(\"$1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%2\"));")
+ .arg(QString::number(i+pushCount), slot.returnType) << endl;
+ else
+ out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2\");")
+ .arg(QString::number(i+pushCount), slot.returnType) << endl;
}
out << QStringLiteral(" }") << endl;
} else