qmldir parser: add support for "depends component version" syntax

Dependency declarations are initially for the benefit of
qmlimportscanner which does not (yet) use this parser.  This patch
adds support for dependencies into the qmldir parser for completeness,
along with autotests.  It is necessary to prevent errors at runtime
when parsing a qmldir which contains the "depends" declaration.

Task-number: QTBUG-41489
Change-Id: Ief2524a30140c42874f94f1735755b171e15dcf7
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
Shawn Rutledge 2014-09-24 17:36:53 +02:00
parent 64e2fa8001
commit 564c1038d1
4 changed files with 65 additions and 0 deletions

View File

@ -231,6 +231,28 @@ bool QQmlDirParser::parse(const QString &source)
reportError(lineNumber, 0, QString::fromLatin1("designersupported does not expect any argument"));
else
_designerSupported = true;
} else if (sections[0] == QLatin1String("depends")) {
if (sectionCount != 3) {
reportError(lineNumber, 0,
QString::fromLatin1("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
const QString &version = sections[2];
const int dotIndex = version.indexOf(QLatin1Char('.'));
bool validVersionNumber = false;
const int majorVersion = parseInt(QStringRef(&version, 0, dotIndex), &validVersionNumber);
if (validVersionNumber) {
const int minorVersion = parseInt(QStringRef(&version, dotIndex+1, version.length()-dotIndex-1), &validVersionNumber);
if (validVersionNumber) {
Component entry(sections[1], QString(), majorVersion, minorVersion);
entry.internal = true;
_dependencies.insert(entry.typeName, entry);
}
} else {
reportError(lineNumber, 0, QString(QLatin1String("invalid version %1")).arg(version));
}
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1);
@ -348,6 +370,11 @@ QHash<QString, QQmlDirParser::Component> QQmlDirParser::components() const
return _components;
}
QHash<QString, QQmlDirParser::Component> QQmlDirParser::dependencies() const
{
return _dependencies;
}
QList<QQmlDirParser::Script> QQmlDirParser::scripts() const
{
return _scripts;

View File

@ -119,6 +119,7 @@ public:
};
QHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const;
QList<Script> scripts() const;
QList<Plugin> plugins() const;
bool designerSupported() const;
@ -137,12 +138,14 @@ public:
#endif
private:
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
void reportError(quint16 line, quint16 column, const QString &message);
private:
QList<QQmlJS::DiagnosticMessage> _errors;
QString _typeNamespace;
QHash<QString,Component> _components; // multi hash
QHash<QString,Component> _dependencies;
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported;

View File

@ -0,0 +1,3 @@
plugin foo
depends bar 1.0

View File

@ -125,6 +125,7 @@ void tst_qqmldirparser::parse_data()
QTest::addColumn<QStringList>("plugins");
QTest::addColumn<QStringList>("components");
QTest::addColumn<QStringList>("scripts");
QTest::addColumn<QStringList>("dependencies");
QTest::addColumn<bool>("designerSupported");
QTest::newRow("empty")
@ -133,6 +134,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("no-content")
@ -141,6 +143,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("one-section")
@ -149,6 +152,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("four-sections")
@ -157,6 +161,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("incomplete-module")
@ -165,6 +170,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("excessive-module")
@ -173,6 +179,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("repeated-module")
@ -181,6 +188,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("non-first-module")
@ -189,6 +197,7 @@ void tst_qqmldirparser::parse_data()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("incomplete-plugin")
@ -197,6 +206,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("excessive-plugin")
@ -205,6 +215,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("name-plugin")
@ -213,6 +224,7 @@ void tst_qqmldirparser::parse_data()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("name-path-plugin")
@ -221,6 +233,7 @@ void tst_qqmldirparser::parse_data()
<< (QStringList() << "foo|bar")
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("unversioned-component")
@ -229,6 +242,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< (QStringList() << "foo|bar|-1|-1|false")
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("invalid-versioned-component")
@ -237,6 +251,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("versioned-component")
@ -245,6 +260,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< (QStringList() << "foo|bar|33|66|false")
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("versioned-script")
@ -253,6 +269,7 @@ void tst_qqmldirparser::parse_data()
<< QStringList()
<< QStringList()
<< (QStringList() << "foo|bar.js|33|66")
<< QStringList()
<< false;
QTest::newRow("multiple")
@ -263,6 +280,7 @@ void tst_qqmldirparser::parse_data()
<< "ComponentA|componenta-1_5.qml|1|5|false"
<< "ComponentB|componentb-1_5.qml|1|5|false")
<< (QStringList() << "ScriptA|scripta-1_0.js|1|0")
<< QStringList()
<< false;
QTest::newRow("designersupported-yes")
@ -271,6 +289,7 @@ void tst_qqmldirparser::parse_data()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList()
<< QStringList()
<< true;
QTest::newRow("designersupported-no")
@ -279,7 +298,17 @@ void tst_qqmldirparser::parse_data()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList()
<< QStringList()
<< false;
QTest::newRow("dependency")
<< "dependency/qmldir"
<< QStringList()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList()
<< (QStringList() << "bar||1|0|true")
<< false;
}
void tst_qqmldirparser::parse()
@ -289,6 +318,7 @@ void tst_qqmldirparser::parse()
QFETCH(QStringList, plugins);
QFETCH(QStringList, components);
QFETCH(QStringList, scripts);
QFETCH(QStringList, dependencies);
QFETCH(bool, designerSupported);
QFile f(testFile(file));
@ -307,6 +337,8 @@ void tst_qqmldirparser::parse()
QCOMPARE(toStringList(p.plugins()), plugins);
QCOMPARE(toStringList(p.components()), components);
QCOMPARE(toStringList(p.scripts()), scripts);
QCOMPARE(toStringList(p.dependencies()), dependencies);
QCOMPARE(p.designerSupported(), designerSupported);
}