aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake2
-rw-r--r--src/qml/Qt6QmlMacros.cmake42
-rw-r--r--src/qml/qml/qqml.cpp8
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp6
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp105
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h17
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp10
-rw-r--r--tests/auto/qml/qmllint/data/Things/qmldir1
-rw-r--r--tests/auto/qml/qmllint/data/optionalImport.qml5
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp1
-rw-r--r--tools/qmlimportscanner/main.cpp2
12 files changed, 123 insertions, 78 deletions
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index d74b1d55fe..0e702feea2 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -39,6 +39,7 @@ function(qt_internal_add_qml_module target)
set(qml_module_multi_args
IMPORTS
+ OPTIONAL_IMPORTS
TYPEINFO
DEPENDENCIES
)
@@ -134,6 +135,7 @@ function(qt_internal_add_qml_module target)
VERSION ${arg_VERSION}
QML_FILES ${arg_QML_FILES}
IMPORTS "${arg_IMPORTS}"
+ OPTIONAL_IMPORTS "${arg_OPTIONAL_IMPORTS}"
TYPEINFO "${arg_TYPEINFO}"
DO_NOT_INSTALL_METADATA
DO_NOT_CREATE_TARGET
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index 4bd457311a..0afd365948 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -63,6 +63,11 @@
# as version to forward the version the current module is being imported with,
# e.g. QtQuick/auto. (OPTIONAL)
#
+# OPTIONAL_IMPORTS: List of other Qml Modules that this module may import at
+# run-time. Those are not automatically imported by the QML engine when
+# importing the current module, but rather serve as hints to tools like
+# qmllint. Versions can be specified in the same as for IMPORT. (OPTIONAL)
+#
# RESOURCE_EXPORT: In static builds, when Qml files are processed via the Qt
# Quick Compiler generate a separate static library that will be linked in
# as an Interface. Supply an output variable to perform any custom actions
@@ -109,6 +114,7 @@ function(qt6_add_qml_module target)
SOURCES
QML_FILES
IMPORTS
+ OPTIONAL_IMPORTS
DEPENDENCIES
)
@@ -283,23 +289,29 @@ function(qt6_add_qml_module target)
# plugins.qmltypes is actually generated.
string(APPEND qmldir_file_contents "typeinfo plugins.qmltypes\n")
endif()
- foreach(import IN LISTS arg_IMPORTS)
- string(FIND ${import} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
- string(APPEND qmldir_file_contents "import ${import}\n")
- else()
- string(SUBSTRING ${import} 0 ${slash_position} import_module)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${import} ${slash_position} -1 import_version)
- if (import_version MATCHES "[0-9]+\\.[0-9]+" OR import_version MATCHES "[0-9]+")
- string(APPEND qmldir_file_contents "import ${import_module} ${import_version}\n")
- elseif (import_version MATCHES "auto")
- string(APPEND qmldir_file_contents "import ${import_module} auto\n")
+
+ macro(_add_imports imports import_string)
+ foreach(import IN LISTS ${imports})
+ string(FIND ${import} "/" slash_position REVERSE)
+ if (slash_position EQUAL -1)
+ string(APPEND qmldir_file_contents "${import_string} ${import}\n")
else()
- message(FATAL_ERROR "Invalid module import version number. Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'.")
+ string(SUBSTRING ${import} 0 ${slash_position} import_module)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING ${import} ${slash_position} -1 import_version)
+ if (import_version MATCHES "[0-9]+\\.[0-9]+" OR import_version MATCHES "[0-9]+")
+ string(APPEND qmldir_file_contents "${import_string} ${import_module} ${import_version}\n")
+ elseif (import_version MATCHES "auto")
+ string(APPEND qmldir_file_contents "${import_string} ${import_module} auto\n")
+ else()
+ message(FATAL_ERROR "Invalid module ${import_string} version number. Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'.")
+ endif()
endif()
- endif()
- endforeach()
+ endforeach()
+ endmacro()
+
+ _add_imports(arg_IMPORTS "import")
+ _add_imports(arg_OPTIONAL_IMPORTS "optional import")
foreach(dependency IN LISTS arg_DEPENDENCIES)
string(FIND ${dependency} "/" slash_position REVERSE)
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index d26a09b081..e61cf417e3 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -75,12 +75,12 @@ void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor)
static QQmlDirParser::Import resolveImport(const QString &uri, int importMajor, int importMinor)
{
if (importMajor == QQmlModuleImportAuto)
- return QQmlDirParser::Import(uri, QTypeRevision(), true);
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Auto);
else if (importMajor == QQmlModuleImportLatest)
- return QQmlDirParser::Import(uri, QTypeRevision(), false);
+ return QQmlDirParser::Import(uri, QTypeRevision(), QQmlDirParser::Import::Default);
else if (importMinor == QQmlModuleImportLatest)
- return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), false);
- return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), false);
+ return QQmlDirParser::Import(uri, QTypeRevision::fromMajorVersion(importMajor), QQmlDirParser::Import::Default);
+ return QQmlDirParser::Import(uri, QTypeRevision::fromVersion(importMajor, importMinor), QQmlDirParser::Import::Default);
}
static QTypeRevision resolveModuleVersion(int moduleMajor)
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 16b05898d1..71fc753c3b 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -724,7 +724,7 @@ void QQmlMetaType::registerModuleImport(const QString &uri, QTypeRevision module
static bool operator==(const QQmlDirParser::Import &a, const QQmlDirParser::Import &b)
{
- return a.module == b.module && a.version == b.version && a.isAutoImport == b.isAutoImport;
+ return a.module == b.module && a.version == b.version && a.flags == b.flags;
}
void QQmlMetaType::unregisterModuleImport(const QString &uri, QTypeRevision moduleVersion,
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 6b4ce26c97..1b14467266 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -742,11 +742,13 @@ bool QQmlTypeLoader::Blob::loadImportDependencies(PendingImportPtr currentImport
= QQmlMetaType::moduleImports(currentImport->uri, currentImport->version)
+ qmldir.imports();
for (const auto &implicitImport : implicitImports) {
+ if (implicitImport.flags & QQmlDirParser::Import::Optional)
+ continue;
auto dependencyImport = std::make_shared<PendingImport>();
dependencyImport->uri = implicitImport.module;
dependencyImport->qualifier = currentImport->qualifier;
- dependencyImport->version = implicitImport.isAutoImport ? currentImport->version
- : implicitImport.version;
+ dependencyImport->version = (implicitImport.flags & QQmlDirParser::Import::Auto)
+ ? currentImport->version : implicitImport.version;
if (!addImport(dependencyImport, QQmlImports::ImportLowPrecedence, errors)) {
QQmlError error;
error.setDescription(
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 0588e5bca7..403c04b1e1 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -110,6 +110,50 @@ bool QQmlDirParser::parse(const QString &source)
quint16 lineNumber = 0;
bool firstLine = true;
+ auto readImport = [&](const QString *sections, int sectionCount, Import::Flags flags) {
+ Import import;
+ if (sectionCount == 2) {
+ import = Import(sections[1], QTypeRevision(), flags);
+ } else if (sectionCount == 3) {
+ if (sections[2] == QLatin1String("auto")) {
+ import = Import(sections[1], QTypeRevision(), flags | Import::Auto);
+ } else {
+ const auto version = parseVersion(sections[2]);
+ if (version.isValid()) {
+ import = Import(sections[1], version, flags);
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("invalid version %1, expected <major>.<minor>")
+ .arg(sections[2]));
+ return false;
+ }
+ }
+ } else {
+ reportError(lineNumber, 0,
+ QStringLiteral("%1 requires 1 or 2 arguments, but %2 were provided")
+ .arg(sections[0]).arg(sectionCount - 1));
+ return false;
+ }
+ if (sections[0] == QStringLiteral("import"))
+ _imports.append(import);
+ else
+ _dependencies.append(import);
+ return true;
+ };
+
+ auto readPlugin = [&](const QString *sections, int sectionCount, bool isOptional) {
+ if (sectionCount < 2 || sectionCount > 3) {
+ reportError(lineNumber, 0, QStringLiteral("plugin directive requires one or two "
+ "arguments, but %1 were provided")
+ .arg(sectionCount - 1));
+ return false;
+ }
+
+ const Plugin entry(sections[1], sections[2], isOptional);
+ _plugins.append(entry);
+ return true;
+ };
+
const QChar *ch = source.constData();
while (!ch->isNull()) {
++lineNumber;
@@ -176,34 +220,26 @@ bool QQmlDirParser::parse(const QString &source)
_typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) {
- if (sectionCount < 2 || sectionCount > 3) {
- reportError(lineNumber, 0,
- QStringLiteral("plugin directive requires one or two arguments, but %1 were provided")
- .arg(sectionCount - 1));
-
+ if (!readPlugin(sections, sectionCount, false))
continue;
- }
-
- const Plugin entry(sections[1], sections[2], false);
-
- _plugins.append(entry);
-
} else if (sections[0] == QLatin1String("optional")) {
- if (sectionCount < 2 || sections[1] != QLatin1String("plugin")) {
- reportError(lineNumber, 0, QStringLiteral("only plugins can be optional"));
+ if (sectionCount < 2) {
+ reportError(lineNumber, 0, QStringLiteral("optional directive requires further "
+ "arguments, but none were provided."));
continue;
}
- if (sectionCount < 3 || sectionCount > 4) {
- reportError(lineNumber, 0,
- QStringLiteral("plugin directive requires one or two arguments, but %1 were provided")
- .arg(sectionCount - 2));
+ if (sections[1] == QStringLiteral("plugin")) {
+ if (!readPlugin(sections + 1, sectionCount - 1, true))
+ continue;
+ } else if (sections[1] == QLatin1String("import")) {
+ if (!readImport(sections + 1, sectionCount - 1, Import::Optional))
+ continue;
+ } else {
+ reportError(lineNumber, 0, QStringLiteral("only import and plugin can be optional, "
+ "not %1.").arg(sections[1]));
continue;
}
-
- const Plugin entry(sections[2], sections[3], true);
- _plugins.append(entry);
-
} else if (sections[0] == QLatin1String("classname")) {
if (sectionCount < 2) {
reportError(lineNumber, 0,
@@ -261,33 +297,8 @@ bool QQmlDirParser::parse(const QString &source)
_designerSupported = true;
} else if (sections[0] == QLatin1String("import")
|| sections[0] == QLatin1String("depends")) {
- Import import;
- if (sectionCount == 2) {
- import = Import(sections[1], QTypeRevision(), false);
- } else if (sectionCount == 3) {
- if (sections[2] == QLatin1String("auto")) {
- import = Import(sections[1], QTypeRevision(), true);
- } else {
- const auto version = parseVersion(sections[2]);
- if (version.isValid()) {
- import = Import(sections[1], version, false);
- } else {
- reportError(lineNumber, 0,
- QStringLiteral("invalid version %1, expected <major>.<minor>")
- .arg(sections[2]));
- continue;
- }
- }
- } else {
- reportError(lineNumber, 0,
- QStringLiteral("%1 requires 1 or 2 arguments, but %2 were provided")
- .arg(sections[0]).arg(sectionCount - 1));
+ if (!readImport(sections, sectionCount, Import::Default))
continue;
- }
- if (sections[0] == QStringLiteral("import"))
- _imports.append(import);
- else
- _dependencies.append(import);
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], QTypeRevision());
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index 48f808ff12..098b15a51b 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -134,13 +134,22 @@ public:
struct Import
{
+ enum Flag {
+ Default = 0x0,
+ Auto = 0x1, // forward the version of the importing module
+ Optional = 0x2 // is not automatically imported but only a tooling hint
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
Import() = default;
- Import(QString module, QTypeRevision version, bool isAutoImport)
- : module(module), version(version), isAutoImport(isAutoImport) {}
+ Import(QString module, QTypeRevision version, Flags flags)
+ : module(module), version(version), flags(flags)
+ {
+ }
QString module;
- QTypeRevision version; // default: lastest version
- bool isAutoImport = false; // if set: forward the version of the importing module
+ QTypeRevision version; // invalid version is latest version, unless Flag::Auto
+ Flags flags;
};
QMultiHash<QString,Component> components() const;
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index 73d7637d79..e33538b653 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -89,14 +89,15 @@ void QQmlJSImporter::readQmltypes(
for (const QString &dependency : qAsConst(dependencyStrings)) {
const auto blank = dependency.indexOf(u' ');
if (blank < 0) {
- dependencies->append(QQmlDirParser::Import(dependency, {}, false));
+ dependencies->append(QQmlDirParser::Import(dependency, {},
+ QQmlDirParser::Import::Default));
continue;
}
const QString module = dependency.left(blank);
const QString versionString = dependency.mid(blank + 1).trimmed();
if (versionString == QStringLiteral("auto")) {
- dependencies->append(QQmlDirParser::Import(module, {}, true));
+ dependencies->append(QQmlDirParser::Import(module, {}, QQmlDirParser::Import::Auto));
continue;
}
@@ -107,7 +108,8 @@ void QQmlJSImporter::readQmltypes(
: QTypeRevision::fromVersion(versionString.left(dot).toUShort(),
versionString.mid(dot + 1).toUShort());
- dependencies->append(QQmlDirParser::Import(module, version, false));
+ dependencies->append(QQmlDirParser::Import(module, version,
+ QQmlDirParser::Import::Default));
}
}
@@ -174,7 +176,7 @@ void QQmlJSImporter::importDependencies(
for (auto const &import : qAsConst(import.imports)) {
importHelper(import.module, types, prefix,
- import.isAutoImport ? version : import.version);
+ (import.flags & QQmlDirParser::Import::Auto) ? version : import.version);
}
}
diff --git a/tests/auto/qml/qmllint/data/Things/qmldir b/tests/auto/qml/qmllint/data/Things/qmldir
index 554f75d313..3c48ae0648 100644
--- a/tests/auto/qml/qmllint/data/Things/qmldir
+++ b/tests/auto/qml/qmllint/data/Things/qmldir
@@ -3,3 +3,4 @@ Something 1.0 SomethingElse.qml
typeinfo plugins.qmltypes
depends QtQuick 2.0
import QtQml
+optional import QtQuick.LocalStorage auto
diff --git a/tests/auto/qml/qmllint/data/optionalImport.qml b/tests/auto/qml/qmllint/data/optionalImport.qml
new file mode 100644
index 0000000000..2be7cd444a
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/optionalImport.qml
@@ -0,0 +1,5 @@
+import Things 6.0
+
+QtObject {
+ property var db: LocalStorage.openDatabaseSync("foo", "2", "bar", 4)
+}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 09ffd2c9ec..4c18253b0c 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -282,6 +282,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("enumFromQtQml") << QStringLiteral("enumFromQtQml.qml");
QTest::newRow("anchors1") << QStringLiteral("anchors1.qml");
QTest::newRow("anchors2") << QStringLiteral("anchors2.qml");
+ QTest::newRow("optionalImport") << QStringLiteral("optionalImport.qml");
}
void TestQmllint::cleanQmlCode()
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 5729c74855..70dec3ed96 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -191,7 +191,7 @@ QVariantMap pluginsForModulePath(const QString &modulePath, const QString &versi
const auto imports = parser.imports();
for (const auto &import : imports) {
- if (import.isAutoImport) {
+ if (import.flags & QQmlDirParser::Import::Auto) {
importsAndDependencies.append(
import.module + QLatin1Char(' ')
+ (version.isEmpty() ? QString::fromLatin1("auto") : version));