aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp6
-rw-r--r--src/qml/parser/qqmljs.g2
-rw-r--r--src/qml/parser/qqmljsast_p.h5
-rw-r--r--src/qml/qml/qqmlengine_p.h4
-rw-r--r--src/qml/qml/qqmlimport.cpp46
-rw-r--r--src/qml/qml/qqmlmetatype.cpp16
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h20
-rw-r--r--src/qml/qml/qqmltype.cpp18
-rw-r--r--src/qml/qml/qqmltypemoduleversion.cpp18
-rw-r--r--src/qml/qml/qqmltypemoduleversion_p.h13
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp80
-rw-r--r--tests/auto/qml/qqmllanguage/data/importVersionMissingBuiltIn.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/importVersionMissingInstalled.errors.txt2
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