summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2017-09-22 15:55:42 +0200
committerUlf Hermann <ulf.hermann@qt.io>2017-11-22 08:43:12 +0000
commit36ce1490fc541489f9091e9d91234aeac4f9df90 (patch)
tree4ec3963fcc6fe23fa4d848ec5d19855c5d3ee581
parentc9a6f55659bc054f835aa682a521425f8fa2bf07 (diff)
Don't reject plugin-only qmldir files
On QQmlImportsPrivate::updateQmldirContent we need to check if the new module has actually been established after figuring out that it doesn't have any components or scripts. If it has, then we shouldn't fail, as obviously a plugin has been loaded. We don't need to check the component and script versions in that case, as plugins don't have separate versions. Change-Id: Ie328b59038fe65c3f6a2eeecfe969927bba6cd68 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/qml/qml/qqmlimport.cpp4
-rw-r--r--tests/auto/qml/qqmltypeloader/data/test_intercept.qml2
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp51
3 files changed, 43 insertions, 14 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 18dc8e4b28..c8d17c4b8e 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1577,8 +1577,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
if (import->setQmldirContent(qmldirUrl, qmldir, nameSpace, errors)) {
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
- // The implicit import qmldir can be empty
- if (uri != QLatin1String(".")) {
+ // The implicit import qmldir can be empty, and plugins have no extra versions
+ if (uri != QLatin1String(".") && !QQmlMetaType::isModule(uri, vmaj, vmin)) {
QQmlError error;
if (QQmlMetaType::isAnyModule(uri))
error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri).arg(vmaj).arg(vmin));
diff --git a/tests/auto/qml/qqmltypeloader/data/test_intercept.qml b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
index 091fbe7f49..0d64cb7e28 100644
--- a/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
+++ b/tests/auto/qml/qqmltypeloader/data/test_intercept.qml
@@ -41,7 +41,7 @@ ListView {
width: ListView.view.width
height: 100
asynchronous: true
- source: "Intercept.qml"
+ source: index == 0 ? "Intercept.qml" : "GenericView.qml"
onLoaded: {
test.loaded++
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index 12aeff7591..5ab729042f 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -72,7 +72,7 @@ void tst_QQMLTypeLoader::loadComponentSynchronously()
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(
QLatin1String(".*nonprotocol::1:1: QtObject is not a type.*")));
QQmlComponent component(&engine, testFileUrl("load_synchronous.qml"));
- QObject *o = component.create();
+ QScopedPointer<QObject> o(component.create());
QVERIFY(o);
}
@@ -113,7 +113,7 @@ void tst_QQMLTypeLoader::trimCache()
void tst_QQMLTypeLoader::trimCache2()
{
- QQuickView *window = new QQuickView();
+ QScopedPointer<QQuickView> window(new QQuickView());
window->setSource(testFileUrl("trim_cache2.qml"));
QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader;
// in theory if gc has already run this could be false
@@ -279,7 +279,7 @@ public:
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
emit loaded(filename);
- reply->setData(file.readAll());
+ reply->setData(transformQmldir(filename, file.readAll()));
} else
reply->fail();
}
@@ -287,6 +287,37 @@ public:
return reply;
}
+ QByteArray transformQmldir(const QString &filename, const QByteArray &content)
+ {
+ if (!filename.endsWith("/qmldir"))
+ return content;
+
+ // Make qmldir plugin paths absolute, so that we don't try to load them over the network
+ QByteArray result;
+ QByteArray path = filename.toUtf8();
+ path.chop(sizeof("qmldir") - 1);
+ for (QByteArray line : content.split('\n')) {
+ if (line.isEmpty())
+ continue;
+ QList<QByteArray> segments = line.split(' ');
+ if (segments.startsWith("plugin")) {
+ if (segments.length() == 2) {
+ segments.append(path);
+ } else if (segments.length() == 3) {
+ if (!segments[2].startsWith('/'))
+ segments[2] = path + segments[2];
+ } else {
+ // Invalid plugin declaration. Ignore
+ }
+ result.append(segments.join(' '));
+ } else {
+ result.append(line);
+ }
+ result.append('\n');
+ }
+ return result;
+ }
+
signals:
void loaded(const QString &filename);
};
@@ -315,13 +346,6 @@ public:
if (!QQmlFile::isLocalFile(path))
return path;
- // Don't rewrite internal Qt paths. We'd hit C++ plugins there.
- QString filename = QQmlFile::urlToLocalFileOrQrc(path);
- if (filename.startsWith(":/qt-project.org/")
- || filename.startsWith(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath))) {
- return path;
- }
-
QUrl result = path;
QString scheme = result.scheme();
if (!scheme.endsWith("+debug"))
@@ -332,8 +356,11 @@ public:
void tst_QQMLTypeLoader::intercept()
{
+ qmlClearTypeRegistrations();
+
QQmlEngine engine;
engine.addImportPath(dataDirectory());
+ engine.addImportPath(QT_TESTCASE_BUILDDIR);
UrlInterceptor interceptor;
NetworkAccessManagerFactory factory;
@@ -353,11 +380,13 @@ void tst_QQMLTypeLoader::intercept()
QTRY_COMPARE(o->property("created").toInt(), 2);
QTRY_COMPARE(o->property("loaded").toInt(), 2);
- QCOMPARE(factory.loadedFiles.length(), 4);
+ QVERIFY(factory.loadedFiles.length() >= 6);
QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/test_intercept.qml"));
QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Intercept.qml"));
QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/qmldir"));
QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/Fast/Fast.qml"));
+ QVERIFY(factory.loadedFiles.contains(dataDirectory() + "/GenericView.qml"));
+ QVERIFY(factory.loadedFiles.contains(QLatin1String(QT_TESTCASE_BUILDDIR) + "/Slow/qmldir"));
}
QTEST_MAIN(tst_QQMLTypeLoader)