aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/auto/qml/qmllint/data/Things/SomethingElse.qml2
-rw-r--r--tests/auto/qml/qmllint/data/Things/plugins.qmltypes16
-rw-r--r--tests/auto/qml/qmllint/data/Things/qmldir3
-rw-r--r--tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml6
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp2
-rw-r--r--tools/qmllint/findunqualified.cpp74
-rw-r--r--tools/qmllint/main.cpp4
7 files changed, 90 insertions, 17 deletions
diff --git a/tests/auto/qml/qmllint/data/Things/SomethingElse.qml b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/SomethingElse.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
new file mode 100644
index 0000000000..00cda191cc
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
@@ -0,0 +1,16 @@
+import QtQuick.tooling 1.2
+Module {
+ dependencies: []
+ Component {
+ name: "SomethingEntirelyStrange"
+ prototype: "QObject"
+ Enum {
+ name: "AnEnum"
+ values: {
+ "AAA": 0,
+ "BBB": 1,
+ "CCC": 2
+ }
+ }
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/Things/qmldir b/tests/auto/qml/qmllint/data/Things/qmldir
new file mode 100644
index 0000000000..c53af3a340
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Things/qmldir
@@ -0,0 +1,3 @@
+module Things
+Something 1.0 SomethingElse.qml
+plugin doesNotExistPlugin
diff --git a/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml
new file mode 100644
index 0000000000..4847fc9196
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml
@@ -0,0 +1,6 @@
+import Things 1.0
+
+Something {
+ property var a: SomethingEntirelyStrange {}
+ property var b: SomethingEntirelyStrange.AAA
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 9dc0a4dd42..7faa3881d5 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -156,6 +156,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("methodInScope") << QStringLiteral("MethodInScope.qml");
QTest::newRow("importWithPrefix") << QStringLiteral("ImportWithPrefix.qml");
QTest::newRow("catchIdentifier") << QStringLiteral("catchIdentifierNoWarning.qml");
+ QTest::newRow("qmldirAndQmltypes") << QStringLiteral("qmldirAndQmltypes.qml");
}
void TestQmllint::cleanQmlCode()
@@ -171,6 +172,7 @@ QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed)
QStringList args;
args << QStringLiteral("-U") << testFile(fileToLint)
<< QStringLiteral("-I") << qmlImportDir
+ << QStringLiteral("-I") << dataDirectory()
<< QStringLiteral("--silent");
QString errors;
auto verify = [&](bool isSilent) {
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 52cc36aeeb..799602d225 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -39,8 +39,18 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qv4codegen_p.h>
+#include <private/qqmldirparser_p.h>
-static QQmlJS::TypeDescriptionReader createReaderForFile(QString const &filename)
+static QQmlDirParser createQmldirParserForFile(const QString &filename)
+{
+ QFile f(filename);
+ f.open(QFile::ReadOnly);
+ QQmlDirParser parser;
+ parser.parse(f.readAll());
+ return parser;
+}
+
+static QQmlJS::TypeDescriptionReader createQmltypesReaderForFile(QString const &filename)
{
QFile f(filename);
f.open(QFile::ReadOnly);
@@ -58,13 +68,12 @@ void FindUnqualifiedIDVisitor::leaveEnvironment()
m_currentScope = m_currentScope->parentScope();
}
-enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned };
+enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned, BasePath };
-QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
+QStringList completeImportPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
{
static const QLatin1Char Slash('/');
static const QLatin1Char Backslash('\\');
- static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
const QVector<QStringRef> parts = uri.splitRef(QLatin1Char('.'), QString::SkipEmptyParts);
@@ -94,7 +103,7 @@ QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePat
return str;
};
- for (int version = FullyVersioned; version <= Unversioned; ++version) {
+ for (int version = FullyVersioned; version <= BasePath; ++version) {
const QString ver = versionString(vmaj, vmin, static_cast<ImportVersion>(version));
for (const QString &path : basePaths) {
@@ -102,20 +111,23 @@ QStringList completeQmltypesPaths(const QString &uri, const QStringList &basePat
if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
dir += Slash;
- // append to the end
- qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + SlashPluginsDotQmltypes;
+ if (version == BasePath) {
+ qmlDirPathsPaths += dir;
+ } else {
+ // append to the end
+ qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver;
+ }
- if (version != Unversioned) {
+ if (version < Unversioned) {
// insert in the middle
for (int index = parts.count() - 2; index >= 0; --index) {
qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ ver + Slash
- + joinStringRefs(parts.mid(index + 1), Slash) + SlashPluginsDotQmltypes;
+ + joinStringRefs(parts.mid(index + 1), Slash);
}
}
}
}
-
return qmlDirPathsPaths;
}
@@ -128,18 +140,50 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int majo
m_alreadySeenImports.insert(importId);
}
id = id.replace(QLatin1String("/"), QLatin1String("."));
- auto qmltypesPaths = completeQmltypesPaths(id, m_qmltypeDirs, major, minor);
+ auto qmltypesPaths = completeImportPaths(id, m_qmltypeDirs, major, minor);
QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> objects;
QList<QQmlJS::ModuleApiInfo> moduleApis;
QStringList dependencies;
+ static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
+ static const QLatin1String SlashQmldir("/qmldir");
for (auto const &qmltypesPath : qmltypesPaths) {
- if (QFile::exists(qmltypesPath)) {
- auto reader = createReaderForFile(qmltypesPath);
+ if (QFile::exists(qmltypesPath + SlashQmldir)) {
+ auto reader = createQmldirParserForFile(qmltypesPath + SlashQmldir);
+ const auto imports = reader.imports();
+ for (const QString &import : imports)
+ importHelper(import, prefix, major, minor);
+
+ QHash<QString, LanguageUtils::FakeMetaObject *> qmlComponents;
+ const auto components = reader.components();
+ for (auto it = components.begin(), end = components.end(); it != end; ++it) {
+ const QString filePath = qmltypesPath + QLatin1Char('/') + it->fileName;
+ if (!QFile::exists(filePath)) {
+ m_colorOut.write(QLatin1String("warning: "), Warning);
+ m_colorOut.write(it->fileName + QLatin1String(" is listed as component in ")
+ + qmltypesPath + SlashQmldir
+ + QLatin1String(" but does not exist.\n"));
+ continue;
+ }
+
+ auto mo = qmlComponents.find(it.key());
+ if (mo == qmlComponents.end())
+ mo = qmlComponents.insert(it.key(), localQmlFile2FakeMetaObject(filePath));
+
+ (*mo)->addExport(
+ it.key(), reader.typeNamespace(),
+ LanguageUtils::ComponentVersion(it->majorVersion, it->minorVersion));
+ }
+ for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it) {
+ objects.insert(it.key(),
+ QSharedPointer<const LanguageUtils::FakeMetaObject>(it.value()));
+ }
+ }
+ if (QFile::exists(qmltypesPath + SlashPluginsDotQmltypes)) {
+ auto reader = createQmltypesReaderForFile(qmltypesPath + SlashPluginsDotQmltypes);
auto succ = reader(&objects, &moduleApis, &dependencies);
if (!succ)
m_colorOut.writeUncolored(reader.errorMessage());
- break;
}
}
for (auto const &dependency : qAsConst(dependencies)) {
@@ -367,7 +411,7 @@ bool FindUnqualifiedIDVisitor::visit(QQmlJS::AST::UiProgram *)
QDirIterator it { dir, QStringList() << QLatin1String("builtins.qmltypes"), QDir::NoFilter,
QDirIterator::Subdirectories };
while (it.hasNext()) {
- auto reader = createReaderForFile(it.next());
+ auto reader = createQmltypesReaderForFile(it.next());
auto succ = reader(&objects, &moduleApis, &dependencies);
if (!succ)
m_colorOut.writeUncolored(reader.errorMessage());
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 0fa2ab53e4..56f72dd020 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -123,9 +123,9 @@ int main(int argv, char *argc[])
// use host qml import path as a sane default if nothing else has been provided
QStringList qmltypeDirs = parser.isSet(qmltypesDirsOption) ? parser.values(qmltypesDirsOption)
#ifndef QT_BOOTSTRAPPED
- : QStringList{QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)};
+ : QStringList{QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QLatin1String(".")};
#else
- : QStringList{};
+ : QStringList{QLatin1String(".")};
#endif
#else
bool silent = false;