aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmlimportscanner/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qmlimportscanner/main.cpp')
-rw-r--r--tools/qmlimportscanner/main.cpp162
1 files changed, 95 insertions, 67 deletions
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 348328f6a4..d1fa0991e8 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -33,6 +33,7 @@
#include <private/qv4staticvalue_p.h>
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmldirparser_p.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
@@ -128,7 +129,8 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
+ QLatin1Char('.')
+ QString::number(importNode->version->version.minorVersion())
: QString();
- import[versionLiteral()] = versionString;
+ if (!versionString.isEmpty())
+ import[versionLiteral()] = versionString;
}
imports.append(import);
@@ -137,43 +139,90 @@ QVariantList findImportsInAst(QQmlJS::AST::UiHeaderItemList *headerItemList, con
return imports;
}
+QVariantList findQmlImportsInQmlFile(const QString &filePath);
+QVariantList findQmlImportsInJavascriptFile(const QString &filePath);
+
+static QString versionSuffix(QTypeRevision version)
+{
+ return QLatin1Char(' ') + QString::number(version.majorVersion()) + QLatin1Char('.')
+ + QString::number(version.minorVersion());
+}
+
// Read the qmldir file, extract a list of plugins by
-// parsing the "plugin" and "classname" lines.
-QVariantMap pluginsForModulePath(const QString &modulePath) {
+// parsing the "plugin", "import", and "classname" directives.
+QVariantMap pluginsForModulePath(const QString &modulePath, const QString &version) {
QFile qmldirFile(modulePath + QLatin1String("/qmldir"));
- if (!qmldirFile.exists())
+ if (!qmldirFile.exists()) {
+ qWarning() << "qmldir file not found at" << modulePath;
return QVariantMap();
+ }
- qmldirFile.open(QIODevice::ReadOnly | QIODevice::Text);
-
- // A qml import may contain several plugins
- QString plugins;
- QString classnames;
- QStringList dependencies;
- QByteArray line;
- do {
- line = qmldirFile.readLine();
- if (line.startsWith("plugin")) {
- plugins += QString::fromUtf8(line.split(' ').at(1));
- plugins += QLatin1Char(' ');
- } else if (line.startsWith("classname")) {
- classnames += QString::fromUtf8(line.split(' ').at(1));
- classnames += QLatin1Char(' ');
- } else if (line.startsWith("depends")) {
- const QList<QByteArray> dep = line.split(' ');
- if (dep.length() != 3)
- std::cerr << "depends: expected 2 arguments: module identifier and version" << std::endl;
- else
- dependencies << QString::fromUtf8(dep[1]) + QLatin1Char(' ') + QString::fromUtf8(dep[2]).simplified();
- }
+ if (!qmldirFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning() << "qmldir file not found at" << modulePath;
+ return QVariantMap();
+ }
- } while (line.length() > 0);
+ QQmlDirParser parser;
+ parser.parse(QString::fromUtf8(qmldirFile.readAll()));
+ if (parser.hasError()) {
+ qWarning() << "qmldir file malformed at" << modulePath;
+ for (const auto error : parser.errors(QLatin1String("qmldir")))
+ qWarning() << error.message;
+ return QVariantMap();
+ }
QVariantMap pluginInfo;
- pluginInfo[pluginsLiteral()] = plugins.simplified();
- pluginInfo[classnamesLiteral()] = classnames.simplified();
- if (dependencies.length())
- pluginInfo[dependenciesLiteral()] = dependencies;
+
+ QStringList pluginNameList;
+ const auto plugins = parser.plugins();
+ for (const auto plugin : plugins)
+ pluginNameList.append(plugin.name);
+ pluginInfo[pluginsLiteral()] = pluginNameList.join(QLatin1Char(' '));
+
+ pluginInfo[classnamesLiteral()] = parser.classNames().join(QLatin1Char(' '));
+
+ QStringList importsAndDependencies;
+ const auto dependencies = parser.dependencies();
+ for (const auto &dependency : dependencies)
+ importsAndDependencies.append(dependency.typeName + versionSuffix(dependency.version));
+
+ const auto imports = parser.imports();
+ for (const auto &import : imports) {
+ if (import.isAutoImport) {
+ importsAndDependencies.append(
+ import.module + QLatin1Char(' ')
+ + (version.isEmpty() ? QString::fromLatin1("auto") : version));
+ } else if (import.version.isValid()) {
+ importsAndDependencies.append(import.module + versionSuffix(import.version));
+ } else {
+ importsAndDependencies.append(import.module);
+ }
+ }
+
+ QVariantList importsFromFiles;
+ const auto components = parser.components();
+ for (const auto component : components) {
+ importsFromFiles
+ += findQmlImportsInQmlFile(modulePath + QLatin1Char('/') + component.fileName);
+ }
+ const auto scripts = parser.scripts();
+ for (const auto script : scripts) {
+ importsFromFiles
+ += findQmlImportsInJavascriptFile(modulePath + QLatin1Char('/') + script.fileName);
+ }
+
+ for (const QVariant &import : importsFromFiles) {
+ const QVariantMap details = qvariant_cast<QVariantMap>(import);
+ if (details.value(typeLiteral()) != moduleLiteral())
+ continue;
+ const QString name = details.value(nameLiteral()).toString();
+ const QString version = details.value(versionLiteral()).toString();
+ importsAndDependencies.append(
+ version.isEmpty() ? name : (name + QLatin1Char(' ') + version));
+ }
+
+ if (!importsAndDependencies.isEmpty())
+ pluginInfo[dependenciesLiteral()] = importsAndDependencies;
return pluginInfo;
}
@@ -238,13 +287,15 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
for (int i = 0; i < importsCopy.length(); ++i) {
QVariantMap import = qvariant_cast<QVariantMap>(importsCopy.at(i));
if (import.value(typeLiteral()) == moduleLiteral()) {
+ const QString version = import.value(versionLiteral()).toString();
const QPair<QString, QString> paths =
- resolveImportPath(import.value(nameLiteral()).toString(), import.value(versionLiteral()).toString());
+ resolveImportPath(import.value(nameLiteral()).toString(), version);
+ QVariantMap plugininfo;
if (!paths.first.isEmpty()) {
import.insert(pathLiteral(), paths.first);
import.insert(relativePathLiteral(), paths.second);
+ plugininfo = pluginsForModulePath(paths.first, version);
}
- QVariantMap plugininfo = pluginsForModulePath(import.value(pathLiteral()).toString());
QString plugins = plugininfo.value(pluginsLiteral()).toString();
QString classnames = plugininfo.value(classnamesLiteral()).toString();
if (!plugins.isEmpty())
@@ -254,15 +305,20 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
if (plugininfo.contains(dependenciesLiteral())) {
const QStringList dependencies = plugininfo.value(dependenciesLiteral()).toStringList();
for (const QString &line : dependencies) {
- const auto dep = QStringView{line}.split(QLatin1Char(' '));
+ const auto dep = QStringView{line}.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ const QString name = dep[0].toString();
QVariantMap depImport;
depImport[typeLiteral()] = moduleLiteral();
- depImport[nameLiteral()] = dep[0].toString();
- depImport[versionLiteral()] = dep[1].toString();
- importsCopy.append(depImport);
+ depImport[nameLiteral()] = name;
+ if (dep.length() > 1)
+ depImport[versionLiteral()] = dep[1].toString();
+
+ if (!importsCopy.contains(depImport))
+ importsCopy.append(depImport);
}
}
}
+ import.remove(versionLiteral());
done.append(import);
}
return done;
@@ -326,7 +382,8 @@ struct ImportCollector : public QQmlJS::Directives
} else {
entry[typeLiteral()] = moduleLiteral();
entry[nameLiteral()] = uri;
- entry[versionLiteral()] = version;
+ if (!version.isEmpty())
+ entry[versionLiteral()] = version;
}
imports << entry;
@@ -452,18 +509,6 @@ QVariantList findQmlImportsInDirectory(const QString &qmlDir)
return ret;
}
-QSet<QString> importModulePaths(const QVariantList &imports) {
- QSet<QString> ret;
- for (const QVariant &importVariant : imports) {
- QVariantMap import = qvariant_cast<QVariantMap>(importVariant);
- QString path = import.value(pathLiteral()).toString();
- QString type = import.value(typeLiteral()).toString();
- if (type == moduleLiteral() && !path.isEmpty())
- ret.insert(QDir(path).canonicalPath());
- }
- return ret;
-}
-
// Find qml imports recursively from a root set of qml files.
// The directories in qmlDirs are searched recursively.
// The files in qmlFiles parsed directly.
@@ -483,23 +528,6 @@ QVariantList findQmlImportsRecursively(const QStringList &qmlDirs, const QString
ret = mergeImports(ret, imports);
}
- // Get the paths to the imports found in the app qml
- QSet<QString> toVisit = importModulePaths(ret);
-
- // Recursively scan for import dependencies.
- QSet<QString> visited;
- while (!toVisit.isEmpty()) {
- QString qmlDir = *toVisit.begin();
- toVisit.erase(toVisit.begin());
- visited.insert(qmlDir);
-
- QVariantList imports = findQmlImportsInDirectory(qmlDir);
- ret = mergeImports(ret, imports);
-
- QSet<QString> candidatePaths = importModulePaths(ret);
- candidatePaths.subtract(visited);
- toVisit.unite(candidatePaths);
- }
return ret;
}