aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-02-01 15:03:19 +0100
committerUlf Hermann <ulf.hermann@qt.io>2021-02-01 16:51:51 +0100
commitf6fc35b45b449fe7aaca3237f29393a12fc3f90c (patch)
treebd808ac4fd916f49417f08e0e32105e614c7f0fd /src
parent24ec3b3e7fa09900d791dcaedb0820a0b1890336 (diff)
QmlCompiler: Allow for multiple extensions per object
Previously, the assumption was that each object could only have a single extension object. As proven by the new qqmllanguage test this is not the case. Each registered object in the type hierarchy can have its own extension. Therefore, adjust the algorithms that generate qmltypes and iterate the extension objects when analyzing them. This leads us to the realization that anonymous types can in fact meaningfully carry extensions and implement interfaces. Adapt qmltyperegistrar accordingly. For the test to compile, however, we need to realize that the class declaring interfaces needs to befriend all potential subclass's QmlInterface structs. Fix that, too. The rabbit hole went deep. Change-Id: Ia451897e927e03b95c3062e829edf1dfcd216613 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqml.h3
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp36
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.cpp9
-rw-r--r--src/qmltyperegistrar/qmltypescreator.cpp22
4 files changed, 27 insertions, 43 deletions
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 61eb5e1ffe..078bd93d25 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -153,7 +153,8 @@
#define QML_IMPLEMENTS_INTERFACES(INTERFACES) \
Q_INTERFACES(INTERFACES) \
- enum class QmlIsInterface {yes = false};
+ enum class QmlIsInterface {yes = false}; \
+ template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlInterface;
#define QML_UNAVAILABLE \
QML_FOREIGN(QQmlTypeNotAvailable)
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 11a2b4a619..1fe22ab5a8 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -41,20 +41,14 @@ QT_BEGIN_NAMESPACE
template<typename Action>
static bool searchBaseAndExtensionTypes(const QQmlJSScope *type, const Action &check)
{
- const QQmlJSScope *nonCompositeBase = nullptr;
for (const QQmlJSScope *scope = type; scope; scope = scope->baseType().data()) {
- if (check(scope))
- return true;
-
- if (!nonCompositeBase && !scope->isComposite())
- nonCompositeBase = scope;
- }
-
- if (!nonCompositeBase)
- return false;
+ // Extensions override their base types
+ for (const QQmlJSScope *extension = scope->extensionType().data(); extension;
+ extension = extension->baseType().data()) {
+ if (check(extension))
+ return true;
+ }
- for (const QQmlJSScope *scope = nonCompositeBase->extensionType().data(); scope;
- scope = scope->baseType().data()) {
if (check(scope))
return true;
}
@@ -263,23 +257,7 @@ void QQmlJSScope::resolveGroupedScopes()
return false;
};
- const QQmlJSScope *nonCompositeBase = isComposite() ? this : nullptr;
- for (const QQmlJSScope *type = this; type; type = type->baseType().data()) {
- if (findProperty(type))
- break;
-
- if (!nonCompositeBase && !type->isComposite())
- nonCompositeBase = type;
- }
-
- if (!childScope->m_baseType && nonCompositeBase && nonCompositeBase != this) {
- for (const QQmlJSScope *type = nonCompositeBase->extensionType().data(); type;
- type = type->baseType().data()) {
- if (findProperty(type))
- break;
- }
- }
-
+ searchBaseAndExtensionTypes(this, findProperty);
childScope->resolveGroupedScopes();
}
}
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp
index 70a4e49d19..2310b8b3b2 100644
--- a/src/qmltyperegistrar/qmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp
@@ -112,9 +112,14 @@ void QmlTypesClassDescription::collectLocalAnonymous(
const auto classInfos = classDef->value(QLatin1String("classInfos")).toArray();
for (const QJsonValue &classInfo : classInfos) {
const QJsonObject obj = classInfo.toObject();
- if (obj[QLatin1String("name")].toString() == QLatin1String("DefaultProperty")) {
+ const QString name = obj[QStringLiteral("name")].toString();
+ const QString value = obj[QStringLiteral("value")].toString();
+
+ if (name == QStringLiteral("DefaultProperty")) {
defaultProp = obj[QLatin1String("value")].toString();
- break;
+ } else if (name == QStringLiteral("QML.Extended")) {
+ extensionType = value;
+ collectRelated(value, types, foreign, defaultRevision);
}
}
diff --git a/src/qmltyperegistrar/qmltypescreator.cpp b/src/qmltyperegistrar/qmltypescreator.cpp
index 4dafdc4490..f754679fb9 100644
--- a/src/qmltyperegistrar/qmltypescreator.cpp
+++ b/src/qmltyperegistrar/qmltypescreator.cpp
@@ -61,6 +61,17 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
if (!collector.sequenceValueType.isEmpty())
m_qml.writeScriptBinding(QLatin1String("valueType"), enquote(collector.sequenceValueType));
+ if (!collector.extensionType.isEmpty())
+ m_qml.writeScriptBinding(QLatin1String("extension"), enquote(collector.extensionType));
+
+ if (!collector.implementsInterfaces.isEmpty()) {
+ QStringList interfaces;
+ for (const QString &interface : collector.implementsInterfaces)
+ interfaces << enquote(interface);
+
+ m_qml.writeArrayBinding(QLatin1String("interfaces"), interfaces);
+ }
+
if (collector.elementName.isEmpty())
return;
@@ -96,17 +107,6 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
if (!collector.attachedType.isEmpty())
m_qml.writeScriptBinding(QLatin1String("attachedType"), enquote(collector.attachedType));
-
- if (!collector.extensionType.isEmpty())
- m_qml.writeScriptBinding(QLatin1String("extension"), enquote(collector.extensionType));
-
- if (!collector.implementsInterfaces.isEmpty()) {
- QStringList interfaces;
- for (const QString &interface : collector.implementsInterfaces)
- interfaces << enquote(interface);
-
- m_qml.writeArrayBinding(QLatin1String("interfaces"), interfaces);
- }
}
void QmlTypesCreator::writeType(const QJsonObject &property, const QString &key, bool isReadonly,