diff options
Diffstat (limited to 'src/remoteobjects/qremoteobjectsource.h')
-rw-r--r-- | src/remoteobjects/qremoteobjectsource.h | 79 |
1 files changed, 78 insertions, 1 deletions
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; |