aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2019-11-14 17:08:15 +0100
committerUlf Hermann <ulf.hermann@qt.io>2019-11-18 13:48:17 +0100
commit355fd4bf5cd0a83b52b37c2a905cee867f9af4d6 (patch)
treebf49f58868963d75b3b9bf8b38b07405c6c1f81f /tools
parent6b1f42c72f060010f3c73f4502dcd10647f205c1 (diff)
qmllint: Read app.qmltypes files for extra type resolution
Change-Id: I7f19b39dd65063ae26b93bf1b40b0be0b0e15c6d Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmllint/findunqualified.cpp172
-rw-r--r--tools/qmllint/findunqualified.h15
2 files changed, 113 insertions, 74 deletions
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 6a4071acc7..6274238f96 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -69,8 +69,7 @@ void FindUnqualifiedIDVisitor::leaveEnvironment()
enum ImportVersion { FullyVersioned, PartiallyVersioned, Unversioned, BasePath };
-QStringList completeImportPaths(const QString &uri, const QStringList &basePaths,
- int vmaj, int vmin)
+QStringList completeImportPaths(const QString &uri, const QString &basePath, int vmaj, int vmin)
{
static const QLatin1Char Slash('/');
static const QLatin1Char Backslash('\\');
@@ -79,7 +78,7 @@ QStringList completeImportPaths(const QString &uri, const QStringList &basePaths
QStringList qmlDirPathsPaths;
// fully & partially versioned parts + 1 unversioned for each base path
- qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
+ qmlDirPathsPaths.reserve(2 * parts.count() + 1);
auto versionString = [](int vmaj, int vmin, ImportVersion version)
{
@@ -107,96 +106,93 @@ QStringList completeImportPaths(const QString &uri, const QStringList &basePaths
for (int version = FullyVersioned; version <= BasePath; ++version) {
const QString ver = versionString(vmaj, vmin, static_cast<ImportVersion>(version));
- for (const QString &path : basePaths) {
- QString dir = path;
- if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
- dir += Slash;
+ QString dir = basePath;
+ if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
+ dir += Slash;
- if (version == BasePath) {
- qmlDirPathsPaths += dir;
- } else {
- // append to the end
- qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver;
- }
+ if (version == BasePath) {
+ qmlDirPathsPaths += dir;
+ } else {
+ // append to the end
+ qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver;
+ }
- 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);
- }
+ 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);
}
}
}
return qmlDirPathsPaths;
}
-void FindUnqualifiedIDVisitor::importHelper(QString id, const QString &prefix, int major, int minor)
-{
- QPair<QString, QString> importId { id, prefix };
- if (m_alreadySeenImports.contains(importId))
- return;
+static const QLatin1String SlashQmldir = QLatin1String("/qmldir");
+static const QLatin1String SlashAppDotQmltypes = QLatin1String("/app.qmltypes");
+static const QLatin1String SlashLibDotQmltypes = QLatin1String("/lib.qmltypes");
+static const QLatin1String SlashPluginsDotQmltypes = QLatin1String("/plugins.qmltypes");
- m_alreadySeenImports.insert(importId);
+void FindUnqualifiedIDVisitor::readQmltypes(const QString &filename,
+ FindUnqualifiedIDVisitor::Import &result)
+{
+ auto reader = createQmltypesReaderForFile(filename);
+ auto succ = reader(&result.objects, &result.moduleApis, &result.dependencies);
+ if (!succ)
+ m_colorOut.writeUncolored(reader.errorMessage());
+}
- id = id.replace(QLatin1String("/"), QLatin1String("."));
- auto qmltypesPaths = completeImportPaths(id, m_qmltypeDirs, major, minor);
+FindUnqualifiedIDVisitor::Import FindUnqualifiedIDVisitor::readQmldir(const QString &path)
+{
+ Import result;
+ auto reader = createQmldirParserForFile(path + SlashQmldir);
+ const auto imports = reader.imports();
+ for (const QString &import : imports)
+ result.dependencies.append(import);
- QHash<QString, ScopeTree::ConstPtr> objects;
- QList<ModuleApiInfo> moduleApis;
- QStringList dependencies;
- static const QLatin1String SlashPluginsDotQmltypes("/plugins.qmltypes");
- static const QLatin1String SlashQmldir("/qmldir");
- for (auto const &qmltypesPath : qmltypesPaths) {
- 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, ScopeTree *> 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;
- }
+ QHash<QString, ScopeTree *> qmlComponents;
+ const auto components = reader.components();
+ for (auto it = components.begin(), end = components.end(); it != end; ++it) {
+ const QString filePath = path + QLatin1Char('/') + it->fileName;
+ if (!QFile::exists(filePath)) {
+ m_colorOut.write(QLatin1String("warning: "), Warning);
+ m_colorOut.write(it->fileName + QLatin1String(" is listed as component in ")
+ + path + SlashQmldir
+ + QLatin1String(" but does not exist.\n"));
+ continue;
+ }
- auto mo = qmlComponents.find(it.key());
- if (mo == qmlComponents.end())
- mo = qmlComponents.insert(it.key(), localQmlFile2ScopeTree(filePath));
+ auto mo = qmlComponents.find(it.key());
+ if (mo == qmlComponents.end())
+ mo = qmlComponents.insert(it.key(), localQmlFile2ScopeTree(filePath));
- (*mo)->addExport(
- it.key(), reader.typeNamespace(),
- ComponentVersion(it->majorVersion, it->minorVersion));
- }
- for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it) {
- objects.insert(it.key(),
- QSharedPointer<const ScopeTree>(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());
- }
+ (*mo)->addExport(
+ it.key(), reader.typeNamespace(),
+ ComponentVersion(it->majorVersion, it->minorVersion));
}
- for (auto const &dependency : qAsConst(dependencies)) {
+ for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
+ result.objects.insert( it.key(), ScopeTree::ConstPtr(it.value()));
+
+ if (!reader.plugins().isEmpty() && QFile::exists(path + SlashPluginsDotQmltypes))
+ readQmltypes(path + SlashPluginsDotQmltypes, result);
+
+ return result;
+}
+
+void FindUnqualifiedIDVisitor::processImport(const QString &prefix, const FindUnqualifiedIDVisitor::Import &import)
+{
+ for (auto const &dependency : qAsConst(import.dependencies)) {
auto const split = dependency.split(" ");
auto const &id = split.at(0);
auto const major = split.at(1).split('.').at(0).toInt();
auto const minor = split.at(1).split('.').at(1).toInt();
importHelper(id, QString(), major, minor);
}
+
// add objects
- for (auto ob_it = objects.begin(); ob_it != objects.end(); ++ob_it) {
- auto val = ob_it.value();
+ for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
+ const auto &val = it.value();
m_exportedName2Scope[prefix + val->className()] = val;
const auto exports = val->exports();
@@ -209,6 +205,38 @@ void FindUnqualifiedIDVisitor::importHelper(QString id, const QString &prefix, i
}
}
+void FindUnqualifiedIDVisitor::importHelper(QString id, QString prefix, int major, int minor)
+{
+ id = id.replace(QLatin1String("/"), QLatin1String("."));
+ QPair<QString, QString> importId { id, prefix };
+ if (m_alreadySeenImports.contains(importId))
+ return;
+ m_alreadySeenImports.insert(importId);
+
+ for (const QString &qmltypeDir : m_qmltypeDirs) {
+ auto qmltypesPaths = completeImportPaths(id, qmltypeDir, major, minor);
+
+ for (auto const &qmltypesPath : qmltypesPaths) {
+ if (QFile::exists(qmltypesPath + SlashQmldir)) {
+ processImport(prefix, readQmldir(qmltypesPath));
+
+ // break so that we don't import unversioned qml components
+ // in addition to versioned ones
+ break;
+ }
+
+ Import result;
+ if (QFile::exists(qmltypesPath + SlashAppDotQmltypes))
+ readQmltypes(qmltypesPath + SlashAppDotQmltypes, result);
+ else if (QFile::exists(qmltypesPath + SlashLibDotQmltypes))
+ readQmltypes(qmltypesPath + SlashLibDotQmltypes, result);
+ else
+ continue;
+ processImport(prefix, result);
+ }
+ }
+}
+
ScopeTree *FindUnqualifiedIDVisitor::localQmlFile2ScopeTree(const QString &filePath)
{
using namespace QQmlJS::AST;
diff --git a/tools/qmllint/findunqualified.h b/tools/qmllint/findunqualified.h
index 8b79918d90..a8fa435464 100644
--- a/tools/qmllint/findunqualified.h
+++ b/tools/qmllint/findunqualified.h
@@ -58,6 +58,12 @@ public:
bool check();
private:
+ struct Import {
+ QHash<QString, ScopeTree::ConstPtr> objects;
+ QList<ModuleApiInfo> moduleApis;
+ QStringList dependencies;
+ };
+
QScopedPointer<ScopeTree> m_rootScope;
ScopeTree *m_currentScope = nullptr;
QHash<QString, ScopeTree::ConstPtr> m_exportedName2Scope;
@@ -82,8 +88,13 @@ private:
void enterEnvironment(ScopeType type, QString name);
void leaveEnvironment();
- void importHelper(QString id, const QString &prefix, int major, int minor);
- ScopeTree* localQmlFile2ScopeTree(const QString &filePath);
+ void importHelper(QString id, QString prefix, int major, int minor);
+
+ void readQmltypes(const QString &filename, Import &result);
+ Import readQmldir(const QString &dirname);
+ void processImport(const QString &prefix, const Import &import);
+
+ ScopeTree *localQmlFile2ScopeTree(const QString &filePath);
void importDirectory(const QString &directory, const QString &prefix);
void importExportedNames(const QStringRef &prefix, QString name);