diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2020-02-17 01:01:00 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-02-17 10:21:59 +0100 |
commit | 3e758800b4daf8fbc870a2ff5d54fce9d4402ce8 (patch) | |
tree | ba237b9da1c7dfd08bf13e71c5dbd6b3c2e77633 /src/qml/qml | |
parent | 925a0e499a5dbdb180fd9969a79abf96006ce4fd (diff) | |
parent | 55546991e24ca6799709cbe0171b9ab87216c35f (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts:
src/imports/qtqml/plugin.cpp
src/qml/qml/qqml.h
src/qml/qml/qqmlmetatype.cpp
src/qml/qml/qqmlmetatype_p.h
src/qml/qml/qqmltypeloader.cpp
src/qml/types/qqmlbind.cpp
src/quick/items/qquickitemsmodule.cpp
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
Change-Id: I52548938a582cb6510271ed4bc3a9aa0c3c11df6
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqml.cpp | 37 | ||||
-rw-r--r-- | src/qml/qml/qqml.h | 71 | ||||
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlcustomparser.cpp | 31 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 22 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 21 | ||||
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 47 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertyvalidator.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypecompiler.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmltypedata.cpp | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 82 | ||||
-rw-r--r-- | src/qml/qml/qqmltypenotavailable.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypenotavailable_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetype.cpp | 92 | ||||
-rw-r--r-- | src/qml/qml/qqmlvaluetype_p.h | 49 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 29 |
20 files changed, 398 insertions, 141 deletions
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index c71e6b68b8..ea6f15e9c2 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -46,6 +46,7 @@ #include <private/qqmlmetatypedata_p.h> #include <private/qqmltype_p_p.h> #include <private/qqmltypemodule_p_p.h> +#include <private/qqmltypenotavailable_p.h> #include <QtCore/qmutex.h> @@ -358,4 +359,40 @@ void QQmlPrivate::qmlunregister(RegistrationType type, quintptr data) } } +namespace QQmlPrivate { + template<> + void qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) + { + using T = QQmlTypeNotAvailable; + + QML_GETTYPENAMES + + RegisterTypeAndRevisions type = { + 0, + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + 0, + nullptr, + + uri, + QTypeRevision::fromMajorVersion(versionMajor), + + &QQmlTypeNotAvailable::staticMetaObject, + classInfoMetaObject, + + attachedPropertiesFunc<T>(), + attachedPropertiesMetaObject<T>(), + + StaticCastSelector<T, QQmlParserStatus>::cast(), + StaticCastSelector<T, QQmlPropertyValueSource>::cast(), + StaticCastSelector<T, QQmlPropertyValueInterceptor>::cast(), + + nullptr, nullptr, qmlCreateCustomParser<T> + }; + + qmlregister(TypeAndRevisionsRegistration, &type); + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 096bef7e4b..b9445e48a8 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -120,6 +120,16 @@ template<typename T, typename... Args> \ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); +#define QML_INTERFACE \ + Q_CLASSINFO("QML.Element", "anonymous") \ + enum class QmlIsInterface {yes = true}; \ + template<typename, typename> friend struct QML_PRIVATE_NAMESPACE::QmlInterface; \ + template<typename T, typename... Args> \ + friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); + +#define QML_UNAVAILABLE \ + QML_FOREIGN(QQmlTypeNotAvailable) + enum { /* TYPEINFO flags */ QML_HAS_ATTACHED_PROPERTIES = 0x01 }; @@ -183,7 +193,8 @@ QT_DEPRECATED_VERSION_X_5_14("Use qmlRegisterAnonymousType instead") int qmlRegi } #endif -int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message); +int Q_QML_EXPORT qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, + const char *qmlName, const QString& message); template<typename T> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) @@ -422,9 +433,8 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } - template<typename T, typename E> -int qmlRegisterExtendedType() +int qmlRegisterExtendedType(const char *uri, int versionMajor) { QML_GETTYPENAMES @@ -437,7 +447,7 @@ int qmlRegisterExtendedType() nullptr, QString(), - nullptr, QTypeRevision::zero(), nullptr, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -455,6 +465,15 @@ int qmlRegisterExtendedType() return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +#if QT_DEPRECATED_SINCE(5, 15) +template<typename T, typename E> +QT_DEPRECATED_VERSION_X_5_15("Use qmlRegisterExtendedType(uri, versionMajor) instead") +int qmlRegisterExtendedType() +{ + return qmlRegisterExtendedType<T, E>("", 0); +} +#endif + template<typename T, typename E> int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) @@ -494,7 +513,9 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +#if QT_DEPRECATED_SINCE(5, 15) template<typename T> +QT_DEPRECATED_VERSION_X_5_15("Use qmlRegisterInterface(uri, versionMajor) instead") int qmlRegisterInterface(const char *typeName) { QByteArray name(typeName); @@ -503,12 +524,33 @@ int qmlRegisterInterface(const char *typeName) QByteArray listName("QQmlListProperty<" + name + '>'); QQmlPrivate::RegisterInterface qmlInterface = { - 0, + 1, qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - qobject_interface_iid<T *>() + qobject_interface_iid<T *>(), + "", + QTypeRevision::zero() + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); +} +#endif + +template<typename T> +int qmlRegisterInterface(const char *uri, int versionMajor) +{ + QML_GETTYPENAMES + + QQmlPrivate::RegisterInterface qmlInterface = { + 1, + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T>>(listName.constData()), + qobject_interface_iid<T *>(), + + uri, + QTypeRevision::fromVersion(versionMajor, 0) }; return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); @@ -766,11 +808,11 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i return QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &type); } -template<class T, class Resolved, class Extended, bool Singleton> +template<class T, class Resolved, class Extended, bool Singleton, bool Interface> struct QmlTypeAndRevisionsRegistration; template<class T, class Resolved, class Extended> -struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false, false> { static void registerTypeAndRevisions(const char *uri, int versionMajor) { QQmlPrivate::qmlRegisterTypeAndRevisions<Resolved, Extended>( @@ -779,7 +821,7 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, Extended, false> { }; template<class T, class Resolved> -struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> { +struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true, false> { static void registerTypeAndRevisions(const char *uri, int versionMajor) { QQmlPrivate::qmlRegisterSingletonAndRevisions<Resolved>( @@ -787,6 +829,14 @@ struct QmlTypeAndRevisionsRegistration<T, Resolved, void, true> { } }; +template<class T, class Resolved> +struct QmlTypeAndRevisionsRegistration<T, Resolved, void, false, true> { + static void registerTypeAndRevisions(const char *uri, int versionMajor) + { + qmlRegisterInterface<Resolved>(uri, versionMajor); + } +}; + template<typename T = void, typename... Args> void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor); @@ -796,7 +846,8 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor) QmlTypeAndRevisionsRegistration< T, typename QQmlPrivate::QmlResolved<T>::Type, typename QQmlPrivate::QmlExtended<T>::Type, - QQmlPrivate::QmlSingleton<T>::Value> + QQmlPrivate::QmlSingleton<T>::Value, + QQmlPrivate::QmlInterface<T>::Value> ::registerTypeAndRevisions(uri, versionMajor); qmlRegisterTypesAndRevisions<Args...>(uri, versionMajor); } diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e14b00af22..b9566d5862 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -43,6 +43,10 @@ #include "qqmlcontext.h" #include "qqmlinfo.h" #include "qqmldata_p.h" + +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qqmldebugconnector_p.h> + #include <private/qqmlprofiler_p.h> #include <private/qqmlexpression_p.h> #include <private/qqmlscriptstring_p.h> @@ -392,6 +396,11 @@ QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer<QV4::Exe b->QQmlJavaScriptExpression::setContext(ctxt); b->setScopeObject(obj); + if (QQmlDebugTranslationService *service + = QQmlDebugConnector::service<QQmlDebugTranslationService>()) { + service->foundTranslationBinding(b, obj, ctxt); + } + return b; } diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 87f7fffe41..02c2b87a6e 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -125,8 +125,13 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const // * <TypeName>.<EnumValue> // * <TypeName>.<ScopedEnumName>.<EnumValue> - int dot = script.indexOf('.'); - if (dot == -1 || dot == script.length()-1) + auto nextDot = [&](int dot) { + const int nextDot = script.indexOf('.', dot + 1); + return (nextDot == script.length() - 1) ? -1 : nextDot; + }; + + int dot = nextDot(-1); + if (dot == -1) return -1; QString scope = QString::fromUtf8(script.left(dot)); @@ -137,18 +142,32 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const QQmlType type; if (imports.isT1()) { - imports.asT1()->resolveType(scope, &type, nullptr, nullptr, nullptr); + QQmlImportNamespace *ns = nullptr; + if (!imports.asT1()->resolveType(scope, &type, nullptr, &ns)) + return -1; + if (!type.isValid() && ns != nullptr) { + dot = nextDot(dot); + if (dot == -1 || !imports.asT1()->resolveType(QString::fromUtf8(script.left(dot)), + &type, nullptr, nullptr)) { + return -1; + } + } } else { QQmlTypeNameCache::Result result = imports.asT2()->query(scope); - if (result.isValid()) + if (result.isValid()) { type = result.type; + } else if (result.importNamespace) { + dot = nextDot(dot); + if (dot != -1) + type = imports.asT2()->query(QString::fromUtf8(script.left(dot))).type; + } } if (!type.isValid()) return -1; - int dot2 = script.indexOf('.', dot+1); - const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1; + const int dot2 = nextDot(dot); + const bool dot2Valid = (dot2 != -1); QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); if (!scopedEnumName.isEmpty()) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 7f30c4d713..c8b41d3684 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -654,11 +654,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate() for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; - - // since unregisterInternalCompositeType() will not be called in this - // case, we have to clean up the type registration manually - QMetaType::unregisterType(iter.value()->metaTypeId); - QMetaType::unregisterType(iter.value()->listMetaTypeId); + QQmlMetaType::unregisterInternalCompositeType({iter.value()->metaTypeId, iter.value()->listMetaTypeId}); } #if QT_CONFIG(qml_debug) delete profiler; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 2c702367a4..8e292c4bbc 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -269,8 +269,24 @@ public: mutable QMutex networkAccessManagerMutex; + QQmlGadgetPtrWrapper *valueTypeInstance(int typeIndex) + { + auto it = cachedValueTypeInstances.find(typeIndex); + if (it != cachedValueTypeInstances.end()) + return *it; + + if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(typeIndex)) { + QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType, q_func()); + cachedValueTypeInstances.insert(typeIndex, instance); + return instance; + } + + return nullptr; + } + private: QHash<QQmlType, QJSValue> singletonInstances; + QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances; // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index c5c767df43..0baf142913 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -92,7 +92,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, d->typeId = type.typeId; d->listId = type.listId; d->isSetup = true; - d->version = QTypeRevision::zero(); + if (type.structVersion > 0) { + d->module = QString::fromUtf8(type.uri); + d->version = type.version; + } else { + d->version = QTypeRevision::zero(); + } data->registerType(d); return d; } @@ -293,6 +298,17 @@ bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri) return data->registerModuleTypes(uri); } +/*! + \internal + Method is only used to in tst_qqmlenginecleanup.cpp to test whether all + types have been removed from qmlLists after shutdown of QQmlEngine + */ +int QQmlMetaType::qmlRegisteredListTypeCount() +{ + QQmlMetaTypeDataPtr data; + return data->qmlLists.count(); +} + void QQmlMetaType::clearTypeRegistrations() { //Only cleans global static, assumed no running engine @@ -329,7 +345,7 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) { - if (type.structVersion > 0) + if (type.structVersion > 1) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); QQmlMetaTypeDataPtr data; @@ -338,8 +354,6 @@ QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &t data->idToType.insert(priv->typeId, priv); data->idToType.insert(priv->listId, priv); - if (!priv->elementName.isEmpty()) - data->nameToType.insert(priv->elementName, priv); if (data->interfaces.size() <= type.typeId) data->interfaces.resize(type.typeId + 16); diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index c68bf0c551..0fc179fd34 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -202,6 +202,8 @@ public: static void qmlRemoveModuleRegistration(const QString &uri); static bool qmlRegisterModuleTypes(const QString &uri); + + static int qmlRegisteredListTypeCount(); }; Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 6cc2bf49c8..28dd3d4ab4 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -173,7 +173,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context = new QQmlContextData; context->isInternal = true; context->imports = compilationUnit->typeNameCache; - context->initFromTypeCompilationUnit(compilationUnit, flags & CreationFlags::NormalObject ? subComponentIndex : -1); + context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex); context->setParent(parentContext); if (!sharedState->rootContext) { @@ -856,12 +856,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) { QObject *groupObject = nullptr; - QQmlValueType *valueType = nullptr; + QQmlGadgetPtrWrapper *valueType = nullptr; const QQmlPropertyData *valueTypeProperty = nullptr; QObject *bindingTarget = _bindingTarget; if (QQmlValueTypeFactory::isValueType(bindingProperty->propType())) { - valueType = QQmlValueTypeFactory::valueType(bindingProperty->propType()); + valueType = QQmlGadgetPtrWrapper::instance(engine, bindingProperty->propType()); if (!valueType) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 527c5ee603..2e4bc60f79 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -125,6 +125,7 @@ class QJSValue; class QJSEngine; class QQmlEngine; class QQmlCustomParser; +class QQmlTypeNotAvailable; template<class T> QQmlCustomParser *qmlCreateCustomParser() @@ -406,6 +407,9 @@ namespace QQmlPrivate int listId; const char *iid; + + const char *uri; + QTypeRevision version; }; struct RegisterAutoParent { @@ -578,6 +582,18 @@ namespace QQmlPrivate static constexpr bool Value = bool(T::QmlIsSingleton::yes); }; + template<class T, class = QmlVoidT<>> + struct QmlInterface + { + static constexpr bool Value = false; + }; + + template<class T> + struct QmlInterface<T, QmlVoidT<typename T::QmlIsInterface>> + { + static constexpr bool Value = bool(T::QmlIsInterface::yes); + }; + template<typename T> void qmlRegisterSingletonAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) @@ -636,6 +652,11 @@ namespace QQmlPrivate qmlregister(TypeAndRevisionsRegistration, &type); } + + template<> + void Q_QML_EXPORT qmlRegisterTypeAndRevisions<QQmlTypeNotAvailable, void>( + const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject); + } // namespace QQmlPrivate QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 93020661e2..8521de6ab3 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -353,10 +353,15 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) if (terminal.count() >= 3 && terminal.at(0) == QLatin1Char('o') && terminal.at(1) == QLatin1Char('n') && - terminal.at(2).isUpper()) { + (terminal.at(2).isUpper() || terminal.at(2) == '_')) { QString signalName = terminal.mid(2).toString(); - signalName[0] = signalName.at(0).toLower(); + int firstNon_; + int length = signalName.length(); + for (firstNon_ = 0; firstNon_ < length; ++firstNon_) + if (signalName.at(firstNon_) != '_') + break; + signalName[firstNon_] = signalName.at(firstNon_).toLower(); // XXX - this code treats methods as signals @@ -1044,13 +1049,19 @@ QVariant QQmlProperty::read(const QObject *object, const QString &name, QQmlEngi QVariant QQmlPropertyPrivate::readValueProperty() { - if (isValueType()) { - - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType()); - Q_ASSERT(valueType); - valueType->read(object, core.coreIndex()); - return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType); + auto doRead = [&](QQmlGadgetPtrWrapper *wrapper) { + wrapper->read(object, core.coreIndex()); + return wrapper->property(valueTypeData.coreIndex()).read(wrapper); + }; + if (isValueType()) { + if (QQmlGadgetPtrWrapper *wrapper = QQmlGadgetPtrWrapper::instance(engine, core.propType())) + return doRead(wrapper); + if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType())) { + QQmlGadgetPtrWrapper wrapper(valueType, nullptr); + return doRead(&wrapper); + } + return QVariant(); } else if (core.isQList()) { QQmlListProperty<QObject> prop; @@ -1183,10 +1194,22 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, bool rv = false; if (valueTypeData.isValid()) { - QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType()); - writeBack->read(object, core.coreIndex()); - rv = write(writeBack, valueTypeData, value, context, flags); - writeBack->write(object, core.coreIndex(), flags); + auto doWrite = [&](QQmlGadgetPtrWrapper *wrapper) { + wrapper->read(object, core.coreIndex()); + rv = write(wrapper, valueTypeData, value, context, flags); + wrapper->write(object, core.coreIndex(), flags); + }; + + QQmlGadgetPtrWrapper *wrapper = context + ? QQmlGadgetPtrWrapper::instance(context->engine, core.propType()) + : nullptr; + if (wrapper) { + doWrite(wrapper); + } else if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType())) { + QQmlGadgetPtrWrapper wrapper(valueType, nullptr); + doWrite(&wrapper); + } + } else { rv = write(object, core, value, context, flags); } diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 001b19a8e5..3fb2eb399f 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -104,7 +104,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr); } - if (obj->flags & QV4::CompiledData::Object::IsComponent) { + if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) { Q_ASSERT(obj->nBindings == 1); const QV4::CompiledData::Binding *componentBinding = obj->bindingTable(); Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object); diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index d7a549e380..3518b21a70 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -881,6 +881,10 @@ bool QQmlComponentAndAliasResolver::resolve() const int objCountWithoutSynthesizedComponents = qmlObjects->count(); for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) { QmlIR::Object *obj = qmlObjects->at(i); + if (obj->isInlineComponent) { + componentRoots.append(i); + continue; + } QQmlPropertyCache *cache = propertyCaches.at(i); if (obj->inheritedTypeNameIndex == 0 && !cache) continue; @@ -936,7 +940,7 @@ bool QQmlComponentAndAliasResolver::resolve() _objectsWithAliases.clear(); - if (!collectIdsAndAliases(rootBinding->value.objectIndex)) + if (!collectIdsAndAliases(component->isInlineComponent ? componentRoots.at(i) : rootBinding->value.objectIndex)) return false; component->namedObjectsInComponent.allocate(pool, _idToObjectIndex); diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index ec9061d04e..30d50b911e 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -829,8 +829,9 @@ void QQmlTypeData::resolveTypes() if (ref.type.isCompositeSingleton()) { ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); - if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies || m_waitingOnMe.contains(ref.typeData.data())) { - // TODO: give an error message? If so, we should record and show the path of the cycle. + if (ref.typeData->isWaiting() || m_waitingOnMe.contains(ref.typeData.data())) { + qWarning() << "Cyclic dependency detected between" << ref.typeData->urlString() + << "and" << urlString(); continue; } addDependency(ref.typeData.data()); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index afad15331c..d8cfd80b9b 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -602,51 +602,59 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo scriptImported(blob, import->location, script.nameSpace, import->qualifier); } } + } else if ( + // Major version of module already registered: + // We believe that the registration is complete. + QQmlMetaType::typeModule(import->uri, import->version) + + // Otherwise, try to register further module types. + || (qmldirResult != QQmlImports::QmldirInterceptedToRemote + && QQmlMetaType::qmlRegisterModuleTypes(import->uri)) + + // Otherwise, there is no way to register any further types. + // Try with any module of that name. + || QQmlMetaType::isAnyModule(import->uri)) { + + if (!m_importCache.addLibraryImport( + importDatabase, import->uri, import->qualifier, import->version, + QString(), QString(), false, errors)) { + return false; + } } else { - // Is this a module? - if (QQmlMetaType::isAnyModule(import->uri) - || (qmldirResult != QQmlImports::QmldirInterceptedToRemote - && QQmlMetaType::qmlRegisterModuleTypes(import->uri))) { + // We haven't yet resolved this import + m_unresolvedImports << import; + + QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); + + // Query any network import paths for this library. + // Interceptor might redirect local paths. + QStringList remotePathList = importDatabase->importPathList( + interceptor ? QQmlImportDatabase::LocalOrRemote + : QQmlImportDatabase::Remote); + if (!remotePathList.isEmpty()) { + // Add this library and request the possible locations for it if (!m_importCache.addLibraryImport( importDatabase, import->uri, import->qualifier, import->version, - QString(), QString(), false, errors)) + QString(), QString(), true, errors)) return false; - } else { - // We haven't yet resolved this import - m_unresolvedImports << import; - - QQmlAbstractUrlInterceptor *interceptor = typeLoader()->engine()->urlInterceptor(); - - // Query any network import paths for this library. - // Interceptor might redirect local paths. - QStringList remotePathList = importDatabase->importPathList( - interceptor ? QQmlImportDatabase::LocalOrRemote - : QQmlImportDatabase::Remote); - if (!remotePathList.isEmpty()) { - // Add this library and request the possible locations for it - if (!m_importCache.addLibraryImport( - importDatabase, import->uri, import->qualifier, import->version, - QString(), QString(), true, errors)) - return false; - // Probe for all possible locations - int priority = 0; - const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths( - import->uri, remotePathList, import->version); - for (const QString &qmldirPath : qmlDirPaths) { - if (interceptor) { - QUrl url = interceptor->intercept( - QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), - QQmlAbstractUrlInterceptor::QmldirFile); - if (!QQmlFile::isLocalFile(url) - && !fetchQmldir(url, import, ++priority, errors)) { - return false; - } - } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { + // Probe for all possible locations + int priority = 0; + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths( + import->uri, remotePathList, import->version); + for (const QString &qmldirPath : qmlDirPaths) { + if (interceptor) { + QUrl url = interceptor->intercept( + QQmlImports::urlFromLocalFileOrQrcOrUrl(qmldirPath), + QQmlAbstractUrlInterceptor::QmldirFile); + if (!QQmlFile::isLocalFile(url) + && !fetchQmldir(url, import, ++priority, errors)) { return false; } - + } else if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) { + return false; } + } } } diff --git a/src/qml/qml/qqmltypenotavailable.cpp b/src/qml/qml/qqmltypenotavailable.cpp index ffa4472e4b..0e95d6062c 100644 --- a/src/qml/qml/qqmltypenotavailable.cpp +++ b/src/qml/qml/qqmltypenotavailable.cpp @@ -46,8 +46,6 @@ int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMi return qmlRegisterUncreatableType<QQmlTypeNotAvailable>(uri,versionMajor,versionMinor,qmlName,message); } -QQmlTypeNotAvailable::QQmlTypeNotAvailable() { } - QT_END_NAMESPACE #include "moc_qqmltypenotavailable_p.cpp" diff --git a/src/qml/qml/qqmltypenotavailable_p.h b/src/qml/qml/qqmltypenotavailable_p.h index 8db5876b10..9bb19ed86c 100644 --- a/src/qml/qml/qqmltypenotavailable_p.h +++ b/src/qml/qml/qqmltypenotavailable_p.h @@ -55,14 +55,10 @@ QT_BEGIN_NAMESPACE - class QQmlTypeNotAvailable : public QObject { Q_OBJECT QML_NAMED_ELEMENT(TypeNotAvailable) QML_UNCREATABLE("Type not available.") - -public: - QQmlTypeNotAvailable(); }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 4beb6a4d07..254f1015e2 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -42,11 +42,11 @@ #include <QtCore/qmutex.h> #include <private/qqmlglobal_p.h> #include <QtCore/qdebug.h> +#include <private/qqmlengine_p.h> #include <private/qmetaobjectbuilder_p.h> #if QT_CONFIG(qml_itemmodel) #include <private/qqmlmodelindexvaluetype_p.h> #endif -#include <private/qmetatype_p.h> Q_DECLARE_METATYPE(QQmlProperty) @@ -221,61 +221,82 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor, #endif } -QQmlValueType::QQmlValueType() : - _metaObject(nullptr), - gadgetPtr(nullptr), - metaType(QMetaType::UnknownType) +QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject) + : metaType(typeId) { + QMetaObjectBuilder builder(gadgetMetaObject); + dynamicMetaObject = builder.toMetaObject(); + *static_cast<QMetaObject*>(this) = *dynamicMetaObject; } -QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject) - : gadgetPtr(QMetaType::create(typeId)) - , metaType(typeId) +QQmlValueType::~QQmlValueType() { - QObjectPrivate *op = QObjectPrivate::get(this); - Q_ASSERT(!op->metaObject); - op->metaObject = this; + ::free(dynamicMetaObject); +} - QMetaObjectBuilder builder(gadgetMetaObject); - _metaObject = builder.toMetaObject(); +QQmlGadgetPtrWrapper *QQmlGadgetPtrWrapper::instance(QQmlEngine *engine, int index) +{ + return engine ? QQmlEnginePrivate::get(engine)->valueTypeInstance(index) : nullptr; +} - *static_cast<QMetaObject*>(this) = *_metaObject; +QQmlGadgetPtrWrapper::QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent) + : QObject(parent), m_gadgetPtr(valueType->create()) +{ + QObjectPrivate *d = QObjectPrivate::get(this); + Q_ASSERT(!d->metaObject); + d->metaObject = valueType; } -QQmlValueType::~QQmlValueType() +QQmlGadgetPtrWrapper::~QQmlGadgetPtrWrapper() { - QObjectPrivate *op = QObjectPrivate::get(this); - Q_ASSERT(op->metaObject == nullptr || op->metaObject == this); - op->metaObject = nullptr; - ::free(const_cast<QMetaObject *>(_metaObject)); - metaType.destroy(gadgetPtr); + QObjectPrivate *d = QObjectPrivate::get(this); + static_cast<const QQmlValueType *>(d->metaObject)->destroy(m_gadgetPtr); + d->metaObject = nullptr; } -void QQmlValueType::read(QObject *obj, int idx) +void QQmlGadgetPtrWrapper::read(QObject *obj, int idx) { - void *a[] = { gadgetPtr, nullptr }; + Q_ASSERT(m_gadgetPtr); + void *a[] = { m_gadgetPtr, nullptr }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); } -void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) +void QQmlGadgetPtrWrapper::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) { - Q_ASSERT(gadgetPtr); + Q_ASSERT(m_gadgetPtr); int status = -1; - void *a[] = { gadgetPtr, nullptr, &status, &flags }; + void *a[] = { m_gadgetPtr, nullptr, &status, &flags }; QMetaObject::metacall(obj, QMetaObject::WriteProperty, idx, a); } -QVariant QQmlValueType::value() +QVariant QQmlGadgetPtrWrapper::value() +{ + Q_ASSERT(m_gadgetPtr); + return QVariant(metaTypeId(), m_gadgetPtr); +} + +void QQmlGadgetPtrWrapper::setValue(const QVariant &value) +{ + Q_ASSERT(m_gadgetPtr); + Q_ASSERT(metaTypeId() == value.userType()); + const QQmlValueType *type = valueType(); + type->destruct(m_gadgetPtr); + type->construct(m_gadgetPtr, value.constData()); +} + +int QQmlGadgetPtrWrapper::metaCall(QMetaObject::Call type, int id, void **argv) { - Q_ASSERT(gadgetPtr); - return QVariant(metaType.id(), gadgetPtr); + Q_ASSERT(m_gadgetPtr); + const QMetaObject *metaObject = valueType(); + QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &id); + metaObject->d.static_metacall(static_cast<QObject *>(m_gadgetPtr), type, id, argv); + return id; } -void QQmlValueType::setValue(const QVariant &value) +const QQmlValueType *QQmlGadgetPtrWrapper::valueType() const { - Q_ASSERT(metaType.id() == value.userType()); - metaType.destruct(gadgetPtr); - metaType.construct(gadgetPtr, value.constData()); + const QObjectPrivate *d = QObjectPrivate::get(this); + return static_cast<const QQmlValueType *>(d->metaObject); } QAbstractDynamicMetaObject *QQmlValueType::toDynamicMetaObject(QObject *) @@ -287,12 +308,9 @@ void QQmlValueType::objectDestroyed(QObject *) { } -int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **argv) +int QQmlValueType::metaCall(QObject *object, QMetaObject::Call type, int _id, void **argv) { - const QMetaObject *mo = _metaObject; - QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &mo, &_id); - mo->d.static_metacall(reinterpret_cast<QObject*>(gadgetPtr), type, _id, argv); - return _id; + return static_cast<QQmlGadgetPtrWrapper *>(object)->metaCall(type, _id, argv); } QString QQmlPointFValueType::toString() const diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 901b7a6fd7..6768991581 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -54,7 +54,9 @@ #include "qqml.h" #include "qqmlproperty.h" #include "qqmlproperty_p.h" + #include <private/qqmlnullablevalue_p.h> +#include <private/qmetatype_p.h> #include <QtCore/qobject.h> #include <QtCore/qrect.h> @@ -65,16 +67,20 @@ QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject +class Q_QML_PRIVATE_EXPORT QQmlValueType : public QAbstractDynamicMetaObject { public: - QQmlValueType(); + QQmlValueType() : metaType(QMetaType::UnknownType) {} QQmlValueType(int userType, const QMetaObject *metaObject); - ~QQmlValueType() override; - void read(QObject *, int); - void write(QObject *, int, QQmlPropertyData::WriteFlags flags); - QVariant value(); - void setValue(const QVariant &); + ~QQmlValueType(); + + void *create() const { return metaType.create(); } + void destroy(void *gadgetPtr) const { metaType.destroy(gadgetPtr); } + + void construct(void *gadgetPtr, const void *copy) const { metaType.construct(gadgetPtr, copy); } + void destruct(void *gadgetPtr) const { metaType.destruct(gadgetPtr); } + + int metaTypeId() const { return metaType.id(); } // ---- dynamic meta object data interface QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) override; @@ -82,12 +88,33 @@ public: int metaCall(QObject *obj, QMetaObject::Call type, int _id, void **argv) override; // ---- -private: - const QMetaObject *_metaObject; - void *gadgetPtr; - public: QMetaType metaType; + QMetaObject *dynamicMetaObject = nullptr; +}; + +class Q_QML_PRIVATE_EXPORT QQmlGadgetPtrWrapper : public QObject +{ + Q_OBJECT +public: + static QQmlGadgetPtrWrapper *instance(QQmlEngine *engine, int index); + + QQmlGadgetPtrWrapper(QQmlValueType *valueType, QObject *parent); + ~QQmlGadgetPtrWrapper(); + + void read(QObject *obj, int idx); + void write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags); + QVariant value(); + void setValue(const QVariant &value); + + int metaTypeId() const { return valueType()->metaTypeId(); } + int metaCall(QMetaObject::Call type, int id, void **argv); + QMetaProperty property(int index) { return valueType()->property(index); } + +private: + const QQmlValueType *valueType() const; + + void *m_gadgetPtr = nullptr; }; class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index ecb86e2f10..de23e929e2 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -136,6 +136,20 @@ static void list_clear(QQmlListProperty<QObject> *prop) resolved.activateSignal(); } +static void list_replace(QQmlListProperty<QObject> *prop, int index, QObject *o) +{ + const ResolvedList resolved(prop); + resolved.list()->replace(index, o); + resolved.activateSignal(); +} + +static void list_removeLast(QQmlListProperty<QObject> *prop) +{ + const ResolvedList resolved(prop); + resolved.list()->removeLast(); + resolved.activateSignal(); +} + QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr() : QQmlGuard<QObject>(nullptr), m_target(nullptr), m_index(-1) { @@ -289,11 +303,13 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) continue; const int valueIndex = vi->m_propertyIndex.valueTypeIndex(); - int type = QQmlData::get(object)->propertyCache->property(id)->propType(); + const QQmlData *data = QQmlData::get(object); + const int type = data->propertyCache->property(id)->propType(); if (type != QMetaType::UnknownType) { if (valueIndex != -1) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(type); + QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance( + data->context->engine, type); Q_ASSERT(valueType); // @@ -327,7 +343,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) // (7) Issue the interceptor call with the new component value. // - QMetaProperty valueProp = valueType->metaObject()->property(valueIndex); + QMetaProperty valueProp = valueType->property(valueIndex); QVariant newValue(type, a[0]); valueType->read(object, id); @@ -735,7 +751,8 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * *static_cast<QQmlListProperty<QObject> *>(a[0]) = QQmlListProperty<QObject>( object, reinterpret_cast<void *>(quintptr(id)), - list_append, list_count, list_at, list_clear); + list_append, list_count, list_at, + list_clear, list_replace, list_removeLast); } else { *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); } @@ -879,9 +896,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); // Value type property or deep alias - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType()); + QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance( + ctxt->engine, pd->propType()); if (valueType) { - valueType->read(target, coreIndex); int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a); |