diff options
17 files changed, 229 insertions, 41 deletions
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 1224efdaac..be870cad4c 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -545,27 +545,27 @@ QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork } } - // TODO: Should this search be omitted if found == true? - - // step 2: search for extension with encoded version major - foreach (const QString &p, database->fileImportPath) { - dir = p+Slash+url; + if (!found) { + // step 2: search for extension with encoded version major + foreach (const QString &p, database->fileImportPath) { + dir = p+Slash+url; - QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir")); - const QString absoluteFilePath = fi.absoluteFilePath(); + QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir")); + const QString absoluteFilePath = fi.absoluteFilePath(); - if (fi.isFile()) { - found = true; + if (fi.isFile()) { + found = true; - const QString absolutePath = fi.absolutePath(); - if (absolutePath.at(0) == QLatin1Char(':')) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(fi.absolutePath()).toString(); - uri = resolvedUri(dir, database); - if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return QString(); - break; + const QString absolutePath = fi.absolutePath(); + if (absolutePath.at(0) == QLatin1Char(':')) + url = QLatin1String("qrc://") + absolutePath.mid(1); + else + url = QUrl::fromLocalFile(fi.absolutePath()).toString(); + uri = resolvedUri(dir, database); + if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) + return QString(); + break; + } } } diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index 8e22e488ed..b1bb5ed866 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -1340,6 +1340,11 @@ bool QQmlScript::Parser::parse(const QByteArray &qmldata, const QUrl &url, _errors[ii].setUrl(url); } + if (_errors.isEmpty()) { + // Sort the imports into desired order + qStableSort(_imports.begin(), _imports.end()); + } + return _errors.isEmpty(); } diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index ddf4c9a392..debe894376 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -121,6 +121,11 @@ public: void extractVersion(int *maj, int *min) const; QQmlScript::LocationSpan location; + + bool operator<(const Import& other) const { + // Shorter URIs first, so 'import X' is before 'import X.Y' + return (uri.length() < other.uri.length()); + } }; class Object; diff --git a/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/InstalledTest3.qml b/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/InstalledTest3.qml new file mode 100644 index 0000000000..26a5d6bba9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/InstalledTest3.qml @@ -0,0 +1,2 @@ +import QtQuick 2.0 +Rectangle {} diff --git a/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/qmldir b/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/qmldir index b301226099..ce51ecae1a 100644 --- a/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/qmldir +++ b/tests/auto/qml/qqmllanguage/data/lib/com/nokia/installedtest0/qmldir @@ -1,2 +1,3 @@ InstalledTest 1.4 InstalledTest2.qml InstalledTestTP 0.0 InstalledTest.qml +Rectangle 1.5 InstalledTest3.qml diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 837a9d2604..f70b212231 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -181,7 +181,7 @@ private slots: private: QQmlEngine engine; - void testType(const QString& qml, const QString& type, const QString& error); + void testType(const QString& qml, const QString& type, const QString& error, bool partialMatch = false); }; #define DETERMINE_ERRORS(errorfile,expected,actual)\ @@ -1480,7 +1480,7 @@ void tst_qqmllanguage::reservedWords() } // Check that first child of qml is of given type. Empty type insists on error. -void tst_qqmllanguage::testType(const QString& qml, const QString& type, const QString& expectederror) +void tst_qqmllanguage::testType(const QString& qml, const QString& type, const QString& expectederror, bool partialMatch) { QQmlComponent component(&engine); component.setData(qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports @@ -1495,7 +1495,7 @@ void tst_qqmllanguage::testType(const QString& qml, const QString& type, const Q actualerror.append("; "); actualerror.append(e.description()); } - QCOMPARE(actualerror,expectederror); + QCOMPARE(actualerror.left(partialMatch ? expectederror.length(): -1),expectederror); } else { VERIFY_ERRORS(0); QObject *object = component.create(); @@ -1616,13 +1616,13 @@ void tst_qqmllanguage::importsBuiltin_data() "import com.nokia.Test 1.12\n" "Test {}" << (!qmlCheckTypes()?"TestType2":"") - << (!qmlCheckTypes()?"":"Test is ambiguous. Found in com/nokia/Test in version 1.12 and 1.11"); + << (!qmlCheckTypes()?"":"Test is ambiguous. Found in com/nokia/Test/ in version 1.12 and 1.11"); QTest::newRow("multiversion 2") << "import com.nokia.Test 1.11\n" "import com.nokia.Test 1.12\n" "OldTest {}" << (!qmlCheckTypes()?"TestType":"") - << (!qmlCheckTypes()?"":"OldTest is ambiguous. Found in com/nokia/Test in version 1.12 and 1.11"); + << (!qmlCheckTypes()?"":"OldTest is ambiguous. Found in com/nokia/Test/ in version 1.12 and 1.11"); QTest::newRow("qualified multiversion 3") << "import com.nokia.Test 1.0 as T0\n" "import com.nokia.Test 1.8 as T8\n" @@ -1691,7 +1691,7 @@ void tst_qqmllanguage::importsLocal_data() "import com.nokia.Test 1.0\n" "Test {}" << (!qmlCheckTypes()?"TestType":"") - << (!qmlCheckTypes()?"":"Test is ambiguous. Found in com/nokia/Test and in subdir"); + << (!qmlCheckTypes()?"":"Test is ambiguous. Found in com/nokia/Test/ and in subdir/"); } void tst_qqmllanguage::importsLocal() @@ -1841,32 +1841,37 @@ void tst_qqmllanguage::importsOrder_data() QTest::addColumn<QString>("qml"); QTest::addColumn<QString>("type"); QTest::addColumn<QString>("error"); + QTest::addColumn<bool>("partialMatch"); QTest::newRow("double import") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << (!qmlCheckTypes()?"QQuickText":"") - << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest in version 1.4 and 1.4"); + << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest/ in version 1.4 and 1.4") + << false; QTest::newRow("installed import overrides 1") << "import com.nokia.installedtest 1.0\n" "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << (!qmlCheckTypes()?"QQuickText":"") - << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest in version 1.4 and 1.0"); + << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest/ in version 1.4 and 1.0") + << false; QTest::newRow("installed import overrides 2") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "InstalledTest {}" << (!qmlCheckTypes()?"QQuickRectangle":"") - << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest in version 1.0 and 1.4"); + << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest/ in version 1.0 and 1.4") + << false; QTest::newRow("installed import re-overrides 1") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" "import com.nokia.installedtest 1.4\n" "InstalledTest {}" << (!qmlCheckTypes()?"QQuickText":"") - << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest in version 1.4 and 1.0"); + << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest/ in version 1.4 and 1.0") + << false; QTest::newRow("installed import re-overrides 2") << "import com.nokia.installedtest 1.4\n" "import com.nokia.installedtest 1.0\n" @@ -1874,41 +1879,49 @@ void tst_qqmllanguage::importsOrder_data() "import com.nokia.installedtest 1.0\n" "InstalledTest {}" << (!qmlCheckTypes()?"QQuickRectangle":"") - << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest in version 1.0 and 1.4"); + << (!qmlCheckTypes()?"":"InstalledTest is ambiguous. Found in lib/com/nokia/installedtest/ in version 1.0 and 1.4") + << false; + // Note: imports are now reordered by increasing order of URI length QTest::newRow("installed import versus builtin 1") << + "import com.nokia.installedtest0 1.5\n" "import com.nokia.installedtest 1.5\n" - "import QtQuick 2.0\n" "Rectangle {}" << (!qmlCheckTypes()?"QQuickRectangle":"") - << (!qmlCheckTypes()?"":"Rectangle is ambiguous. Found in Qt and in lib/com/nokia/installedtest"); + << (!qmlCheckTypes()?"":"Rectangle is ambiguous. Found in lib/com/nokia/installedtest0/ and in ") + << true; QTest::newRow("installed import versus builtin 2") << "import QtQuick 2.0\n" "import com.nokia.installedtest 1.5\n" "Rectangle {}" << (!qmlCheckTypes()?"QQuickText":"") - << (!qmlCheckTypes()?"":"Rectangle is ambiguous. Found in lib/com/nokia/installedtest and in Qt"); + << (!qmlCheckTypes()?"":"Rectangle is ambiguous. Found in lib/com/nokia/installedtest/ and in ") + << true; QTest::newRow("namespaces cannot be overridden by types 1") << "import QtQuick 2.0 as Rectangle\n" "import com.nokia.installedtest 1.5\n" "Rectangle {}" - << "" - << "Namespace Rectangle cannot be used as a type"; + << "" + << "Namespace Rectangle cannot be used as a type" + << false; QTest::newRow("namespaces cannot be overridden by types 2") << "import QtQuick 2.0 as Rectangle\n" "import com.nokia.installedtest 1.5\n" "Rectangle.Image {}" - << "QQuickImage" - << ""; + << "QQuickImage" + << "" + << false; QTest::newRow("local last 1") << "LocalLast {}" - << "QQuickText" - << ""; + << "QQuickText" + << "" + << false; QTest::newRow("local last 2") << "import com.nokia.installedtest 1.0\n" "LocalLast {}" << (!qmlCheckTypes()?"QQuickRectangle":"")// i.e. from com.nokia.installedtest, not data/LocalLast.qml - << (!qmlCheckTypes()?"":"LocalLast is ambiguous. Found in lib/com/nokia/installedtest and in local directory"); + << (!qmlCheckTypes()?"":"LocalLast is ambiguous. Found in lib/com/nokia/installedtest/ and in ") + << false; } void tst_qqmllanguage::importsOrder() @@ -1916,7 +1929,8 @@ void tst_qqmllanguage::importsOrder() QFETCH(QString, qml); QFETCH(QString, type); QFETCH(QString, error); - testType(qml,type,error); + QFETCH(bool, partialMatch); + testType(qml,type,error,partialMatch); } void tst_qqmllanguage::importIncorrectCase() diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml new file mode 100644 index 0000000000..b3f9ac6c3f --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.1.qml @@ -0,0 +1,5 @@ +import com.nokia.AutoTestQmlNestedPluginType.Nested 1.0 +import com.nokia.AutoTestQmlNestedPluginType 1.0 + +MyNestedPluginType { +} diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml new file mode 100644 index 0000000000..cb8e0e33d1 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.2.qml @@ -0,0 +1,5 @@ +import com.nokia.AutoTestQmlNestedPluginType 1.0 +import com.nokia.AutoTestQmlNestedPluginType.Nested 1.0 + +MyNestedPluginType { +} diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.errors.txt new file mode 100644 index 0000000000..f0c73e336f --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.errors.txt @@ -0,0 +1 @@ +3:1:MyNestedPluginType is not a type diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml new file mode 100644 index 0000000000..69c6a34f46 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.3.qml @@ -0,0 +1,4 @@ +import com.nokia.AutoTestQmlNestedPluginType 1.0 + +MyNestedPluginType { +} diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt new file mode 100644 index 0000000000..9743ae4f68 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.errors.txt @@ -0,0 +1 @@ +2:1:module "com.nokia.AutoTestQmlNestedPluginType.Nested" version 6.66 is not installed diff --git a/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml new file mode 100644 index 0000000000..dce8b7564a --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/data/importsNested.4.qml @@ -0,0 +1,5 @@ +import com.nokia.AutoTestQmlNestedPluginType 1.0 +import com.nokia.AutoTestQmlNestedPluginType.Nested 6.66 + +MyNestedPluginType { +} diff --git a/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/AutoTestQmlNestedPluginType/qmldir b/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/AutoTestQmlNestedPluginType/qmldir new file mode 100644 index 0000000000..f6ed20dda4 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/imports/com/nokia/AutoTestQmlNestedPluginType/qmldir @@ -0,0 +1 @@ +plugin nestedPlugin diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp new file mode 100644 index 0000000000..2d0af471c2 --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QStringList> +#include <QtQml/qqmlextensionplugin.h> +#include <QtQml/qqml.h> +#include <QDebug> + +class MyPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString value READ value) + +public: + MyPluginType(QObject *parent=0) : QObject(parent) {} + + QString value() const { return "Hello"; } +}; + +class MyNestedPluginType : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString value READ value) + +public: + MyNestedPluginType(QObject *parent=0) : QObject(parent) {} + + QString value() const { return "Goodbye"; } +}; + + +class MyPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface" FILE "../empty.json") + +public: + MyPlugin() {} + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "com.nokia.AutoTestQmlNestedPluginType"); + qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType"); + + QString nestedUri(uri); + nestedUri += QLatin1String(".Nested"); + + qmlRegisterType<MyNestedPluginType>(nestedUri.toLatin1().constData(), 1, 0, "MyNestedPluginType"); + } +}; + +#include "nestedPlugin.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro new file mode 100644 index 0000000000..94dc236a4c --- /dev/null +++ b/tests/auto/qml/qqmlmoduleplugin/nestedPlugin/nestedPlugin.pro @@ -0,0 +1,7 @@ +TEMPLATE = lib +CONFIG += nestedPlugin +SOURCES = nestedPlugin.cpp +QT = core qml +DESTDIR = ../imports/com/nokia/AutoTestQmlNestedPluginType + +QT += core-private gui-private qml-private diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro index 42eedc20f2..6da88320cd 100644 --- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro +++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro @@ -1,6 +1,6 @@ QT = core TEMPLATE = subdirs -SUBDIRS = plugin plugin.2 plugin.2.1 pluginWrongCase pluginWithQmlFile pluginMixed pluginVersion +SUBDIRS = plugin plugin.2 plugin.2.1 pluginWrongCase pluginWithQmlFile pluginMixed pluginVersion nestedPlugin tst_qqmlmoduleplugin_pro.depends += plugin SUBDIRS += tst_qqmlmoduleplugin.pro diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index b574bad595..c110ce71d3 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -70,6 +70,8 @@ private slots: void versionNotInstalled_data(); void implicitQmldir(); void implicitQmldir_data(); + void importsNested(); + void importsNested_data(); private: QString m_importsDirectory; @@ -347,6 +349,47 @@ void tst_qqmlmoduleplugin::implicitQmldir() delete obj; } +void tst_qqmlmoduleplugin::importsNested_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("errorFile"); + + // Note: specific order required to induce failure (no other test case should import the + // plugin used for this test, or the alternate order test will pass spuriously) + QTest::newRow("alternateOrder") << "importsNested.1.qml" << QString(); + QTest::newRow("expectedOrder") << "importsNested.2.qml" << QString(); + QTest::newRow("missingImport") << "importsNested.3.qml" << "importsNested.3.errors.txt"; + QTest::newRow("invalidVersion") << "importsNested.4.qml" << "importsNested.4.errors.txt"; +} +void tst_qqmlmoduleplugin::importsNested() +{ + QFETCH(QString, file); + QFETCH(QString, errorFile); + + // Note: because imports are cached between test case data rows (and the plugins remain loaded), + // these tests should really be run in new instances of the app... + + QQmlEngine engine; + engine.addImportPath(m_importsDirectory); + + if (!errorFile.isEmpty()) { + QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready"); + } + + QQmlComponent component(&engine, testFile(file)); + QObject *obj = component.create(); + + if (errorFile.isEmpty()) { + if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) + qWarning() << "Unexpected Errors:" << component.errors(); + QVERIFY(obj); + delete obj; + } else { + QList<QQmlError> errors = component.errors(); + VERIFY_ERRORS(errorFile.toLatin1().constData()); + QVERIFY(!obj); + } +} QTEST_MAIN(tst_qqmlmoduleplugin) |