diff options
Diffstat (limited to 'src/qml/qml')
70 files changed, 1787 insertions, 1340 deletions
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 7d2ad354d6..0f7726ef65 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -188,13 +188,7 @@ void QQmlThreadPrivate::threadEvent() lock(); for (;;) { - if (m_shutdown) { - quit(); - wakeOne(); - unlock(); - - return; - } else if (!threadList.isEmpty()) { + if (!threadList.isEmpty()) { m_threadProcessing = true; QQmlThread::Message *message = threadList.first(); @@ -206,6 +200,12 @@ void QQmlThreadPrivate::threadEvent() lock(); delete threadList.takeFirst(); + } else if (m_shutdown) { + quit(); + wakeOne(); + unlock(); + + return; } else { wakeOne(); @@ -242,6 +242,7 @@ void QQmlThread::shutdown() d->lock(); Q_ASSERT(!d->m_shutdown); + d->m_shutdown = true; for (;;) { if (d->mainSync || !d->mainList.isEmpty()) { d->unlock(); @@ -254,13 +255,10 @@ void QQmlThread::shutdown() } } - d->m_shutdown = true; - if (QCoreApplication::closingDown()) { + if (QCoreApplication::closingDown()) d->quit(); - } else { + else d->triggerThreadEvent(); - d->wait(); - } d->unlock(); d->QThread::wait(); diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index a33936647f..20dd3827c5 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> @@ -61,19 +62,20 @@ void qmlClearTypeRegistrations() // Declared in qqml.h //From qqml.h bool qmlProtectModule(const char *uri, int majVersion) { - return QQmlMetaType::protectModule(QString::fromUtf8(uri), majVersion); + return QQmlMetaType::protectModule(QString::fromUtf8(uri), + QTypeRevision::fromMajorVersion(majVersion)); } //From qqml.h void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor) { - QQmlMetaType::registerModule(uri, versionMajor, versionMinor); + QQmlMetaType::registerModule(uri, QTypeRevision::fromVersion(versionMajor, versionMinor)); } //From qqml.h int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { - return QQmlMetaType::typeId(uri, versionMajor, versionMinor, qmlName); + return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName); } // From qqmlprivate.h @@ -103,9 +105,9 @@ QObject *QQmlPrivate::RegisterSingletonFunctor::operator()(QQmlEngine *qeng, QJS return m_object; }; -static QVector<int> availableRevisions(const QMetaObject *metaObject) +static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject) { - QVector<int> revisions; + QVector<QTypeRevision> revisions; if (!metaObject) return revisions; const int propertyOffset = metaObject->propertyOffset(); @@ -114,7 +116,7 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject) propertyIndex < propertyEnd; ++propertyIndex) { const QMetaProperty property = metaObject->property(propertyIndex); if (int revision = property.revision()) - revisions.append(revision); + revisions.append(QTypeRevision::fromEncodedVersion(revision)); } const int methodOffset = metaObject->methodOffset(); const int methodCount = metaObject->methodCount(); @@ -122,7 +124,7 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject) methodIndex < methodEnd; ++methodIndex) { const QMetaMethod method = metaObject->method(methodIndex); if (int revision = method.revision()) - revisions.append(revision); + revisions.append(QTypeRevision::fromEncodedVersion(revision)); } // Need to also check parent meta objects, as their revisions are inherited. @@ -132,6 +134,54 @@ static QVector<int> availableRevisions(const QMetaObject *metaObject) return revisions; } +template<typename Registration> +void assignVersions(Registration *registration, QTypeRevision revision, + QTypeRevision defaultVersion) +{ + const quint8 majorVersion = revision.hasMajorVersion() ? revision.majorVersion() + : defaultVersion.majorVersion(); + registration->version = revision.hasMinorVersion() + ? QTypeRevision::fromVersion(majorVersion, revision.minorVersion()) + : QTypeRevision::fromMajorVersion(majorVersion); + registration->revision = revision; +} + +static QVector<QTypeRevision> prepareRevisions(const QMetaObject *metaObject, QTypeRevision added) +{ + auto revisions = availableRevisions(metaObject); + revisions.append(added); + return revisions; +} + +static void uniqueRevisions(QVector<QTypeRevision> *revisions, QTypeRevision defaultVersion, + QTypeRevision added) +{ + bool revisionsHaveMajorVersions = false; + for (QTypeRevision revision : QVector<QTypeRevision>(*revisions)) { // yes, copy + // allow any minor version for each explicitly specified past major one + if (revision.hasMajorVersion()) { + revisionsHaveMajorVersions = true; + if (revision.majorVersion() < defaultVersion.majorVersion()) + revisions->append(QTypeRevision::fromVersion(revision.majorVersion(), 254)); + } + } + + if (revisionsHaveMajorVersions) { + if (!added.hasMajorVersion()) { + // If added in unspecified major version, assume default one. + revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), + added.minorVersion())); + } else if (added.majorVersion() < defaultVersion.majorVersion()) { + // If added in past major version, add .0 of default version. + revisions->append(QTypeRevision::fromVersion(defaultVersion.majorVersion(), 0)); + } + } + + std::sort(revisions->begin(), revisions->end()); + const auto it = std::unique(revisions->begin(), revisions->end()); + revisions->erase(it, revisions->end()); +} + /* This method is "over generalized" to allow us to (potentially) register more types of things in the future without adding exported symbols. @@ -163,8 +213,7 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) nullptr, noCreateReason, type.uri, - type.versionMajor, - -1, + type.version, nullptr, type.metaObject, type.attachedPropertiesFunction, @@ -175,28 +224,26 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) type.extensionObjectCreate, type.extensionMetaObject, nullptr, - -1 + QTypeRevision() }; - const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); - const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + const QTypeRevision added = revisionClassInfo( + type.classInfoMetaObject, "QML.AddedInVersion", + QTypeRevision::fromMinorVersion(0)); + const QTypeRevision removed = revisionClassInfo( + type.classInfoMetaObject, "QML.RemovedInVersion"); - auto revisions = availableRevisions(type.metaObject); - revisions.append(qMax(added, 0)); + auto revisions = prepareRevisions(type.metaObject, added); if (type.attachedPropertiesMetaObject) revisions += availableRevisions(type.attachedPropertiesMetaObject); + uniqueRevisions(&revisions, type.version, added); - std::sort(revisions.begin(), revisions.end()); - const auto it = std::unique(revisions.begin(), revisions.end()); - revisions.erase(it, revisions.end()); - - const bool typeWasRemoved = removed >= added; - for (int revision : revisions) { + for (QTypeRevision revision : revisions) { if (revision < added) continue; // When removed, we still add revisions, but anonymous ones - if (typeWasRemoved && revision >= removed) { + if (removed.isValid() && !(revision < removed)) { revisionRegistration.elementName = nullptr; revisionRegistration.create = nullptr; } else { @@ -204,11 +251,8 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) revisionRegistration.create = creatable ? type.create : nullptr; } - // Equivalent of qmlRegisterRevision<T, revision>(...) - revisionRegistration.versionMinor = revision; - revisionRegistration.revision = revision; + assignVersions(&revisionRegistration, revision, type.version); revisionRegistration.customParser = type.customParserFactory(); - qmlregister(TypeRegistration, &revisionRegistration); } break; @@ -220,36 +264,33 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) RegisterSingletonType revisionRegistration = { QmlCurrentSingletonTypeRegistrationVersion, type.uri, - type.versionMajor, - -1, + type.version, elementName, type.scriptApi, nullptr, type.instanceMetaObject, type.typeId, - -1, + QTypeRevision(), type.generalizedQobjectApi }; - const int added = intClassInfo(type.classInfoMetaObject, "QML.AddedInMinorVersion", 0); - const int removed = intClassInfo(type.classInfoMetaObject, "QML.RemovedInMinorVersion", -1); + const QTypeRevision added = revisionClassInfo( + type.classInfoMetaObject, "QML.AddedInVersion", + QTypeRevision::fromMinorVersion(0)); + const QTypeRevision removed = revisionClassInfo( + type.classInfoMetaObject, "QML.RemovedInVersion"); - auto revisions = availableRevisions(type.instanceMetaObject); - revisions.append(qMax(added, 0)); + auto revisions = prepareRevisions(type.instanceMetaObject, added); + uniqueRevisions(&revisions, type.version, added); - std::sort(revisions.begin(), revisions.end()); - const auto it = std::unique(revisions.begin(), revisions.end()); - revisions.erase(it, revisions.end()); - - const bool typeWasRemoved = removed >= added; - for (int revision : qAsConst(revisions)) { + for (QTypeRevision revision : qAsConst(revisions)) { if (revision < added) continue; // When removed, we still add revisions, but anonymous ones - if (typeWasRemoved && revision >= removed) { + if (removed.isValid() && !(revision < removed)) { revisionRegistration.typeName = nullptr; revisionRegistration.scriptApi = nullptr; revisionRegistration.generalizedQobjectApi = nullptr; @@ -259,10 +300,7 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data) revisionRegistration.generalizedQobjectApi = type.generalizedQobjectApi; } - // Equivalent of qmlRegisterRevision<T, revision>(...) - revisionRegistration.versionMinor = revision; - revisionRegistration.revision = revision; - + assignVersions(&revisionRegistration, revision, type.version); qmlregister(SingletonRegistration, &revisionRegistration); } break; @@ -321,4 +359,38 @@ 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; + + RegisterTypeAndRevisions type = { + 0, + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T>>(), + 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 ae3893dd73..840c6aaee3 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -44,6 +44,7 @@ #include <QtCore/qbytearray.h> #include <QtCore/qmetaobject.h> +#include <QtCore/qversionnumber.h> #define QML_VERSION 0x020000 #define QML_VERSION_STR "2.0" @@ -88,10 +89,16 @@ friend void QML_REGISTER_TYPES_AND_REVISIONS(const char *uri, int versionMajor); #define QML_ADDED_IN_MINOR_VERSION(VERSION) \ - Q_CLASSINFO("QML.AddedInMinorVersion", #VERSION) + Q_CLASSINFO("QML.AddedInVersion", Q_REVISION(VERSION)) + +#define QML_ADDED_IN_VERSION(MAJOR, MINOR) \ + Q_CLASSINFO("QML.AddedInVersion", Q_REVISION(MAJOR, MINOR)) #define QML_REMOVED_IN_MINOR_VERSION(VERSION) \ - Q_CLASSINFO("QML.RemovedInMinorVersion", #VERSION) + Q_CLASSINFO("QML.RemovedInVersion", Q_REVISION(VERSION)) + +#define QML_REMOVED_IN_VERSION(MAJOR, MINOR) \ + Q_CLASSINFO("QML.RemovedInVersion", Q_REVISION(MAJOR, MINOR)) #define QML_ATTACHED(ATTACHED_TYPE) \ Q_CLASSINFO("QML.Attached", #ATTACHED_TYPE) \ @@ -113,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 }; @@ -139,18 +156,16 @@ QQmlCustomParser *qmlCreateCustomParser(); template<typename T> int qmlRegisterAnonymousType(const char *uri, int versionMajor) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), 0, nullptr, QString(), - uri, versionMajor, 0, nullptr, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -162,7 +177,7 @@ int qmlRegisterAnonymousType(const char *uri, int versionMajor) nullptr, nullptr, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -176,23 +191,22 @@ 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) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T>>(), 0, nullptr, reason, - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -204,7 +218,7 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin nullptr, nullptr, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -213,18 +227,16 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin template<typename T, int metaObjectRevision> int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), 0, nullptr, reason, - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -236,7 +248,7 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin nullptr, nullptr, nullptr, - metaObjectRevision + QTypeRevision::fromMinorVersion(metaObjectRevision) }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -245,8 +257,6 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin template<typename T, typename E> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) { - QML_GETTYPENAMES - QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); if (!attached) { @@ -257,13 +267,13 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), 0, nullptr, reason, - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, attached, attachedMetaObject, @@ -275,7 +285,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::createParent<E>, &E::staticMetaObject, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -284,8 +294,6 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve template<typename T, typename E, int metaObjectRevision> int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) { - QML_GETTYPENAMES - QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); if (!attached) { @@ -296,13 +304,13 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::RegisterType type = { 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), 0, nullptr, reason, - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, attached, attachedMetaObject, @@ -314,7 +322,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::createParent<E>, &E::staticMetaObject, nullptr, - metaObjectRevision + QTypeRevision::fromMinorVersion(metaObjectRevision) }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -325,17 +333,15 @@ Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaO template<typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -347,7 +353,7 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c nullptr, nullptr, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -356,17 +362,15 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c template<typename T, int metaObjectRevision> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -378,7 +382,7 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c nullptr, nullptr, nullptr, - metaObjectRevision + QTypeRevision::fromMinorVersion(metaObjectRevision) }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -387,17 +391,15 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c template<typename T, int metaObjectRevision> int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, nullptr, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -409,28 +411,25 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) nullptr, nullptr, nullptr, - metaObjectRevision + QTypeRevision::fromMinorVersion(metaObjectRevision) }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } - template<typename T, typename E> -int qmlRegisterExtendedType() +int qmlRegisterExtendedType(const char *uri, int versionMajor) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), 0, nullptr, QString(), - nullptr, 0, 0, nullptr, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, 0), nullptr, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -442,18 +441,25 @@ int qmlRegisterExtendedType() QQmlPrivate::createParent<E>, &E::staticMetaObject, nullptr, - 0 + QTypeRevision::zero() }; 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) { - QML_GETTYPENAMES - QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); if (!attached) { @@ -464,12 +470,12 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, attached, attachedMetaObject, @@ -481,13 +487,15 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::createParent<E>, &E::staticMetaObject, nullptr, - 0 + QTypeRevision::zero() }; 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); @@ -496,12 +504,31 @@ int qmlRegisterInterface(const char *typeName) QByteArray listName("QQmlListProperty<" + name + '>'); QQmlPrivate::RegisterInterface qmlInterface = { - 0, + 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), - 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) +{ + QQmlPrivate::RegisterInterface qmlInterface = { + 1, + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), + qobject_interface_iid<T *>(), + + uri, + QTypeRevision::fromVersion(versionMajor, 0) }; return QQmlPrivate::qmlregister(QQmlPrivate::InterfaceRegistration, &qmlInterface); @@ -511,17 +538,15 @@ template<typename T> int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -533,7 +558,7 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, nullptr, nullptr, parser, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -543,17 +568,15 @@ template<typename T, int metaObjectRevision> int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser) { - QML_GETTYPENAMES - QQmlPrivate::RegisterType type = { 1, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -565,7 +588,7 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, nullptr, nullptr, parser, - metaObjectRevision + QTypeRevision::fromMinorVersion(metaObjectRevision) }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -575,8 +598,6 @@ template<typename T, typename E> int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser) { - QML_GETTYPENAMES - QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); if (!attached) { @@ -587,12 +608,12 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T *>(), + QMetaType::fromType<QQmlListProperty<T> >(), sizeof(T), QQmlPrivate::createInto<T>, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, attached, attachedMetaObject, @@ -604,7 +625,7 @@ int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int version QQmlPrivate::createParent<E>, &E::staticMetaObject, parser, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -667,9 +688,9 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi QQmlPrivate::RegisterSingletonType api = { 0, - uri, versionMajor, versionMinor, typeName, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), typeName, - callback, nullptr, nullptr, 0, 0, {} + callback, nullptr, nullptr, QMetaType(), QTypeRevision::zero(), {} }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -680,14 +701,13 @@ template <typename T> inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, QObject *(*callback)(QQmlEngine *, QJSEngine *)) { - QML_GETTYPENAMES - QQmlPrivate::RegisterSingletonType api = { QmlCurrentSingletonTypeRegistrationVersion, - uri, versionMajor, versionMinor, typeName, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), typeName, + - nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback + nullptr, nullptr, &T::staticMetaObject, QMetaType::fromType<T *>(), QTypeRevision::zero(), callback }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -698,15 +718,13 @@ template <typename T, typename F, typename std::enable_if<std::is_convertible<F, inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName, F&& callback) { - - QML_GETTYPENAMES - QQmlPrivate::RegisterSingletonType api = { QmlCurrentSingletonTypeRegistrationVersion, - uri, versionMajor, versionMinor, typeName, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), typeName, - nullptr, nullptr, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, callback + + nullptr, nullptr, &T::staticMetaObject, QMetaType::fromType<T *>(), QTypeRevision::zero(), callback }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -732,8 +750,7 @@ inline int qmlRegisterSingletonType(const QUrl &url, const char *uri, int versio QQmlPrivate::RegisterCompositeSingletonType type = { url, uri, - versionMajor, - versionMinor, + QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName }; @@ -751,19 +768,18 @@ inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, i QQmlPrivate::RegisterCompositeType type = { url, uri, - versionMajor, - versionMinor, + QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName }; 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>( @@ -772,7 +788,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>( @@ -780,6 +796,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); @@ -789,7 +813,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); } @@ -797,6 +822,38 @@ void qmlRegisterTypesAndRevisions(const char *uri, int versionMajor) template<> inline void qmlRegisterTypesAndRevisions<>(const char *, int) {} +inline void qmlRegisterNamespaceAndRevisions(const QMetaObject *metaObject, + const char *uri, int versionMajor) +{ + QQmlPrivate::RegisterTypeAndRevisions type = { + 0, + QMetaType(), + QMetaType(), + 0, + nullptr, + + uri, + QTypeRevision::fromMajorVersion(versionMajor), + + metaObject, + metaObject, + + nullptr, + nullptr, + + -1, + -1, + -1, + + nullptr, + nullptr, + + &qmlCreateCustomParser<void> + }; + + qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type); +} + int Q_QML_EXPORT qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName); QT_END_NAMESPACE 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/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 279998b5de..ede2816d5f 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -50,6 +50,7 @@ #include "qqmlincubator.h" #include "qqmlincubator_p.h" #include <private/qqmljavascriptexpression_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> @@ -1424,8 +1425,8 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP } error.setDescription(description); error.setUrl(unsetRequiredProperty.fileUrl); - error.setLine(unsetRequiredProperty.location.line); - error.setColumn(unsetRequiredProperty.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.column)); return error; } diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index cb5d5a787c..9a4ea711f3 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -71,6 +71,7 @@ class Q_QML_EXPORT QQmlComponent : public QObject Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl url READ url CONSTANT) QML_NAMED_ELEMENT(Component) + QML_ADDED_IN_VERSION(2, 0) QML_ATTACHED(QQmlComponentAttached) Q_CLASSINFO("QML.Builtin", "QML") diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h index 8ecd9da17d..eb6d35652b 100644 --- a/src/qml/qml/qqmlcomponentattached_p.h +++ b/src/qml/qml/qqmlcomponentattached_p.h @@ -66,6 +66,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject // when registering QQmlComponent, but we cannot #include it from qqmlcomponent.h. Therefore we // force an anonymous type registration here. QML_ANONYMOUS + QML_ADDED_IN_VERSION(2, 0) public: QQmlComponentAttached(QObject *parent = nullptr); ~QQmlComponentAttached(); diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 87f7fffe41..b0df4f26dc 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -40,6 +40,7 @@ #include "qqmlcustomparser_p.h" #include <private/qv4compileddata_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <QtCore/qdebug.h> @@ -100,10 +101,10 @@ void QQmlCustomParser::clearErrors() */ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { - QQmlJS::DiagnosticMessage error; - error.line = location.line; - error.column = location.column; - error.message = description; + QQmlError error; + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setDescription(description); exceptions << error; } @@ -125,8 +126,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 +143,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/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index df8cbc9072..4eb709228e 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -83,7 +83,7 @@ public: virtual void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; virtual void applyBindings(QObject *, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &, const QList<const QV4::CompiledData::Binding *> &) = 0; - QVector<QQmlJS::DiagnosticMessage> errors() const { return exceptions; } + QVector<QQmlError> errors() const { return exceptions; } protected: void error(const QV4::CompiledData::Binding *binding, const QString& description) @@ -97,7 +97,7 @@ protected: const QMetaObject *resolveType(const QString&) const; private: - QVector<QQmlJS::DiagnosticMessage> exceptions; + QVector<QQmlError> exceptions; QQmlEnginePrivate *engine; const QQmlPropertyValidator *validator; Flags m_flags; @@ -107,11 +107,6 @@ private: }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags) -#if 0 -#define QML_REGISTER_CUSTOM_TYPE(URI, VERSION_MAJ, VERSION_MIN, NAME, TYPE, CUSTOMTYPE) \ - qmlRegisterCustomType<TYPE>(#URI, VERSION_MAJ, VERSION_MIN, #NAME, #TYPE, new CUSTOMTYPE) -#endif - QT_END_NAMESPACE #endif diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp index 1ab6002f0a..c29f207ae3 100644 --- a/src/qml/qml/qqmldatablob.cpp +++ b/src/qml/qml/qqmldatablob.cpp @@ -42,6 +42,7 @@ #include <private/qqmlprofiler_p.h> #include <private/qqmltypeloader_p.h> #include <private/qqmltypeloaderthread_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <QtQml/qqmlengine.h> @@ -289,7 +290,18 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) Q_ASSERT(status() != Error); Q_ASSERT(m_errors.isEmpty()); - m_errors = errors; // Must be set before the m_data fence + // m_errors must be set before the m_data fence + m_errors.reserve(errors.count()); + for (const QQmlError &error : errors) { + if (error.url().isEmpty()) { + QQmlError mutableError = error; + mutableError.setUrl(url()); + m_errors.append(mutableError); + } else { + m_errors.append(error); + } + } + m_data.setStatus(Error); if (dumpErrors()) { @@ -306,28 +318,13 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) void QQmlDataBlob::setError(const QQmlJS::DiagnosticMessage &error) { QQmlError e; - e.setColumn(error.column); - e.setLine(error.line); + e.setColumn(qmlConvertSourceCoordinate<quint32, int>(error.loc.startColumn)); + e.setLine(qmlConvertSourceCoordinate<quint32, int>(error.loc.startLine)); e.setDescription(error.message); e.setUrl(url()); setError(e); } -void QQmlDataBlob::setError(const QVector<QQmlJS::DiagnosticMessage> &errors) -{ - QList<QQmlError> finalErrors; - finalErrors.reserve(errors.count()); - for (const auto &error : errors) { - QQmlError e; - e.setColumn(error.column); - e.setLine(error.line); - e.setDescription(error.message); - e.setUrl(url()); - finalErrors << e; - } - setError(finalErrors); -} - void QQmlDataBlob::setError(const QString &description) { QQmlError e; diff --git a/src/qml/qml/qqmldatablob_p.h b/src/qml/qml/qqmldatablob_p.h index 0450e94c02..17db8f2dfe 100644 --- a/src/qml/qml/qqmldatablob_p.h +++ b/src/qml/qml/qqmldatablob_p.h @@ -132,7 +132,6 @@ protected: void setError(const QQmlError &); void setError(const QList<QQmlError> &errors); void setError(const QQmlJS::DiagnosticMessage &error); - void setError(const QVector<QQmlJS::DiagnosticMessage> &errors); void setError(const QString &description); void addDependency(QQmlDataBlob *); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 5d7dddd153..725d2e7c7a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -57,11 +57,11 @@ #include "qqmlnotifier_p.h" #include "qqmlincubator.h" #include "qqmlabstracturlinterceptor.h" +#include "qqmlsourcecoordinate_p.h" #include <private/qqmldirparser_p.h> #include <private/qqmlboundsignal_p.h> #include <private/qqmljsdiagnosticmessage_p.h> #include <QtCore/qstandardpaths.h> -#include <QtCore/qsettings.h> #include <QtCore/qmetaobject.h> #include <QDebug> #include <QtCore/qcoreapplication.h> @@ -112,13 +112,13 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, QQmlPrivate::RegisterType type = { 0, - 0, - 0, + QMetaType(), + QMetaType(), 0, nullptr, reason, - uri, versionMajor, versionMinor, qmlName, &staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &staticMetaObject, QQmlAttachedPropertiesFunc(), nullptr, @@ -130,7 +130,7 @@ int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, nullptr, nullptr, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); @@ -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; @@ -1335,12 +1331,16 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) \code class MySingleton : public QObject { \Q_OBJECT + + // Register as default constructed singleton. + QML_ELEMENT + QML_SINGLETON + static int typeId; // ... }; - // Register with QObject* callback - MySingleton::typeId = qmlRegisterSingletonType<MySingleton>(...); + MySingleton::typeId = qmlTypeId(...); // Retrieve as QObject* QQmlEngine engine; @@ -1357,11 +1357,10 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) QJSValue instance = engine.singletonInstance<QJSValue>(typeId); \endcode - It is recommended to store the QML type id during registration, e.g. as a static member - in the singleton class. Otherwise, a costly lookup via qmlTypeId() has to be performed - at run-time. + It is recommended to store the QML type id, e.g. as a static member in the + singleton class. The lookup via qmlTypeId() is costly. - \sa qmlRegisterSingletonType(), qmlTypeId() + \sa QML_SINGLETON, qmlRegisterSingletonType(), qmlTypeId() \since 5.12 */ template<> @@ -2096,15 +2095,15 @@ QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics( QList<QQmlError> errors; for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(fileName), m.line, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); continue; } QQmlError error; error.setUrl(QUrl(fileName)); error.setDescription(m.message); - error.setLine(m.line); - error.setColumn(m.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(m.loc.startLine)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(m.loc.startColumn)); errors << error; } return errors; @@ -2244,7 +2243,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths) bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors) { Q_D(QQmlEngine); - return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), -1, errors); + return d->importDatabase.importDynamicPlugin(filePath, uri, QString(), QTypeRevision(), errors); } #endif @@ -2301,17 +2300,6 @@ QString QQmlEngine::offlineStorageDatabaseFilePath(const QString &databaseName) return d->offlineStorageDatabaseDirectory() + QLatin1String(md5.result().toHex()); } -// #### Qt 6: Remove this function, it exists only for binary compatibility. -/*! - * \internal - */ -bool QQmlEngine::addNamedBundle(const QString &name, const QString &fileName) -{ - Q_UNUSED(name) - Q_UNUSED(fileName) - return false; -} - QString QQmlEnginePrivate::offlineStorageDatabaseDirectory() const { Q_Q(const QQmlEngine); @@ -2356,67 +2344,100 @@ int QQmlEnginePrivate::listType(int t) const static QQmlPropertyCache *propertyCacheForPotentialInlineComponentType(int t, const QHash<int, QV4::ExecutableCompilationUnit *>::const_iterator &iter) { - if (t != (*iter)->metaTypeId) { + if (t != (*iter)->metaTypeId.id()) { // this is an inline component, and what we have in the iterator is currently the parent compilation unit for (auto &&icDatum: (*iter)->inlineComponentData) - if (icDatum.typeIds.id == t) + if (icDatum.typeIds.id.id() == t) return (*iter)->propertyCaches.at(icDatum.objectIndex); } return (*iter)->rootPropertyCache().data(); } +/*! + * \internal + * + * Look up by type's baseMetaObject. + */ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { - Locker locker(this); - auto iter = m_compositeTypes.constFind(t); - if (iter != m_compositeTypes.cend()) { - return propertyCacheForPotentialInlineComponentType(t, iter); - } else { - QQmlType type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type.baseMetaObject()); - } + if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t)) + return QQmlMetaObject(composite); + + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.baseMetaObject()); } +/*! + * \internal + * + * Look up by type's metaObject. + */ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { - Locker locker(this); - auto iter = m_compositeTypes.constFind(t); - if (iter != m_compositeTypes.cend()) { - return propertyCacheForPotentialInlineComponentType(t, iter); - } else { - QQmlType type = QQmlMetaType::qmlType(t); - return QQmlMetaObject(type.metaObject()); - } + if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t)) + return QQmlMetaObject(composite); + + QQmlType type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type.metaObject()); } +/*! + * \internal + * + * Look up by type's metaObject and version. + */ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) { - Locker locker(this); - auto iter = m_compositeTypes.constFind(t); - if (iter != m_compositeTypes.cend()) { - return propertyCacheForPotentialInlineComponentType(t, iter); - } else { - QQmlType type = QQmlMetaType::qmlType(t); - locker.unlock(); - return type.isValid() ? cache(type.metaObject()) : nullptr; - } + if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t)) + return composite; + + QQmlType type = QQmlMetaType::qmlType(t); + return type.isValid() ? cache(type.metaObject(), type.version()) : nullptr; +} + +/*! + * \internal + * + * Look up by type's baseMetaObject and unspecified/any version. + * TODO: Is this correct? Passing a plain QTypeRevision() rather than QTypeRevision::zero() or + * the actual type's version seems strange. The behavior has been in place for a while. + */ +QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) +{ + if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t)) + return composite; + + QQmlType type = QQmlMetaType::qmlType(t); + return type.isValid() ? cache(type.baseMetaObject(), QTypeRevision()) : nullptr; +} + +/*! + * \internal + * + * Look up by QQmlType and version. We only fall back to lookup by metaobject if the type + * has no revisiononed attributes here. Unspecified versions are interpreted as "any". + */ +QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, QTypeRevision version) +{ + if (QQmlPropertyCache *composite = findPropertyCacheInCompositeTypes(t)) + return composite; + + QQmlType type = QQmlMetaType::qmlType(t); + if (!type.isValid()) + return nullptr; + + return type.containsRevisionedAttributes() + ? QQmlMetaType::propertyCache(type, version) + : cache(type.metaObject(), version); } -QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVersion) +QQmlPropertyCache *QQmlEnginePrivate::findPropertyCacheInCompositeTypes(int t) const { Locker locker(this); auto iter = m_compositeTypes.constFind(t); - if (iter != m_compositeTypes.cend()) { - return propertyCacheForPotentialInlineComponentType(t, iter); - } else { - QQmlType type = QQmlMetaType::qmlType(t); - locker.unlock(); - - if (minorVersion >= 0) - return type.isValid() ? cache(type, minorVersion) : nullptr; - else - return type.isValid() ? cache(type.baseMetaObject()) : nullptr; - } + return (iter == m_compositeTypes.constEnd()) + ? nullptr + : propertyCacheForPotentialInlineComponentType(t, iter); } void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) @@ -2426,10 +2447,9 @@ void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilation Locker locker(this); // The QQmlCompiledData is not referenced here, but it is removed from this // hash in the QQmlCompiledData destructor - m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit); - for (auto &&data: compilationUnit->inlineComponentData) { - m_compositeTypes.insert(data.typeIds.id, compilationUnit); - } + m_compositeTypes.insert(compilationUnit->metaTypeId.id(), compilationUnit); + for (auto &&data: compilationUnit->inlineComponentData) + m_compositeTypes.insert(data.typeIds.id.id(), compilationUnit); } void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) @@ -2437,9 +2457,9 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilati compilationUnit->isRegisteredWithEngine = false; Locker locker(this); - m_compositeTypes.remove(compilationUnit->metaTypeId); + m_compositeTypes.remove(compilationUnit->metaTypeId.id()); for (auto&& icDatum: compilationUnit->inlineComponentData) - m_compositeTypes.remove(icDatum.typeIds.id); + m_compositeTypes.remove(icDatum.typeIds.id.id()); } QV4::ExecutableCompilationUnit *QQmlEnginePrivate::obtainExecutableCompilationUnit(int typeId) diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 31fe3a1849..a686d8a1d9 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -112,7 +112,9 @@ public: void setPluginPathList(const QStringList &paths); void addPluginPath(const QString& dir); - bool addNamedBundle(const QString &name, const QString &fileName); +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED bool addNamedBundle(const QString &, const QString &) { return false; } +#endif #if QT_CONFIG(library) bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 33fa800ff4..424335b61a 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -105,6 +105,7 @@ struct QObjectForeign { Q_GADGET QML_FOREIGN(QObject) QML_NAMED_ELEMENT(QtObject) + QML_ADDED_IN_VERSION(2, 0) Q_CLASSINFO("QML.Root", "QML") }; @@ -216,7 +217,7 @@ public: QString offlineStorageDatabaseDirectory() const; // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(const QQmlType &, int); + inline QQmlPropertyCache *cache(const QQmlType &, QTypeRevision version); using QJSEnginePrivate::cache; // These methods may be called from the loader thread @@ -228,7 +229,8 @@ public: QQmlMetaObject rawMetaObjectForType(int) const; QQmlMetaObject metaObjectForType(int) const; QQmlPropertyCache *propertyCacheForType(int); - QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1); + QQmlPropertyCache *rawPropertyCacheForType(int); + QQmlPropertyCache *rawPropertyCacheForType(int, QTypeRevision version); void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(int typeId); @@ -268,8 +270,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. @@ -282,6 +300,7 @@ private: void doDeleteInEngineThread(); void cleanupScarceResources(); + QQmlPropertyCache *findPropertyCacheInCompositeTypes(int t) const; }; /* @@ -380,15 +399,15 @@ Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersion) +QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, QTypeRevision version) { Q_ASSERT(type.isValid()); - if (minorVersion == -1 || !type.containsRevisionedAttributes()) - return cache(type.metaObject(), minorVersion); + if (!version.hasMinorVersion() || !type.containsRevisionedAttributes()) + return cache(type.metaObject(), version); Locker locker(this); - return QQmlMetaType::propertyCache(type, minorVersion); + return QQmlMetaType::propertyCache(type, version); } QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e) diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 0b94ed3b49..da585d2126 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -77,12 +77,15 @@ QT_BEGIN_NAMESPACE \sa QQuickView::errors(), QQmlComponent::errors() */ -class QQmlErrorPrivate : public QQmlJS::DiagnosticMessage +class QQmlErrorPrivate { public: - QQmlErrorPrivate() { type = QtWarningMsg; } QUrl url; QPointer<QObject> object; + QString message; + QtMsgType type = QtWarningMsg; + int line = -1; + int column = -1; }; /*! @@ -185,7 +188,7 @@ void QQmlError::setDescription(const QString &description) int QQmlError::line() const { if (d) - return qmlConvertSourceCoordinate<quint32, int>(d->line); + return d->line; return -1; } @@ -196,7 +199,7 @@ void QQmlError::setLine(int line) { if (!d) d = new QQmlErrorPrivate; - d->line = qmlConvertSourceCoordinate<int, quint32>(line); + d->line = line; } /*! @@ -205,7 +208,7 @@ void QQmlError::setLine(int line) int QQmlError::column() const { if (d) - return qmlConvertSourceCoordinate<quint32, int>(d->column); + return d->column; return -1; } @@ -216,7 +219,7 @@ void QQmlError::setColumn(int column) { if (!d) d = new QQmlErrorPrivate; - d->column = qmlConvertSourceCoordinate<int, quint32>(column); + d->column = column; } /*! diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index 7a62c967e7..f779199b74 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -117,6 +117,16 @@ QUrl QQmlExtensionPlugin::baseUrl() const } /*! + \since 6.0 + + Override this method to unregister types manually registered in registerTypes. +*/ +void QQmlExtensionPlugin::unregisterTypes() +{ + +} + +/*! \internal */ diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h index ef7ff422cd..78371106bd 100644 --- a/src/qml/qml/qqmlextensionplugin.h +++ b/src/qml/qml/qqmlextensionplugin.h @@ -64,6 +64,7 @@ public: QUrl baseUrl() const; void registerTypes(const char *uri) override = 0; + virtual void unregisterTypes(); void initializeEngine(QQmlEngine *engine, const char *uri) override; private: diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index ee54359d0f..465a342129 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -187,7 +187,7 @@ void QQmlFileNetworkReply::networkFinished() } } - if (m_reply->networkError()) { + if (m_reply->error()) { m_p->errorString = m_reply->errorString(); m_p->error = QQmlFilePrivate::Network; } else { diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 80eafdf146..47f7b40938 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -161,9 +161,17 @@ void qmlClearEnginePlugins() #if QT_CONFIG(library) for (auto &plugin : qAsConst(*plugins)) { QPluginLoader* loader = plugin.loader; - if (loader && !loader->unload()) - qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); - delete loader; + if (loader) { + auto extensionPlugin = qobject_cast<QQmlExtensionPlugin *>(loader->instance()); + if (extensionPlugin) { + extensionPlugin->unregisterTypes(); + } +#ifndef Q_OS_MACOS + if (!loader->unload()) + qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); + delete loader; +#endif + } } #endif plugins->clear(); @@ -213,12 +221,12 @@ public: QQmlImportNamespace *importNamespace(const QString &prefix) const; bool addLibraryImport(const QString& uri, const QString &prefix, - int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, + QTypeRevision version, const QString &qmldirIdentifier, + const QString &qmldirUrl, bool incomplete, QQmlImportDatabase *database, QList<QQmlError> *errors); - bool addFileImport(const QString &uri, const QString &prefix, - int vmaj, int vmin, + bool addFileImport(const QString &uri, const QString &prefix, QTypeRevision version, bool isImplicitImport, bool incomplete, QQmlImportDatabase *database, QList<QQmlError> *errors); @@ -227,7 +235,7 @@ public: QQmlImportDatabase *database, QList<QQmlError> *errors); - bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor, + bool resolveType(const QHashedStringRef &type, QTypeRevision *version_return, QQmlType *type_return, QList<QQmlError> *errors, QQmlType::RegistrationType registrationType, bool *typeRecursionDetected = nullptr); @@ -247,14 +255,13 @@ public: QQmlTypeLoader *typeLoader; static QQmlImports::LocalQmldirResult locateLocalQmldir( - const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database, + const QString &uri, QTypeRevision version, QQmlImportDatabase *database, QString *outQmldirFilePath, QString *outUrl); - static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin, - QList<QQmlError> *errors); + static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, + QTypeRevision version, QList<QQmlError> *errors); - bool importExtension(const QString &absoluteFilePath, const QString &uri, - int vmaj, int vmin, + bool importExtension(const QString &absoluteFilePath, const QString &uri, QTypeRevision version, QQmlImportDatabase *database, const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors); @@ -264,10 +271,10 @@ public: QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); - QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace, - const QString &uri, const QString &url, - int vmaj, int vmin, QV4::CompiledData::Import::ImportType type, - QList<QQmlError> *errors, bool lowPrecedence = false); + QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace, const QString &uri, + const QString &url, QTypeRevision version, + QV4::CompiledData::Import::ImportType type, + QList<QQmlError> *errors, bool lowPrecedence = false); bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris, const QString &qmldirPath, QList<QQmlError> *errors); @@ -344,9 +351,9 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const for (int ii = set.imports.count() - 1; ii >= 0; --ii) { const QQmlImportInstance *import = set.imports.at(ii); - QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion); + QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version); if (module) { - cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion)); + cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->version)); } } @@ -360,10 +367,10 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const for (int ii = set.imports.count() - 1; ii >= 0; --ii) { const QQmlImportInstance *import = set.imports.at(ii); - QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion); + QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version); if (module) { QQmlImportRef &typeimport = cache->m_namedImports[set.prefix]; - typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion)); + typeimport.modules.append(QQmlTypeModuleVersion(module, import->version)); } } } @@ -395,36 +402,35 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports:: const QQmlDirComponents &components = import->qmlDirComponents; - const int importMajorVersion = import->majversion; - const int importMinorVersion = import->minversion; - auto shouldSkipSingleton = [importMajorVersion, importMinorVersion](int singletonMajorVersion, int singletonMinorVersion) -> bool { - return importMajorVersion != -1 && - (singletonMajorVersion > importMajorVersion || (singletonMajorVersion == importMajorVersion && singletonMinorVersion > importMinorVersion)); + const QTypeRevision importVersion = import->version; + auto shouldSkipSingleton = [importVersion](QTypeRevision singletonVersion) -> bool { + return importVersion.hasMajorVersion() && + (singletonVersion.majorVersion() > importVersion.majorVersion() + || (singletonVersion.majorVersion() == importVersion.majorVersion() + && singletonVersion.minorVersion() > importVersion.minorVersion())); }; ConstIterator cend = components.constEnd(); for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) { if (cit->singleton && excludeBaseUrl(import->url, cit->fileName, baseUrl.toString())) { - if (shouldSkipSingleton(cit->majorVersion, cit->minorVersion)) + if (shouldSkipSingleton(cit->version)) continue; QQmlImports::CompositeSingletonReference ref; ref.typeName = cit->typeName; ref.prefix = set.prefix; - ref.majorVersion = cit->majorVersion; - ref.minorVersion = cit->minorVersion; + ref.version = cit->version; resultList.append(ref); } } - if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion)) { + if (QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->version)) { module->walkCompositeSingletons([&resultList, &set, &shouldSkipSingleton](const QQmlType &singleton) { - if (shouldSkipSingleton(singleton.majorVersion(), singleton.minorVersion())) + if (shouldSkipSingleton(singleton.version())) return; QQmlImports::CompositeSingletonReference ref; ref.typeName = singleton.elementName(); ref.prefix = set.prefix; - ref.majorVersion = singleton.majorVersion(); - ref.minorVersion = singleton.minorVersion(); + ref.version = singleton.version(); resultList.append(ref); }); } @@ -461,9 +467,9 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi if (lhs.typeName != rhs.typeName) return lhs.typeName < rhs.typeName; - return lhs.majorVersion != rhs.majorVersion - ? lhs.majorVersion < rhs.majorVersion - : lhs.minorVersion < rhs.minorVersion; + return lhs.version.majorVersion() != rhs.version.majorVersion() + ? lhs.version.majorVersion() < rhs.version.majorVersion() + : lhs.version.minorVersion() < rhs.version.minorVersion(); }); return compositeSingletons; @@ -532,16 +538,17 @@ static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep) - base/QtQml.2/Models/qmldir - base/QtQml/Models/qmldir */ -QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin) +QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, + QTypeRevision version) { - const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts); + const QVector<QStringRef> parts = uri.splitRef(Dot, Qt::SkipEmptyParts); QStringList qmlDirPathsPaths; // fully & partially versioned parts + 1 unversioned for each base path qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1)); - for (int version = FullyVersioned; version <= Unversioned; ++version) { - const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); + for (int versionMode = FullyVersioned; versionMode <= Unversioned; ++versionMode) { + const QString ver = versionString(version, QQmlImports::ImportVersion(versionMode)); for (const QString &path : basePaths) { QString dir = path; @@ -551,7 +558,7 @@ QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringLi // append to the end qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir; - if (version != Unversioned) { + if (versionMode != Unversioned) { // insert in the middle for (int index = parts.count() - 2; index >= 0; --index) { qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash) @@ -565,14 +572,14 @@ QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringLi return qmlDirPathsPaths; } -QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) +QString QQmlImports::versionString(QTypeRevision version, ImportVersion versionMode) { - if (version == QQmlImports::FullyVersioned) { + if (versionMode == QQmlImports::FullyVersioned) { // extension with fully encoded version number (eg. MyModule.3.2) - return QString::asprintf(".%d.%d", vmaj, vmin); - } else if (version == QQmlImports::PartiallyVersioned) { + return QString::asprintf(".%d.%d", version.majorVersion(), version.minorVersion()); + } else if (versionMode == QQmlImports::PartiallyVersioned) { // extension with encoded version major (eg. MyModule.3) - return QString::asprintf(".%d", vmaj); + return QString::asprintf(".%d", version.majorVersion()); } // else extension without version number (eg. MyModule) return QString(); } @@ -591,7 +598,7 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) \sa addFileImport(), addLibraryImport */ bool QQmlImports::resolveType(const QHashedStringRef &type, - QQmlType *type_return, int *vmaj, int *vmin, + QQmlType *type_return, QTypeRevision *version_return, QQmlImportNamespace** ns_return, QList<QQmlError> *errors, QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) const @@ -603,7 +610,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return true; } if (type_return) { - if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType, + if (d->resolveType(type, version_return, type_return, errors, registrationType, typeRecursionDetected)) { if (qmlImportTrace()) { #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ @@ -627,7 +634,9 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return false; } -bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) +bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, + const QQmlTypeLoaderQmldirContent &qmldir, + QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) { Q_ASSERT(resolvedUrl.endsWith(Slash)); url = resolvedUrl; @@ -648,24 +657,27 @@ bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQml } } - qmlDirScripts = getVersionedScripts(scripts, majversion, minversion); + qmlDirScripts = getVersionedScripts(scripts, version); } return true; } -QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin) +QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, + QTypeRevision version) { QMap<QString, QQmlDirParser::Script> versioned; for (QList<QQmlDirParser::Script>::const_iterator sit = qmldirscripts.constBegin(); sit != qmldirscripts.constEnd(); ++sit) { // Only include scripts that match our requested version - if (((vmaj == -1) || (sit->majorVersion == vmaj)) && - ((vmin == -1) || (sit->minorVersion <= vmin))) { + if ((!version.hasMajorVersion() || (sit->version.majorVersion() == version.majorVersion())) + && (!version.hasMinorVersion() + || (sit->version.minorVersion() <= version.minorVersion()))) { // Load the highest version that matches QMap<QString, QQmlDirParser::Script>::iterator vit = versioned.find(sit->nameSpace); - if (vit == versioned.end() || (vit->minorVersion < sit->minorVersion)) { + if (vit == versioned.end() + || (vit->version.minorVersion() < sit->version.minorVersion())) { versioned.insert(sit->nameSpace, *sit); } } @@ -685,26 +697,25 @@ QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qml If the return pointer is 0, the corresponding search is not done. */ bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &type, - QQmlType *type_return, int *vmaj, int *vmin, + QQmlType *type_return, QTypeRevision *version_return, QQmlType::RegistrationType registrationType) const { - return ns->resolveType(d->typeLoader, type, vmaj, vmin, type_return, nullptr, nullptr, registrationType); + return ns->resolveType(d->typeLoader, type, version_return, type_return, nullptr, nullptr, + registrationType); } bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, - int *vmajor, int *vminor, QQmlType *type_return, QString *base, - bool *typeRecursionDetected, + QTypeRevision *version_return, QQmlType *type_return, + QString *base, bool *typeRecursionDetected, QQmlType::RegistrationType registrationType, QQmlImport::RecursionRestriction recursionRestriction, QList<QQmlError> *errors) const { - if (majversion >= 0 && minversion >= 0) { - QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion); + if (version.hasMajorVersion() && version.hasMinorVersion()) { + QQmlType t = QQmlMetaType::qmlType(type, uri, version); if (t.isValid()) { - if (vmajor) - *vmajor = majversion; - if (vminor) - *vminor = minversion; + if (version_return) + *version_return = version; if (type_return) *type_return = t; return true; @@ -724,6 +735,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt Q_ASSERT(ok); typePriv->extraData.id->url = QUrl(this->url); auto icType = QQmlType(typePriv); + typePriv->release(); return icType; }; if (containingType.isValid()) { @@ -763,14 +775,16 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt break; } - // importing version -1 means import ALL versions - if ((majversion == -1) || - (implicitlyImported && c.internal) || // allow the implicit import of internal types - (c.majorVersion == majversion && c.minorVersion <= minversion)) { + // importing invalid version means import ALL versions + if (!version.hasMajorVersion() || (implicitlyImported && c.internal) + // allow the implicit import of internal types + || (c.version.majorVersion() == version.majorVersion() + && c.version.minorVersion() <= version.minorVersion())) { // Is this better than the previous candidate? - if ((candidate == end) || - (c.majorVersion > candidate->majorVersion) || - ((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) { + if ((candidate == end) + || (c.version.majorVersion() > candidate->version.majorVersion()) + || ((c.version.majorVersion() == candidate->version.majorVersion()) + && (c.version.minorVersion() > candidate->version.minorVersion()))) { if (base) { componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName); if (c.internal) { @@ -798,12 +812,9 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (!base) // ensure we have a componentUrl componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); QQmlType returnType = QQmlMetaType::typeForUrl(componentUrl, type, isCompositeSingleton, - nullptr, candidate->majorVersion, - candidate->minorVersion); - if (vmajor) - *vmajor = candidate->majorVersion; - if (vminor) - *vminor = candidate->minorVersion; + nullptr, candidate->version); + if (version_return) + *version_return = candidate->version; if (type_return) *type_return = returnType; return returnType.isValid(); @@ -855,14 +866,14 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt return false; } -bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor, +bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, QTypeRevision *version_return, QQmlType *type_return, QList<QQmlError> *errors, QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) { const QVector<QHashedStringRef> splitName = type.split(Dot); auto resolveTypeInNamespace = [&](QHashedStringRef unqualifiedtype, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) -> bool { - if (nameSpace->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors, + if (nameSpace->resolveType(typeLoader, unqualifiedtype, version_return, type_return, &base, errors, registrationType, typeRecursionDetected)) return true; if (nameSpace->imports.count() == 1 && !nameSpace->imports.at(0)->isLibrary && type_return && nameSpace != &unqualifiedset) { @@ -900,6 +911,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int placeholderId = type_return->generatePlaceHolderICId(); icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId)); auto icType = QQmlType(icTypePriv); + icTypePriv->release(); type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType); *type_return = icType; } @@ -936,6 +948,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int placeholderId = type_return->generatePlaceHolderICId(); icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId)); auto icType = QQmlType(icTypePriv); + icTypePriv->release(); type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType); *type_return = icType; } @@ -973,7 +986,7 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const } bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType *type_return, + QTypeRevision *version_return, QQmlType *type_return, QString *base, QList<QQmlError> *errors, QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) @@ -987,13 +1000,13 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS for (int i=0; i<imports.count(); ++i) { const QQmlImportInstance *import = imports.at(i); - if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base, + if (import->resolveType(typeLoader, type, version_return, type_return, base, typeRecursionDetected, registrationType, recursionRestriction, errors)) { if (qmlCheckTypes()) { // check for type clashes for (int j = i+1; j<imports.count(); ++j) { const QQmlImportInstance *import2 = imports.at(j); - if (import2->resolveType(typeLoader, type, vmajor, vminor, nullptr, base, + if (import2->resolveType(typeLoader, type, version_return, nullptr, base, nullptr, registrationType)) { if (errors) { QString u1 = import->url; @@ -1020,9 +1033,11 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2)); } else { error.setDescription(QQmlImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5") - .arg(u1) - .arg(import->majversion).arg(import->minversion) - .arg(import2->majversion).arg(import2->minversion)); + .arg(u1) + .arg(import->version.majorVersion()) + .arg(import->version.minorVersion()) + .arg(import2->version.majorVersion()) + .arg(import2->version.minorVersion())); } errors->prepend(error); } @@ -1068,18 +1083,19 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following: [QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models] */ -static QStringList versionUriList(const QString &uri, int vmaj, int vmin) +static QStringList versionUriList(const QString &uri, QTypeRevision version) { QStringList result; - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { + for (int mode = QQmlImports::FullyVersioned; mode <= QQmlImports::Unversioned; ++mode) { int index = uri.length(); do { QString versionUri = uri; - versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version))); + versionUri.insert(index, QQmlImports::versionString( + version, QQmlImports::ImportVersion(mode))); result += versionUri; index = uri.lastIndexOf(Dot, index - 1); - } while (index > 0 && version != QQmlImports::Unversioned); + } while (index > 0 && mode != QQmlImports::Unversioned); } return result; } @@ -1144,8 +1160,7 @@ Import an extension defined by a qmldir file. \a qmldirFilePath is a raw file path. */ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, - const QString &uri, - int vmaj, int vmin, + const QString &uri, QTypeRevision version, QQmlImportDatabase *database, const QQmlTypeLoaderQmldirContent &qmldir, QList<QQmlError> *errors) @@ -1170,13 +1185,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (qmldirPluginCount == 0) return true; - if (database->qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) { - if ((vmaj >= 0 && vmin >= 0) - ? !QQmlMetaType::isModule(uri, vmaj, vmin) - : !QQmlMetaType::isAnyModule(uri)) { - QQmlMetaType::qmlRegisterModuleTypes(uri, vmaj); - } - } else { + if (!database->qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(qmldirFilePath)) { // First search for listed qmldir plugins dynamically. If we cannot resolve them all, we continue // searching static plugins that has correct metadata uri. Note that since we only know the uri // for a static plugin, and not the filename, we cannot know which static plugin belongs to which @@ -1198,7 +1207,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name); if (!resolvedFilePath.isEmpty()) { dynamicPluginsFound++; - if (!database->importDynamicPlugin(resolvedFilePath, uri, typeNamespace, vmaj, errors)) { + if (!database->importDynamicPlugin(resolvedFilePath, uri, typeNamespace, version, errors)) { if (errors) { // XXX TODO: should we leave the import plugin error alone? // Here, we pop it off the top and coalesce it into this error's message. @@ -1223,7 +1232,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // versioned to unversioned, we need to compare with differnt version strings. If a module // has several plugins, they must all have the same version. Start by populating pluginPairs // with relevant plugins to cut the list short early on: - const QStringList versionUris = versionUriList(uri, vmaj, vmin); + const QStringList versionUris = versionUriList(uri, version); QVector<StaticPluginPair> pluginPairs; if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors)) return false; @@ -1235,7 +1244,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (versionUri == metaTagUri.toString()) { staticPluginsFound++; QObject *instance = pair.first.instance(); - if (!database->importStaticPlugin(instance, basePath, uri, typeNamespace, vmaj, errors)) { + if (!database->importStaticPlugin(instance, basePath, uri, typeNamespace, version, errors)) { if (errors) { QQmlError poppedError = errors->takeFirst(); QQmlError error; @@ -1338,10 +1347,11 @@ and fills in outQmldirFilePath and outQmldirUrl appropriately. Otherwise return false. */ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( - const QString &uri, int vmaj, int vmin, QQmlImportDatabase *database, + const QString &uri, QTypeRevision version, QQmlImportDatabase *database, QString *outQmldirFilePath, QString *outQmldirPathUrl) { - Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries + // Versions are always specified for libraries + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); // Check cache first @@ -1352,7 +1362,7 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( cacheHead = *cachePtr; QQmlImportDatabase::QmldirCache *cache = cacheHead; while (cache) { - if (cache->versionMajor == vmaj && cache->versionMinor == vmin) { + if (cache->version == version) { *outQmldirFilePath = cache->qmldirFilePath; *outQmldirPathUrl = cache->qmldirPathUrl; return cache->qmldirFilePath.isEmpty() ? QQmlImports::QmldirNotFound @@ -1372,7 +1382,7 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( // Search local import paths for a matching version const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths( - uri, localImportPaths, vmaj, vmin); + uri, localImportPaths, version); bool pathTurnedRemote = false; for (QString qmldirPath : qmlDirPaths) { if (interceptor) { @@ -1394,8 +1404,7 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( url = QUrl::fromLocalFile(absolutePath.toString()).toString(); QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; - cache->versionMajor = vmaj; - cache->versionMinor = vmin; + cache->version = version; cache->qmldirFilePath = absoluteFilePath; cache->qmldirPathUrl = url; cache->next = cacheHead; @@ -1409,19 +1418,19 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( } QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; - cache->versionMajor = vmaj; - cache->versionMinor = vmin; + cache->version = version; cache->next = cacheHead; database->qmldirCache.insert(uri, cache); return pathTurnedRemote ? QQmlImports::QmldirInterceptedToRemote : QQmlImports::QmldirNotFound; } -bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, const QString &uri, int vmaj, int vmin, +bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent &qmldir, + const QString &uri, QTypeRevision version, QList<QQmlError> *errors) { - int lowest_min = INT_MAX; - int highest_min = INT_MIN; + quint8 lowest_min = std::numeric_limits<quint8>::max(); + quint8 highest_min = 0; typedef QQmlDirComponents::const_iterator ConstIterator; const QQmlDirComponents &components = qmldir.components(); @@ -1429,21 +1438,20 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent ConstIterator cend = components.constEnd(); for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) { for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) { - if ((cit2->typeName == cit->typeName) && - (cit2->majorVersion == cit->majorVersion) && - (cit2->minorVersion == cit->minorVersion)) { + if (cit2->typeName == cit->typeName && cit2->version == cit->version) { // This entry clashes with a predecessor QQmlError error; error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"") - .arg(cit->typeName).arg(cit->majorVersion).arg(cit->minorVersion).arg(uri)); + .arg(cit->typeName).arg(cit->version.majorVersion()) + .arg(cit->version.minorVersion()).arg(uri)); errors->prepend(error); return false; } } - if (cit->majorVersion == vmaj) { - lowest_min = qMin(lowest_min, cit->minorVersion); - highest_min = qMax(highest_min, cit->minorVersion); + if (cit->version.majorVersion() == version.majorVersion()) { + lowest_min = qMin(lowest_min, cit->version.minorVersion()); + highest_min = qMax(highest_min, cit->version.minorVersion()); } } @@ -1453,27 +1461,27 @@ bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent SConstIterator send = scripts.constEnd(); for (SConstIterator sit = scripts.constBegin(); sit != send; ++sit) { for (SConstIterator sit2 = scripts.constBegin(); sit2 != sit; ++sit2) { - if ((sit2->nameSpace == sit->nameSpace) && - (sit2->majorVersion == sit->majorVersion) && - (sit2->minorVersion == sit->minorVersion)) { + if (sit2->nameSpace == sit->nameSpace && sit2->version == sit->version) { // This entry clashes with a predecessor QQmlError error; error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"") - .arg(sit->nameSpace).arg(sit->majorVersion).arg(sit->minorVersion).arg(uri)); + .arg(sit->nameSpace).arg(sit->version.majorVersion()) + .arg(sit->version.minorVersion()).arg(uri)); errors->prepend(error); return false; } } - if (sit->majorVersion == vmaj) { - lowest_min = qMin(lowest_min, sit->minorVersion); - highest_min = qMax(highest_min, sit->minorVersion); + if (sit->version.majorVersion() == version.majorVersion()) { + lowest_min = qMin(lowest_min, sit->version.minorVersion()); + highest_min = qMax(highest_min, sit->version.minorVersion()); } } - if (lowest_min > vmin || highest_min < vmin) { + if (lowest_min > version.minorVersion() || highest_min < version.minorVersion()) { QQmlError error; - error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin)); + error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed") + .arg(uri).arg(version.majorVersion()).arg(version.minorVersion())); errors->prepend(error); return false; } @@ -1500,10 +1508,9 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix) return nameSpace; } -QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace, - const QString &uri, const QString &url, int vmaj, int vmin, - QV4::CompiledData::Import::ImportType type, - QList<QQmlError> *errors, bool lowPrecedence) +QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace( + QQmlImportNamespace *nameSpace, const QString &uri, const QString &url, QTypeRevision version, + QV4::CompiledData::Import::ImportType type, QList<QQmlError> *errors, bool lowPrecedence) { Q_ASSERT(nameSpace); Q_ASSERT(errors); @@ -1514,8 +1521,7 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace import->uri = uri; import->url = url; import->localDirectoryPath = QQmlFile::urlToLocalFileOrQrc(url); - import->majversion = vmaj; - import->minversion = vmin; + import->version = version; import->isLibrary = (type == QV4::CompiledData::Import::ImportLibrary); if (lowPrecedence) @@ -1526,10 +1532,10 @@ QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace return import; } -bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &prefix, - int vmaj, int vmin, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, - QQmlImportDatabase *database, - QList<QQmlError> *errors) +bool QQmlImportsPrivate::addLibraryImport( + const QString& uri, const QString &prefix, QTypeRevision version, + const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, + QQmlImportDatabase *database, QList<QQmlError> *errors) { Q_ASSERT(database); Q_ASSERT(errors); @@ -1537,7 +1543,9 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre QQmlImportNamespace *nameSpace = importNamespace(prefix); Q_ASSERT(nameSpace); - QQmlImportInstance *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors); + QQmlImportInstance *inserted = addImportToNamespace( + nameSpace, uri, qmldirUrl, version, + QV4::CompiledData::Import::ImportLibrary, errors); Q_ASSERT(inserted); if (!incomplete) { @@ -1548,7 +1556,7 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre return false; if (qmldir.hasContent()) { - if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) + if (!importExtension(qmldir.pluginLocation(), uri, version, database, qmldir, errors)) return false; if (!inserted->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) @@ -1557,18 +1565,22 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre } // Ensure that we are actually providing something - if ((vmaj < 0) || (vmin < 0) || !QQmlMetaType::isModule(uri, vmaj, vmin)) { + if (!version.hasMajorVersion() || !version.hasMinorVersion() + || !QQmlMetaType::isModule(uri, version)) { if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) { QQmlError error; - if (QQmlMetaType::isAnyModule(uri)) - error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin)); - else + if (QQmlMetaType::isAnyModule(uri)) { + error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed") + .arg(uri).arg(version.majorVersion()).arg(version.minorVersion())); + } else { error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri)); + } errors->prepend(error); return false; - } else if ((vmaj >= 0) && (vmin >= 0) && qmldir.hasContent()) { + } else if (version.hasMajorVersion() && version.hasMinorVersion() + && qmldir.hasContent()) { // Verify that the qmldir content is valid for this version - if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors)) + if (!validateQmldirVersion(qmldir, uri, version, errors)) return false; } } @@ -1577,10 +1589,9 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre return true; } -bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix, - int vmaj, int vmin, - bool isImplicitImport, bool incomplete, QQmlImportDatabase *database, - QList<QQmlError> *errors) +bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix, QTypeRevision version, + bool isImplicitImport, bool incomplete, + QQmlImportDatabase *database, QList<QQmlError> *errors) { Q_ASSERT(errors); @@ -1656,7 +1667,9 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix } } - QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport); + QQmlImportInstance *inserted = addImportToNamespace( + nameSpace, importUri, url, version, QV4::CompiledData::Import::ImportFile, + errors, isImplicitImport); Q_ASSERT(inserted); if (!incomplete && !qmldirIdentifier.isEmpty()) { @@ -1665,7 +1678,7 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix return false; if (qmldir.hasContent()) { - if (!importExtension(qmldir.pluginLocation(), importUri, vmaj, vmin, database, qmldir, errors)) + if (!importExtension(qmldir.pluginLocation(), importUri, version, database, qmldir, errors)) return false; if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors)) @@ -1689,26 +1702,27 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString & return false; if (qmldir.hasContent()) { - int vmaj = import->majversion; - int vmin = import->minversion; - if (!importExtension(qmldir.pluginLocation(), uri, vmaj, vmin, database, qmldir, errors)) + QTypeRevision version = import->version; + if (!importExtension(qmldir.pluginLocation(), uri, version, database, qmldir, errors)) return false; if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) { if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) { // The implicit import qmldir can be empty, and plugins have no extra versions - if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, vmaj, vmin)) { + if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, version)) { QQmlError error; - if (QQmlMetaType::isAnyModule(uri)) - error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin)); - else + if (QQmlMetaType::isAnyModule(uri)) { + error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed") + .arg(uri).arg(version.majorVersion()).arg(version.minorVersion())); + } else { error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri)); + } errors->prepend(error); return false; } - } else if ((vmaj >= 0) && (vmin >= 0)) { + } else if (version.hasMajorVersion() && version.hasMinorVersion()) { // Verify that the qmldir content is valid for this version - if (!validateQmldirVersion(qmldir, uri, vmaj, vmin, errors)) + if (!validateQmldirVersion(qmldir, uri, version, errors)) return false; } return true; @@ -1742,7 +1756,8 @@ bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlErro << ")::addImplicitImport"; bool incomplete = !isLocal(baseUrl()); - return d->addFileImport(QLatin1String("."), QString(), -1, -1, true, incomplete, importDb, errors); + return d->addFileImport(QLatin1String("."), QString(), QTypeRevision(), true, incomplete, + importDb, errors); } /*! @@ -1753,8 +1768,7 @@ bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInsta importInstance->url = importUrl.toString(); importInstance->uri = name; importInstance->isInlineComponent = true; - importInstance->majversion = 0; - importInstance->minversion = 0; + importInstance->version = QTypeRevision::zero(); importInstance->containingType = containingType; d->unqualifiedset.imports.push_back(importInstance); return true; @@ -1782,7 +1796,7 @@ bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInsta filled appropriately. */ bool QQmlImports::addFileImport(QQmlImportDatabase *importDb, - const QString& uri, const QString& prefix, int vmaj, int vmin, + const QString& uri, const QString& prefix, QTypeRevision version, bool incomplete, QList<QQmlError> *errors) { Q_ASSERT(importDb); @@ -1790,13 +1804,13 @@ bool QQmlImports::addFileImport(QQmlImportDatabase *importDb, if (qmlImportTrace()) qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addFileImport: " - << uri << ' ' << vmaj << '.' << vmin << " as " << prefix; + << uri << ' ' << version << " as " << prefix; - return d->addFileImport(uri, prefix, vmaj, vmin, false, incomplete, importDb, errors); + return d->addFileImport(uri, prefix, version, false, incomplete, importDb, errors); } bool QQmlImports::addLibraryImport(QQmlImportDatabase *importDb, - const QString &uri, const QString &prefix, int vmaj, int vmin, + const QString &uri, const QString &prefix, QTypeRevision version, const QString &qmldirIdentifier, const QString& qmldirUrl, bool incomplete, QList<QQmlError> *errors) { Q_ASSERT(importDb); @@ -1804,9 +1818,9 @@ bool QQmlImports::addLibraryImport(QQmlImportDatabase *importDb, if (qmlImportTrace()) qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) << ')' << "::addLibraryImport: " - << uri << ' ' << vmaj << '.' << vmin << " as " << prefix; + << uri << ' ' << version << " as " << prefix; - return d->addLibraryImport(uri, prefix, vmaj, vmin, qmldirIdentifier, qmldirUrl, incomplete, importDb, errors); + return d->addLibraryImport(uri, prefix, version, qmldirIdentifier, qmldirUrl, incomplete, importDb, errors); } bool QQmlImports::updateQmldirContent(QQmlImportDatabase *importDb, @@ -1824,10 +1838,10 @@ bool QQmlImports::updateQmldirContent(QQmlImportDatabase *importDb, } QQmlImports::LocalQmldirResult QQmlImports::locateLocalQmldir( - QQmlImportDatabase *importDb, const QString &uri, int vmaj, int vmin, + QQmlImportDatabase *importDb, const QString &uri, QTypeRevision version, QString *qmldirFilePath, QString *url) { - return d->locateLocalQmldir(uri, vmaj, vmin, importDb, qmldirFilePath, url); + return d->locateLocalQmldir(uri, version, importDb, qmldirFilePath, url); } bool QQmlImports::isLocal(const QString &url) @@ -1878,7 +1892,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) #else QLatin1Char pathSep(':'); #endif - QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts); + QStringList paths = envImportPath.split(pathSep, Qt::SkipEmptyParts); for (int ii = paths.count() - 1; ii >= 0; --ii) addImportPath(paths.at(ii)); } @@ -1890,7 +1904,7 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_BUNDLED_LIBS_PATH"))) { const QString envImportPath = qEnvironmentVariable("QT_BUNDLED_LIBS_PATH"); QLatin1Char pathSep(':'); - QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts); + QStringList paths = envImportPath.split(pathSep, Qt::SkipEmptyParts); for (int ii = paths.count() - 1; ii >= 0; --ii) addPluginPath(paths.at(ii)); } @@ -1993,8 +2007,11 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, static const QStringList suffixes = { # ifdef QT_DEBUG QLatin1String("d.dll"), // try a qmake-style debug build first -# endif QLatin1String(".dll") +#else + QLatin1String(".dll"), + QLatin1String("d.dll") // try a qmake-style debug build after +# endif }; #elif defined(Q_OS_DARWIN) static const QString prefix = QLatin1String("lib"); @@ -2133,19 +2150,21 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths) \internal */ static bool registerPluginTypes(QObject *instance, const QString &basePath, const QString &uri, - const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) + const QString &typeNamespace, QTypeRevision version, + QList<QQmlError> *errors) { if (qmlImportTrace()) qDebug().nospace() << "QQmlImportDatabase::registerPluginTypes: " << uri << " from " << basePath; - if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors)) + if (!QQmlMetaType::registerPluginTypes(instance, basePath, uri, typeNamespace, version, errors)) return false; - if (vmaj >= 0 && !typeNamespace.isEmpty() && !QQmlMetaType::protectModule(uri, vmaj)) { + if (version.hasMajorVersion() && !typeNamespace.isEmpty() + && !QQmlMetaType::protectModule(uri, version)) { QQmlError error; error.setDescription( QString::fromLatin1("Cannot protect module %1 %2 as it was never registered") - .arg(uri).arg(vmaj)); + .arg(uri).arg(version.majorVersion())); errors->append(error); return false; } @@ -2156,8 +2175,9 @@ static bool registerPluginTypes(QObject *instance, const QString &basePath, cons /*! \internal */ -bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &basePath, - const QString &uri, const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) +bool QQmlImportDatabase::importStaticPlugin( + QObject *instance, const QString &basePath, const QString &uri, + const QString &typeNamespace, QTypeRevision version, QList<QQmlError> *errors) { // Dynamic plugins are differentiated by their filepath. For static plugins we // don't have that information so we use their address as key instead. @@ -2180,7 +2200,7 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba plugin.loader = nullptr; plugins->insert(uniquePluginID, plugin); - if (!registerPluginTypes(instance, basePath, uri, typeNamespace, vmaj, errors)) + if (!registerPluginTypes(instance, basePath, uri, typeNamespace, version, errors)) return false; } @@ -2200,8 +2220,9 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba /*! \internal */ -bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QString &uri, - const QString &typeNamespace, int vmaj, QList<QQmlError> *errors) +bool QQmlImportDatabase::importDynamicPlugin( + const QString &filePath, const QString &uri, const QString &typeNamespace, + QTypeRevision version, QList<QQmlError> *errors) { QFileInfo fileInfo(filePath); const QString absoluteFilePath = fileInfo.absoluteFilePath(); @@ -2255,7 +2276,7 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr plugins->insert(absoluteFilePath, plugin); // Continue with shared code path for dynamic and static plugins: - if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, vmaj, errors)) + if (!registerPluginTypes(instance, fileInfo.absolutePath(), uri, typeNamespace, version, errors)) return false; } } diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 2e994fd27f..7416bb7a4c 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -81,8 +81,7 @@ struct QQmlImportInstance QString url; // the base path of the import QString localDirectoryPath; // the base path of the import if it's a local file QQmlType containingType; // points to the containing type for inline components - int majversion; // the major version imported - int minversion; // the minor version imported + QTypeRevision version; // the version imported bool isLibrary; // true means that this is not a file import bool implicitlyImported = false; bool isInlineComponent = false; @@ -92,10 +91,11 @@ struct QQmlImportInstance bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent &qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors); - static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin); + static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, + QTypeRevision version); bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, - int *vmajor, int *vminor, QQmlType* type_return, + QTypeRevision *version_return, QQmlType* type_return, QString *base = nullptr, bool *typeRecursionDetected = nullptr, QQmlType::RegistrationType = QQmlType::AnyRegistrationType, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion, @@ -113,7 +113,7 @@ public: QQmlImportInstance *findImport(const QString &uri) const; bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, - int *vmajor, int *vminor, QQmlType* type_return, + QTypeRevision *version_return, QQmlType* type_return, QString *base = nullptr, QList<QQmlError> *errors = nullptr, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, bool *typeRecursionDeteced = nullptr); @@ -140,14 +140,14 @@ public: bool resolveType(const QHashedStringRef &type, QQmlType *type_return, - int *version_major, int *version_minor, + QTypeRevision *version_return, QQmlImportNamespace **ns_return, QList<QQmlError> *errors = nullptr, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, bool *typeRecursionDetected = nullptr) const; bool resolveType(QQmlImportNamespace *, const QHashedStringRef& type, - QQmlType *type_return, int *version_major, int *version_minor, + QQmlType *type_return, QTypeRevision *version_return, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType) const; @@ -156,11 +156,11 @@ public: bool addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType); bool addFileImport(QQmlImportDatabase *, - const QString& uri, const QString& prefix, int vmaj, int vmin, bool incomplete, - QList<QQmlError> *errors); + const QString& uri, const QString& prefix, QTypeRevision version, + bool incomplete, QList<QQmlError> *errors); bool addLibraryImport(QQmlImportDatabase *importDb, - const QString &uri, const QString &prefix, int vmaj, int vmin, + const QString &uri, const QString &prefix, QTypeRevision version, const QString &qmldirIdentifier, const QString &qmldirUrl, bool incomplete, QList<QQmlError> *errors); bool updateQmldirContent(QQmlImportDatabase *importDb, @@ -174,7 +174,7 @@ public: }; LocalQmldirResult locateLocalQmldir( - QQmlImportDatabase *, const QString &uri, int vmaj, int vmin, + QQmlImportDatabase *, const QString &uri, QTypeRevision version, QString *qmldirFilePath, QString *url); void populateCache(QQmlTypeNameCache *cache) const; @@ -192,14 +192,14 @@ public: { QString typeName; QString prefix; - int majorVersion; - int minorVersion; + QTypeRevision version; }; QList<CompositeSingletonReference> resolvedCompositeSingletons() const; - static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin); - static QString versionString(int vmaj, int vmin, ImportVersion version); + static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, + QTypeRevision version); + static QString versionString(QTypeRevision version, ImportVersion importVersion); static bool isLocal(const QString &url); static bool isLocal(const QUrl &url); @@ -222,7 +222,9 @@ public: ~QQmlImportDatabase(); #if QT_CONFIG(library) - bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors); + bool importDynamicPlugin(const QString &filePath, const QString &uri, + const QString &importNamespace, QTypeRevision version, + QList<QQmlError> *errors); bool removeDynamicPlugin(const QString &filePath); QStringList dynamicPlugins() const; #endif @@ -245,13 +247,13 @@ private: const QString &qmldirPath, const QString &qmldirPluginPath, const QString &baseName); bool importStaticPlugin(QObject *instance, const QString &basePath, const QString &uri, - const QString &typeNamespace, int vmaj, QList<QQmlError> *errors); + const QString &typeNamespace, QTypeRevision version, + QList<QQmlError> *errors); void clearDirCache(); void finalizePlugin(QObject *instance, const QString &path, const QString &uri); struct QmldirCache { - int versionMajor; - int versionMinor; + QTypeRevision version; QString qmldirFilePath; QString qmldirPathUrl; QmldirCache *next; diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 4911cd2879..0ad013e90b 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -722,8 +722,8 @@ bool QQmlIncubatorPrivate::hadRequiredProperties() const } /*! -Stores a mapping from property names to initial values with which the incubated -component will be initialized +Stores a mapping from property names to initial values, contained in +\a initialProperties, with which the incubated component will be initialized. \sa QQmlComponent::setInitialProperties \since 5.15 diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index aadb147bd5..a674ff274f 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -61,9 +61,7 @@ QT_BEGIN_NAMESPACE -class QQmlPropertyData; -struct RequiredPropertyInfo; -using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>; +class RequiredProperties; class QQmlIncubator; class Q_QML_PRIVATE_EXPORT QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp index dd401bdb20..7204d5ccd2 100644 --- a/src/qml/qml/qqmlinfo.cpp +++ b/src/qml/qml/qqmlinfo.cpp @@ -44,6 +44,7 @@ #include "qqmlcontext_p.h" #include "qqmlmetatype_p.h" #include "qqmlengine_p.h" +#include "qqmlsourcecoordinate_p.h" #include <QCoreApplication> @@ -218,8 +219,8 @@ QQmlInfo::~QQmlInfo() QQmlData *ddata = QQmlData::get(object, false); if (ddata && ddata->outerContext) { error.setUrl(ddata->outerContext->url()); - error.setLine(ddata->lineNumber); - error.setColumn(ddata->columnNumber); + error.setLine(qmlConvertSourceCoordinate<quint16, int>(ddata->lineNumber)); + error.setColumn(qmlConvertSourceCoordinate<quint16, int>(ddata->columnNumber)); } } diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp index b284e44fdf..f66094fad7 100644 --- a/src/qml/qml/qqmlirloader.cpp +++ b/src/qml/qml/qqmlirloader.cpp @@ -78,14 +78,14 @@ struct FakeExpression : public QQmlJS::AST::NullExpression : location(start, length) {} - virtual QQmlJS::AST::SourceLocation firstSourceLocation() const + virtual QQmlJS::SourceLocation firstSourceLocation() const { return location; } - virtual QQmlJS::AST::SourceLocation lastSourceLocation() const + virtual QQmlJS::SourceLocation lastSourceLocation() const { return location; } private: - QQmlJS::AST::SourceLocation location; + QQmlJS::SourceLocation location; }; QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject) diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 8661ebcc13..6a9ef06159 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -50,6 +50,7 @@ #include <private/qqmlglobal_p.h> #include <private/qv4qobjectwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> +#include <private/qqmlsourcecoordinate_p.h> QT_BEGIN_NAMESPACE @@ -72,8 +73,8 @@ bool QQmlDelayedError::addError(QQmlEnginePrivate *e) void QQmlDelayedError::setErrorLocation(const QQmlSourceLocation &sourceLocation) { m_error.setUrl(QUrl(sourceLocation.sourceFile)); - m_error.setLine(sourceLocation.line); - m_error.setColumn(sourceLocation.column); + m_error.setLine(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.line)); + m_error.setColumn(qmlConvertSourceCoordinate<quint16, int>(sourceLocation.column)); } void QQmlDelayedError::setErrorDescription(const QString &description) diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 1743410776..bc227ad713 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -314,7 +314,7 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function QLocale locale; QString dateString = s->toQString(); QDate date = locale.toDate(dateString); - RETURN_RESULT(engine->newDateObject(QDateTime(date))); + RETURN_RESULT(engine->newDateObject(date.startOfDay())); } } @@ -341,7 +341,7 @@ ReturnedValue QQmlDateExtension::method_fromLocaleDateString(const QV4::Function dt = r->d()->locale->toDate(dateString, enumFormat); } - RETURN_RESULT(engine->newDateObject(QDateTime(dt))); + RETURN_RESULT(engine->newDateObject(dt.startOfDay())); } ReturnedValue QQmlDateExtension::method_timeZoneUpdated(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int argc) diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 1d6fdb12a7..d7bff5a1b7 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -96,7 +96,7 @@ class Q_QML_PRIVATE_EXPORT QQmlLocale Q_GADGET QML_NAMED_ELEMENT(Locale) QML_UNCREATABLE("Locale cannot be instantiated. Use Qt.locale().") - QML_ADDED_IN_MINOR_VERSION(2) + QML_ADDED_IN_VERSION(2, 2) public: ~QQmlLocale(); diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/qml/qqmlloggingcategory_p.h index c7377528b4..9cee029a9b 100644 --- a/src/qml/qml/qqmlloggingcategory_p.h +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -66,9 +66,9 @@ class QQmlLoggingCategory : public QObject, public QQmlParserStatus Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION 12) + Q_PROPERTY(DefaultLogLevel defaultLogLevel READ defaultLogLevel WRITE setDefaultLogLevel REVISION(2, 12)) QML_NAMED_ELEMENT(LoggingCategory) - QML_ADDED_IN_MINOR_VERSION(8) + QML_ADDED_IN_VERSION(2, 8) public: enum DefaultLogLevel { diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 76816618ac..68b95d1cc3 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -92,8 +92,12 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, d->typeId = type.typeId; d->listId = type.listId; d->isSetup = true; - d->version_maj = 0; - d->version_min = 0; + if (type.structVersion > 0) { + d->module = QString::fromUtf8(type.uri); + d->version = type.version; + } else { + d->version = QTypeRevision::zero(); + } data->registerType(d); return d; } @@ -105,28 +109,30 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); - d->version_maj = type.versionMajor; - d->version_min = type.versionMinor; + d->version = type.version; - if (type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi)) { - if (type.version >= 1) // static metaobject added in version 1 + if (type.qobjectApi || (type.structVersion >= 3 && type.generalizedQobjectApi)) { + if (type.structVersion >= 1) // static metaobject added in version 1 d->baseMetaObject = type.instanceMetaObject; - if (type.version >= 2) // typeId added in version 2 + if (type.structVersion >= 2) // typeId added in version 2 d->typeId = type.typeId; - if (type.version >= 2) // revisions added in version 2 + if (type.structVersion >= 2) // revisions added in version 2 d->revision = type.revision; } d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->scriptCallback = type.scriptApi; - if (type.version >= 3) { + if (type.structVersion >= 3) { d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.generalizedQobjectApi; } else { d->extraData.sd->singletonInstanceInfo->qobjectCallback = type.qobjectApi; } d->extraData.sd->singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName); d->extraData.sd->singletonInstanceInfo->instanceMetaObject - = ((type.qobjectApi || (type.version >= 3 && type.generalizedQobjectApi) ) && type.version >= 1) ? type.instanceMetaObject : nullptr; + = ((type.qobjectApi || (type.structVersion >= 3 && type.generalizedQobjectApi) ) + && type.structVersion >= 1) + ? type.instanceMetaObject + : nullptr; return d; } @@ -138,9 +144,8 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); - d->version_maj = type.versionMajor; - d->version_min = type.versionMinor; - if (type.version >= 1) // revisions added in version 1 + d->version = type.version; + if (type.structVersion >= 1) // revisions added in version 1 d->revision = type.revision; d->typeId = type.typeId; d->listId = type.listId; @@ -176,8 +181,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el auto *d = new QQmlTypePrivate(QQmlType::CompositeType); data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); - d->version_maj = type.versionMajor; - d->version_min = type.versionMinor; + d->version = type.version; d->extraData.fd->url = QQmlTypeLoader::normalize(type.url); return d; @@ -190,8 +194,7 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el data->registerType(d); d->setName(QString::fromUtf8(type.uri), elementName); - d->version_maj = type.versionMajor; - d->version_min = type.versionMinor; + d->version = type.version; d->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; d->extraData.sd->singletonInstanceInfo->url = QQmlTypeLoader::normalize(type.url); @@ -267,35 +270,43 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo, } } -void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, int majorVersion, - void (*registerFunction)()) +void QQmlMetaType::qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)()) { - const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion); QQmlMetaTypeDataPtr data; - if (data->moduleTypeRegistrationFunctions.contains(versionedUri)) - qFatal("Cannot add multiple registrations for %s %d", qPrintable(uri), majorVersion); + if (data->moduleTypeRegistrationFunctions.contains(uri)) + qFatal("Cannot add multiple registrations for %s", qPrintable(uri)); else - data->moduleTypeRegistrationFunctions.insert(versionedUri, registerFunction); + data->moduleTypeRegistrationFunctions.insert(uri, registerFunction); } -void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri, int majorVersion) +void QQmlMetaType::qmlRemoveModuleRegistration(const QString &uri) { - const QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion); QQmlMetaTypeDataPtr data; if (!data.isValid()) return; // shutdown/deletion race. Not a problem. - if (!data->moduleTypeRegistrationFunctions.contains(versionedUri)) - qFatal("Cannot remove multiple registrations for %s %d", qPrintable(uri), majorVersion); + if (!data->moduleTypeRegistrationFunctions.contains(uri)) + qFatal("Cannot remove multiple registrations for %s", qPrintable(uri)); else - data->moduleTypeRegistrationFunctions.remove(versionedUri); + data->moduleTypeRegistrationFunctions.remove(uri); +} + +bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri) +{ + QQmlMetaTypeDataPtr data; + return data->registerModuleTypes(uri); } -bool QQmlMetaType::qmlRegisterModuleTypes(const QString &uri, int majorVersion) +/*! + \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->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, majorVersion)); + return data->qmlLists.count(); } void QQmlMetaType::clearTypeRegistrations() @@ -334,24 +345,19 @@ void QQmlMetaType::unregisterAutoParentFunction(const QQmlPrivate::AutoParentFun QQmlType QQmlMetaType::registerInterface(const QQmlPrivate::RegisterInterface &type) { - if (type.version > 0) + if (type.structVersion > 1) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); QQmlMetaTypeDataPtr data; QQmlTypePrivate *priv = createQQmlType(data, type); Q_ASSERT(priv); - 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); - if (data->lists.size() <= type.listId) - data->lists.resize(type.listId + 16); - data->interfaces.setBit(type.typeId, true); - data->lists.setBit(type.listId, true); + data->idToType.insert(priv->typeId.id(), priv); + data->idToType.insert(priv->listId.id(), priv); + + data->interfaces.insert(type.typeId.id()); + data->lists.insert(type.listId.id()); return QQmlType(priv); } @@ -372,7 +378,7 @@ QString registrationTypeString(QQmlType::RegistrationType typeType) // NOTE: caller must hold a QMutexLocker on "data" bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, - const char *uri, const QString &typeName, int majorVersion) + const char *uri, const QString &typeName, QTypeRevision version) { if (!typeName.isEmpty()) { if (typeName.at(0).isLower()) { @@ -393,14 +399,14 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da if (uri && !typeName.isEmpty()) { QString nameSpace = QString::fromUtf8(uri); - QQmlMetaTypeData::VersionedUri versionedUri; - versionedUri.uri = nameSpace; - versionedUri.majorVersion = majorVersion; + QQmlMetaTypeData::VersionedUri versionedUri(nameSpace, version); if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){ if (qqtm->isLocked()){ QString failure(QCoreApplication::translate("qmlRegisterType", "Cannot install %1 '%2' into protected module '%3' version '%4'")); - data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion)); + data->recordTypeRegFailure(failure.arg(registrationTypeString(typeType)) + .arg(typeName).arg(nameSpace) + .arg(version.majorVersion())); return false; } } @@ -410,9 +416,9 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da } // NOTE: caller must hold a QMutexLocker on "data" -QQmlTypeModule *getTypeModule(const QHashedString &uri, int majorVersion, QQmlMetaTypeData *data) +QQmlTypeModule *getTypeModule(const QHashedString &uri, QTypeRevision version, QQmlMetaTypeData *data) { - QQmlMetaTypeData::VersionedUri versionedUri(uri, majorVersion); + QQmlMetaTypeData::VersionedUri versionedUri(uri, version); QQmlTypeModule *module = data->uriToModule.value(versionedUri); if (!module) { module = new QQmlTypeModule(versionedUri.uri, versionedUri.majorVersion); @@ -432,24 +438,20 @@ void addTypeToData(QQmlTypePrivate *type, QQmlMetaTypeData *data) if (type->baseMetaObject) data->metaObjectToType.insert(type->baseMetaObject, type); - if (type->typeId) { - data->idToType.insert(type->typeId, type); - if (data->objects.size() <= type->typeId) - data->objects.resize(type->typeId + 16); - data->objects.setBit(type->typeId, true); + if (type->typeId.isValid()) { + data->idToType.insert(type->typeId.id(), type); + data->objects.insert(type->typeId.id()); } - if (type->listId) { - if (data->lists.size() <= type->listId) - data->lists.resize(type->listId + 16); - data->lists.setBit(type->listId, true); - data->idToType.insert(type->listId, type); + if (type->listId.isValid()) { + data->idToType.insert(type->listId.id(), type); + data->lists.insert(type->listId.id()); } if (!type->module.isEmpty()) { const QHashedString &mod = type->module; - QQmlTypeModule *module = getTypeModule(mod, type->version_maj, data); + QQmlTypeModule *module = getTypeModule(mod, type->version, data); Q_ASSERT(module); module->add(type); } @@ -460,14 +462,14 @@ QQmlType QQmlMetaType::registerType(const QQmlPrivate::RegisterType &type) QQmlMetaTypeDataPtr data; QString elementName = QString::fromUtf8(type.elementName); - if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor)) + if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.version)) return QQmlType(); QQmlTypePrivate *priv = createQQmlType(data, elementName, type); addTypeToData(priv, data); - if (!type.typeId) - data->idToType.insert(priv->typeId, priv); + if (!type.typeId.isValid()) + data->idToType.insert(priv->typeId.id(), priv); return QQmlType(priv); } @@ -477,7 +479,7 @@ QQmlType QQmlMetaType::registerSingletonType(const QQmlPrivate::RegisterSingleto QQmlMetaTypeDataPtr data; QString typeName = QString::fromUtf8(type.typeName); - if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor)) + if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.version)) return QQmlType(); QQmlTypePrivate *priv = createQQmlType(data, typeName, type); @@ -497,7 +499,7 @@ QQmlType QQmlMetaType::registerCompositeSingletonType(const QQmlPrivate::Registe if (*(type.uri) == '\0') fileImport = true; if (!checkRegistration(QQmlType::CompositeSingletonType, data, fileImport ? nullptr : type.uri, - typeName, type.versionMajor)) { + typeName, type.version)) { return QQmlType(); } @@ -519,7 +521,7 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit bool fileImport = false; if (*(type.uri) == '\0') fileImport = true; - if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.versionMajor)) + if (!checkRegistration(QQmlType::CompositeType, data, fileImport?nullptr:type.uri, typeName, type.version)) return QQmlType(); QQmlTypePrivate *priv = createQQmlType(data, typeName, type); @@ -531,26 +533,50 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit return QQmlType(priv); } + + +template <typename T> +struct QQmlMetaTypeInterface : QtPrivate::QMetaTypeInterface +{ + const QByteArray name; + QQmlMetaTypeInterface(const QByteArray &name) + : QMetaTypeInterface { + /*.revision=*/ 0, + /*.size=*/ sizeof(T), + /*.alignment=*/ alignof(T), + /*.flags=*/ QtPrivate::QMetaTypeTypeFlags<T>::Flags, + /*.metaObject=*/ nullptr, + /*.name=*/ name.constData(), + /*.typeId=*/ 0, + /*.ref=*/ Q_REFCOUNT_INITIALIZE_STATIC, + /*.deleteSelf=*/ [](QMetaTypeInterface *self) { + delete static_cast<QQmlMetaTypeInterface *>(self); + }, + /*.defaultCtr=*/ [](const QMetaTypeInterface *, void *addr) { new (addr) T(); }, + /*.copyCtr=*/ [](const QMetaTypeInterface *, void *addr, const void *other) { + new (addr) T(*reinterpret_cast<const T *>(other)); + }, + /*.moveCtr=*/ [](const QMetaTypeInterface *, void *addr, void *other) { + new (addr) T(std::move(*reinterpret_cast<T *>(other))); + }, + /*.dtor=*/ [](const QMetaTypeInterface *, void *addr) { + reinterpret_cast<T *>(addr)->~T(); + }, + /*.legacyRegisterOp=*/ nullptr + } + , name(name) { } +}; + CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className) { QByteArray ptr = className + '*'; QByteArray lst = "QQmlListProperty<" + className + '>'; - int ptr_type = QMetaType::registerNormalizedType(ptr, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QObject*>::Construct, - sizeof(QObject*), - static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags), - nullptr); - int lst_type = QMetaType::registerNormalizedType(lst, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Destruct, - QtMetaTypePrivate::QMetaTypeFunctionHelper<QQmlListProperty<QObject> >::Construct, - sizeof(QQmlListProperty<QObject>), - static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags), - static_cast<QMetaObject*>(nullptr)); + QMetaType ptr_type(new QQmlMetaTypeInterface<QObject*>(ptr)); + QMetaType lst_type(new QQmlMetaTypeInterface<QQmlListProperty<QObject>>(lst)); QQmlMetaTypeDataPtr data; - data->qmlLists.insert(lst_type, ptr_type); + data->qmlLists.insert(lst_type.id(), ptr_type.id()); return {ptr_type, lst_type}; } @@ -558,16 +584,13 @@ CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArra void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds) { QQmlMetaTypeDataPtr data; - data->qmlLists.remove(typeIds.listId); - - QMetaType::unregisterType(typeIds.id); - QMetaType::unregisterType(typeIds.listId); + data->qmlLists.remove(typeIds.listId.id()); } int QQmlMetaType::registerUnitCacheHook( const QQmlPrivate::RegisterQmlUnitCacheHook &hookRegistration) { - if (hookRegistration.version > 0) + if (hookRegistration.structVersion > 0) qFatal("qmlRegisterType(): Cannot mix incompatible QML versions."); QQmlMetaTypeDataPtr data; @@ -575,40 +598,37 @@ int QQmlMetaType::registerUnitCacheHook( return 0; } -bool QQmlMetaType::protectModule(const QString &uri, int majVersion) +bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version) { QQmlMetaTypeDataPtr data; - QQmlMetaTypeData::VersionedUri versionedUri; - versionedUri.uri = uri; - versionedUri.majorVersion = majVersion; - - if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) { + if (QQmlTypeModule* qqtm = data->uriToModule.value( + QQmlMetaTypeData::VersionedUri(uri, version), nullptr)) { qqtm->lock(); return true; } return false; } -void QQmlMetaType::registerModule(const char *uri, int versionMajor, int versionMinor) +void QQmlMetaType::registerModule(const char *uri, QTypeRevision version) { QQmlMetaTypeDataPtr data; - QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data); + QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data); Q_ASSERT(module); - module->addMinorVersion(versionMinor); + module->addMinorVersion(version.minorVersion()); } -int QQmlMetaType::typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName) +int QQmlMetaType::typeId(const char *uri, QTypeRevision version, const char *qmlName) { QQmlMetaTypeDataPtr data; - QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), versionMajor, data); + QQmlTypeModule *module = getTypeModule(QString::fromUtf8(uri), version, data); if (!module) return -1; - QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), versionMinor); + QQmlType type = module->type(QHashedStringRef(QString::fromUtf8(qmlName)), version); if (!type.isValid()) return -1; @@ -622,12 +642,12 @@ void QQmlMetaType::registerUndeletableType(const QQmlType &dtype) } static bool namespaceContainsRegistrations(const QQmlMetaTypeData *data, const QString &uri, - int majorVersion) + QTypeRevision version) { // Has any type previously been installed to this namespace? QHashedString nameSpace(uri); for (const QQmlType &type : data->types) { - if (type.module() == nameSpace && type.majorVersion() == majorVersion) + if (type.module() == nameSpace && type.version().majorVersion() == version.majorVersion()) return true; } @@ -654,8 +674,8 @@ public: bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePath, - const QString &uri, const QString &typeNamespace, int vmaj, - QList<QQmlError> *errors) + const QString &uri, const QString &typeNamespace, + QTypeRevision version, QList<QQmlError> *errors) { if (!typeNamespace.isEmpty() && typeNamespace != uri) { // This is an 'identified' module @@ -676,7 +696,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat QQmlMetaTypeRegistrationFailureRecorder failureRecorder(data, &failures); if (!typeNamespace.isEmpty()) { // This is an 'identified' module - if (namespaceContainsRegistrations(data, typeNamespace, vmaj)) { + if (namespaceContainsRegistrations(data, typeNamespace, version)) { // Other modules have already installed to this namespace if (errors) { QQmlError error; @@ -718,7 +738,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat iface->registerTypes(moduleId); } - data->registerModuleTypes(QQmlMetaTypeData::VersionedUri(uri, vmaj)); + data->registerModuleTypes(uri); if (!failures.isEmpty()) { if (errors) { @@ -749,7 +769,7 @@ bool QQmlMetaType::registerPluginTypes(QObject *instance, const QString &basePat QQmlType QQmlMetaType::typeForUrl(const QString &urlString, const QHashedStringRef &qualifiedType, bool isCompositeSingleton, QList<QQmlError> *errors, - int majorVersion, int minorVersion) + QTypeRevision version) { // ### unfortunate (costly) conversion const QUrl url = QQmlTypeLoader::normalize(QUrl(urlString)); @@ -794,11 +814,10 @@ QQmlType QQmlMetaType::typeForUrl(const QString &urlString, const QQmlType::RegistrationType registrationType = isCompositeSingleton ? QQmlType::CompositeSingletonType : QQmlType::CompositeType; - if (checkRegistration(registrationType, data, nullptr, typeName, majorVersion)) { + if (checkRegistration(registrationType, data, nullptr, typeName, version)) { auto *priv = new QQmlTypePrivate(registrationType); priv->setName(QString(), typeName); - priv->version_maj = majorVersion; - priv->version_min = minorVersion; + priv->version = version; if (isCompositeSingleton) { priv->extraData.sd->singletonInstanceInfo = new QQmlType::SingletonInstanceInfo; @@ -851,14 +870,12 @@ bool QQmlMetaType::isAnyModule(const QString &uri) /* Returns true if a module \a uri of this version is installed and locked; */ -bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion) +bool QQmlMetaType::isLockedModule(const QString &uri, QTypeRevision version) { QQmlMetaTypeDataPtr data; - QQmlMetaTypeData::VersionedUri versionedUri; - versionedUri.uri = uri; - versionedUri.majorVersion = majVersion; - if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) + if (QQmlTypeModule* qqtm = data->uriToModule.value( + QQmlMetaTypeData::VersionedUri(uri, version), nullptr)) return qqtm->isLocked(); return false; } @@ -870,24 +887,24 @@ bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion) So if only 4.7 and 4.9 have been registered, 4.7,4.8, and 4.9 are valid, but not 4.6 nor 4.10. */ -bool QQmlMetaType::isModule(const QString &module, int versionMajor, int versionMinor) +bool QQmlMetaType::isModule(const QString &module, QTypeRevision version) { - Q_ASSERT(versionMajor >= 0 && versionMinor >= 0); + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); QQmlMetaTypeDataPtr data; // first, check Types QQmlTypeModule *tm = - data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, versionMajor)); - if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor) + data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, version)); + if (tm && tm->minimumMinorVersion() <= version.minorVersion() && tm->maximumMinorVersion() >= version.minorVersion()) return true; return false; } -QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, int majorVersion) +QQmlTypeModule *QQmlMetaType::typeModule(const QString &uri, QTypeRevision version) { QQmlMetaTypeDataPtr data; - return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, majorVersion)); + return data->uriToModule.value(QQmlMetaTypeData::VersionedUri(uri, version)); } QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions() @@ -912,9 +929,8 @@ bool QQmlMetaType::isQObject(int userType) { if (userType == QMetaType::QObjectStar) return true; - QQmlMetaTypeDataPtr data; - return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); + return data->objects.contains(userType); } /* @@ -927,8 +943,8 @@ int QQmlMetaType::listType(int id) if (iter != data->qmlLists.cend()) return *iter; QQmlTypePrivate *type = data->idToType.value(id); - if (type && type->listId == id) - return type->typeId; + if (type && type->listId.id() == id) + return type->typeId.id(); else return 0; } @@ -1028,9 +1044,9 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) QQmlMetaTypeDataPtr data; if (data->qmlLists.contains(userType)) return List; - else if (userType < data->objects.size() && data->objects.testBit(userType)) + else if (data->objects.contains(userType)) return Object; - else if (userType < data->lists.size() && data->lists.testBit(userType)) + else if (data->lists.contains(userType)) return List; else return Unknown; @@ -1042,7 +1058,7 @@ QQmlMetaType::TypeCategory QQmlMetaType::typeCategory(int userType) bool QQmlMetaType::isInterface(int userType) { const QQmlMetaTypeDataPtr data; - return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); + return data->interfaces.contains(userType); } const char *QQmlMetaType::interfaceIId(int userType) @@ -1055,7 +1071,7 @@ const char *QQmlMetaType::interfaceIId(int userType) } QQmlType type(typePrivate); - if (type.isInterface() && type.typeId() == userType) + if (type.isInterface() && type.typeId().id() == userType) return type.interfaceIId(); else return nullptr; @@ -1063,10 +1079,10 @@ const char *QQmlMetaType::interfaceIId(int userType) bool QQmlMetaType::isList(int userType) { - const QQmlMetaTypeDataPtr data; + QQmlMetaTypeDataPtr data; if (data->qmlLists.contains(userType)) return true; - return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); + return data->lists.contains(userType); } /*! @@ -1106,7 +1122,7 @@ QQmlMetaType::StringConverter QQmlMetaType::customStringConverter(int type) Returns the type (if any) of URI-qualified named \a qualifiedName and version specified by \a version_major and \a version_minor. */ -QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision version) { int slash = qualifiedName.indexOf(QLatin1Char('/')); if (slash <= 0) @@ -1115,23 +1131,23 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, int version_major, QHashedStringRef module(qualifiedName.constData(), slash); QHashedStringRef name(qualifiedName.constData() + slash + 1, qualifiedName.length() - slash - 1); - return qmlType(name, module, version_major, version_minor); + return qmlType(name, module, version); } /*! Returns the type (if any) of \a name in \a module and version specified by \a version_major and \a version_minor. */ -QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, + QTypeRevision version) { - Q_ASSERT(version_major >= 0 && version_minor >= 0); + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); while (it != data->nameToType.cend() && it.key() == name) { QQmlType t(*it); - // XXX version_major<0 just a kludge for QQmlPropertyPrivate::initProperty - if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) + if (module.isEmpty() || t.availableInVersion(module, version)) return t; ++it; } @@ -1154,15 +1170,16 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) by \a version_major and \a version_minor in module specified by \a uri. Returns null if no type is registered. */ -QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor) +QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, + QTypeRevision version) { - Q_ASSERT(version_major >= 0 && version_minor >= 0); + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); while (it != data->metaObjectToType.cend() && it.key() == metaObject) { QQmlType t(*it); - if (version_major < 0 || module.isEmpty() || t.availableInVersion(module, version_major,version_minor)) + if (module.isEmpty() || t.availableInVersion(module, version)) return t; ++it; } @@ -1181,7 +1198,7 @@ QQmlType QQmlMetaType::qmlType(int typeId, TypeIdCategory category) if (category == TypeIdCategory::MetaType) { QQmlTypePrivate *type = data->idToType.value(typeId); - if (type && type->typeId == typeId) + if (type && type->typeId.id() == typeId) return QQmlType(type); } else if (category == TypeIdCategory::QmlType) { QQmlType type = data->types.value(typeId); @@ -1212,16 +1229,16 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } -QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion) +QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, QTypeRevision version) { QQmlMetaTypeDataPtr data; // not const: the cache is created on demand - return data->propertyCache(metaObject, minorVersion); + return data->propertyCache(metaObject, version); } -QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion) +QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, QTypeRevision version) { QQmlMetaTypeDataPtr data; // not const: the cache is created on demand - return data->propertyCache(type, minorVersion); + return data->propertyCache(type, version); } void QQmlMetaType::unregisterType(int typeIndex) @@ -1236,7 +1253,7 @@ void QQmlMetaType::unregisterType(int typeIndex) removeQQmlTypePrivate(data->metaObjectToType, d); for (auto & module : data->uriToModule) module->remove(d); - data->clearPropertyCachesForMinorVersion(typeIndex); + data->clearPropertyCachesForVersion(typeIndex); data->types[typeIndex] = QQmlType(); data->undeletableTypes.remove(type); } @@ -1268,7 +1285,7 @@ void QQmlMetaType::freeUnusedTypesAndCaches() for (auto &module : data->uriToModule) module->remove(d); - data->clearPropertyCachesForMinorVersion(d->index); + data->clearPropertyCachesForVersion(d->index); *it = QQmlType(); } else { ++it; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 037cf89beb..28d647520d 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -65,11 +65,9 @@ namespace QV4 { class ExecutableCompilationUnit; } struct CompositeMetaTypeIds { - int id = -1; - int listId = -1; - CompositeMetaTypeIds() = default; - CompositeMetaTypeIds(int id, int listId) : id(id), listId(listId) {} - bool isValid() const { return id != -1 && listId != -1; } + QMetaType id; + QMetaType listId; + bool isValid() const { return id.isValid() && listId.isValid(); } }; class Q_QML_PRIVATE_EXPORT QQmlMetaType @@ -81,20 +79,20 @@ public: static QQmlType registerCompositeSingletonType(const QQmlPrivate::RegisterCompositeSingletonType &type); static QQmlType registerCompositeType(const QQmlPrivate::RegisterCompositeType &type); static bool registerPluginTypes(QObject *instance, const QString &basePath, - const QString &uri, const QString &typeNamespace, int vmaj, - QList<QQmlError> *errors); + const QString &uri, const QString &typeNamespace, + QTypeRevision version, QList<QQmlError> *errors); static QQmlType typeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList<QQmlError> *errors, - int majorVersion = -1, int minorVersion = -1); + QTypeRevision version = QTypeRevision()); static void unregisterType(int type); static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className); static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds); - static void registerModule(const char *uri, int versionMajor, int versionMinor); - static bool protectModule(const QString &uri, int majVersion); + static void registerModule(const char *uri, QTypeRevision version); + static bool protectModule(const QString &uri, QTypeRevision version); - static int typeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName); + static int typeId(const char *uri, QTypeRevision version, const char *qmlName); static void registerUndeletableType(const QQmlType &dtype); @@ -108,15 +106,16 @@ public: QmlType }; - static QQmlType qmlType(const QString &qualifiedName, int, int); - static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); + static QQmlType qmlType(const QString &qualifiedName, QTypeRevision version); + static QQmlType qmlType(const QHashedStringRef &name, const QHashedStringRef &module, QTypeRevision version); static QQmlType qmlType(const QMetaObject *); - static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, int version_major, int version_minor); + static QQmlType qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, QTypeRevision version); static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType); static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false); - static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion = -1); - static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); + static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, + QTypeRevision version = QTypeRevision()); + static QQmlPropertyCache *propertyCache(const QQmlType &type, QTypeRevision version); static void freeUnusedTypesAndCaches(); @@ -150,9 +149,9 @@ public: static StringConverter customStringConverter(int); static bool isAnyModule(const QString &uri); - static bool isLockedModule(const QString &uri, int majorVersion); - static bool isModule(const QString &module, int versionMajor, int versionMinor); - static QQmlTypeModule *typeModule(const QString &uri, int majorVersion); + static bool isLockedModule(const QString &uri, QTypeRevision version); + static bool isModule(const QString &module, QTypeRevision version); + static QQmlTypeModule *typeModule(const QString &uri, QTypeRevision version); static QList<QQmlPrivate::AutoParentFunction> parentFunctions(); @@ -197,11 +196,12 @@ public: static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd); - static void qmlInsertModuleRegistration(const QString &uri, int majorVersion, - void (*registerFunction)()); - static void qmlRemoveModuleRegistration(const QString &uri, int majorVersion); + static void qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)()); + static void qmlRemoveModuleRegistration(const QString &uri); - static bool qmlRegisterModuleTypes(const QString &uri, int majorVersion); + static bool qmlRegisterModuleTypes(const QString &uri); + + static int qmlRegisteredListTypeCount(); }; Q_DECLARE_TYPEINFO(QQmlMetaType, Q_MOVABLE_TYPE); diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp index ed885eaa97..a34a0c1ae4 100644 --- a/src/qml/qml/qqmlmetatypedata.cpp +++ b/src/qml/qml/qqmlmetatypedata.cpp @@ -78,9 +78,9 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) priv->release(); } -bool QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri) +bool QQmlMetaTypeData::registerModuleTypes(const QString &uri) { - auto function = moduleTypeRegistrationFunctions.constFind(versionedUri); + auto function = moduleTypeRegistrationFunctions.constFind(uri); if (function != moduleTypeRegistrationFunctions.constEnd()) { (*function)(); return true; @@ -88,28 +88,28 @@ bool QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri return false; } -QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const +QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForVersion(int index, QTypeRevision version) const { return (index < typePropertyCaches.length()) - ? typePropertyCaches.at(index).value(minorVersion).data() + ? typePropertyCaches.at(index).value(version).data() : nullptr; } -void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion, - QQmlPropertyCache *cache) +void QQmlMetaTypeData::setPropertyCacheForVersion(int index, QTypeRevision version, + QQmlPropertyCache *cache) { if (index >= typePropertyCaches.length()) typePropertyCaches.resize(index + 1); - typePropertyCaches[index][minorVersion] = cache; + typePropertyCaches[index][version] = cache; } -void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index) +void QQmlMetaTypeData::clearPropertyCachesForVersion(int index) { if (index < typePropertyCaches.length()) typePropertyCaches[index].clear(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion) +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, QTypeRevision version) { if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) return rv; @@ -119,29 +119,36 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject propertyCaches.insert(metaObject, rv); return rv; } - QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion); - QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion); + QQmlPropertyCache *super = propertyCache(metaObject->superClass(), version); + QQmlPropertyCache *rv = super->copyAndAppend(metaObject, version); propertyCaches.insert(metaObject, rv); return rv; } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion) +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, QTypeRevision version) { Q_ASSERT(type.isValid()); - if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), minorVersion)) + if (QQmlPropertyCache *pc = propertyCacheForVersion(type.index(), version)) return pc; QVector<QQmlType> types; - int maxMinorVersion = 0; + quint8 maxMinorVersion = 0; const QMetaObject *metaObject = type.metaObject(); + const QTypeRevision combinedVersion = version.hasMajorVersion() + ? version + : (version.hasMinorVersion() + ? QTypeRevision::fromVersion(type.version().majorVersion(), + version.minorVersion()) + : type.version()); + while (metaObject) { - QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), type.majorVersion(), minorVersion); + QQmlType t = QQmlMetaType::qmlType(metaObject, type.module(), combinedVersion); if (t.isValid()) { - maxMinorVersion = qMax(maxMinorVersion, t.minorVersion()); + maxMinorVersion = qMax(maxMinorVersion, t.version().minorVersion()); types << t; } else { types << QQmlType(); @@ -150,12 +157,14 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min metaObject = metaObject->superClass(); } - if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(type.index(), maxMinorVersion)) { - setPropertyCacheForMinorVersion(type.index(), minorVersion, pc); + const QTypeRevision maxVersion = QTypeRevision::fromVersion(combinedVersion.majorVersion(), + maxMinorVersion); + if (QQmlPropertyCache *pc = propertyCacheForVersion(type.index(), maxVersion)) { + setPropertyCacheForVersion(type.index(), maxVersion, pc); return pc; } - QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion); + QQmlPropertyCache *raw = propertyCache(type.metaObject(), combinedVersion); bool hasCopied = false; @@ -164,7 +173,7 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min if (!currentType.isValid()) continue; - int rev = currentType.metaObjectRevision(); + QTypeRevision rev = currentType.metaObjectRevision(); int moIndex = types.count() - 1 - ii; if (raw->allowedRevision(moIndex) != rev) { @@ -222,13 +231,13 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min } #endif - setPropertyCacheForMinorVersion(type.index(), minorVersion, raw); + setPropertyCacheForVersion(type.index(), version, raw); if (hasCopied) raw->release(); - if (minorVersion != maxMinorVersion) - setPropertyCacheForMinorVersion(type.index(), maxMinorVersion, raw); + if (version != maxVersion) + setPropertyCacheForVersion(type.index(), maxVersion, raw); return raw; } diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h index e51d4ca1a4..322ead084a 100644 --- a/src/qml/qml/qqmlmetatypedata_p.h +++ b/src/qml/qml/qqmlmetatypedata_p.h @@ -57,7 +57,6 @@ #include <QtCore/qset.h> #include <QtCore/qvector.h> -#include <QtCore/qbitarray.h> QT_BEGIN_NAMESPACE @@ -83,29 +82,28 @@ struct QQmlMetaTypeData MetaObjects metaObjectToType; typedef QHash<int, QQmlMetaType::StringConverter> StringConverters; StringConverters stringConverters; - QVector<QHash<int, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches; + QVector<QHash<QTypeRevision, QQmlRefPointer<QQmlPropertyCache>>> typePropertyCaches; struct VersionedUri { - VersionedUri() - : majorVersion(0) {} - VersionedUri(const QHashedString &uri, int majorVersion) - : uri(uri), majorVersion(majorVersion) {} + VersionedUri() : majorVersion(0) {} + VersionedUri(const QHashedString &uri, QTypeRevision version) + : uri(uri), majorVersion(version.majorVersion()) {} bool operator==(const VersionedUri &other) const { return other.majorVersion == majorVersion && other.uri == uri; } QHashedString uri; - int majorVersion; + quint8 majorVersion; }; typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules; TypeModules uriToModule; - QHash<VersionedUri, void (*)()> moduleTypeRegistrationFunctions; - bool registerModuleTypes(const VersionedUri &versionedUri); + QHash<QString, void (*)()> moduleTypeRegistrationFunctions; + bool registerModuleTypes(const QString &uri); - QBitArray objects; - QBitArray interfaces; - QBitArray lists; + QSet<int> interfaces; + QSet<int> objects; + QSet<int> lists; QList<QQmlPrivate::AutoParentFunction> parentFunctions; QVector<QQmlPrivate::QmlUnitCacheLookupFunction> lookupCachedQmlUnit; @@ -114,12 +112,12 @@ struct QQmlMetaTypeData QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches; - QQmlPropertyCache *propertyCacheForMinorVersion(int index, int minorVersion) const; - void setPropertyCacheForMinorVersion(int index, int minorVersion, QQmlPropertyCache *cache); - void clearPropertyCachesForMinorVersion(int index); + QQmlPropertyCache *propertyCacheForVersion(int index, QTypeRevision version) const; + void setPropertyCacheForVersion(int index, QTypeRevision version, QQmlPropertyCache *cache); + void clearPropertyCachesForVersion(int index); - QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion); - QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); + QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, QTypeRevision version); + QQmlPropertyCache *propertyCache(const QQmlType &type, QTypeRevision version); void setTypeRegistrationFailures(QStringList *failures) { diff --git a/src/qml/qml/qqmlmoduleregistration.cpp b/src/qml/qml/qqmlmoduleregistration.cpp index b7bc3555a6..422a5c0551 100644 --- a/src/qml/qml/qqmlmoduleregistration.cpp +++ b/src/qml/qml/qqmlmoduleregistration.cpp @@ -39,27 +39,33 @@ #include <QtQml/private/qqmlmetatype_p.h> #include <QtQml/qqmlmoduleregistration.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE struct QQmlModuleRegistrationPrivate { const QString uri; - const int majorVersion; }; +QQmlModuleRegistration::QQmlModuleRegistration(const char *uri, void (*registerFunction)()) : + d(new QQmlModuleRegistrationPrivate { QString::fromUtf8(uri) }) +{ + QQmlMetaType::qmlInsertModuleRegistration(d->uri, registerFunction); +} + +#if QT_DEPRECATED_SINCE(6, 0) QQmlModuleRegistration::QQmlModuleRegistration( - const char *uri, int majorVersion, - void (*registerFunction)()) : - d(new QQmlModuleRegistrationPrivate { QString::fromUtf8(uri), majorVersion }) + const char *uri, int majorVersion, void (*registerFunction)()) : + QQmlModuleRegistration(uri, registerFunction) { - QQmlMetaType::qmlInsertModuleRegistration(d->uri, d->majorVersion, - registerFunction); + Q_UNUSED(majorVersion); } +#endif QQmlModuleRegistration::~QQmlModuleRegistration() { - QQmlMetaType::qmlRemoveModuleRegistration(d->uri, d->majorVersion); + QQmlMetaType::qmlRemoveModuleRegistration(d->uri); delete d; } diff --git a/src/qml/qml/qqmlmoduleregistration.h b/src/qml/qml/qqmlmoduleregistration.h index 6f553a2823..3db535faa0 100644 --- a/src/qml/qml/qqmlmoduleregistration.h +++ b/src/qml/qml/qqmlmoduleregistration.h @@ -49,9 +49,14 @@ class Q_QML_EXPORT QQmlModuleRegistration { Q_DISABLE_COPY_MOVE(QQmlModuleRegistration) public: - QQmlModuleRegistration(const char *uri, int majorVersion, void (*registerFunction)()); + QQmlModuleRegistration(const char *uri, void (*registerFunction)()); ~QQmlModuleRegistration(); +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_X("Use registration without major version") + QQmlModuleRegistration(const char *uri, int majorVersion, void (*registerFunction)()); +#endif + private: QQmlModuleRegistrationPrivate *d = nullptr; }; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 198ce98f2d..538a87ff5b 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -56,6 +56,7 @@ #include <private/qqmldebugconnector_p.h> #include <private/qqmldebugserviceinterfaces_p.h> #include <private/qqmlscriptdata_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <private/qjsvalue_p.h> #include <private/qv4generatorobject_p.h> @@ -173,7 +174,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 +857,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; @@ -1135,8 +1136,8 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, { QQmlError error; error.setUrl(compilationUnit->url()); - error.setLine(location.line); - error.setColumn(location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); error.setDescription(description); errors << error; } @@ -1147,11 +1148,6 @@ void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::O context->setIdProperty(object->id, instance); } -void QQmlObjectCreator::createQmlContext() -{ - _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); -} - QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index); @@ -1264,7 +1260,10 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo ddata->columnNumber = obj->location.column; ddata->setImplicitDestructible(); - if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation) { + // inline components are root objects, but their index is != 0, so we need + // an additional check + const bool isInlineComponent = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot; + if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation || isInlineComponent) { if (ddata->context) { Q_ASSERT(ddata->context != context); Q_ASSERT(ddata->outerContext); @@ -1505,15 +1504,45 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) _ddata->deferData(_compiledObjectIndex, compilationUnit, context); + QSet<QString> postHocRequired; + for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it) + postHocRequired.insert(stringAt(it->nameIndex)); + bool hadInheritedRequiredProperties = !postHocRequired.empty(); + for (int propertyIndex = 0; propertyIndex != _compiledObject->propertyCount(); ++propertyIndex) { const QV4::CompiledData::Property* property = _compiledObject->propertiesBegin() + propertyIndex; QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex); - if (property->isRequired) { - sharedState->hadRequiredProperties = true; - sharedState->requiredProperties.insert(propertyData, - RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}}); - } + // only compute stringAt if there's a chance for the lookup to succeed + auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex)); + if (!property->isRequired && postHocRequired.end() == postHocIt) + continue; + if (postHocIt != postHocRequired.end()) + postHocRequired.erase(postHocIt); + sharedState->hadRequiredProperties = true; + sharedState->requiredProperties.insert(propertyData, + RequiredPropertyInfo {compilationUnit->stringAt(property->nameIndex), compilationUnit->finalUrl(), property->location, {}}); + + } + + for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) { + QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i); + if (!propertyData) + continue; + if (!propertyData->isRequired() && postHocRequired.isEmpty()) + continue; + QString name = propertyData->name(_qobject); + auto postHocIt = postHocRequired.find(name); + if (!propertyData->isRequired() && postHocRequired.end() == postHocIt ) + continue; + + if (postHocIt != postHocRequired.end()) + postHocRequired.erase(postHocIt); + + sharedState->hadRequiredProperties = true; + sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {name, compilationUnit->finalUrl(), _compiledObject->location, {}}); } + if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties) + recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin())); if (_compiledObject->nFunctions > 0) setupFunctions(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index f8ad90be15..50ce8d5909 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -86,7 +86,7 @@ struct RequiredPropertyInfo QVector<AliasToRequiredInfo> aliasesToRequired; }; -using RequiredProperties = QHash<QQmlPropertyData*, RequiredPropertyInfo>; +class RequiredProperties : public QHash<QQmlPropertyData*, RequiredPropertyInfo> {}; struct QQmlObjectCreatorSharedState : public QSharedData { @@ -162,7 +162,6 @@ private: void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const; inline QV4::QmlContext *currentQmlContext(); - Q_NEVER_INLINE void createQmlContext(); QV4::ResolvedTypeReference *resolvedType(int id) const { return compilationUnit->resolvedType(id); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 9504fc37dc..8a1cbc2ddf 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -63,24 +63,11 @@ #include <QtCore/qvariant.h> #include <QtCore/qurl.h> #include <QtCore/qpointer.h> +#include <QtCore/qversionnumber.h> #include <QtCore/qmetaobject.h> #include <QtCore/qdebug.h> -#define QML_GETTYPENAMES \ - const char *className = T::staticMetaObject.className(); \ - const int nameLen = int(strlen(className)); \ - QVarLengthArray<char,48> pointerName(nameLen+2); \ - memcpy(pointerName.data(), className, size_t(nameLen)); \ - pointerName[nameLen] = '*'; \ - pointerName[nameLen+1] = '\0'; \ - const int listLen = int(strlen("QQmlListProperty<")); \ - QVarLengthArray<char,64> listName(listLen + nameLen + 2); \ - memcpy(listName.data(), "QQmlListProperty<", size_t(listLen)); \ - memcpy(listName.data()+listLen, className, size_t(nameLen)); \ - listName[listLen+nameLen] = '>'; \ - listName[listLen+nameLen+1] = '\0'; - QT_BEGIN_NAMESPACE class QQmlPropertyValueInterceptor; @@ -124,6 +111,7 @@ class QJSValue; class QJSEngine; class QQmlEngine; class QQmlCustomParser; +class QQmlTypeNotAvailable; template<class T> QQmlCustomParser *qmlCreateCustomParser() @@ -342,17 +330,16 @@ namespace QQmlPrivate typedef AutoParentResult (*AutoParentFunction)(QObject *object, QObject *parent); struct RegisterType { - int version; + int structVersion; - int typeId; - int listId; + QMetaType typeId; + QMetaType listId; int objectSize; void (*create)(void *); QString noCreationReason; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *elementName; const QMetaObject *metaObject; @@ -368,20 +355,20 @@ namespace QQmlPrivate QQmlCustomParser *customParser; - int revision; + QTypeRevision revision; // If this is extended ensure "version" is bumped!!! }; struct RegisterTypeAndRevisions { - int version; + int structVersion; - int typeId; - int listId; + QMetaType typeId; + QMetaType listId; int objectSize; void (*create)(void *); const char *uri; - int versionMajor; + QTypeRevision version; const QMetaObject *metaObject; const QMetaObject *classInfoMetaObject; @@ -400,12 +387,15 @@ namespace QQmlPrivate }; struct RegisterInterface { - int version; + int structVersion; - int typeId; - int listId; + QMetaType typeId; + QMetaType listId; const char *iid; + + const char *uri; + QTypeRevision version; }; struct RegisterAutoParent { @@ -415,48 +405,45 @@ namespace QQmlPrivate }; struct RegisterSingletonType { - int version; + int structVersion; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *typeName; QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); QObject *(*qobjectApi)(QQmlEngine *, QJSEngine *); const QMetaObject *instanceMetaObject; // new in version 1 - int typeId; // new in version 2 - int revision; // new in version 2 + QMetaType typeId; // new in version 2 + QTypeRevision revision; // new in version 2 std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 // If this is extended ensure "version" is bumped!!! }; struct RegisterSingletonTypeAndRevisions { - int version; + int structVersion; const char *uri; - int versionMajor; + QTypeRevision version; QJSValue (*scriptApi)(QQmlEngine *, QJSEngine *); const QMetaObject *instanceMetaObject; const QMetaObject *classInfoMetaObject; - int typeId; + QMetaType typeId; std::function<QObject*(QQmlEngine *, QJSEngine *)> generalizedQobjectApi; // new in version 3 }; struct RegisterCompositeType { QUrl url; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *typeName; }; struct RegisterCompositeSingletonType { QUrl url; const char *uri; - int versionMajor; - int versionMinor; + QTypeRevision version; const char *typeName; }; @@ -468,7 +455,7 @@ namespace QQmlPrivate typedef const CachedQmlUnit *(*QmlUnitCacheLookupFunction)(const QUrl &url); struct RegisterQmlUnitCacheHook { - int version; + int structVersion; QmlUnitCacheLookupFunction lookupCachedQmlUnit; }; @@ -512,11 +499,13 @@ namespace QQmlPrivate return metaObject->classInfo(indexOfOwnClassInfo(metaObject, key)).value(); } - inline int intClassInfo(const QMetaObject *metaObject, const char *key, int defaultValue = 0) + inline QTypeRevision revisionClassInfo(const QMetaObject *metaObject, const char *key, + QTypeRevision defaultValue = QTypeRevision()) { const int index = indexOfOwnClassInfo(metaObject, key); return (index == -1) ? defaultValue - : QByteArray(metaObject->classInfo(index).value()).toInt(); + : QTypeRevision::fromEncodedVersion( + QByteArray(metaObject->classInfo(index).value()).toInt()); } inline bool boolClassInfo(const QMetaObject *metaObject, const char *key, @@ -579,24 +568,34 @@ 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) { - QML_GETTYPENAMES - RegisterSingletonTypeAndRevisions api = { 0, uri, - versionMajor, + QTypeRevision::fromMajorVersion(versionMajor), nullptr, &T::staticMetaObject, classInfoMetaObject, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), + QMetaType::fromType<T *>(), Constructors<T>::createSingletonInstance }; @@ -607,17 +606,15 @@ namespace QQmlPrivate void qmlRegisterTypeAndRevisions(const char *uri, int versionMajor, const QMetaObject *classInfoMetaObject) { - QML_GETTYPENAMES - RegisterTypeAndRevisions type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), - qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + QMetaType::fromType<T*>(), + QMetaType::fromType<QQmlListProperty<T>>(), int(sizeof(T)), Constructors<T>::createInto, uri, - versionMajor, + QTypeRevision::fromMajorVersion(versionMajor), &T::staticMetaObject, classInfoMetaObject, @@ -637,6 +634,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/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index c4afbbd598..09e16fdbe0 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -75,6 +75,7 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) flags.setIsWritable(p.isWritable()); flags.setIsResettable(p.isResettable()); flags.setIsFinal(p.isFinal()); + flags.setIsRequired(p.isRequired()); if (p.isEnumType()) flags.type = QQmlPropertyData::Flags::EnumType; @@ -82,13 +83,11 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) return flags; } -// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to -// load -static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags) +// Flags that do depend on the property's QMetaType +static void flagsForPropertyType(QMetaType metaType, QQmlPropertyData::Flags &flags) { - Q_ASSERT(propType != -1); - - if (propType == QMetaType::QObjectStar) { + int propType = metaType.id(); + if (metaType.flags() & QMetaType::PointerToQObject) { flags.type = QQmlPropertyData::Flags::QObjectDerivedType; } else if (propType == QMetaType::QVariant) { flags.type = QQmlPropertyData::Flags::QVariantType; @@ -100,8 +99,7 @@ static void flagsForPropertyType(int propType, QQmlPropertyData::Flags &flags) flags.type = QQmlPropertyData::Flags::QJSValueType; } else { QQmlMetaType::TypeCategory cat = QQmlMetaType::typeCategory(propType); - - if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) + if (cat == QQmlMetaType::Object) flags.type = QQmlPropertyData::Flags::QObjectDerivedType; else if (cat == QQmlMetaType::List) flags.type = QQmlPropertyData::Flags::QListType; @@ -120,17 +118,17 @@ QQmlPropertyData::Flags QQmlPropertyData::flagsForProperty(const QMetaProperty &p) { auto flags = fastFlagsForProperty(p); - flagsForPropertyType(p.userType(), flags); + flagsForPropertyType(p.metaType(), flags); return flags; } static void populate(QQmlPropertyData *data, const QMetaProperty &p) { - Q_ASSERT(p.revision() <= Q_INT16_MAX); + Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max()); data->setCoreIndex(p.propertyIndex()); data->setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); data->setFlags(fastFlagsForProperty(p)); - data->setRevision(p.revision()); + data->setRevision(QTypeRevision::fromEncodedVersion(p.revision())); } void QQmlPropertyData::lazyLoad(const QMetaProperty &p) @@ -153,8 +151,9 @@ void QQmlPropertyData::lazyLoad(const QMetaProperty &p) void QQmlPropertyData::load(const QMetaProperty &p) { populate(this, p); - setPropType(p.userType()); - flagsForPropertyType(propType(), m_flags); + QMetaType type = p.metaType(); + setPropType(type.id()); + flagsForPropertyType(type, m_flags); } void QQmlPropertyData::load(const QMetaMethod &m) @@ -182,8 +181,8 @@ void QQmlPropertyData::load(const QMetaMethod &m) if (m.attributes() & QMetaMethod::Cloned) m_flags.setIsCloned(true); - Q_ASSERT(m.revision() <= Q_INT16_MAX); - setRevision(m.revision()); + Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max()); + setRevision(QTypeRevision::fromEncodedVersion(m.revision())); } void QQmlPropertyData::lazyLoad(const QMetaMethod &m) @@ -211,14 +210,14 @@ QQmlPropertyCache::QQmlPropertyCache() /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, int metaObjectRevision) +QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevision metaObjectRevision) : QQmlPropertyCache() { Q_ASSERT(metaObject); update(metaObject); - if (metaObjectRevision > 0) { + if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) { // Set the revision of the meta object that this cache describes to be // 'metaObjectRevision'. This is useful when constructing a property cache // from a type that was created directly in C++, and not through QML. For such @@ -290,14 +289,15 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth This is different from QMetaMethod::methodIndex(). */ void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags, - int coreIndex, int propType, int minorVersion, int notifyIndex) + int coreIndex, int propType, QTypeRevision version, + int notifyIndex) { QQmlPropertyData data; data.setPropType(propType); data.setCoreIndex(coreIndex); data.setNotifyIndex(notifyIndex); data.setFlags(flags); - data.setTypeMinorVersion(minorVersion); + data.setTypeVersion(version); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -398,6 +398,19 @@ const QMetaObject *QQmlPropertyCache::createMetaObject() return _metaObject; } +QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const +{ + if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) + return nullptr; + + QQmlPropertyData *rv = nullptr; + if (index < propertyIndexCacheStart) + return _parent->maybeUnresolvedProperty(index); + else + rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); + return rv; +} + QQmlPropertyData *QQmlPropertyCache::defaultProperty() const { return property(defaultPropertyName(), nullptr, nullptr); @@ -419,12 +432,12 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) { - return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags); + return copyAndAppend(metaObject, QTypeRevision(), propertyFlags, methodFlags, signalFlags); } QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - int typeMinorVersion, + QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) @@ -438,13 +451,13 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, QMetaObjectPrivate::get(metaObject)->signalCount + QMetaObjectPrivate::get(metaObject)->propertyCount); - rv->append(metaObject, typeMinorVersion, propertyFlags, methodFlags, signalFlags); + rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags); return rv; } void QQmlPropertyCache::append(const QMetaObject *metaObject, - int typeMinorVersion, + QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) @@ -453,7 +466,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, bool dynamicMetaObject = isDynamicMetaObject(metaObject); - allowedRevisionCache.append(0); + allowedRevisionCache.append(QTypeRevision::zero()); int methodCount = metaObject->methodCount(); Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); @@ -598,7 +611,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, data->setFlags(propertyFlags); data->lazyLoad(p); - data->setTypeMinorVersion(typeMinorVersion); + data->setTypeVersion(typeVersion); data->m_flags.setIsDirect(!dynamicMetaObject); @@ -672,7 +685,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); } } - flagsForPropertyType(data->propType(), data->m_flags); + flagsForPropertyType(QMetaType(data->propType()), data->m_flags); } } @@ -683,7 +696,7 @@ void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) updateRecur(metaObject->superClass()); - append(metaObject, -1); + append(metaObject, QTypeRevision()); } void QQmlPropertyCache::update(const QMetaObject *metaObject) @@ -731,7 +744,7 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) methodIndexCacheStart = parent()->methodIndexCache.count() + parent()->methodIndexCacheStart; signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.count() + parent()->signalHandlerIndexCacheStart; stringCache.linkAndReserve(parent()->stringCache, reserve); - append(metaObject, -1); + append(metaObject, QTypeRevision()); } else { propertyIndexCacheStart = 0; methodIndexCacheStart = 0; diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index bfd78eef88..9e6eaf9778 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -60,6 +60,7 @@ #include <private/qlinkedstringhash_p.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> +#include <QtCore/qversionnumber.h> #include <private/qv4value_p.h> #include <private/qqmlpropertydata_p.h> @@ -80,7 +81,7 @@ class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount { public: QQmlPropertyCache(); - QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0); + QQmlPropertyCache(const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero()); ~QQmlPropertyCache() override; void update(const QMetaObject *); @@ -92,7 +93,8 @@ public: QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()); - QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion, + QQmlPropertyCache *copyAndAppend( + const QMetaObject *, QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()); @@ -100,7 +102,7 @@ public: QQmlPropertyCache *copyAndReserve(int propertyCount, int methodCount, int signalCount, int enumCount); void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex, - int propType, int revision, int notifyIndex); + int propType, QTypeRevision revision, int notifyIndex); void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex, const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>()); void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, int returnType, @@ -118,6 +120,7 @@ public: } QQmlPropertyData *property(int) const; + QQmlPropertyData *maybeUnresolvedProperty(int) const; QQmlPropertyData *method(int) const; QQmlPropertyData *signal(int index) const; QQmlEnumData *qmlEnum(int) const; @@ -173,8 +176,8 @@ public: QByteArray checksum(bool *ok); - int allowedRevision(int index) const { return allowedRevisionCache[index]; } - void setAllowedRevision(int index, int allowed) { allowedRevisionCache[index] = allowed; } + QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; } + void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; } private: friend class QQmlEnginePrivate; @@ -186,7 +189,7 @@ private: inline QQmlPropertyCache *copy(int reserve); - void append(const QMetaObject *, int typeMinorVersion, + void append(const QMetaObject *, QTypeRevision typeVersion, QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()); @@ -195,7 +198,7 @@ private: typedef QVector<QQmlPropertyData> IndexCache; typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache; - typedef QVector<int> AllowedRevisionCache; + typedef QVector<QTypeRevision> AllowedRevisionCache; QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const; QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const; @@ -351,8 +354,9 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const { - return (data->metaObjectOffset() == -1 && data->revision() == 0) || - (allowedRevisionCache[data->metaObjectOffset()] >= data->revision()); + return (data->metaObjectOffset() == -1 && data->revision() == QTypeRevision::zero()) + || (allowedRevisionCache[data->metaObjectOffset()].toEncodedVersion<quint16>() + >= data->revision().toEncodedVersion<quint16>()); } int QQmlPropertyCache::propertyCount() const diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp index 36581bda4e..f132fb2d78 100644 --- a/src/qml/qml/qqmlpropertycachecreator.cpp +++ b/src/qml/qml/qqmlpropertycachecreator.cpp @@ -119,9 +119,12 @@ QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiating { if (instantiatingProperty) { if (instantiatingProperty->isQObject()) { - return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion()); + // rawPropertyCacheForType assumes a given unspecified version means "any version". + // There is another overload that takes no version, which we shall not use here. + return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), + instantiatingProperty->typeVersion()); } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) { - return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion()); + return enginePrivate->cache(vtmo, instantiatingProperty->typeVersion()); } } return QQmlRefPointer<QQmlPropertyCache>(); diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h index a050a0bf0a..cadbfdd481 100644 --- a/src/qml/qml/qqmlpropertycachecreator_p.h +++ b/src/qml/qml/qqmlpropertycachecreator_p.h @@ -56,19 +56,20 @@ #include <private/qqmlpropertyresolver_p.h> #include <private/qqmltypedata_p.h> #include <private/inlinecomponentutils_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <QScopedValueRollback> #include <vector> QT_BEGIN_NAMESPACE -inline QQmlJS::DiagnosticMessage qQmlCompileError(const QV4::CompiledData::Location &location, +inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location, const QString &description) { - QQmlJS::DiagnosticMessage error; - error.line = location.line; - error.column = location.column; - error.message = description; + QQmlError error; + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); + error.setDescription(description); return error; } @@ -117,16 +118,16 @@ public: const ObjectContainer *objectContainer, const QQmlImports *imports, const QByteArray &typeClassName); - QQmlJS::DiagnosticMessage buildMetaObjects(); + QQmlError buildMetaObjects(); enum class VMEMetaObjectIsRequired { Maybe, Always }; protected: - QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired); - QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const; - QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); + QQmlError buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired); + QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const; + QQmlError createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache); int metaTypeForParameter(const QV4::CompiledData::ParameterType ¶m, QString *customTypeName = nullptr); @@ -153,12 +154,13 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP , propertyCaches(propertyCaches) , pendingGroupPropertyBindings(pendingGroupPropertyBindings) , typeClassName(typeClassName) + , currentRoot(-1) { propertyCaches->resize(objectContainer->objectCount()); } template <typename ObjectContainer> -inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() +inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects() { using namespace icutils; QQmlBindingInstantiationContext context; @@ -185,8 +187,8 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle); if (hasCycle) { - QQmlJS::DiagnosticMessage diag; - diag.message = QLatin1String("Inline components form a cycle!"); + QQmlError diag; + diag.setDescription(QLatin1String("Inline components form a cycle!")); return diag; } @@ -200,7 +202,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil QByteArray icTypeName { objectContainer->stringAt(ic.nameIndex).toUtf8() }; QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName}; QScopedValueRollback<unsigned int> rootChange {currentRoot, ic.objectIndex}; - QQmlJS::DiagnosticMessage diag = buildMetaObjectRecursively(ic.objectIndex, context, VMEMetaObjectIsRequired::Always); + QQmlError diag = buildMetaObjectRecursively(ic.objectIndex, context, VMEMetaObjectIsRequired::Always); if (diag.isValid()) { return diag; } @@ -212,7 +214,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil } template <typename ObjectContainer> -inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired) +inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired) { auto isAddressable = [](const QUrl &url) { const QString fileName = url.fileName(); @@ -241,7 +243,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); QQmlRefPointer<QQmlPropertyCache> baseTypeCache = typeRef->createPropertyCache(QQmlEnginePrivate::get(enginePrivate)); - QQmlJS::DiagnosticMessage error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); + QQmlError error = createMetaObject(context.referencingObjectIndex, obj, baseTypeCache); if (error.isValid()) return error; } @@ -256,7 +258,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil QQmlRefPointer<QQmlPropertyCache> baseTypeCache; { - QQmlJS::DiagnosticMessage error; + QQmlError error; baseTypeCache = propertyCacheForObject(obj, context, &error); if (error.isValid()) return error; @@ -264,7 +266,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil if (baseTypeCache) { if (needVMEMetaObject) { - QQmlJS::DiagnosticMessage error = createMetaObject(objectIndex, obj, baseTypeCache); + QQmlError error = createMetaObject(objectIndex, obj, baseTypeCache); if (error.isValid()) return error; } else { @@ -286,18 +288,18 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil if (!context.resolveInstantiatingProperty()) pendingGroupPropertyBindings->append(context); - QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); + QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe); if (error.isValid()) return error; } } - QQmlJS::DiagnosticMessage noError; + QQmlError noError; return noError; } template <typename ObjectContainer> -inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const +inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContainer>::propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlError *error) const { if (context.instantiatingProperty) { return context.instantiatingPropertyCache(enginePrivate); @@ -343,7 +345,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine } template <typename ObjectContainer> -inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) +inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache) { QQmlRefPointer<QQmlPropertyCache> cache; cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(), @@ -537,7 +539,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea pend = obj->propertiesEnd(); for ( ; p != pend; ++p, ++propertyIdx) { int propertyType = 0; - int propertTypeMinorVersion = 0; + QTypeRevision propertyTypeVersion = QTypeRevision::zero(); QQmlPropertyData::Flags propertyFlags; const QV4::CompiledData::BuiltinType type = p->builtinType(); @@ -556,7 +558,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea QQmlType qmltype; bool selfReference = false; - if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr, + if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr, nullptr, QQmlType::AnyRegistrationType, &selfReference)) { return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type")); } @@ -589,16 +591,16 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea } if (p->isList) { - propertyType = typeIds.listId; + propertyType = typeIds.listId.id(); } else { - propertyType = typeIds.id; + propertyType = typeIds.id.id(); } } else { if (p->isList) { - propertyType = qmltype.qListTypeId(); + propertyType = qmltype.qListTypeId().id(); } else { - propertyType = qmltype.typeId(); - propertTypeMinorVersion = qmltype.minorVersion(); + propertyType = qmltype.typeId().id(); + propertyTypeVersion = qmltype.version(); } } @@ -616,12 +618,12 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias) cache->_defaultPropertyName = propertyName; cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - propertyType, propertTypeMinorVersion, effectiveSignalIndex); + propertyType, propertyTypeVersion, effectiveSignalIndex); effectiveSignalIndex++; } - QQmlJS::DiagnosticMessage noError; + QQmlError noError; return noError; } @@ -640,15 +642,15 @@ inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const *customTypeName = typeName; QQmlType qmltype; bool selfReference = false; - if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr, nullptr, QQmlType::AnyRegistrationType, - &selfReference)) + if (!imports->resolveType(typeName, &qmltype, nullptr, nullptr, nullptr, + QQmlType::AnyRegistrationType, &selfReference)) return QMetaType::UnknownType; if (!qmltype.isComposite()) - return qmltype.typeId(); + return qmltype.typeId().id(); if (selfReference) - return objectContainer->typeIdsForComponent().id; + return objectContainer->typeIdsForComponent().id.id(); QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl()); Q_ASSERT(tdata); @@ -656,7 +658,7 @@ inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const auto compilationUnit = tdata->compilationUnit(); - return compilationUnit->metaTypeId; + return compilationUnit->metaTypeId.id(); } template <typename ObjectContainer> @@ -669,11 +671,11 @@ public: void appendAliasPropertiesToMetaObjects(QQmlEnginePrivate *enginePriv); - QQmlJS::DiagnosticMessage appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv); + QQmlError appendAliasesToPropertyCache(const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv); private: void appendAliasPropertiesInMetaObjectsWithinComponent(const CompiledObject &component, int firstObjectIndex, QQmlEnginePrivate *enginePriv); - QQmlJS::DiagnosticMessage propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *rev, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv); + QQmlError propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv); void collectObjectsWithAliasesRecursively(int objectIndex, QVector<int> *objectsWithAliases) const; @@ -784,8 +786,10 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl } template <typename ObjectContainer> -inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias(const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, int *minorVersion, - QQmlPropertyData::Flags *propertyFlags, QQmlEnginePrivate *enginePriv) +inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataForAlias( + const CompiledObject &component, const QV4::CompiledData::Alias &alias, int *type, + QTypeRevision *version, QQmlPropertyData::Flags *propertyFlags, + QQmlEnginePrivate *enginePriv) { *type = 0; bool writable = false; @@ -817,7 +821,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>: lastAlias = targetAlias; } while (lastAlias->aliasToLocalAlias); - return propertyDataForAlias(component, *lastAlias, type, minorVersion, propertyFlags, enginePriv); + return propertyDataForAlias(component, *lastAlias, type, version, propertyFlags, enginePriv); } const int targetObjectIndex = objectForId(component, alias.targetObjectId); @@ -836,11 +840,11 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>: } if (typeRef->type.isValid()) - *type = typeRef->type.typeId(); + *type = typeRef->type.typeId().id(); else - *type = typeRef->compilationUnit->metaTypeId; + *type = typeRef->compilationUnit->metaTypeId.id(); - *minorVersion = typeRef->minorVersion; + *version = typeRef->version; propertyFlags->type = QQmlPropertyData::Flags::QObjectDerivedType; } else { @@ -895,16 +899,16 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>: propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable); propertyFlags->setIsResettable(resettable); - return QQmlJS::DiagnosticMessage(); + return QQmlError(); } template <typename ObjectContainer> -inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( +inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesToPropertyCache( const CompiledObject &component, int objectIndex, QQmlEnginePrivate *enginePriv) { const CompiledObject &object = *objectContainer->objectAt(objectIndex); if (!object.aliasCount()) - return QQmlJS::DiagnosticMessage(); + return QQmlError(); QQmlPropertyCache *propertyCache = propertyCaches->at(objectIndex); Q_ASSERT(propertyCache); @@ -919,9 +923,10 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>: Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved); int type = 0; - int minorVersion = 0; + QTypeRevision version = QTypeRevision::zero(); QQmlPropertyData::Flags propertyFlags; - QQmlJS::DiagnosticMessage error = propertyDataForAlias(component, *alias, &type, &minorVersion, &propertyFlags, enginePriv); + QQmlError error = propertyDataForAlias(component, *alias, &type, &version, + &propertyFlags, enginePriv); if (error.isValid()) return error; @@ -931,10 +936,10 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>: propertyCache->_defaultPropertyName = propertyName; propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, - type, minorVersion, effectiveSignalIndex++); + type, version, effectiveSignalIndex++); } - return QQmlJS::DiagnosticMessage(); + return QQmlError(); } template <typename ObjectContainer> diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h index 2d9091edcd..f21b502b50 100644 --- a/src/qml/qml/qqmlpropertydata_p.h +++ b/src/qml/qml/qqmlpropertydata_p.h @@ -53,6 +53,7 @@ #include <private/qobject_p.h> #include <QtCore/qglobal.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE @@ -109,7 +110,7 @@ public: unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args unsigned isSignalHandler : 1; // Function is a signal handler unsigned isOverload : 1; // Function is an overload of another function - unsigned isCloned : 1; // The function was marked as cloned + unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned unsigned isConstructor : 1; // The function was marked is a constructor unsigned isDirect : 1; // Exists on a C++ QMetaObject unsigned isOverridden : 1; // Is overridden by a extension property @@ -159,6 +160,11 @@ public: isDirect = b; } + void setIsRequired(bool b) { + Q_ASSERT(type != FunctionType); + isRequiredORisCloned = b; + } + void setIsVMEFunction(bool b) { Q_ASSERT(type == FunctionType); isConstantORisVMEFunction = b; @@ -193,7 +199,7 @@ public: void setIsCloned(bool b) { Q_ASSERT(type == FunctionType); - isCloned = b; + isRequiredORisCloned = b; } void setIsConstructor(bool b) { @@ -224,6 +230,7 @@ public: bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; } bool isOverridden() const { return m_flags.isOverridden; } bool isDirect() const { return m_flags.isOverload; } + bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; } bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } bool isFunction() const { return m_flags.type == Flags::FunctionType; } bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; } @@ -241,11 +248,11 @@ public: bool isSignalHandler() const { return m_flags.isSignalHandler; } bool isOverload() const { return m_flags.isOverload; } void setOverload(bool onoff) { m_flags.isOverload = onoff; } - bool isCloned() const { return isFunction() && m_flags.isCloned; } + bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; } bool isConstructor() const { return m_flags.isConstructor; } bool hasOverride() const { return overrideIndex() >= 0; } - bool hasRevision() const { return revision() != 0; } + bool hasRevision() const { return revision() != QTypeRevision::zero(); } bool isFullyResolved() const { return !m_flags.notFullyResolved; } @@ -284,12 +291,8 @@ public: m_coreIndex = qint16(idx); } - quint8 revision() const { return m_revision; } - void setRevision(quint8 rev) - { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - m_revision = quint8(rev); - } + QTypeRevision revision() const { return m_revision; } + void setRevision(QTypeRevision revision) { m_revision = revision; } /* If a property is a C++ type, then we store the minor * version of this type. @@ -309,12 +312,8 @@ public: * */ - quint8 typeMinorVersion() const { return m_typeMinorVersion; } - void setTypeMinorVersion(quint8 rev) - { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - m_typeMinorVersion = quint8(rev); - } + QTypeRevision typeVersion() const { return m_typeVersion; } + void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; } QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; } void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; } @@ -406,18 +405,20 @@ private: qint16 m_notifyIndex = -1; qint16 m_overrideIndex = -1; - quint8 m_revision = 0; - quint8 m_typeMinorVersion = 0; qint16 m_metaObjectOffset = -1; + quint16 m_reserved = 0; + + QTypeRevision m_revision = QTypeRevision::zero(); + QTypeRevision m_typeVersion = QTypeRevision::zero(); QQmlPropertyCacheMethodArguments *m_arguments = nullptr; StaticMetaCallFunction m_staticMetaCallFunction = nullptr; }; #if QT_POINTER_SIZE == 4 - Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24); + Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 28); #else // QT_POINTER_SIZE == 8 - Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32); + Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 40); #endif bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const @@ -438,7 +439,7 @@ QQmlPropertyData::Flags::Flags() , isFinalORisV4Function(false) , isSignalHandler(false) , isOverload(false) - , isCloned(false) + , isRequiredORisCloned(false) , isConstructor(false) , isOverridden(false) , type(OtherType) @@ -455,7 +456,7 @@ bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) c isFinalORisV4Function == other.isFinalORisV4Function && isOverridden == other.isOverridden && isSignalHandler == other.isSignalHandler && - isCloned == other.isCloned && + isRequiredORisCloned == other.isRequiredORisCloned && type == other.type && isConstructor == other.isConstructor && notFullyResolved == other.notFullyResolved && diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp index 8762dc328d..312153576a 100644 --- a/src/qml/qml/qqmlpropertyvalidator.cpp +++ b/src/qml/qml/qqmlpropertyvalidator.cpp @@ -73,7 +73,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, c bindingPropertyDataPerObject->resize(compilationUnit->objectCount()); } -QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validate() +QVector<QQmlError> QQmlPropertyValidator::validate() { return validateObject(/*root object*/0, /*instantiatingBinding*/nullptr); } @@ -96,7 +96,7 @@ struct BindingFinder } }; -QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( +QVector<QQmlError> QQmlPropertyValidator::validateObject( int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex); @@ -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); @@ -113,7 +113,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex); if (!propertyCache) - return QVector<QQmlJS::DiagnosticMessage>(); + return QVector<QQmlError>(); QQmlCustomParser *customParser = nullptr; if (auto typeRef = resolvedType(obj->inheritedTypeNameIndex)) { @@ -192,7 +192,10 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( QString typeName = stringAt(obj->inheritedTypeNameIndex); auto *objectType = resolvedType(obj->inheritedTypeNameIndex); if (objectType && objectType->type.isValid()) { - return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(name).arg(objectType->type.module()).arg(objectType->majorVersion).arg(objectType->minorVersion)); + return recordError(binding->location, tr("\"%1.%2\" is not available in %3 %4.%5.") + .arg(typeName).arg(name).arg(objectType->type.module()) + .arg(objectType->version.majorVersion()) + .arg(objectType->version.minorVersion())); } else { return recordError(binding->location, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(name)); } @@ -212,7 +215,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( if (name.constData()->isUpper() && !binding->isAttachedProperty()) { QQmlType type; QQmlImportNamespace *typeNamespace = nullptr; - imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, nullptr, &typeNamespace); + imports.resolveType(stringAt(binding->propertyNameIndex), &type, nullptr, &typeNamespace); if (typeNamespace) return recordError(binding->location, tr("Invalid use of namespace")); return recordError(binding->location, tr("Invalid attached object assignment")); @@ -223,7 +226,7 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( = pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType()) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment); - const QVector<QQmlJS::DiagnosticMessage> subObjectValidatorErrors + const QVector<QQmlError> subObjectValidatorErrors = validateObject(binding->value.objectIndex, binding, populatingValueTypeGroupProperty); if (!subObjectValidatorErrors.isEmpty()) @@ -280,11 +283,11 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( } if (binding->type < QV4::CompiledData::Binding::Type_Script) { - QQmlJS::DiagnosticMessage bindingError = validateLiteralBinding(propertyCache, pd, binding); + QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding); if (bindingError.isValid()) return recordError(bindingError); } else if (binding->type == QV4::CompiledData::Binding::Type_Object) { - QQmlJS::DiagnosticMessage bindingError = validateObjectBinding(pd, name, binding); + QQmlError bindingError = validateObjectBinding(pd, name, binding); if (bindingError.isValid()) return recordError(bindingError); } else if (binding->isGroupProperty()) { @@ -346,24 +349,24 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject( customParser->validator = nullptr; customParser->engine = nullptr; customParser->imports = (QQmlImports*)nullptr; - QVector<QQmlJS::DiagnosticMessage> parserErrors = customParser->errors(); + QVector<QQmlError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) return parserErrors; } (*bindingPropertyDataPerObject)[objectIndex] = collectedBindingPropertyData; - QVector<QQmlJS::DiagnosticMessage> noError; + QVector<QQmlError> noError; return noError; } -QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const +QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const { if (property->isQList()) { return qQmlCompileError(binding->valueLocation, tr("Cannot assign primitives to lists")); } - QQmlJS::DiagnosticMessage noError; + QQmlError noError; if (property->isEnum()) { if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) @@ -387,8 +390,8 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateLiteralBinding(QQmlProp if (binding->type == QV4::CompiledData::Binding::Type_Null) { QQmlError warning; warning.setUrl(compilationUnit->url()); - warning.setLine(binding->valueLocation.line); - warning.setColumn(binding->valueLocation.column); + warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line)); + warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.column)); warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML " "is deprecated. This will become a compile error in " "future versions of Qt.")); @@ -659,23 +662,23 @@ bool QQmlPropertyValidator::canCoerce(int to, QQmlPropertyCache *fromMo) const return false; } -QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const +QVector<QQmlError> QQmlPropertyValidator::recordError(const QV4::CompiledData::Location &location, const QString &description) const { - QVector<QQmlJS::DiagnosticMessage> errors; + QVector<QQmlError> errors; errors.append(qQmlCompileError(location, description)); return errors; } -QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::recordError(const QQmlJS::DiagnosticMessage &error) const +QVector<QQmlError> QQmlPropertyValidator::recordError(const QQmlError &error) const { - QVector<QQmlJS::DiagnosticMessage> errors; + QVector<QQmlError> errors; errors.append(error); return errors; } -QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const +QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const { - QQmlJS::DiagnosticMessage noError; + QQmlError noError; if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object); @@ -744,8 +747,8 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope // We want to use the raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might // effect the properties on the type, but don't effect assignability - // Using -1 for the minor version ensures that we get the raw metaObject. - QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1); + // Not passing a version ensures that we get the raw metaObject. + QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType); if (propertyMetaObject) { // Will be true if the assigned type inherits propertyMetaObject diff --git a/src/qml/qml/qqmlpropertyvalidator_p.h b/src/qml/qml/qqmlpropertyvalidator_p.h index 74a1281927..281472981c 100644 --- a/src/qml/qml/qqmlpropertyvalidator_p.h +++ b/src/qml/qml/qqmlpropertyvalidator_p.h @@ -66,25 +66,24 @@ class QQmlPropertyValidator public: QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); - QVector<QQmlJS::DiagnosticMessage> validate(); + QVector<QQmlError> validate(); private: - QVector<QQmlJS::DiagnosticMessage> validateObject( + QVector<QQmlError> validateObject( int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty = false) const; - QQmlJS::DiagnosticMessage validateLiteralBinding( + QQmlError validateLiteralBinding( QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const; - QQmlJS::DiagnosticMessage validateObjectBinding( + QQmlError validateObjectBinding( QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const; bool canCoerce(int to, QQmlPropertyCache *fromMo) const; - Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( + Q_REQUIRED_RESULT QVector<QQmlError> recordError( const QV4::CompiledData::Location &location, const QString &description) const; - Q_REQUIRED_RESULT QVector<QQmlJS::DiagnosticMessage> recordError( - const QQmlJS::DiagnosticMessage &error) const; + Q_REQUIRED_RESULT QVector<QQmlError> recordError(const QQmlError &error) const; QString stringAt(int index) const { return compilationUnit->stringAt(index); } QV4::ResolvedTypeReference *resolvedType(int id) const { diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp index eb103dc434..dac21f7ee7 100644 --- a/src/qml/qml/qqmlscriptblob.cpp +++ b/src/qml/qml/qqmlscriptblob.cpp @@ -41,6 +41,7 @@ #include <private/qqmlirbuilder_p.h> #include <private/qqmlscriptblob_p.h> #include <private/qqmlscriptdata_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <private/qv4runtimecodegen_p.h> #include <private/qv4script_p.h> @@ -167,8 +168,8 @@ void QQmlScriptBlob::done() QList<QQmlError> errors = script.script->errors(); QQmlError error; error.setUrl(url()); - error.setLine(script.location.line); - error.setColumn(script.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column)); error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 28fefca239..db22c93733 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) - : regType(type), iid(nullptr), typeId(0), listId(0), revision(0), + : regType(type), iid(nullptr), revision(QTypeRevision::zero()), containsRevisionedAttributes(false), baseMetaObject(nullptr), index(-1), isSetup(false), isEnumFromCacheSetup(false), isEnumFromBaseSetup(false), haveSuperType(false) @@ -132,34 +132,29 @@ QHashedString QQmlType::module() const return d->module; } -int QQmlType::majorVersion() const +QTypeRevision QQmlType::version() const { if (!d) - return -1; - return d->version_maj; + return QTypeRevision(); + return d->version; } -int QQmlType::minorVersion() const +bool QQmlType::availableInVersion(QTypeRevision version) const { - if (!d) - return -1; - return d->version_min; -} - -bool QQmlType::availableInVersion(int vmajor, int vminor) const -{ - Q_ASSERT(vmajor >= 0 && vminor >= 0); + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); if (!d) return false; - return vmajor == d->version_maj && vminor >= d->version_min; + return version.majorVersion() == d->version.majorVersion() + && version.minorVersion() >= d->version.minorVersion(); } -bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const +bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const { - Q_ASSERT(vmajor >= 0 && vminor >= 0); + Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); if (!d) return false; - return module == d->module && vmajor == d->version_maj && vminor >= d->version_min; + return module == d->module && version.majorVersion() == d->version.majorVersion() + && version.minorVersion() >= d->version.minorVersion(); } QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const @@ -592,14 +587,14 @@ bool QQmlType::isQJSValueSingleton() const return d && d->regType == SingletonType && d->extraData.sd->singletonInstanceInfo->scriptCallback; } -int QQmlType::typeId() const +QMetaType QQmlType::typeId() const { - return d ? d->typeId : -1; + return d ? d->typeId : QMetaType{}; } -int QQmlType::qListTypeId() const +QMetaType QQmlType::qListTypeId() const { - return d ? d->listId : -1; + return d ? d->listId : QMetaType{}; } const QMetaObject *QQmlType::metaObject() const @@ -629,21 +624,21 @@ bool QQmlType::containsRevisionedAttributes() const return d->containsRevisionedAttributes; } -int QQmlType::metaObjectRevision() const +QTypeRevision QQmlType::metaObjectRevision() const { - return d ? d->revision : -1; + return d ? d->revision : QTypeRevision(); } QQmlAttachedPropertiesFunc QQmlType::attachedPropertiesFunction(QQmlEnginePrivate *engine) const { - if (const QQmlTypePrivate *base = d->attachedPropertiesBase(engine)) + if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr) return base->extraData.cd->attachedPropertiesFunc; return nullptr; } const QMetaObject *QQmlType::attachedPropertiesType(QQmlEnginePrivate *engine) const { - if (const QQmlTypePrivate *base = d->attachedPropertiesBase(engine)) + if (const QQmlTypePrivate *base = d ? d->attachedPropertiesBase(engine) : nullptr) return base->extraData.cd->attachedPropertiesType; return nullptr; } @@ -946,7 +941,8 @@ int QQmlType::generatePlaceHolderICId() const void QQmlType::associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType) { - auto priv = existingType.isValid() ? const_cast<QQmlTypePrivate *>(existingType.d.data()) : new QQmlTypePrivate { RegistrationType::InlineComponentType } ; + bool const reuseExistingType = existingType.isValid(); + auto priv = reuseExistingType ? const_cast<QQmlTypePrivate *>(existingType.d.data()) : new QQmlTypePrivate { RegistrationType::InlineComponentType } ; priv->setName( QString::fromUtf8(typeName()), name); auto icUrl = QUrl(sourceUrl()); icUrl.setFragment(QString::number(objectID)); @@ -958,6 +954,8 @@ void QQmlType::associateInlineComponent(const QString &name, int objectID, const d->namesToInlineComponentObjectIndex.insert(name, objectID); QQmlType icType(priv); d->objectIdToICType.insert(objectID, icType); + if (!reuseExistingType) + priv->release(); } void QQmlType::setPendingResolutionName(const QString &name) diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h index 387baa74bb..2b37ec16be 100644 --- a/src/qml/qml/qqmltype_p.h +++ b/src/qml/qml/qqmltype_p.h @@ -60,6 +60,7 @@ #include <QtQml/qjsvalue.h> #include <QtCore/qobject.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE @@ -98,11 +99,10 @@ public: QString elementName() const; QHashedString module() const; - int majorVersion() const; - int minorVersion() const; + QTypeRevision version() const; - bool availableInVersion(int vmajor, int vminor) const; - bool availableInVersion(const QHashedStringRef &module, int vmajor, int vminor) const; + bool availableInVersion(QTypeRevision version) const; + bool availableInVersion(const QHashedStringRef &module, QTypeRevision version) const; QObject *create() const; void create(QObject **, void **, size_t) const; @@ -124,12 +124,12 @@ public: bool isQObjectSingleton() const; bool isQJSValueSingleton() const; - int typeId() const; - int qListTypeId() const; + QMetaType typeId() const; + QMetaType qListTypeId() const; const QMetaObject *metaObject() const; const QMetaObject *baseMetaObject() const; - int metaObjectRevision() const; + QTypeRevision metaObjectRevision() const; bool containsRevisionedAttributes() const; QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const; diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h index 43344827db..c94ac8c130 100644 --- a/src/qml/qml/qqmltype_p_p.h +++ b/src/qml/qml/qqmltype_p_p.h @@ -157,11 +157,10 @@ public: QHashedString module; QString name; QString elementName; - int version_maj; - int version_min; - int typeId; - int listId; - int revision; + QMetaType typeId; + QMetaType listId; + QTypeRevision version; + QTypeRevision revision; mutable bool containsRevisionedAttributes; mutable QQmlType superType; const QMetaObject *baseMetaObject; diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp index 842ca697e0..5c04abf367 100644 --- a/src/qml/qml/qqmltypecompiler.cpp +++ b/src/qml/qml/qqmltypecompiler.cpp @@ -82,7 +82,7 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() { QQmlPropertyCacheCreator<QQmlTypeCompiler> propertyCacheBuilder(&m_propertyCaches, &pendingGroupPropertyBindings, engine, this, imports(), typeData->typeClassName()); - QQmlJS::DiagnosticMessage error = propertyCacheBuilder.buildMetaObjects(); + QQmlError error = propertyCacheBuilder.buildMetaObjects(); if (error.isValid()) { recordError(error); return nullptr; @@ -174,8 +174,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile() void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setLine(location.line); - error.setColumn(location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column)); error.setDescription(description); error.setUrl(url()); errors << error; @@ -185,8 +185,15 @@ void QQmlTypeCompiler::recordError(const QQmlJS::DiagnosticMessage &message) { QQmlError error; error.setDescription(message.message); - error.setLine(message.line); - error.setColumn(message.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(message.loc.startLine)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(message.loc.startColumn)); + error.setUrl(url()); + errors << error; +} + +void QQmlTypeCompiler::recordError(const QQmlError &e) +{ + QQmlError error = e; error.setUrl(url()); errors << error; } @@ -257,7 +264,7 @@ QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scrip return object->bindingAsString(document, scriptIndex); } -void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion) +void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier, QTypeRevision version) { const quint32 moduleIdx = registerString(module); const quint32 qualifierIdx = registerString(qualifier); @@ -272,8 +279,7 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier auto pool = memoryPool(); QV4::CompiledData::Import *import = pool->New<QV4::CompiledData::Import>(); import->type = QV4::CompiledData::Import::ImportLibrary; - import->majorVersion = majorVersion; - import->minorVersion = minorVersion; + import->version = version; import->uriIndex = moduleIdx; import->qualifierIndex = qualifierIdx; document->imports.append(import); @@ -394,7 +400,10 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio auto *typeRef = resolvedType(obj->inheritedTypeNameIndex); const QQmlType type = typeRef ? typeRef->type : QQmlType(); if (type.isValid()) { - COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.").arg(typeName).arg(originalPropertyName).arg(type.module()).arg(type.majorVersion()).arg(type.minorVersion())); + COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available in %3 %4.%5.") + .arg(typeName).arg(originalPropertyName).arg(type.module()) + .arg(type.version().majorVersion()) + .arg(type.version().minorVersion())); } else { COMPILE_EXCEPTION(binding, tr("\"%1.%2\" is not available due to component versioning.").arg(typeName).arg(originalPropertyName)); } @@ -816,7 +825,12 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI if (!pd || !pd->isQObject()) continue; - QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeMinorVersion()); + // If the version is given, use it and look up by QQmlType. + // Otherwise, make sure we look up by metaobject. + // TODO: Is this correct? + QQmlPropertyCache *pc = pd->typeVersion().hasMinorVersion() + ? enginePrivate->rawPropertyCacheForType(pd->propType(), pd->typeVersion()) + : enginePrivate->rawPropertyCacheForType(pd->propType()); const QMetaObject *mo = pc ? pc->firstCppMetaObject() : nullptr; while (mo) { if (mo == &QQmlComponent::staticMetaObject) @@ -832,7 +846,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI Q_ASSERT(componentType.isValid()); const QString qualifier = QStringLiteral("QmlInternals"); - compiler->addImport(componentType.module(), qualifier, componentType.majorVersion(), componentType.minorVersion()); + compiler->addImport(componentType.module(), qualifier, componentType.version()); QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>(); syntheticComponent->init(pool, compiler->registerString(qualifier + QLatin1Char('.') + componentType.elementName()), compiler->registerString(QString())); @@ -842,8 +856,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) { auto typeRef = new QV4::ResolvedTypeReference; typeRef->type = componentType; - typeRef->majorVersion = componentType.majorVersion(); - typeRef->minorVersion = componentType.minorVersion(); + typeRef->version = componentType.version(); insertResolvedType(syntheticComponent->inheritedTypeNameIndex, typeRef); } @@ -875,6 +888,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; @@ -930,7 +947,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); @@ -1006,7 +1023,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) for (int objectIndex: qAsConst(_objectsWithAliases)) { - QQmlJS::DiagnosticMessage error; + QQmlError error; const auto result = resolveAliasesInObject(objectIndex, &error); if (error.isValid()) { @@ -1015,7 +1032,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) } if (result == AllAliasesResolved) { - QQmlJS::DiagnosticMessage error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate); + QQmlError error = aliasCacheCreator.appendAliasesToPropertyCache(*qmlObjects->at(componentIndex), objectIndex, enginePrivate); if (error.isValid()) { recordError(error); return false; @@ -1046,7 +1063,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex) QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex, - QQmlJS::DiagnosticMessage *error) + QQmlError *error) { const QmlIR::Object * const obj = qmlObjects->at(objectIndex); if (!obj->aliasCount()) diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h index 319df8673b..883fbf0d68 100644 --- a/src/qml/qml/qqmltypecompiler_p.h +++ b/src/qml/qml/qqmltypecompiler_p.h @@ -100,7 +100,8 @@ public: QList<QQmlError> compilationErrors() const { return errors; } void recordError(const QV4::CompiledData::Location &location, const QString &description); - void recordError(const QQmlJS::DiagnosticMessage &error); + void recordError(const QQmlJS::DiagnosticMessage &message); + void recordError(const QQmlError &e); int registerString(const QString &str); int registerConstant(QV4::ReturnedValue v); @@ -124,7 +125,7 @@ public: QString bindingAsString(const QmlIR::Object *object, int scriptIndex) const; - void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion); + void addImport(const QString &module, const QString &qualifier, QTypeRevision version); QV4::ResolvedTypeReference *resolvedType(int id) const { @@ -157,7 +158,7 @@ struct QQmlCompilePass protected: void recordError(const QV4::CompiledData::Location &location, const QString &description) const { compiler->recordError(location, description); } - void recordError(const QQmlJS::DiagnosticMessage &error) + void recordError(const QQmlError &error) { compiler->recordError(error); } QV4::ResolvedTypeReference *resolvedType(int id) const @@ -280,7 +281,7 @@ protected: AllAliasesResolved }; - AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlJS::DiagnosticMessage *error); + AliasResolutionResult resolveAliasesInObject(int objectIndex, QQmlError *error); QQmlEnginePrivate *enginePrivate; QQmlJS::MemoryPool *pool; diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp index f7abe67921..7b21edec37 100644 --- a/src/qml/qml/qqmltypedata.cpp +++ b/src/qml/qml/qqmltypedata.cpp @@ -182,8 +182,8 @@ bool QQmlTypeData::tryLoadFromDiskCache() const QV4::CompiledData::Import *import = m_compiledData->importAt(i); if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".") && import->qualifierIndex == 0 - && import->majorVersion == -1 - && import->minorVersion == -1) { + && !import->version.hasMajorVersion() + && !import->version.hasMinorVersion()) { QList<QQmlError> errors; auto pendingImport = std::make_shared<PendingImport>(this, import); if (!fetchQmldir(qmldirUrl, pendingImport, 1, &errors)) { @@ -203,8 +203,8 @@ bool QQmlTypeData::tryLoadFromDiskCache() Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(import->location.line); - error.setColumn(import->location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return false; @@ -213,9 +213,9 @@ bool QQmlTypeData::tryLoadFromDiskCache() QQmlType containingType; auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first(); - int major = -1, minor = -1; + QTypeRevision version; QQmlImportNamespace *ns = nullptr; - m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns); + m_importCache.resolveType(containingTypeName, &containingType, &version, &ns); for (auto&& ic: ics) { QString const nameString = m_compiledData->stringAt(ic.nameIndex); QByteArray const name = nameString.toUtf8(); @@ -244,7 +244,7 @@ void QQmlTypeData::createTypeAndPropertyCaches( QQmlPropertyCacheCreator<QV4::ExecutableCompilationUnit> propertyCacheCreator( &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine, m_compiledData.data(), &m_importCache, typeClassName()); - QQmlJS::DiagnosticMessage error = propertyCacheCreator.buildMetaObjects(); + QQmlError error = propertyCacheCreator.buildMetaObjects(); if (error.isValid()) { setError(error); return; @@ -325,8 +325,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = script.script->errors(); QQmlError error; error.setUrl(url()); - error.setLine(script.location.line); - error.setColumn(script.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column)); error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString())); errors.prepend(error); setError(errors); @@ -349,8 +349,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{}; QQmlError error; error.setUrl(url()); - error.setLine(type.location.line); - error.setColumn(type.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(typeName.leftRef(lastDot), type.type.pendingResolutionName())); errors.prepend(error); setError(errors); @@ -365,8 +365,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; error.setUrl(url()); - error.setLine(type.location.line); - error.setColumn(type.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); @@ -384,8 +384,8 @@ void QQmlTypeData::done() QList<QQmlError> errors = type.typeData->errors(); QQmlError error; error.setUrl(url()); - error.setLine(type.location.line); - error.setColumn(type.location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column)); error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); @@ -414,7 +414,7 @@ void QQmlTypeData::done() QV4::ResolvedTypeReferenceMap resolvedTypeCache; QQmlRefPointer<QQmlTypeNameCache> typeNameCache; { - QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); + QQmlError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); if (error.isValid()) { setError(error); qDeleteAll(resolvedTypeCache); @@ -461,7 +461,7 @@ void QQmlTypeData::done() { // Sanity check property bindings QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData); - QVector<QQmlJS::DiagnosticMessage> errors = validator.validate(); + QVector<QQmlError> errors = validator.validate(); if (!errors.isEmpty()) { setError(errors); return; @@ -625,8 +625,8 @@ bool QQmlTypeData::loadFromSource() for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { QQmlError e; e.setUrl(url()); - e.setLine(msg.line); - e.setColumn(msg.column); + e.setLine(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startLine)); + e.setColumn(qmlConvertSourceCoordinate<quint32, int>(msg.loc.startColumn)); e.setDescription(msg.message); errors << e; } @@ -651,9 +651,9 @@ void QQmlTypeData::continueLoadFromIR() { QQmlType containingType; auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first(); - int major = -1, minor = -1; + QTypeRevision version; QQmlImportNamespace *ns = nullptr; - m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns); + m_importCache.resolveType(containingTypeName, &containingType, &version, &ns); for (auto const& object: m_document->objects) { for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) { QString const nameString = m_document->stringAt(it->nameIndex); @@ -679,8 +679,7 @@ void QQmlTypeData::continueLoadFromIR() // This qmldir is for the implicit import auto implicitImport = std::make_shared<PendingImport>(); implicitImport->uri = QLatin1String("."); - implicitImport->majorVersion = -1; - implicitImport->minorVersion = -1; + implicitImport->version = QTypeRevision(); QList<QQmlError> errors; if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) { @@ -697,8 +696,8 @@ void QQmlTypeData::continueLoadFromIR() Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(import->location.line); - error.setColumn(import->location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); errors.prepend(error); // put it back on the list after filling out information. setError(errors); return; @@ -724,8 +723,8 @@ void QQmlTypeData::allDependenciesDone() QQmlError error; error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri)); error.setUrl(m_importCache.baseUrl()); - error.setLine(import->location.line); - error.setColumn(import->location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); errors.prepend(error); } } @@ -824,17 +823,15 @@ void QQmlTypeData::resolveTypes() typeName = csRef.typeName; } - int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1; - int minorVersion = csRef.minorVersion > -1 ? csRef.minorVersion : -1; - - if (!resolveType(typeName, majorVersion, minorVersion, ref, -1, -1, true, - QQmlType::CompositeSingletonType)) + QTypeRevision version = csRef.version; + if (!resolveType(typeName, version, ref, -1, -1, true, QQmlType::CompositeSingletonType)) return; 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()); @@ -851,14 +848,13 @@ void QQmlTypeData::resolveTypes() const bool reportErrors = unresolvedRef->errorWhenNotFound; - int majorVersion = -1; - int minorVersion = -1; + QTypeRevision version; const QString name = stringAt(unresolvedRef.key()); bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference; - if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, + if (!resolveType(name, version, ref, unresolvedRef->location.line, unresolvedRef->location.column, reportErrors, QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors) return; @@ -878,8 +874,7 @@ void QQmlTypeData::resolveTypes() } } } - ref.majorVersion = majorVersion; - ref.minorVersion = minorVersion; + ref.version = version; ref.location.line = unresolvedRef->location.line; ref.location.column = unresolvedRef->location.column; @@ -893,7 +888,7 @@ void QQmlTypeData::resolveTypes() loadImplicitImport(); } -QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( +QQmlError QQmlTypeData::buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const @@ -939,7 +934,8 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( ref->type = qmlType; if (qmlType.isValid()) { // this is required for inline components in singletons - auto typeID = qmlType.lookupInlineComponentById(qmlType.inlineComponendId()).typeId(); + auto type = qmlType.lookupInlineComponentById(qmlType.inlineComponendId()).typeId(); + auto typeID = type.isValid() ? type.id() : -1; auto exUnit = engine->obtainExecutableCompilationUnit(typeID); if (exUnit) { ref->compilationUnit = exUnit; @@ -962,21 +958,18 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches( return qQmlCompileError(resolvedType->location, reason); } - if (ref->type.containsRevisionedAttributes()) { - ref->typePropertyCache = engine->cache(ref->type, - resolvedType->minorVersion); - } + if (ref->type.containsRevisionedAttributes()) + ref->typePropertyCache = engine->cache(ref->type, resolvedType->version); } - ref->majorVersion = resolvedType->majorVersion; - ref->minorVersion = resolvedType->minorVersion; + ref->version = resolvedType->version; ref->doDynamicTypeCheck(); resolvedTypeCache->insert(resolvedType.key(), ref.take()); } - QQmlJS::DiagnosticMessage noError; + QQmlError noError; return noError; } -bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, +bool QQmlTypeData::resolveType(const QString &typeName, QTypeRevision &version, TypeReference &ref, int lineNumber, int columnNumber, bool reportErrors, QQmlType::RegistrationType registrationType, bool *typeRecursionDetected) @@ -984,7 +977,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int & QQmlImportNamespace *typeNamespace = nullptr; QList<QQmlError> errors; - bool typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, + bool typeFound = m_importCache.resolveType(typeName, &ref.type, &version, &typeNamespace, &errors, registrationType, typeRecursionDetected); if (!typeNamespace && !typeFound && !m_implicitImportLoaded) { @@ -992,7 +985,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int & if (loadImplicitImport()) { // Try again to find the type errors.clear(); - typeFound = m_importCache.resolveType(typeName, &ref.type, &majorVersion, &minorVersion, + typeFound = m_importCache.resolveType(typeName, &ref.type, &version, &typeNamespace, &errors, registrationType, typeRecursionDetected); } else { diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h index d894090b36..c3b0faa5b4 100644 --- a/src/qml/qml/qqmltypedata_p.h +++ b/src/qml/qml/qqmltypedata_p.h @@ -62,12 +62,11 @@ class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob public: struct TypeReference { - TypeReference() : majorVersion(0), minorVersion(0), needsCreation(true) {} + TypeReference() : version(QTypeRevision::zero()), needsCreation(true) {} QV4::CompiledData::Location location; QQmlType type; - int majorVersion; - int minorVersion; + QTypeRevision version; QQmlRefPointer<QQmlTypeData> typeData; bool selfReference = false; QString prefix; // used by CompositeSingleton types @@ -125,7 +124,7 @@ private: void restoreIR(QV4::CompiledData::CompilationUnit &&unit); void continueLoadFromIR(); void resolveTypes(); - QQmlJS::DiagnosticMessage buildTypeResolutionCaches( + QQmlError buildTypeResolutionCaches( QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const; @@ -134,7 +133,7 @@ private: const QV4::CompiledData::DependentTypesHasher &dependencyHasher); void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::ResolvedTypeReferenceMap &resolvedTypeCache); - bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, + bool resolveType(const QString &typeName, QTypeRevision &version, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true, QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index e9a38945fa..75dc9d15a5 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -45,6 +45,7 @@ #include <private/qqmltypedata_p.h> #include <private/qqmltypeloaderqmldircontent_p.h> #include <private/qqmltypeloaderthread_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <QtQml/qqmlabstracturlinterceptor.h> #include <QtQml/qqmlengine.h> @@ -357,8 +358,8 @@ void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) } } - if (reply->networkError()) { - blob->networkError(reply->networkError()); + if (reply->error()) { + blob->networkError(reply->error()); } else { QByteArray data = reply->readAll(); setData(blob, data); @@ -393,7 +394,7 @@ QQmlEngine *QQmlTypeLoader::engine() const return m_engine; } -/*! +/*! \internal Call the initializeEngine() method on \a iface. Used by QQmlImportDatabase to ensure it gets called in the correct thread. */ @@ -487,8 +488,7 @@ QQmlTypeLoader::Blob::PendingImport::PendingImport(QQmlTypeLoader::Blob *blob, c type = static_cast<QV4::CompiledData::Import::ImportType>(quint32(import->type)); uri = blob->stringAt(import->uriIndex); qualifier = blob->stringAt(import->qualifierIndex); - majorVersion = import->majorVersion; - minorVersion = import->minorVersion; + version = import->version; location = import->location; } @@ -578,12 +578,13 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo QString qmldirUrl; const QQmlImports::LocalQmldirResult qmldirResult = m_importCache.locateLocalQmldir( - importDatabase, import->uri, import->majorVersion, import->minorVersion, + importDatabase, import->uri, import->version, &qmldirFilePath, &qmldirUrl); if (qmldirResult == QQmlImports::QmldirFound) { // This is a local library import - if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion, - import->minorVersion, qmldirFilePath, qmldirUrl, false, errors)) + if (!m_importCache.addLibraryImport( + importDatabase, import->uri, import->qualifier, + import->version, qmldirFilePath, qmldirUrl, false, errors)) return false; if (!loadImportDependencies(import, qmldirFilePath, errors)) @@ -602,49 +603,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, - import->majorVersion))) { - if (!m_importCache.addLibraryImport(importDatabase, import->uri, import->qualifier, import->majorVersion, - import->minorVersion, QString(), QString(), false, errors)) + // 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; - } 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->majorVersion, - import->minorVersion, QString(), QString(), true, errors)) - return false; - // Probe for all possible locations - int priority = 0; - const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(import->uri, remotePathList, import->majorVersion, import->minorVersion); - 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; } + } } } @@ -663,8 +674,8 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo incomplete = true; } - if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, import->majorVersion, - import->minorVersion, incomplete, errors)) + if (!m_importCache.addFileImport(importDatabase, import->uri, import->qualifier, + import->version, incomplete, errors)) return false; if (incomplete) { @@ -688,8 +699,8 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob) Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); error.setUrl(m_importCache.baseUrl()); - error.setLine(import->location.line); - error.setColumn(import->location.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column)); errors.prepend(error); // put it back on the list after filling out information. setError(errors); } @@ -703,8 +714,7 @@ bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport auto dependencyImport = std::make_shared<PendingImport>(); dependencyImport->uri = implicitImports; dependencyImport->qualifier = currentImport->qualifier; - dependencyImport->majorVersion = currentImport->majorVersion; - dependencyImport->minorVersion = currentImport->minorVersion; + dependencyImport->version = currentImport->version; if (!addImport(dependencyImport, errors)) return false; } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index adecf61896..a1ba2967e3 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -97,8 +97,7 @@ public: QString uri; QString qualifier; - int majorVersion = -1; - int minorVersion = -1; + QTypeRevision version; QV4::CompiledData::Location location; diff --git a/src/qml/qml/qqmltypeloaderqmldircontent.cpp b/src/qml/qml/qqmltypeloaderqmldircontent.cpp index 860971d296..714ea79e67 100644 --- a/src/qml/qml/qqmltypeloaderqmldircontent.cpp +++ b/src/qml/qml/qqmltypeloaderqmldircontent.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include <private/qqmltypeloaderqmldircontent_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <QtQml/qqmlerror.h> QT_BEGIN_NAMESPACE @@ -59,8 +60,8 @@ QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const for (const auto &parseError : parseErrors) { QQmlError error; error.setUrl(url); - error.setLine(parseError.line); - error.setColumn(parseError.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startLine)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(parseError.loc.startColumn)); error.setDescription(parseError.message); errors.append(error); } @@ -83,8 +84,8 @@ void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QStr void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error) { QQmlJS::DiagnosticMessage parseError; - parseError.line = error.line(); - parseError.column = error.column(); + parseError.loc.startLine = error.line(); + parseError.loc.startColumn = error.column(); parseError.message = error.description(); m_parser.setError(parseError); } diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp index 9d6f269030..e6bf796d74 100644 --- a/src/qml/qml/qqmltypemodule.cpp +++ b/src/qml/qml/qqmltypemodule.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE -QQmlTypeModule::QQmlTypeModule(const QString &module, int majorVersion) +QQmlTypeModule::QQmlTypeModule(const QString &module, quint8 majorVersion) : d(new QQmlTypeModulePrivate(module, majorVersion)) { } @@ -61,23 +61,23 @@ QString QQmlTypeModule::module() const return d->module; } -int QQmlTypeModule::majorVersion() const +quint8 QQmlTypeModule::majorVersion() const { // No need to lock. d->majorVersion is const return d->majorVersion; } -int QQmlTypeModule::minimumMinorVersion() const +quint8 QQmlTypeModule::minimumMinorVersion() const { return d->minMinorVersion.loadRelaxed(); } -int QQmlTypeModule::maximumMinorVersion() const +quint8 QQmlTypeModule::maximumMinorVersion() const { return d->maxMinorVersion.loadRelaxed(); } -void QQmlTypeModule::addMinorVersion(int version) +void QQmlTypeModule::addMinorVersion(quint8 version) { for (int oldVersion = d->minMinorVersion.loadRelaxed(); oldVersion > version && !d->minMinorVersion.testAndSetOrdered(oldVersion, version); @@ -93,16 +93,16 @@ void QQmlTypeModule::addMinorVersion(int version) void QQmlTypeModule::add(QQmlTypePrivate *type) { QMutexLocker lock(&d->mutex); - addMinorVersion(type->version_min); + addMinorVersion(type->version.minorVersion()); QList<QQmlTypePrivate *> &list = d->typeHash[type->elementName]; for (int ii = 0; ii < list.count(); ++ii) { QQmlTypePrivate *in_list = list.at(ii); Q_ASSERT(in_list); - if (in_list->version_min < type->version_min) { + if (in_list->version.minorVersion() < type->version.minorVersion()) { list.insert(ii, type); return; - } else if (in_list->version_min == type->version_min) { + } else if (in_list->version.minorVersion() == type->version.minorVersion()) { list[ii] = type; return; } @@ -137,26 +137,26 @@ void QQmlTypeModule::lock() d->locked.storeRelaxed(1); } -QQmlType QQmlTypeModule::type(const QHashedStringRef &name, int minor) const +QQmlType QQmlTypeModule::type(const QHashedStringRef &name, QTypeRevision version) const { QMutexLocker lock(&d->mutex); QList<QQmlTypePrivate *> *types = d->typeHash.value(name); if (types) { for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->version_min <= minor) + if (types->at(ii)->version.minorVersion() <= version.minorVersion()) return QQmlType(types->at(ii)); } return QQmlType(); } -QQmlType QQmlTypeModule::type(const QV4::String *name, int minor) const +QQmlType QQmlTypeModule::type(const QV4::String *name, QTypeRevision version) const { QMutexLocker lock(&d->mutex); QList<QQmlTypePrivate *> *types = d->typeHash.value(name); if (types) { for (int ii = 0; ii < types->count(); ++ii) - if (types->at(ii)->version_min <= minor) + if (types->at(ii)->version.minorVersion() <= version.minorVersion()) return QQmlType(types->at(ii)); } diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h index b84a91b5db..d3149567a3 100644 --- a/src/qml/qml/qqmltypemodule_p.h +++ b/src/qml/qml/qqmltypemodule_p.h @@ -53,6 +53,7 @@ #include <QtQml/qtqmlglobal.h> #include <QtCore/qstring.h> +#include <QtCore/qversionnumber.h> #include <functional> @@ -72,7 +73,7 @@ class QQmlTypeModulePrivate; class QQmlTypeModule { public: - QQmlTypeModule(const QString &uri = QString(), int majorVersion = 0); + QQmlTypeModule(const QString &uri = QString(), quint8 majorVersion = 0); ~QQmlTypeModule(); void add(QQmlTypePrivate *); @@ -82,14 +83,14 @@ public: void lock(); QString module() const; - int majorVersion() const; + quint8 majorVersion() const; - void addMinorVersion(int minorVersion); - int minimumMinorVersion() const; - int maximumMinorVersion() const; + void addMinorVersion(quint8 minorVersion); + quint8 minimumMinorVersion() const; + quint8 maximumMinorVersion() const; - QQmlType type(const QHashedStringRef &, int) const; - QQmlType type(const QV4::String *, int) const; + QQmlType type(const QHashedStringRef &, QTypeRevision version) const; + QQmlType type(const QV4::String *, QTypeRevision version) const; void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const; diff --git a/src/qml/qml/qqmltypemodule_p_p.h b/src/qml/qml/qqmltypemodule_p_p.h index b1dab1c4a0..5d4d2e458a 100644 --- a/src/qml/qml/qqmltypemodule_p_p.h +++ b/src/qml/qml/qqmltypemodule_p_p.h @@ -62,15 +62,15 @@ QT_BEGIN_NAMESPACE class QQmlTypeModulePrivate { public: - QQmlTypeModulePrivate(QString module, int majorVersion) : + QQmlTypeModulePrivate(QString module, quint8 majorVersion) : module(std::move(module)), majorVersion(majorVersion) {} const QString module; - const int majorVersion = 0; + const quint8 majorVersion = 0; // Can only ever decrease - QAtomicInt minMinorVersion = std::numeric_limits<int>::max(); + QAtomicInt minMinorVersion = std::numeric_limits<quint8>::max(); // Can only ever increase QAtomicInt maxMinorVersion = 0; diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp index bbbfa1a7b6..207b77770a 100644 --- a/src/qml/qml/qqmltypemoduleversion.cpp +++ b/src/qml/qml/qqmltypemoduleversion.cpp @@ -49,11 +49,11 @@ QQmlTypeModuleVersion::QQmlTypeModuleVersion() { } -QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, int minor) - : m_module(module), m_minor(minor) +QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, QTypeRevision version) + : m_module(module), m_minor(version.minorVersion()) { Q_ASSERT(m_module); - Q_ASSERT(m_minor >= 0); + Q_ASSERT(QTypeRevision::isValidSegment(m_minor)); } QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o) @@ -68,28 +68,18 @@ QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVers return *this; } -QQmlTypeModule *QQmlTypeModuleVersion::module() const -{ - return m_module; -} - -int QQmlTypeModuleVersion::minorVersion() const -{ - return m_minor; -} - QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const { if (!m_module) return QQmlType(); - return m_module->type(name, m_minor); + return m_module->type(name, QTypeRevision::fromMinorVersion(m_minor)); } QQmlType QQmlTypeModuleVersion::type(const QV4::String *name) const { if (!m_module) return QQmlType(); - return m_module->type(name, m_minor); + return m_module->type(name, QTypeRevision::fromMinorVersion(m_minor)); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h index 20f4709ecb..b7e94ef27b 100644 --- a/src/qml/qml/qqmltypemoduleversion_p.h +++ b/src/qml/qml/qqmltypemoduleversion_p.h @@ -52,6 +52,7 @@ // #include <QtQml/qtqmlglobal.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE @@ -67,19 +68,16 @@ class QQmlTypeModuleVersion { public: QQmlTypeModuleVersion(); - QQmlTypeModuleVersion(QQmlTypeModule *, int); + QQmlTypeModuleVersion(QQmlTypeModule *, QTypeRevision); QQmlTypeModuleVersion(const QQmlTypeModuleVersion &); QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &); - QQmlTypeModule *module() const; - int minorVersion() const; - QQmlType type(const QHashedStringRef &) const; QQmlType type(const QV4::String *) const; private: QQmlTypeModule *m_module; - int m_minor; + quint8 m_minor; }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index 1015403226..45333668e3 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -101,7 +101,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) QQmlImportNamespace *typeNamespace = nullptr; QList<QQmlError> errors; QQmlType t; - bool typeFound = m_imports.resolveType(name, &t, nullptr, nullptr, &typeNamespace, &errors); + bool typeFound = m_imports.resolveType(name, &t, nullptr, &typeNamespace, &errors); if (typeFound) { return Result(t); } @@ -129,7 +129,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, QQmlImportNamespace *typeNamespace = nullptr; QList<QQmlError> errors; QQmlType t; - bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, nullptr, &typeNamespace, &errors); + bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors); if (typeFound) { return Result(t); } @@ -155,7 +155,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQml QList<QQmlError> errors; QQmlType t; bool typeRecursionDetected = false; - bool typeFound = m_imports.resolveType(typeName, &t, nullptr, nullptr, &typeNamespace, &errors, + bool typeFound = m_imports.resolveType(typeName, &t, nullptr, &typeNamespace, &errors, QQmlType::AnyRegistrationType, recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr); if (typeFound) { @@ -191,7 +191,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons QQmlImportNamespace *typeNamespace = nullptr; QList<QQmlError> errors; QQmlType t; - bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, nullptr, &typeNamespace, &errors); + bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors); if (typeFound) { return Result(t); } 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..dbd37ace2a 100644 --- a/src/qml/qml/qqmltypenotavailable_p.h +++ b/src/qml/qml/qqmltypenotavailable_p.h @@ -55,14 +55,11 @@ QT_BEGIN_NAMESPACE - class QQmlTypeNotAvailable : public QObject { Q_OBJECT QML_NAMED_ELEMENT(TypeNotAvailable) + QML_ADDED_IN_VERSION(2, 15) QML_UNCREATABLE("Type not available.") - -public: - QQmlTypeNotAvailable(); }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index fa5d36503d..7bcc5e9900 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -407,9 +407,9 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const if (!wrapperObject) return engine->throwTypeError(); - const int myTypeId = typeWrapper->d()->type().typeId(); + const QMetaType myTypeId = typeWrapper->d()->type().typeId(); QQmlMetaObject myQmlType; - if (myTypeId == 0) { + if (!myTypeId.isValid()) { // we're a composite type; a composite type cannot be equal to a // non-composite object instance (Rectangle{} is never an instance of // CustomRectangle) @@ -420,9 +420,9 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); ExecutableCompilationUnit *cu = td->compilationUnit(); - myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); + myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId.id()); } else { - myQmlType = qenginepriv->metaObjectForType(myTypeId); + myQmlType = qenginepriv->metaObjectForType(myTypeId.id()); } const QMetaObject *theirType = wrapperObject->metaObject(); 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 ff664adbe7..0b38c746d6 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 @@ -219,6 +246,7 @@ struct QQmlEasingValueType QEasingCurve v; Q_GADGET QML_NAMED_ELEMENT(Easing) + QML_ADDED_IN_VERSION(2, 0) QML_UNCREATABLE("Use the Type enum.") Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL) @@ -282,18 +310,14 @@ public: template<typename T> int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { - QByteArray name(T::staticMetaObject.className()); - - QByteArray pointerName(name + '*'); - QQmlPrivate::RegisterType type = { 0, - qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0, 0, nullptr, + QMetaType::fromType<T*>(), QMetaType(), 0, nullptr, QString(), - uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName, &T::staticMetaObject, nullptr, nullptr, @@ -302,7 +326,7 @@ int qmlRegisterValueTypeEnums(const char *uri, int versionMajor, int versionMino nullptr, nullptr, nullptr, - 0 + QTypeRevision::zero() }; return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index ecb86e2f10..aa9f4bc1bd 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -48,6 +48,7 @@ #include "qqmlcontext_p.h" #include "qqmlbinding_p.h" #include "qqmlpropertyvalueinterceptor_p.h" +#include <qqmlinfo.h> #include <private/qqmlglobal_p.h> @@ -60,6 +61,8 @@ #include <private/qqmlpropertycachecreator_p.h> #include <private/qqmlpropertycachemethodarguments_p.h> +#include <climits> // for CHAR_BIT + QT_BEGIN_NAMESPACE class ResolvedList @@ -67,13 +70,22 @@ class ResolvedList Q_DISABLE_COPY_MOVE(ResolvedList) public: - ResolvedList(QQmlListProperty<QObject> *prop) : - m_metaObject(static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject)), - m_id(quintptr(prop->data)) + ResolvedList(QQmlListProperty<QObject> *prop) { + // see QQmlVMEMetaObject::metaCall for how this was constructed + auto encodedIndex = quintptr(prop->data); + constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT; + quintptr inheritanceDepth = encodedIndex >> (usableBits / 2); + m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1); + + // walk up to the correct meta object if necessary + auto mo = prop->object->metaObject(); + while (inheritanceDepth--) + mo = mo->superClass(); + m_metaObject = static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(mo)); Q_ASSERT(m_metaObject); + Q_ASSERT( ::strstr(m_metaObject->property(m_metaObject->propOffset() + m_id).typeName(), "QQmlListProperty") ); Q_ASSERT(m_metaObject->object == prop->object); - Q_ASSERT(m_id <= quintptr(std::numeric_limits<int>::max() - m_metaObject->methodOffset())); // readPropertyAsList() with checks transformed into Q_ASSERT // and without allocation. @@ -136,6 +148,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 +315,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 +355,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); @@ -731,11 +759,37 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * break; case QV4::CompiledData::BuiltinType::InvalidBuiltin: if (property.isList) { + // when reading from the list, we need to find the correct MetaObject, + // namely this. However, obejct->metaObject might point to any MetaObject + // down the inheritance hierarchy, so we need to store how far we have + // to go down + // To do this, we encode the hierarchy depth together with the id of the + // property in a single quintptr, with the first half storing the depth + // and the second half storing the property id + auto mo = object->metaObject(); + quintptr inheritanceDepth = 0u; + while (mo && mo != this) { + mo = mo->superClass(); + ++inheritanceDepth; + } + constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT; + if (Q_UNLIKELY(inheritanceDepth >= (quintptr(1) << quintptr(usableBits / 2u) ) )) { + qmlWarning(object) << "Too many objects in inheritance hierarchy for list property"; + return -1; + } + if (Q_UNLIKELY(quintptr(id) >= (quintptr(1) << quintptr(usableBits / 2) ) )) { + qmlWarning(object) << "Too many properties in object for list property"; + return -1; + } + quintptr encodedIndex = (inheritanceDepth << (usableBits/2)) + id; + + readPropertyAsList(id); // Initializes if necessary *static_cast<QQmlListProperty<QObject> *>(a[0]) = QQmlListProperty<QObject>( - object, reinterpret_cast<void *>(quintptr(id)), - list_append, list_count, list_at, list_clear); + object, reinterpret_cast<void *>(quintptr(encodedIndex)), + list_append, list_count, list_at, + list_clear, list_replace, list_removeLast); } else { *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); } @@ -879,9 +933,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); @@ -1184,7 +1238,7 @@ void QQmlVMEMetaObject::ensureQObjectWrapper() void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack) { - if (engine != markStack->engine) + if (engine != markStack->engine()) return; propertyAndMethodStorage.markOnce(markStack); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index c820499703..61070113cc 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1203,25 +1203,15 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) if (m_method == QLatin1String("PUT")) { if (!xhrFileWrite()) { - if (qEnvironmentVariableIsSet("QML_XHR_ALLOW_FILE_WRITE")) { - qWarning("XMLHttpRequest: Tried to use PUT on a local file despite being disabled."); - return; - } else { - qWarning("XMLHttpRequest: Using PUT on a local file is dangerous " - "and will be disabled by default in a future Qt version." - "Set QML_XHR_ALLOW_FILE_WRITE to 1 if you wish to continue using this feature."); - } + qWarning("XMLHttpRequest: Using PUT on a local file is disabled by default.\n" + "Set QML_XHR_ALLOW_FILE_WRITE to 1 to enable this feature."); + return; } } else if (m_method == QLatin1String("GET")) { if (!xhrFileRead()) { - if (qEnvironmentVariableIsSet("QML_XHR_ALLOW_FILE_READ")) { - qWarning("XMLHttpRequest: Tried to use GET on a local file despite being disabled."); - return; - } else { - qWarning("XMLHttpRequest: Using GET on a local file is dangerous " - "and will be disabled by default in a future Qt version." - "Set QML_XHR_ALLOW_FILE_READ to 1 if you wish to continue using this feature."); - } + qWarning("XMLHttpRequest: Using GET on a local file is disabled by default.\n" + "Set QML_XHR_ALLOW_FILE_READ to 1 to enable this feature."); + return; } } else { qWarning("XMLHttpRequest: Unsupported method used on a local file"); @@ -1291,7 +1281,7 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) if (m_network->bytesAvailable() > 0) readyRead(); - QNetworkReply::NetworkError networkError = m_network->networkError(); + QNetworkReply::NetworkError networkError = m_network->error(); if (networkError != QNetworkReply::NoError) { error(networkError); } else { diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 02032142ee..4e5ab9b899 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -722,70 +722,114 @@ ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, cons return scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2)); } +namespace { +template <typename T> +QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) { + switch (format) { + case Qt::TextDate: + case Qt::ISODate: + case Qt::RFC2822Date: + case Qt::ISODateWithMs: + return formatThis.toString(format); + default: // ### Qt 6: remove once qtbase has removed the rest of the enum ! + break; + } + // Q_UNREACHABLE(); // ### Qt 6: restore once the default is gone + return QString(); +} + +template <typename T> +ReturnedValue formatDateTimeObject(const T &formatThis, const QV4::Scope &scope, const QString &functionName, int argc, const Value *argv) { + + QString formatted; + if (argc >= 2) { + QV4::ScopedString s(scope, argv[1]); + if (s) { + if (argc == 3) + scope.engine->throwError(QLatin1String("%1(): Stay argument, third argument can only be used if second argument is a locale").arg(functionName)); + QString format = s->toQString(); + formatted = formatThis.toString(format); + } else if (argv[1].isNumber()) { + if (argc == 3) + scope.engine->throwError(QLatin1String("%1(): Stay argument, third argument can only be used if second argument is a locale").arg(functionName)); + quint32 intFormat = argv[1].asDouble(); + Qt::DateFormat format = Qt::DateFormat(intFormat); + formatted = formatDateTimeObjectUsingDateFormat(formatThis, format); + } else { + QLocale::FormatType formatOptions = QLocale::ShortFormat; + if (argc == 3) { + if (argv[2].isNumber()) + formatOptions = QLocale::FormatType(quint32(argv[2].asDouble())); + else + scope.engine->throwError(QLatin1String("%1(): Third argument must be a Locale format option").arg(functionName)); + } + auto enginePriv = QQmlEnginePrivate::get(scope.engine->qmlEngine()); + auto localeMetaTypeId = qMetaTypeId<QLocale>(); + QVariant locale = enginePriv->v4engine()->toVariant(argv[1], localeMetaTypeId); + if (!locale.canConvert(localeMetaTypeId)) + scope.engine->throwError(QLatin1String("%1(): Bad second argument (must be either string, number or locale)").arg(functionName)); + formatted = locale.value<QLocale>().toString(formatThis, formatOptions); + } + } else { + formatted = QLocale().toString(formatThis, QLocale::ShortFormat); + } + + return Encode(scope.engine->newString(formatted)); +} + +} + /*! -\qmlmethod string Qt::formatDate(datetime date, variant format) +\qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption) -Returns a string representation of \a date, optionally formatted according -to \a format. +Returns a string representation of \a date, optionally formatted using \a format. The \a date parameter may be a JavaScript \c Date object, a \l{date}{date} -property, a QDate, or QDateTime value. The \a format parameter may be any of -the possible format values as described for +property, a QDate, or QDateTime value. The \a format and \a localeFormatOption +parameter may be any of the possible format values as described for \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}. If \a format is not specified, \a date is formatted using -\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. +\l {QLocale::FormatType}{Locale.ShortFormat} using the +default locale. \sa Locale */ ReturnedValue QtObject::method_formatDate(const FunctionObject *b, const Value *, const Value *argv, int argc) { QV4::Scope scope(b); - if (argc < 1 || argc > 2) - THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments"); + if (argc < 1) + THROW_GENERIC_ERROR("Qt.formatDate(): Missing argument"); + if (argc > 3) + THROW_GENERIC_ERROR("Qt.formatDate(): Stray arguments; formatDate takes at most 3 arguments."); - Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; QDate date = scope.engine->toVariant(argv[0], -1).toDateTime().date(); - QString formattedDate; - if (argc == 2) { - QV4::ScopedString s(scope, argv[1]); - if (s) { - QString format = s->toQString(); - formattedDate = date.toString(format); - } else if (argv[1].isNumber()) { - quint32 intFormat = argv[1].asDouble(); - Qt::DateFormat format = Qt::DateFormat(intFormat); - formattedDate = date.toString(format); - } else { - THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format"); - } - } else { - formattedDate = date.toString(enumFormat); - } - - return Encode(scope.engine->newString(formattedDate)); + return formatDateTimeObject(date, scope, QLatin1String("Qt.formatDate"), argc, argv); } /*! -\qmlmethod string Qt::formatTime(datetime time, variant format) +\qmlmethod string Qt::formatTime(datetime time, variant format, variant localeFormatOption) -Returns a string representation of \a time, optionally formatted according to -\a format. +Returns a string representation of \a time, optionally formatted using +\a format, and, if provided, \a localeFormatOption. The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime -value. The \a format parameter may be any of the possible format values as -described for \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}. +value. The \a format and \a localeFormatOption parameter may be any of the +possible format values as described for +\l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}. If \a format is not specified, \a time is formatted using -\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. +\l {QLocale::FormatType}{Locale.ShortFormat} using the default locale. \sa Locale */ ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value *, const Value *argv, int argc) { QV4::Scope scope(b); - if (argc < 1 || argc > 2) - THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments"); + if (argc < 1) + THROW_GENERIC_ERROR("Qt.formatTime(): Missing argument"); + if (argc > 3) + THROW_GENERIC_ERROR("Qt.formatTime(): Stray arguments; formatTime takes at most 3 arguments."); QVariant argVariant = scope.engine->toVariant(argv[0], -1); QTime time; @@ -793,47 +837,34 @@ ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value * time = argVariant.toDateTime().time(); else // if (argVariant.type() == QVariant::Time), or invalid. time = argVariant.toTime(); - - Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; - QString formattedTime; - if (argc == 2) { - QV4::ScopedString s(scope, argv[1]); - if (s) { - QString format = s->toQString(); - formattedTime = time.toString(format); - } else if (argv[1].isNumber()) { - quint32 intFormat = argv[1].asDouble(); - Qt::DateFormat format = Qt::DateFormat(intFormat); - formattedTime = time.toString(format); - } else { - THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format"); - } - } else { - formattedTime = time.toString(enumFormat); - } - - return Encode(scope.engine->newString(formattedTime)); + return formatDateTimeObject(time, scope, QLatin1String("Qt.formatTime"), argc, argv); } /*! -\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format) +\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format, variant localeFormatOption) -Returns a string representation of \a dateTime, optionally formatted according to -\a format. +Returns a string representation of \a dateTime, optionally formatted using +\a format and \a localeFormatOption. The \a dateTime parameter may be a JavaScript \c Date object, a \l{date}{date} property, a QDate, QTime, or QDateTime value. If \a format is not provided, \a dateTime is formatted using -\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise, -\a format should be either: +\l {QLocale::FormatType}{Locale.ShortFormat} using the +default locale. Otherwise, \a format should be either: \list \li One of the Qt::DateFormat enumeration values, such as - \c Qt.DefaultLocaleShortDate or \c Qt.ISODate + \c Qt.RFC2822Date or \c Qt.ISODate. \li A string that specifies the format of the returned string, as detailed below. +\li A \c locale object. \endlist +If \a format specifies a locale object, \dateTime is formatted +with \l{QLocale::toString}. In this case, \a localeFormatOption can hold a value +of type \l {QLocale::FormatType} to further tune the formatting. If none is +provided, \l {QLocale::FormatType}{Locale.ShortFormat} is used. + If \a format specifies a format string, it should use the following expressions to specify the date: @@ -910,29 +941,13 @@ with the \a format values below to produce the following results: ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Value *, const Value *argv, int argc) { QV4::Scope scope(b); - if (argc < 1 || argc > 2) - THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments"); + if (argc < 1) + THROW_GENERIC_ERROR("Qt.formatDateTime(): Missing argument"); + if (argc > 3) + THROW_GENERIC_ERROR("Qt.formatDateTime(): Stray arguments; formatDate takes at most 3 arguments."); - Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; QDateTime dt = scope.engine->toVariant(argv[0], -1).toDateTime(); - QString formattedDt; - if (argc == 2) { - QV4::ScopedString s(scope, argv[1]); - if (s) { - QString format = s->toQString(); - formattedDt = dt.toString(format); - } else if (argv[1].isNumber()) { - quint32 intFormat = argv[1].asDouble(); - Qt::DateFormat format = Qt::DateFormat(intFormat); - formattedDt = dt.toString(format); - } else { - THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format"); - } - } else { - formattedDt = dt.toString(enumFormat); - } - - return Encode(scope.engine->newString(formattedDt)); + return formatDateTimeObject(dt, scope, QLatin1String("Qt.formatDateTime"), argc, argv); } /*! |