Type erase native interfaces via string instead of typeid

The latter forces users to build with RTTI enabled, as the typeid
use is in our public headers. Surprisingly this is also the case
even without instantiating the relevant template.

Change-Id: Icd18a2b85b250e0b77960797e5c43b7eaf9bd891
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Tor Arne Vestbø 2021-05-20 11:36:39 +02:00
parent e253a30238
commit 486b7a8f8a
7 changed files with 25 additions and 23 deletions

View File

@ -43,8 +43,6 @@
#include <QtCore/qglobal.h>
#include <QtCore/qloggingcategory.h>
#include <typeinfo>
#ifndef QT_STATIC
# define Q_NATIVE_INTERFACE_EXPORT Q_DECL_EXPORT
# define Q_NATIVE_INTERFACE_IMPORT Q_DECL_IMPORT
@ -65,6 +63,7 @@ QT_BEGIN_NAMESPACE
virtual ~NativeInterface(); \
struct TypeInfo { \
using baseType = BaseType; \
static constexpr char const *name = QT_STRINGIFY(NativeInterface); \
static constexpr int revision = Revision; \
}; \
public: \
@ -85,6 +84,7 @@ namespace QNativeInterface::Private {
template <typename NativeInterface>
struct TypeInfo : private NativeInterface
{
static constexpr char const *name() { return NativeInterface::TypeInfo::name; }
static constexpr int revision() { return NativeInterface::TypeInfo::revision; }
template<typename BaseType>
@ -93,7 +93,7 @@ namespace QNativeInterface::Private {
};
template <typename T>
Q_NATIVE_INTERFACE_IMPORT void *resolveInterface(const T *that, const std::type_info &type, int revision);
Q_NATIVE_INTERFACE_IMPORT void *resolveInterface(const T *that, const char *name, int revision);
Q_CORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcNativeInterface)
}
@ -104,10 +104,12 @@ namespace QNativeInterface::Private {
I *nativeInterface() const \
{ \
using T = std::decay_t<decltype(*this)>; \
static_assert(QNativeInterface::Private::TypeInfo<I>::template isCompatibleWith<T>, \
using NativeInterface = QNativeInterface::Private::TypeInfo<I>; \
static_assert(NativeInterface::template isCompatibleWith<T>, \
"T::nativeInterface<I>() requires that native interface I is compatible with T"); \
\
return static_cast<I*>(QNativeInterface::Private::resolveInterface(this, typeid(I), QNativeInterface::Private::TypeInfo<I>::revision())); \
return static_cast<I*>(QNativeInterface::Private::resolveInterface(this, \
NativeInterface::name(), NativeInterface::revision())); \
}
// Provides a definition for the interface destructor
@ -119,17 +121,17 @@ namespace QNativeInterface::Private {
#define QT_NATIVE_INTERFACE_RETURN_IF(NativeInterface, baseType) \
using QNativeInterface::Private::lcNativeInterface; \
qCDebug(lcNativeInterface, "Comparing requested type id %s with available %s", \
type.name(), typeid(NativeInterface).name()); \
if (type == typeid(NativeInterface)) { \
qCDebug(lcNativeInterface, "Match for type id %s. Comparing revisions (requested %d / available %d)", \
type.name(), revision, TypeInfo<NativeInterface>::revision()); \
qCDebug(lcNativeInterface, "Comparing requested interface name %s with available %s", \
name, TypeInfo<NativeInterface>::name()); \
if (qstrcmp(name, TypeInfo<NativeInterface>::name()) == 0) { \
qCDebug(lcNativeInterface, "Match for interface %s. Comparing revisions (requested %d / available %d)", \
name, revision, TypeInfo<NativeInterface>::revision()); \
if (revision == TypeInfo<NativeInterface>::revision()) { \
qCDebug(lcNativeInterface) << "Full match. Returning dynamic cast of" << baseType; \
return dynamic_cast<NativeInterface*>(baseType); \
} else { \
qCWarning(lcNativeInterface, "Native interface revision mismatch (requested %d / available %d) for interface %s", \
revision, TypeInfo<NativeInterface>::revision(), type.name()); \
revision, TypeInfo<NativeInterface>::revision(), name); \
return nullptr; \
} \
}

View File

@ -3241,9 +3241,9 @@ QCoreApplication::checkPermission(const QString &permission)
#endif // future && QT_NO_QOBJECT
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QCoreApplication *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QCoreApplication *that, const char *name, int revision)
{
Q_UNUSED(that); Q_UNUSED(type); Q_UNUSED(revision);
Q_UNUSED(that); Q_UNUSED(name); Q_UNUSED(revision);
return nullptr;
}

View File

@ -4197,7 +4197,7 @@ QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
}
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QGuiApplication *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QGuiApplication *that, const char *name, int revision)
{
using namespace QNativeInterface::Private;
@ -4208,7 +4208,7 @@ Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(cons
QT_NATIVE_INTERFACE_RETURN_IF(QWindowsApplication, platformIntegration);
#endif
return resolveInterface<QCoreApplication>(that, type, revision);
return resolveInterface<QCoreApplication>(that, name, revision);
}
#include "moc_qguiapplication.cpp"

View File

@ -136,9 +136,9 @@ QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
}
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QKeyMapper *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QKeyMapper *that, const char *name, int revision)
{
Q_UNUSED(that); Q_UNUSED(type); Q_UNUSED(revision);
Q_UNUSED(that); Q_UNUSED(name); Q_UNUSED(revision);
using namespace QNativeInterface::Private;
#if QT_CONFIG(evdev)

View File

@ -372,9 +372,9 @@ QPlatformSurface *QOffscreenSurface::surfaceHandle() const
using namespace QNativeInterface;
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QOffscreenSurface *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QOffscreenSurface *that, const char *name, int revision)
{
Q_UNUSED(that); Q_UNUSED(type); Q_UNUSED(revision);
Q_UNUSED(that); Q_UNUSED(name); Q_UNUSED(revision);
auto *surfacePrivate = QOffscreenSurfacePrivate::get(const_cast<QOffscreenSurface*>(that));
Q_UNUSED(surfacePrivate);

View File

@ -1312,9 +1312,9 @@ QDebug operator<<(QDebug debug, const QOpenGLContextGroup *cg)
using namespace QNativeInterface;
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QOpenGLContext *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QOpenGLContext *that, const char *name, int revision)
{
Q_UNUSED(that); Q_UNUSED(type); Q_UNUSED(revision);
Q_UNUSED(that); Q_UNUSED(name); Q_UNUSED(revision);
auto *platformContext = that->handle();
Q_UNUSED(platformContext);

View File

@ -4101,9 +4101,9 @@ QPixmap QApplicationPrivate::applyQIconStyleHelper(QIcon::Mode mode, const QPixm
}
template <>
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QApplication *that, const std::type_info &type, int revision)
Q_NATIVE_INTERFACE_EXPORT void *QNativeInterface::Private::resolveInterface(const QApplication *that, const char *name, int revision)
{
return resolveInterface<QGuiApplication>(that, type, revision);
return resolveInterface<QGuiApplication>(that, name, revision);
}
QT_END_NAMESPACE