QML: Fix conflicts between QML_ANONYMOUS, QML_UNCREATABLE and namespaces

Even though it makes no sense, we have to allow QML_ANONYMOUS and
QML_UNCREATABLE in the same class since we've documented it. You
cannot trigger the custom message because you'd need a name to attempt
to create an instance of the type. Therefore, the documentation
suggesting this is nonsensical.

In theory you could indeed provide a custom message for namespaces, but
in order to continue supporting this, we would either have to drop the
QmlIsUncreatable mechanism, or we would need a different macro. So,
let's drop this for now. If we really need it, we can introduce a
different macro later.

[ChangeLog][QtQml][Important Behavior Changes] You can no longer
override the "uncreatable" message for QML-exposed namespaces using
QML_UNCREATABLE. This would be incompatible with making the
QML_UNCREATABLE macro safe from unintended inheritance. The latter is
much more important.

Fixes: QTBUG-111470
Change-Id: Ib736a2411128d58d939fa2a57d28a0b31c0777e6
Reviewed-by: Robert Griebl <robert.griebl@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit a60968283b)
This commit is contained in:
Ulf Hermann 2023-02-27 14:19:23 +01:00
parent 064fd7e6e5
commit 2acf4db153
6 changed files with 40 additions and 6 deletions

View File

@ -153,8 +153,7 @@
Some QML types are implicitly uncreatable, in particular types exposed with
\l QML_ANONYMOUS or namespaces exposed with \l QML_ELEMENT or
\l QML_NAMED_ELEMENT(). For such types, \l QML_UNCREATABLE() can be used to
provide a custom error message.
\l QML_NAMED_ELEMENT().
Since Qt 6.0 you can use "" instead of a reason to use a standard message instead.

View File

@ -891,7 +891,7 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor, QList<int>
QQmlPrivate::QmlSingleton<T>::Value,
QQmlPrivate::QmlInterface<T>::Value,
QQmlPrivate::QmlSequence<T>::Value,
QQmlPrivate::QmlUncreatable<T>::Value>
QQmlPrivate::QmlUncreatable<T>::Value || QQmlPrivate::QmlAnonymous<T>::Value>
::registerTypeAndRevisions(uri, versionMajor, qmlTypeIds,
QQmlPrivate::QmlExtendedNamespace<T>::metaObject()), ...);
}

View File

@ -897,6 +897,20 @@ namespace QQmlPrivate
&& bool(T::QmlIsUncreatable::yes);
};
template<class T, class = std::void_t<>>
struct QmlAnonymous
{
static constexpr bool Value = false;
};
template<class T>
struct QmlAnonymous<T, std::void_t<typename T::QmlIsAnonymous>>
{
static constexpr bool Value =
QmlTypeHasMarker<T, decltype(&T::qt_qmlMarker_anonymous)>::value
&& bool(T::QmlIsAnonymous::yes);
};
template<class T, class = std::void_t<>>
struct QmlSingleton

View File

@ -18,6 +18,8 @@ namespace QQmlPrivate {
struct QmlExtendedNamespace;
template<class, class>
struct QmlUncreatable;
template<class, class>
struct QmlAnonymous;
}
template <typename T> class QList;
@ -41,11 +43,11 @@ QT_END_NAMESPACE
#define QML_ANONYMOUS \
Q_CLASSINFO("QML.Element", "anonymous") \
enum class QmlIsUncreatable {yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlUncreatable; \
enum class QmlIsAnonymous{yes = true}; \
template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlAnonymous; \
template<typename... Args> \
friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor, QList<int> *); \
inline constexpr void qt_qmlMarker_uncreatable() {}
inline constexpr void qt_qmlMarker_anonymous() {}
#define QML_NAMED_ELEMENT(NAME) \
Q_CLASSINFO("QML.Element", #NAME)

View File

@ -573,4 +573,15 @@ void tst_qmltyperegistrar::baseVersionInQmltypes()
QVERIFY(qmltypesData.contains("exports: [\"QmlTypeRegistrarTest/WithMethod 1.0\"]"));
}
void tst_qmltyperegistrar::anonymousAndUncreatable()
{
QVERIFY(qmltypesData.contains(
R"(Component {
file: "tst_qmltyperegistrar.h"
name: "AnonymousAndUncreatable"
accessSemantics: "reference"
prototype: "QObject"
})"));
}
QTEST_MAIN(tst_qmltyperegistrar)

View File

@ -501,6 +501,13 @@ signals:
void clonedSignal(int i = 7);
};
class AnonymousAndUncreatable : public QObject
{
Q_OBJECT
QML_ANONYMOUS
QML_UNCREATABLE("Pointless uncreatable message")
};
class tst_qmltyperegistrar : public QObject
{
Q_OBJECT
@ -549,6 +556,7 @@ private slots:
void duplicateExportWarnings();
void clonedSignal();
void baseVersionInQmltypes();
void anonymousAndUncreatable();
private:
QByteArray qmltypesData;