diff options
-rw-r--r-- | src/qml/qml/qqml.cpp | 25 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 82 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 77 | ||||
-rw-r--r-- | src/qmlintegration/qqmlintegration.h | 16 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt | 15 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h | 187 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp | 91 | ||||
-rw-r--r-- | tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h | 1 |
9 files changed, 470 insertions, 26 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 73eff6f3fc..07aea5e553 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -141,6 +141,31 @@ QObject *QQmlPrivate::qmlExtendedObject(QObject *object, int index) return static_cast<QObject *>(result); } +void QQmlPrivate::qmlRegistrationWarning( + QQmlPrivate::QmlRegistrationWarning warning, QMetaType metaType) +{ + switch (warning) { + case UnconstructibleType: + qWarning() + << metaType.name() + << "is neither a QObject, nor default- and copy-constructible, nor uncreatable." + << "You should not use it as a QML type."; + break; + case UnconstructibleSingleton: + qWarning() + << "Singleton" << metaType.name() + << "needs either a default constructor or, when adding a default" + << "constructor is infeasible, a public static" + << "create(QQmlEngine *, QJSEngine *) method."; + break; + case NonQObjectWithAtached: + qWarning() + << metaType.name() + << "is not a QObject, but has attached properties. This won't work."; + break; + } +} + int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, const char *uri, int versionMajor, int versionMinor, const char *qmlName, diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index fcc8aa1968..1695a78bbf 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -127,6 +127,7 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor) template<typename T> void qmlRegisterAnonymousTypesAndRevisions(const char *uri, int versionMajor) { + // Anonymous types are not creatable, no need to warn about missing acceptable constructors. QQmlPrivate::qmlRegisterTypeAndRevisions<T, void>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), nullptr, nullptr, true); @@ -795,14 +796,56 @@ inline int qmlRegisterAnonymousSequentialContainer(const char *uri, int versionM return QQmlPrivate::qmlregister(QQmlPrivate::SequentialContainerRegistration, &type); } -template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence> +template<class T, class Resolved, class Extended, bool Singleton, bool Interface, bool Sequence, bool Uncreatable> struct QmlTypeAndRevisionsRegistration; template<class T, class Resolved, class Extended> -struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, false> { static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, const QMetaObject *extension) { +#if QT_DEPRECATED_SINCE(6, 4) + // ### Qt7: Remove the warnings, and leave only the static asserts below. + if constexpr (!QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors()) { + QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleType, + QMetaType::fromType<Resolved>()); + } + + if constexpr (!std::is_base_of_v<QObject, Resolved> + && QQmlTypeInfo<T>::hasAttachedProperties) { + QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached, + QMetaType::fromType<Resolved>()); + } +#else + static_assert(QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableCtors(), + "This type is neither a QObject, nor default- and copy-constructible, nor" + "uncreatable.\n" + "You should not use it as a QML type."); + static_assert(std::is_base_of_v<QObject, Resolved> + || !QQmlTypeInfo<Resolved>::hasAttachedProperties); +#endif + QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>( + uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), + qmlTypeIds, extension); + } +}; + +template<class T, class Resolved, class Extended> +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, false, true> { + static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, + const QMetaObject *extension) + { +#if QT_DEPRECATED_SINCE(6, 4) + // ### Qt7: Remove the warning, and leave only the static assert below. + if constexpr (!std::is_base_of_v<QObject, Resolved> + && QQmlTypeInfo<Resolved>::hasAttachedProperties) { + QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::NonQObjectWithAtached, + QMetaType::fromType<Resolved>()); + } +#else + static_assert(std::is_base_of_v<QObject, Resolved> + || !QQmlTypeInfo<Resolved>::hasAttachedProperties); +#endif QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), qmlTypeIds, extension); @@ -810,10 +853,11 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false, fals }; template<class T, class Resolved> -struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true, true> { static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, const QMetaObject *) { + // Sequences have to be anonymous for now, which implies uncreatable. QQmlPrivate::qmlRegisterSequenceAndRevisions<Resolved>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), qmlTypeIds); @@ -821,10 +865,35 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, false, true> { }; template<class T, class Resolved, class Extended> -struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, false> { + static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, + const QMetaObject *extension) + { +#if QT_DEPRECATED_SINCE(6, 4) + // ### Qt7: Remove the warning, and leave only the static assert below. + if constexpr (!QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableSingletonCtors()) { + QQmlPrivate::qmlRegistrationWarning(QQmlPrivate::UnconstructibleSingleton, + QMetaType::fromType<Resolved>()); + } +#else + static_assert(QQmlPrivate::QmlMetaType<Resolved>::hasAcceptableSingletonCtors(), + "A singleton needs either a default constructor or, when adding a default " + "constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method"); +#endif + + QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>( + uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), + qmlTypeIds, extension); + } +}; + +template<class T, class Resolved, class Extended> +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false, true> { static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, const QMetaObject *extension) { + // An uncreatable singleton makes little sense? OK, you can still use the enums. QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved, Extended, T>( uri, versionMajor, QQmlPrivate::StaticMetaObject<T>::staticMetaObject(), qmlTypeIds, extension); @@ -832,7 +901,7 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, true, false, false }; template<class T, class Resolved> -struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true, false, false> { static void registerTypeAndRevisions(const char *uri, int versionMajor, QList<int> *qmlTypeIds, const QMetaObject *) { @@ -850,7 +919,8 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int> typename QQmlPrivate::QmlExtended<T>::Type, QQmlPrivate::QmlSingleton<T>::Value, QQmlPrivate::QmlInterface<T>::Value, - QQmlPrivate::QmlSequence<T>::Value> + QQmlPrivate::QmlSequence<T>::Value, + QQmlPrivate::QmlUncreatable<T>::Value> ::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds, QQmlPrivate::QmlExtendedNamespace<T>::metaObject()), ...); } diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index c15965f6e0..7d5f99ca5c 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -880,6 +880,21 @@ namespace QQmlPrivate }; template<class T, class = std::void_t<>> + struct QmlUncreatable + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlUncreatable<T, std::void_t<typename T::QmlIsUncreatable>> + { + static constexpr bool Value = + QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_uncreatable)>::value + && bool(T::QmlIsUncreatable::yes); + }; + + + template<class T, class = std::void_t<>> struct QmlSingleton { static constexpr bool Value = false; @@ -931,13 +946,47 @@ namespace QQmlPrivate static const QMetaObject *staticMetaObject() { return &T::staticMetaObject; } }; + /*! \internal + For singletons: check that there is a static create method. It is needed by the engine to + initialize a singleton object in case T has no default constructor. + + Using a default constructor is preferred over the static create method. + */ + template<class T, class = std::void_t<>> + struct HasStaticCreate + { + static constexpr bool Value = false; + }; + + // std::is_member_pointer<&X::Y> returns false when Y is a static member, and + // sfinae takes care of the existence Y being a member of X + template<class T> + struct HasStaticCreate< + T, + typename std::enable_if<!std::is_member_pointer<decltype(&T::create)>::value + && std::is_invocable_r_v<T *, decltype(&T::create), + QQmlEngine *, QJSEngine *>>::type> + { + static constexpr bool Value = true; + }; + template<class T> struct QmlMetaType { + static constexpr bool hasAcceptableSingletonCtors() + { + return std::is_default_constructible_v<T> || HasStaticCreate<T>::Value; + } + + static constexpr bool hasAcceptableCtors() { - return std::is_base_of_v<QObject, T> - || (std::is_default_constructible_v<T> && std::is_copy_constructible_v<T>); + if constexpr (!std::is_default_constructible_v<T>) + return false; + else if constexpr (std::is_base_of_v<QObject, T>) + return true; + else + return std::is_copy_constructible_v<T>; } static QMetaType self() @@ -999,22 +1048,6 @@ namespace QQmlPrivate QVector<int> *qmlTypeIds, const QMetaObject *extension, bool forceAnonymous = false) { -#if QT_DEPRECATED_SINCE(6, 4) - // ### Qt7: Remove the warnings, and leave only the static asserts below. - if (!QmlMetaType<T>::hasAcceptableCtors()) { - qWarning() << QMetaType::fromType<T>().name() - << "is neither a QObject, nor default- and copy-constructible." - << "You should not use it as a QML type."; - } - if (!std::is_base_of_v<QObject, T> && QQmlTypeInfo<T>::hasAttachedProperties) { - qWarning() << QMetaType::fromType<T>().name() - << "is not a QObject, but has attached properties. This won't work."; - } -#else - static_assert(QmlMetaType<T>::hasAcceptableCtors()); - static_assert(std::is_base_of_v<QObject, T> || !QQmlTypeInfo<T>::hasAttachedProperties); -#endif - RegisterTypeAndRevisions type = { 3, QmlMetaType<T>::self(), @@ -1103,6 +1136,14 @@ namespace QQmlPrivate Q_QML_EXPORT QObject *qmlExtendedObject(QObject *, int); + enum QmlRegistrationWarning { + UnconstructibleType, + UnconstructibleSingleton, + NonQObjectWithAtached, + }; + + Q_QML_EXPORT void qmlRegistrationWarning(QmlRegistrationWarning warning, QMetaType type); + } // namespace QQmlPrivate QT_END_NAMESPACE diff --git a/src/qmlintegration/qqmlintegration.h b/src/qmlintegration/qqmlintegration.h index 6c1ba86112..d7c9f9968d 100644 --- a/src/qmlintegration/qqmlintegration.h +++ b/src/qmlintegration/qqmlintegration.h @@ -16,6 +16,8 @@ namespace QQmlPrivate { template<typename, typename> struct QmlInterface; template<class, class> struct QmlExtendedNamespace; + template<class, class> + struct QmlUncreatable; } template <typename T> class QList; @@ -38,14 +40,24 @@ QT_END_NAMESPACE Q_CLASSINFO("QML.Element", "auto") #define QML_ANONYMOUS \ - Q_CLASSINFO("QML.Element", "anonymous") + Q_CLASSINFO("QML.Element", "anonymous") \ + enum class QmlIsUncreatable {yes = true}; \ + template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlUncreatable; \ + template<typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \ + inline constexpr void qt_qmlMarker_uncreatable() {} #define QML_NAMED_ELEMENT(NAME) \ Q_CLASSINFO("QML.Element", #NAME) #define QML_UNCREATABLE(REASON) \ Q_CLASSINFO("QML.Creatable", "false") \ - Q_CLASSINFO("QML.UncreatableReason", REASON) + Q_CLASSINFO("QML.UncreatableReason", REASON) \ + enum class QmlIsUncreatable {yes = true}; \ + template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlUncreatable; \ + template<typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \ + inline constexpr void qt_qmlMarker_uncreatable() {} #define QML_VALUE_TYPE(NAME) \ Q_CLASSINFO("QML.Element", #NAME) diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index 3a50625c0f..a7bd600315 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -8,6 +8,7 @@ ##################################################################### add_subdirectory(VersionZero) +add_subdirectory(UnregisteredTypes) add_subdirectory(foreign) qt_manual_moc(moc_files OUTPUT_MOC_JSON_FILES json_list noextheader @@ -39,6 +40,7 @@ qt_internal_add_test(tst_qmltyperegistrar tst_qmltyperegistrarPrivate Qt::QmlTypeRegistrarPrivate tst_qmltyperegistrar_major_version_zero + UnregisteredTypes ) qt_internal_extend_target(tst_qmltyperegistrar CONDITION TARGET Qt::Quick diff --git a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt new file mode 100644 index 0000000000..21cf8b4b56 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# Use NO_GENERATE_QMLTYPES to avoid static asserts during compilation of the types to be tested, same for NO_PLUGIN +qt_add_qml_module(UnregisteredTypes + STATIC + URI UnregisteredTypes + VERSION 1.0 + NO_GENERATE_QMLTYPES + NO_PLUGIN + SOURCES uncreatable.h + AUTO_RESOURCE_PREFIX +) + +qt_enable_autogen_tool(UnregisteredTypes "moc" ON) diff --git a/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h new file mode 100644 index 0000000000..9726f4683c --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h @@ -0,0 +1,187 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef UNCREATABLE_H +#define UNCREATABLE_H + +#include <QtCore/qobject.h> +#include <QtCore/qproperty.h> +#include <QtQml/qqmlregistration.h> +#include <QtQml/qqmlengine.h> + +class SingletonCreatable : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON +public: + SingletonCreatable() = delete; + // not default constructible but has the static create method +public: + static SingletonCreatable *create(QQmlEngine *, QJSEngine *) { return nullptr; } +}; + +class SingletonCreatable2 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + // is default constructible +}; + +class SingletonCreatable3 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON +public: + // is default constructible and has the create method + static SingletonCreatable3 *create(QQmlEngine *, QJSEngine *) { return nullptr; } +}; + +class SingletonIncreatable : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + SingletonIncreatable() = delete; + +public: + static SingletonCreatable *create(QQmlEngine *, QJSEngine *) + { + return nullptr; + } // wrong return type +}; + +class SingletonIncreatable2 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + SingletonIncreatable2() = delete; + +public: + static SingletonCreatable2 *create(QQmlEngine *) { return nullptr; } // wrong argument type +}; + +class SingletonIncreatable3 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + SingletonIncreatable3() = delete; + +public: + SingletonCreatable3 *create(QQmlEngine *, QJSEngine *) { return nullptr; } // should be static +}; + +class SingletonIncreatable4 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + SingletonIncreatable4() = delete; + static SingletonIncreatable4 *create(QQmlEngine *, QJSEngine *) + { + return nullptr; + } // should be public +}; + +class BadUncreatable : public QObject +{ + Q_OBJECT + QML_ELEMENT + + BadUncreatable() = delete; +}; + +class GoodUncreatable : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") + GoodUncreatable() = delete; +}; + +class UncreatableNeedsForeign : public QObject +{ + Q_OBJECT + + virtual void f() = 0; +}; + +class GoodUncreatable2 +{ + Q_GADGET + QML_FOREIGN(UncreatableNeedsForeign) + QML_ELEMENT + QML_UNCREATABLE("") +}; + +class Creatable : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + Creatable(QObject *parent = nullptr) { Q_UNUSED(parent); }; // default constructor in disguise +}; + +class Extension : public QObject +{ + Q_OBJECT + +public: + Extension(QObject *parent = nullptr) : QObject(parent) {} + + enum HelloWorld { Hello, Hallo, Bonjour }; + Q_ENUM(HelloWorld) +}; + +class Creatable2 : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_EXTENDED(Extension) +public: + Creatable2(QObject *parent = nullptr) { Q_UNUSED(parent); }; // default constructor in disguise +}; + +class SingletonIncreatableExtended : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + QML_EXTENDED(Extension) + SingletonIncreatableExtended() = delete; + static SingletonIncreatableExtended *create(QQmlEngine *, QJSEngine *) + { + return nullptr; + } // should be public +}; + +class BadUncreatableExtended : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_EXTENDED(Extension) + + BadUncreatableExtended() = delete; +}; + +class GoodUncreatableExtended : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") + QML_EXTENDED(Extension) + + GoodUncreatableExtended() = delete; +}; + +class FixingBadUncreatable +{ + Q_GADGET + QML_FOREIGN(BadUncreatable) + QML_UNCREATABLE("") +}; +#endif // UNCREATABLE_H diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index 8434f6bcef..f1776b0cc6 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -7,8 +7,10 @@ #include <QtCore/qfile.h> #include <QtQml/QQmlEngine> #include <QtQml/QQmlComponent> +#include <QtQml/qqmlprivate.h> #include "hppheader.hpp" +#include "UnregisteredTypes/uncreatable.h" void tst_qmltyperegistrar::initTestCase() { @@ -446,4 +448,93 @@ void tst_qmltyperegistrar::hasIsConstantInParameters() )")); } +void tst_qmltyperegistrar::uncreatable() +{ + // "normal" constructible types + QVERIFY(QQmlPrivate::QmlMetaType<Creatable>::hasAcceptableCtors()); + QVERIFY(QQmlPrivate::QmlMetaType<Creatable2>::hasAcceptableCtors()); + + // good singletons + QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable>::hasAcceptableSingletonCtors()); + QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable2>::hasAcceptableSingletonCtors()); + QVERIFY(QQmlPrivate::QmlMetaType<SingletonCreatable3>::hasAcceptableSingletonCtors()); + + // bad singletons + QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable>::hasAcceptableSingletonCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable2>::hasAcceptableSingletonCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable3>::hasAcceptableSingletonCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatable4>::hasAcceptableSingletonCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<SingletonIncreatableExtended>::hasAcceptableSingletonCtors()); +#if QT_DEPRECATED_SINCE(6, 4) + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonIncreatable needs either a default constructor or, " + "when adding a default constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonIncreatable>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonIncreatable2 needs either a default constructor or, " + "when adding a default constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonIncreatable2>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonIncreatable3 needs either a default constructor or, " + "when adding a default constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonIncreatable3>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonIncreatable4 needs either a default constructor or, " + "when adding a default constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonIncreatable4>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "Singleton SingletonIncreatableExtended needs either a default constructor or, " + "when adding a default constructor is infeasible, a public static " + "create(QQmlEngine *, QJSEngine *) method."); + qmlRegisterTypesAndRevisions<SingletonIncreatableExtended>("A", 1); +#endif + + // QML_UNCREATABLE types + QVERIFY(!QQmlPrivate::QmlMetaType<BadUncreatable>::hasAcceptableCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<BadUncreatableExtended>::hasAcceptableCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<GoodUncreatable>::hasAcceptableCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<UncreatableNeedsForeign>::hasAcceptableCtors()); + QVERIFY(!QQmlPrivate::QmlMetaType<GoodUncreatableExtended>::hasAcceptableCtors()); +#if QT_DEPRECATED_SINCE(6, 4) + QTest::ignoreMessage( + QtWarningMsg, + "BadUncreatable is neither a QObject, nor default- and copy-constructible, " + "nor uncreatable. You should not use it as a QML type."); + qmlRegisterTypesAndRevisions<BadUncreatable>("A", 1); + QTest::ignoreMessage( + QtWarningMsg, + "BadUncreatableExtended is neither a QObject, nor default- and copy-constructible, " + "nor uncreatable. You should not use it as a QML type."); + qmlRegisterTypesAndRevisions<BadUncreatableExtended>("A", 1); +#endif + + const auto oldHandler = qInstallMessageHandler( + [](QtMsgType, const QMessageLogContext &, const QString &message) { + QFAIL(qPrintable(message)); + }); + const auto guard = qScopeGuard([oldHandler](){qInstallMessageHandler(oldHandler); }); + + // These should not print any messages. + + qmlRegisterTypesAndRevisions<Creatable>("A", 1); + qmlRegisterTypesAndRevisions<Creatable2>("A", 1); + + qmlRegisterTypesAndRevisions<SingletonCreatable>("A", 1); + qmlRegisterTypesAndRevisions<SingletonCreatable2>("A", 1); + qmlRegisterTypesAndRevisions<SingletonCreatable3>("A", 1); + + qmlRegisterTypesAndRevisions<GoodUncreatable>("A", 1); + qmlRegisterTypesAndRevisions<GoodUncreatable2>("A", 1); + qmlRegisterTypesAndRevisions<GoodUncreatableExtended>("A", 1); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 7b0aad8c80..969bb73f2b 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -536,6 +536,7 @@ private slots: void derivedFromForeignPrivate(); void methodReturnType(); void hasIsConstantInParameters(); + void uncreatable(); #ifdef QT_QUICK_LIB void foreignRevisionedProperty(); |