From c9b7582a2e7ad9fcd03dd999c3b7a16b72803238 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Wed, 25 Jul 2012 16:59:17 +1000 Subject: [PATCH] Implement strict mode for qmldir modules Allow a module's qmldir to contain a module directive, which when present specifies 'strict mode' import processing. In strict mode, type registrations are only permitted into the namespace identified in the qmldir file's module directive. In addition, any type registrations to that namespace originating from other modules are treated as error conditions. Task-number: QTBUG-26551 Change-Id: I081bde2d3b83d3f28524440177fb2cd1ccee34ad Reviewed-by: Chris Adams Reviewed-by: Roberto Raggi --- src/imports/folderlistmodel/qmldir | 1 + src/imports/localstorage/qmldir | 3 +- src/imports/particles/qmldir | 1 + src/imports/qtquick2/qmldir | 1 + src/imports/testlib/qmldir | 1 + src/imports/window/qmldir | 1 + src/imports/xmllistmodel/qmldir | 3 +- src/qml/qml/qqmldirparser.cpp | 42 ++- src/qml/qml/qqmldirparser_p.h | 6 +- src/qml/qml/qqmlengine.cpp | 2 +- src/qml/qml/qqmlimport.cpp | 53 +++- src/qml/qml/qqmlimport_p.h | 2 +- src/qml/qml/qqmlmetatype.cpp | 74 +++++- src/qml/qml/qqmlmetatype_p.h | 10 + src/qml/qml/qqmltypeloader.cpp | 5 + src/qml/qml/qqmltypeloader_p.h | 2 + .../data/imports/bundletest/bundledata/qmldir | 1 + tests/auto/qml/qqmldirparser/data/empty/qmldir | 0 .../qml/qqmldirparser/data/excessive-module/qmldir | 1 + .../qml/qqmldirparser/data/excessive-plugin/qmldir | 1 + .../qml/qqmldirparser/data/four-sections/qmldir | 1 + .../qqmldirparser/data/incomplete-module/qmldir | 1 + .../qqmldirparser/data/incomplete-plugin/qmldir | 1 + .../data/invalid-versioned-component/qmldir | 1 + tests/auto/qml/qqmldirparser/data/multiple/qmldir | 15 ++ .../qml/qqmldirparser/data/name-path-plugin/qmldir | 1 + .../auto/qml/qqmldirparser/data/name-plugin/qmldir | 1 + .../auto/qml/qqmldirparser/data/no-content/qmldir | 4 + .../qml/qqmldirparser/data/non-first-module/qmldir | 2 + .../auto/qml/qqmldirparser/data/one-section/qmldir | 1 + .../qml/qqmldirparser/data/repeated-module/qmldir | 2 + .../data/unversioned-component/qmldir | 1 + .../qqmldirparser/data/versioned-component/qmldir | 1 + .../qml/qqmldirparser/data/versioned-script/qmldir | 1 + tests/auto/qml/qqmldirparser/qqmldirparser.pro | 10 + tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp | 288 +++++++++++++++++++++ .../data/implicit2/implicitQmldir.2.errors.txt | 3 +- .../invalidNamespaceModule.pro | 12 + .../invalidNamespaceModule/plugin.cpp | 69 +++++ .../qqmlmoduleplugin/invalidNamespaceModule/qmldir | 2 + .../invalidStrictModule/invalidStrictModule.pro | 12 + .../invalidStrictModule/plugin.cpp | 69 +++++ .../qqmlmoduleplugin/invalidStrictModule/qmldir | 2 + .../nonstrictModule/nonstrictModule.pro | 12 + .../qqmlmoduleplugin/nonstrictModule/plugin.cpp | 71 +++++ .../qml/qqmlmoduleplugin/nonstrictModule/qmldir | 1 + .../preemptedStrictModule/plugin.cpp | 69 +++++ .../preemptedStrictModule.pro | 12 + .../qqmlmoduleplugin/preemptedStrictModule/qmldir | 2 + .../qqmlmoduleplugin/preemptiveModule/plugin.cpp | 72 ++++++ .../preemptiveModule/preemptiveModule.pro | 12 + .../qml/qqmlmoduleplugin/preemptiveModule/qmldir | 1 + .../auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro | 17 +- .../qml/qqmlmoduleplugin/strictModule/plugin.cpp | 69 +++++ .../auto/qml/qqmlmoduleplugin/strictModule/qmldir | 2 + .../qqmlmoduleplugin/strictModule/strictModule.pro | 12 + .../qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp | 86 ++++++ .../qquickanimations/tst_qquickanimations.cpp | 8 +- .../quick/qquickwindow/data/ownershipRootItem.qml | 1 + tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 2 +- 60 files changed, 1142 insertions(+), 17 deletions(-) create mode 100644 tests/auto/qml/qqmldirparser/data/empty/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/excessive-module/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/excessive-plugin/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/four-sections/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/incomplete-module/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/incomplete-plugin/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/invalid-versioned-component/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/multiple/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/name-path-plugin/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/name-plugin/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/no-content/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/non-first-module/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/one-section/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/repeated-module/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/unversioned-component/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/versioned-component/qmldir create mode 100644 tests/auto/qml/qqmldirparser/data/versioned-script/qmldir create mode 100644 tests/auto/qml/qqmldirparser/qqmldirparser.pro create mode 100644 tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/invalidNamespaceModule.pro create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidNamespaceModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/nonstrictModule/nonstrictModule.pro create mode 100644 tests/auto/qml/qqmlmoduleplugin/nonstrictModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/nonstrictModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/preemptedStrictModule.pro create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptedStrictModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptiveModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptiveModule/preemptiveModule.pro create mode 100644 tests/auto/qml/qqmlmoduleplugin/preemptiveModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/strictModule/plugin.cpp create mode 100644 tests/auto/qml/qqmlmoduleplugin/strictModule/qmldir create mode 100644 tests/auto/qml/qqmlmoduleplugin/strictModule/strictModule.pro diff --git a/src/imports/folderlistmodel/qmldir b/src/imports/folderlistmodel/qmldir index 6e115bb..bbd9135 100644 --- a/src/imports/folderlistmodel/qmldir +++ b/src/imports/folderlistmodel/qmldir @@ -1 +1,2 @@ +module Qt.labs.folderlistmodel plugin qmlfolderlistmodelplugin diff --git a/src/imports/localstorage/qmldir b/src/imports/localstorage/qmldir index 33288a1..8bb2c3b 100644 --- a/src/imports/localstorage/qmldir +++ b/src/imports/localstorage/qmldir @@ -1 +1,2 @@ -plugin qmllocalstorageplugin \ No newline at end of file +module QtQuick.LocalStorage +plugin qmllocalstorageplugin diff --git a/src/imports/particles/qmldir b/src/imports/particles/qmldir index 593915f..25d58de 100644 --- a/src/imports/particles/qmldir +++ b/src/imports/particles/qmldir @@ -1 +1,2 @@ +module QtQuick.Particles plugin particlesplugin diff --git a/src/imports/qtquick2/qmldir b/src/imports/qtquick2/qmldir index bb4d33a..1fcbb13 100644 --- a/src/imports/qtquick2/qmldir +++ b/src/imports/qtquick2/qmldir @@ -1 +1,2 @@ +module QtQuick plugin qtquick2plugin diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir index 9e872f9..d126464 100644 --- a/src/imports/testlib/qmldir +++ b/src/imports/testlib/qmldir @@ -1,3 +1,4 @@ +module QtTest plugin qmltestplugin TestCase 1.0 TestCase.qml SignalSpy 1.0 SignalSpy.qml diff --git a/src/imports/window/qmldir b/src/imports/window/qmldir index 32844a6..2dad388 100644 --- a/src/imports/window/qmldir +++ b/src/imports/window/qmldir @@ -1 +1,2 @@ +module QtQuick.Window plugin windowplugin diff --git a/src/imports/xmllistmodel/qmldir b/src/imports/xmllistmodel/qmldir index dd39bcd..945d15a 100644 --- a/src/imports/xmllistmodel/qmldir +++ b/src/imports/xmllistmodel/qmldir @@ -1 +1,2 @@ -plugin qmlxmllistmodelplugin \ No newline at end of file +module QtQuick.XmlListModel +plugin qmlxmllistmodelplugin diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 0805a24..705f715 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -99,11 +99,13 @@ bool QQmlDirParser::parse(const QString &source) _scripts.clear(); int lineNumber = 0; + bool firstLine = true; const QChar *ch = source.constData(); while (!ch->isNull()) { ++lineNumber; + bool invalidLine = false; const QChar *lineStart = ch; scanSpace(ch); @@ -129,6 +131,7 @@ bool QQmlDirParser::parse(const QString &source) } else { reportError(lineNumber, start-lineStart, QLatin1String("unexpected token")); scanToEnd(ch); + invalidLine = true; break; } scanSpace(ch); @@ -137,9 +140,32 @@ bool QQmlDirParser::parse(const QString &source) if (!ch->isNull()) ++ch; - if (sectionCount == 0) { + if (invalidLine) { + reportError(lineNumber, -1, + QString::fromUtf8("invalid qmldir directive contains too many tokens")); + continue; + } else if (sectionCount == 0) { continue; // no sections, no party. + } else if (sections[0] == QLatin1String("module")) { + if (sectionCount != 2) { + reportError(lineNumber, -1, + QString::fromUtf8("module directive requires one argument, but %1 were provided").arg(sectionCount - 1)); + continue; + } + if (!_typeNamespace.isEmpty()) { + reportError(lineNumber, -1, + QString::fromUtf8("only one module directive may be defined in a qmldir file")); + continue; + } + if (!firstLine) { + reportError(lineNumber, -1, + QString::fromUtf8("module directive must be the first directive in a qmldir file")); + continue; + } + + _typeNamespace = sections[1]; + } else if (sections[0] == QLatin1String("plugin")) { if (sectionCount < 2) { reportError(lineNumber, -1, @@ -209,6 +235,8 @@ bool QQmlDirParser::parse(const QString &source) reportError(lineNumber, -1, QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount)); } + + firstLine = false; } return hasError(); @@ -239,16 +267,28 @@ void QQmlDirParser::setError(const QQmlError &e) QList QQmlDirParser::errors(const QString &uri) const { + QUrl url(uri); QList errors = _errors; for (int i = 0; i < errors.size(); ++i) { QQmlError &e = errors[i]; QString description = e.description(); description.replace(QLatin1String("$$URI$$"), uri); e.setDescription(description); + e.setUrl(url); } return errors; } +QString QQmlDirParser::typeNamespace() const +{ + return _typeNamespace; +} + +void QQmlDirParser::setTypeNamespace(const QString &s) +{ + _typeNamespace = s; +} + QList QQmlDirParser::plugins() const { return _plugins; diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h index c38a3e1..7a90781 100644 --- a/src/qml/qml/qqmldirparser_p.h +++ b/src/qml/qml/qqmldirparser_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE class QQmlError; class QQmlEngine; -class QQmlDirParser +class Q_AUTOTEST_EXPORT QQmlDirParser { Q_DISABLE_COPY(QQmlDirParser) @@ -76,6 +76,9 @@ public: void setError(const QQmlError &); QList errors(const QString &uri) const; + QString typeNamespace() const; + void setTypeNamespace(const QString &s); + struct Plugin { Plugin() {} @@ -139,6 +142,7 @@ private: private: QList _errors; + QString _typeNamespace; QHash _components; // multi hash QList