diff options
-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 | ||||
-rw-r--r-- | tests/auto/qml/qqmlimport/tst_qqmlimport.cpp | 80 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt | 2 |
13 files changed, 153 insertions, 78 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; diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 6e95ddfdea..e332d86338 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -48,6 +48,8 @@ private slots: void interceptQmldir(); void singletonVersionResolution(); void removeDynamicPlugin(); + void partialImportVersions_data(); + void partialImportVersions(); void cleanup(); }; @@ -162,37 +164,57 @@ void tst_QQmlImport::completeQmldirPaths_data() { QTest::addColumn<QString>("uri"); QTest::addColumn<QStringList>("basePaths"); - QTest::addColumn<int>("majorVersion"); - QTest::addColumn<int>("minorVersion"); + QTest::addColumn<QTypeRevision>("version"); QTest::addColumn<QStringList>("expectedPaths"); - QTest::newRow("QtQml") << "QtQml" << (QStringList() << "qtbase/qml/" << "path/to/qml") << 2 << 7 + QTest::newRow("QtQml") << "QtQml" << (QStringList() << "qtbase/qml/" << "path/to/qml") + << QTypeRevision::fromVersion(2, 7) << (QStringList() << "qtbase/qml/QtQml.2.7/qmldir" << "path/to/qml/QtQml.2.7/qmldir" << "qtbase/qml/QtQml.2/qmldir" << "path/to/qml/QtQml.2/qmldir" << "qtbase/qml/QtQml/qmldir" << "path/to/qml/QtQml/qmldir"); - QTest::newRow("QtQml.Models") << "QtQml.Models" << QStringList("qtbase/qml/") << 2 << 2 + QTest::newRow("QtQml.Models") << "QtQml.Models" << QStringList("qtbase/qml/") + << QTypeRevision::fromVersion(2, 2) << (QStringList() << "qtbase/qml/QtQml/Models.2.2/qmldir" << "qtbase/qml/QtQml.2.2/Models/qmldir" << "qtbase/qml/QtQml/Models.2/qmldir" << "qtbase/qml/QtQml.2/Models/qmldir" << "qtbase/qml/QtQml/Models/qmldir"); - QTest::newRow("org.qt-project.foo.bar") << "org.qt-project.foo.bar" << QStringList("qtbase/qml/") << 0 << 1 - << (QStringList() << "qtbase/qml/org/qt-project/foo/bar.0.1/qmldir" << "qtbase/qml/org/qt-project/foo.0.1/bar/qmldir" << "qtbase/qml/org/qt-project.0.1/foo/bar/qmldir" << "qtbase/qml/org.0.1/qt-project/foo/bar/qmldir" - << "qtbase/qml/org/qt-project/foo/bar.0/qmldir" << "qtbase/qml/org/qt-project/foo.0/bar/qmldir" << "qtbase/qml/org/qt-project.0/foo/bar/qmldir" << "qtbase/qml/org.0/qt-project/foo/bar/qmldir" - << "qtbase/qml/org/qt-project/foo/bar/qmldir"); + QTest::newRow("org.qt-project.foo.bar 0.1") << "org.qt-project.foo.bar" << QStringList("qtbase/qml/") + << QTypeRevision::fromVersion(0, 1) + << (QStringList() + << "qtbase/qml/org/qt-project/foo/bar.0.1/qmldir" + << "qtbase/qml/org/qt-project/foo.0.1/bar/qmldir" + << "qtbase/qml/org/qt-project.0.1/foo/bar/qmldir" + << "qtbase/qml/org.0.1/qt-project/foo/bar/qmldir" + << "qtbase/qml/org/qt-project/foo/bar.0/qmldir" + << "qtbase/qml/org/qt-project/foo.0/bar/qmldir" + << "qtbase/qml/org/qt-project.0/foo/bar/qmldir" + << "qtbase/qml/org.0/qt-project/foo/bar/qmldir" + << "qtbase/qml/org/qt-project/foo/bar/qmldir"); + + QTest::newRow("org.qt-project.foo.bar 4") << "org.qt-project.foo.bar" << QStringList("qtbase/qml/") + << QTypeRevision::fromMajorVersion(4) + << (QStringList() + << "qtbase/qml/org/qt-project/foo/bar.4/qmldir" + << "qtbase/qml/org/qt-project/foo.4/bar/qmldir" + << "qtbase/qml/org/qt-project.4/foo/bar/qmldir" + << "qtbase/qml/org.4/qt-project/foo/bar/qmldir" + << "qtbase/qml/org/qt-project/foo/bar/qmldir"); + + QTest::newRow("org.qt-project.foo.bar") << "org.qt-project.foo.bar" << QStringList("qtbase/qml/") + << QTypeRevision() + << (QStringList() + << "qtbase/qml/org/qt-project/foo/bar/qmldir"); } void tst_QQmlImport::completeQmldirPaths() { QFETCH(QString, uri); QFETCH(QStringList, basePaths); - QFETCH(int, majorVersion); - QFETCH(int, minorVersion); + QFETCH(QTypeRevision, version); QFETCH(QStringList, expectedPaths); - QCOMPARE(QQmlImports::completeQmldirPaths( - uri, basePaths, QTypeRevision::fromVersion(majorVersion, minorVersion)), - expectedPaths); + QCOMPARE(QQmlImports::completeQmldirPaths(uri, basePaths, version), expectedPaths); } class QmldirUrlInterceptor : public QQmlAbstractUrlInterceptor { @@ -283,6 +305,38 @@ void tst_QQmlImport::removeDynamicPlugin() qmlClearTypeRegistrations(); } +void tst_QQmlImport::partialImportVersions_data() +{ + QTest::addColumn<QString>("version"); + QTest::addColumn<bool>("valid"); + + QTest::addRow("empty") << "" << true; + QTest::addRow("2") << "2" << true; + QTest::addRow("6") << "6" << true; + QTest::addRow("2.0") << "2.0" << false; + QTest::addRow("2.3") << "2.3" << true; + QTest::addRow("2.15") << "2.15" << true; + QTest::addRow("6.0") << "6.0" << true; +} + +void tst_QQmlImport::partialImportVersions() +{ + QFETCH(QString, version); + QFETCH(bool, valid); + + QQmlEngine engine; + + QQmlComponent component(&engine); + + component.setData("import QtQml " + version.toUtf8() + "; Connections { enabled: false }", + QUrl()); + QCOMPARE(component.isReady(), valid); + if (valid) { + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + } +} + QTEST_MAIN(tst_QQmlImport) diff --git a/tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt b/tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt index c7d880e79e..e69de29bb2 100644 --- a/tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt @@ -1 +0,0 @@ -1:16:Library import requires a version diff --git a/tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt b/tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt index 59b0b87477..9900700753 100644 --- a/tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt @@ -1 +1 @@ -1:39:Library import requires a version +1:1:module "org.qtproject.installedtest" is not installed |