summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier De Cannière <olivier.decanniere@qt.io>2023-05-11 09:52:24 +0200
committerOlivier De Cannière <olivier.decanniere@qt.io>2023-05-12 15:06:42 +0200
commit5860c9c12c1c948ce1498da30581bfd5b9c05988 (patch)
tree46be2f41ebc66900ad8259a809cdb1327bc9c5b7
parent825d23a84687e67818dfff0485d08cd6d7186de3 (diff)
downloadqtdeclarative-5860c9c12c1c948ce1498da30581bfd5b9c05988.tar.gz
qmllint: Separate logic by import type in QQmlJSImportVisitor::visit
This patch reorganizes the logic of the import visitor to deal with each import type (paths, qrc: urls, file: urls) separately. This reorganisation fixes QTBUG-108803 which happened because "qrc:" imports were being treated as paths leading to things like ":/untitled/qrc:/untitled/components". Fixes: QTBUG-108803 Pick-to: 6.5 Change-Id: I5af20d10c533455215895be66b5cd98a977fd18a Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp110
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h5
-rw-r--r--tests/auto/qml/qmllint/data/untitled/components/Foo.qml5
-rw-r--r--tests/auto/qml/qmllint/data/untitled/main.qml9
-rw-r--r--tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc6
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp11
6 files changed, 100 insertions, 46 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index ddf9a1a588..8873047697 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -2149,63 +2149,81 @@ void QQmlJSImportVisitor::addImportWithLocation(const QString &name,
m_importLocations.insert(loc);
}
+void QQmlJSImportVisitor::importFromHost(const QString &path, const QString &prefix,
+ const QQmlJS::SourceLocation &location)
+{
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile()) {
+ const auto scope = m_importer->importFile(path);
+ const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix;
+ m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
+ addImportWithLocation(actualPrefix, location);
+ } else if (fileInfo.isDir()) {
+ const auto scopes = m_importer->importDirectory(path, prefix);
+ m_rootScopeImports.addTypes(scopes);
+ for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++)
+ addImportWithLocation(*it, location);
+ }
+}
+
+void QQmlJSImportVisitor::importFromQrc(const QString &path, const QString &prefix,
+ const QQmlJS::SourceLocation &location)
+{
+ if (const auto &mapper = m_importer->resourceFileMapper()) {
+ if (mapper->isFile(path)) {
+ const auto entry = m_importer->resourceFileMapper()->entry(
+ QQmlJSResourceFileMapper::resourceFileFilter(path));
+ const auto scope = m_importer->importFile(entry.filePath);
+ const QString actualPrefix =
+ prefix.isEmpty() ? QFileInfo(entry.resourcePath).baseName() : prefix;
+ m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
+ addImportWithLocation(actualPrefix, location);
+ } else {
+ const auto scopes = m_importer->importDirectory(path, prefix);
+ m_rootScopeImports.addTypes(scopes);
+ for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++)
+ addImportWithLocation(*it, location);
+ }
+ }
+}
+
bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
{
- auto addImportLocation = [this, import](const QString &name) {
- addImportWithLocation(name, import->firstSourceLocation());
- };
// construct path
QString prefix = QLatin1String("");
if (import->asToken.isValid()) {
prefix += import->importId;
}
+
auto filename = import->fileName.toString();
if (!filename.isEmpty()) {
- const QFileInfo file(filename);
- const QString absolute = file.isRelative()
- ? QDir::cleanPath(QDir(m_implicitImportDirectory).filePath(filename))
- : filename;
-
- if (absolute.startsWith(u':')) {
- if (m_importer->resourceFileMapper()) {
- if (m_importer->resourceFileMapper()->isFile(absolute.mid(1))) {
- const auto entry = m_importer->resourceFileMapper()->entry(
- QQmlJSResourceFileMapper::resourceFileFilter(absolute.mid(1)));
- const auto scope = m_importer->importFile(entry.filePath);
- const QString actualPrefix = prefix.isEmpty()
- ? QFileInfo(entry.resourcePath).baseName()
- : prefix;
- m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
-
- addImportLocation(actualPrefix);
- } else {
- const auto scopes = m_importer->importDirectory(absolute, prefix);
- m_rootScopeImports.addTypes(scopes);
- for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end;
- it++)
- addImportLocation(*it);
- }
+ const QUrl url(filename);
+ const QString scheme = url.scheme();
+ const QQmlJS::SourceLocation importLocation = import->firstSourceLocation();
+ if (scheme == ""_L1) {
+ QFileInfo fileInfo(url.path());
+ QString absolute = fileInfo.isRelative()
+ ? QDir::cleanPath(QDir(m_implicitImportDirectory).filePath(filename))
+ : filename;
+ if (absolute.startsWith(u':')) {
+ importFromQrc(absolute, prefix, importLocation);
+ } else {
+ importFromHost(absolute, prefix, importLocation);
}
-
- processImportWarnings(QStringLiteral("URL \"%1\"").arg(absolute), import->firstSourceLocation());
+ processImportWarnings("path \"%1\""_L1.arg(url.path()), importLocation);
return true;
+ } else if (scheme == "file"_L1) {
+ importFromHost(url.path(), prefix, importLocation);
+ processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation);
+ return true;
+ } else if (scheme == "qrc"_L1) {
+ importFromQrc(":"_L1 + url.path(), prefix, importLocation);
+ processImportWarnings("URL \"%1\""_L1.arg(url.path()), importLocation);
+ return true;
+ } else {
+ m_logger->log("Unknown import syntax. Imports can be paths, qrc urls or file urls"_L1,
+ qmlImport, import->firstSourceLocation());
}
-
- QFileInfo path(absolute);
- if (path.isDir()) {
- const auto scopes = m_importer->importDirectory(path.canonicalFilePath(), prefix);
- m_rootScopeImports.addTypes(scopes);
- for (auto it = scopes.types().keyBegin(), end = scopes.types().keyEnd(); it != end; it++)
- addImportLocation(*it);
- } else if (path.isFile()) {
- const auto scope = m_importer->importFile(path.canonicalFilePath());
- const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix;
- m_rootScopeImports.setType(actualPrefix, { scope, QTypeRevision() });
- addImportLocation(actualPrefix);
- }
-
- processImportWarnings(QStringLiteral("path \"%1\"").arg(path.canonicalFilePath()), import->firstSourceLocation());
- return true;
}
const QString path = buildName(import->importUri);
@@ -2217,7 +2235,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
&staticModulesProvided);
m_rootScopeImports.addTypes(imported);
for (auto it = imported.types().keyBegin(), end = imported.types().keyEnd(); it != end; it++)
- addImportLocation(*it);
+ addImportWithLocation(*it, import->firstSourceLocation());
if (prefix.isEmpty()) {
for (const QString &staticModule : staticModulesProvided) {
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 3d9f094334..0a23704e71 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -347,6 +347,11 @@ private:
void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
const QQmlJS::SourceLocation &location);
+ void importFromHost(const QString &path, const QString &prefix,
+ const QQmlJS::SourceLocation &location);
+ void importFromQrc(const QString &path, const QString &prefix,
+ const QQmlJS::SourceLocation &location);
+
public:
friend class QQmlJS::Dom::QQmlDomAstCreatorWithQQmlJSScope;
};
diff --git a/tests/auto/qml/qmllint/data/untitled/components/Foo.qml b/tests/auto/qml/qmllint/data/untitled/components/Foo.qml
new file mode 100644
index 0000000000..10e5741900
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/untitled/components/Foo.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Text {
+ text: "Here I am!"
+}
diff --git a/tests/auto/qml/qmllint/data/untitled/main.qml b/tests/auto/qml/qmllint/data/untitled/main.qml
new file mode 100644
index 0000000000..cf8980ab55
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/untitled/main.qml
@@ -0,0 +1,9 @@
+pragma Strict
+
+import QtQuick
+import 'qrc:/untitled/components' as C
+
+Window {
+ id: root
+ C.Foo {}
+}
diff --git a/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc b/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc
new file mode 100644
index 0000000000..0ad0d57fbb
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/untitled/">
+ <file alias="main.qml">main.qml</file>
+ <file alias="components/Foo.qml">components/Foo.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 56705712d0..110017b371 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -79,6 +79,8 @@ private Q_SLOTS:
void additionalImplicitImport();
+ void qrcUrlImport();
+
void attachedPropertyReuse();
void missingBuiltinsNoCrash();
@@ -1654,7 +1656,16 @@ void TestQmllint::additionalImplicitImport()
const auto guard = qScopeGuard([this]() {m_linter.clearCache(); });
runTest("additionalImplicitImport.qml", Result::clean(), {}, {},
{ testFile("implicitImportResource.qrc") });
+}
+void TestQmllint::qrcUrlImport()
+{
+ const auto guard = qScopeGuard([this]() { m_linter.clearCache(); });
+
+ QJsonArray warnings;
+ callQmllint(testFile("untitled/main.qml"), true, &warnings, {}, {},
+ { testFile("untitled/qrcUrlImport.qrc") });
+ checkResult(warnings, Result::clean());
}
void TestQmllint::attachedPropertyReuse()