diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-01-27 17:31:06 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-03-17 14:44:17 +0100 |
commit | 1eb20d70619cc896fc283bd6605b257a8750c518 (patch) | |
tree | 1d308932d38759a643d8eef49b211329a2cd5467 /src | |
parent | e3c64aff6579f04353608d4b218f031d9137d3f4 (diff) |
Allow partial and absent version specifiers in import statements
An import statement without version specifier imports the latest version
available, one with only a major version imports the latest minor
version from that major version.
Task-number: QTBUG-71278
Change-Id: I43907ae4e1052be533039d545de5391c41d38307
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 6 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 2 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 5 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlimport.cpp | 46 | ||||
-rw-r--r-- | src/qml/qml/qqmlmetatype.cpp | 16 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 20 | ||||
-rw-r--r-- | src/qml/qml/qqmltype.cpp | 18 | ||||
-rw-r--r-- | src/qml/qml/qqmltypemoduleversion.cpp | 18 | ||||
-rw-r--r-- | src/qml/qml/qqmltypemoduleversion_p.h | 13 |
10 files changed, 85 insertions, 63 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 5217e11115..0316e54c09 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -749,12 +749,8 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node) if (node->version) { import->version = node->version->version; - } else if (import->type == QV4::CompiledData::Import::ImportLibrary) { - recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Library import requires a version")); - return false; } else { - // For backward compatibility in how the imports are loaded we - // must otherwise initialize the major and minor version to invalid. + // Otherwise initialize the major and minor version to invalid to signal "latest". import->version = QTypeRevision(); } diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index ef814a57b0..67f9cc7581 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -861,7 +861,7 @@ UiVersionSpecifier: T_VERSION_NUMBER; QLatin1String("Invalid major version. Version numbers must be >= 0 and < 255."))); return false; } - auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval, 0); + auto version = new (pool) AST::UiVersionSpecifier(sym(1).dval); version->majorToken = loc(1); sym(1).UiVersionSpecifier = version; } break; diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index de554a53af..8c1d8a2510 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -647,6 +647,11 @@ class QML_PARSER_EXPORT UiVersionSpecifier : public Node public: QQMLJS_DECLARE_AST_NODE(UiVersionSpecifier) + UiVersionSpecifier(int majorum) : version(QTypeRevision::fromMajorVersion(majorum)) + { + kind = K; + } + UiVersionSpecifier(int majorum, int minorum) : version(QTypeRevision::fromVersion(majorum, minorum)) { kind = K; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 424335b61a..7b9b293832 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -402,9 +402,7 @@ The returned cache is not referenced, so if it is to be stored, call addref(). QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, QTypeRevision version) { Q_ASSERT(type.isValid()); - - if (!version.hasMinorVersion() || !type.containsRevisionedAttributes()) - return cache(type.metaObject(), version); + Q_ASSERT(type.containsRevisionedAttributes()); Locker locker(this); return QQmlMetaType::propertyCache(type, version); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 47f7b40938..7f8728f364 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -548,6 +548,19 @@ QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringLi qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1)); for (int versionMode = FullyVersioned; versionMode <= Unversioned; ++versionMode) { + switch (versionMode) { + case FullyVersioned: + if (!version.hasMinorVersion()) + continue; + break; + case PartiallyVersioned: + if (!version.hasMajorVersion()) + continue; + break; + default: + break; + } + const QString ver = versionString(version, QQmlImports::ImportVersion(versionMode)); for (const QString &path : basePaths) { @@ -711,15 +724,13 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt QQmlImport::RecursionRestriction recursionRestriction, QList<QQmlError> *errors) const { - if (version.hasMajorVersion() && version.hasMinorVersion()) { - QQmlType t = QQmlMetaType::qmlType(type, uri, version); - if (t.isValid()) { - if (version_return) - *version_return = version; - if (type_return) - *type_return = t; - return true; - } + QQmlType t = QQmlMetaType::qmlType(type, uri, version); + if (t.isValid()) { + if (version_return) + *version_return = version; + if (type_return) + *type_return = t; + return true; } const QString typeStr = type.toString(); @@ -1350,9 +1361,6 @@ QQmlImports::LocalQmldirResult QQmlImportsPrivate::locateLocalQmldir( const QString &uri, QTypeRevision version, QQmlImportDatabase *database, QString *outQmldirFilePath, QString *outQmldirPathUrl) { - // Versions are always specified for libraries - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); - // Check cache first QQmlImportDatabase::QmldirCache *cacheHead = nullptr; @@ -1565,15 +1573,19 @@ bool QQmlImportsPrivate::addLibraryImport( } // Ensure that we are actually providing something - if (!version.hasMajorVersion() || !version.hasMinorVersion() - || !QQmlMetaType::isModule(uri, version)) { + if (!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(version.majorVersion()).arg(version.minorVersion())); + error.setDescription(QQmlImportDatabase::tr( + "module \"%1\" version %2.%3 is not installed") + .arg(uri).arg(version.majorVersion()) + .arg(version.hasMinorVersion() + ? QString::number(version.minorVersion()) + : QLatin1String("x"))); } else { - error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri)); + error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed") + .arg(uri)); } errors->prepend(error); return false; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index c692986e74..a90c85cac7 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -889,14 +889,18 @@ bool QQmlMetaType::isLockedModule(const QString &uri, QTypeRevision version) */ bool QQmlMetaType::isModule(const QString &module, QTypeRevision version) { - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); + if (!version.hasMajorVersion()) + return isAnyModule(module); + QQmlMetaTypeDataPtr data; // first, check Types - QQmlTypeModule *tm = - data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, version)); - if (tm && tm->minimumMinorVersion() <= version.minorVersion() && tm->maximumMinorVersion() >= version.minorVersion()) - return true; + if (QQmlTypeModule *tm + = data->uriToModule.value(QQmlMetaTypeData::VersionedUri(module, version))) { + return !version.hasMinorVersion() + || (tm->minimumMinorVersion() <= version.minorVersion() + && tm->maximumMinorVersion() >= version.minorVersion()); + } return false; } @@ -1141,7 +1145,6 @@ QQmlType QQmlMetaType::qmlType(const QString &qualifiedName, QTypeRevision versi QQmlType QQmlMetaType::qmlType(const QHashedStringRef &name, const QHashedStringRef &module, QTypeRevision version) { - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::Names::ConstIterator it = data->nameToType.constFind(name); @@ -1173,7 +1176,6 @@ QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject) QQmlType QQmlMetaType::qmlType(const QMetaObject *metaObject, const QHashedStringRef &module, QTypeRevision version) { - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); const QQmlMetaTypeDataPtr data; QQmlMetaTypeData::MetaObjects::const_iterator it = data->metaObjectToType.constFind(metaObject); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 9e6eaf9778..6038056991 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -354,9 +354,23 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const { - return (data->metaObjectOffset() == -1 && data->revision() == QTypeRevision::zero()) - || (allowedRevisionCache[data->metaObjectOffset()].toEncodedVersion<quint16>() - >= data->revision().toEncodedVersion<quint16>()); + const QTypeRevision requested = data->revision(); + const int offset = data->metaObjectOffset(); + if (offset == -1 && requested == QTypeRevision::zero()) + return true; + + Q_ASSERT(offset >= 0); + Q_ASSERT(offset < allowedRevisionCache.length()); + const QTypeRevision allowed = allowedRevisionCache[data->metaObjectOffset()]; + + if (requested.hasMajorVersion()) { + if (requested.majorVersion() > allowed.majorVersion()) + return false; + if (requested.majorVersion() < allowed.majorVersion()) + return true; + } + + return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion(); } int QQmlPropertyCache::propertyCount() const diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index db22c93733..5eb77b617d 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -141,20 +141,24 @@ QTypeRevision QQmlType::version() const bool QQmlType::availableInVersion(QTypeRevision version) const { - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); if (!d) return false; - return version.majorVersion() == d->version.majorVersion() - && version.minorVersion() >= d->version.minorVersion(); + + if (!version.hasMajorVersion()) + return true; + + if (version.majorVersion() != d->version.majorVersion()) + return false; + + return !version.hasMinorVersion() || version.minorVersion() >= d->version.minorVersion(); } bool QQmlType::availableInVersion(const QHashedStringRef &module, QTypeRevision version) const { - Q_ASSERT(version.hasMajorVersion() && version.hasMinorVersion()); - if (!d) + if (!d || module != d->module) return false; - return module == d->module && version.majorVersion() == d->version.majorVersion() - && version.minorVersion() >= d->version.minorVersion(); + + return availableInVersion(version); } QQmlType QQmlTypePrivate::resolveCompositeBaseType(QQmlEnginePrivate *engine) const diff --git a/src/qml/qml/qqmltypemoduleversion.cpp b/src/qml/qml/qqmltypemoduleversion.cpp index 207b77770a..932ff7f503 100644 --- a/src/qml/qml/qqmltypemoduleversion.cpp +++ b/src/qml/qml/qqmltypemoduleversion.cpp @@ -39,9 +39,6 @@ #include "qqmltypemoduleversion_p.h" -#include <private/qqmltype_p.h> -#include <private/qqmltypemodule_p.h> - QT_BEGIN_NAMESPACE QQmlTypeModuleVersion::QQmlTypeModuleVersion() @@ -53,7 +50,6 @@ QQmlTypeModuleVersion::QQmlTypeModuleVersion(QQmlTypeModule *module, QTypeRevisi : m_module(module), m_minor(version.minorVersion()) { Q_ASSERT(m_module); - Q_ASSERT(QTypeRevision::isValidSegment(m_minor)); } QQmlTypeModuleVersion::QQmlTypeModuleVersion(const QQmlTypeModuleVersion &o) @@ -68,18 +64,4 @@ QQmlTypeModuleVersion &QQmlTypeModuleVersion::operator=(const QQmlTypeModuleVers return *this; } -QQmlType QQmlTypeModuleVersion::type(const QHashedStringRef &name) const -{ - if (!m_module) - return QQmlType(); - 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, QTypeRevision::fromMinorVersion(m_minor)); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypemoduleversion_p.h b/src/qml/qml/qqmltypemoduleversion_p.h index b7e94ef27b..c5379b2158 100644 --- a/src/qml/qml/qqmltypemoduleversion_p.h +++ b/src/qml/qml/qqmltypemoduleversion_p.h @@ -52,6 +52,8 @@ // #include <QtQml/qtqmlglobal.h> +#include <QtQml/private/qqmltype_p.h> +#include <QtQml/private/qqmltypemodule_p.h> #include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE @@ -72,8 +74,15 @@ public: QQmlTypeModuleVersion(const QQmlTypeModuleVersion &); QQmlTypeModuleVersion &operator=(const QQmlTypeModuleVersion &); - QQmlType type(const QHashedStringRef &) const; - QQmlType type(const QV4::String *) const; + template<typename String> + QQmlType type(String name) const + { + if (!m_module) + return QQmlType(); + return m_module->type(name, QTypeRevision::isValidSegment(m_minor) + ? QTypeRevision::fromMinorVersion(m_minor) + : QTypeRevision()); + } private: QQmlTypeModule *m_module; |