aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqml.cpp25
-rw-r--r--src/qml/qml/qqml.h82
-rw-r--r--src/qml/qml/qqmlprivate.h77
-rw-r--r--src/qmlintegration/qqmlintegration.h16
-rw-r--r--tests/auto/qml/qmltyperegistrar/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmltyperegistrar/UnregisteredTypes/CMakeLists.txt15
-rw-r--r--tests/auto/qml/qmltyperegistrar/UnregisteredTypes/uncreatable.h187
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp91
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h1
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();