qmldir: Allow for specifying default imports
Adds the option to specify default optional imports in qmldir for tooling to load. Previously we would just load all entries. This allows code that that relies on modules utilizing optional imports (i.e. everything utilizing QtQuick.Controls) to still be supported in a limited capacity. This change also adds the necessary CMake API to add these entries to qmldir files. It also disables loading optional imports by default and only leaves them enabled for qmllint. Change-Id: Iff6aaac9cb0ec72b7a2853b60840a4d28c84aa25 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
0f0987c160
commit
2ea887cca0
|
@ -36,6 +36,7 @@ macro(qt_internal_get_internal_add_qml_module_keywords
|
|||
IMPORTS
|
||||
IMPORT_PATH
|
||||
OPTIONAL_IMPORTS
|
||||
DEFAULT_IMPORTS
|
||||
DEPENDENCIES
|
||||
PAST_MAJOR_VERSIONS
|
||||
)
|
||||
|
|
|
@ -66,6 +66,7 @@ function(qt6_add_qml_module target)
|
|||
IMPORTS
|
||||
IMPORT_PATH
|
||||
OPTIONAL_IMPORTS
|
||||
DEFAULT_IMPORTS
|
||||
DEPENDENCIES
|
||||
PAST_MAJOR_VERSIONS
|
||||
)
|
||||
|
@ -382,7 +383,7 @@ function(qt6_add_qml_module target)
|
|||
set(arg_TYPEINFO ${target}.qmltypes)
|
||||
endif()
|
||||
|
||||
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS)
|
||||
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS DEFAULT_IMPORTS)
|
||||
foreach(import IN LISTS arg_${import_set})
|
||||
string(FIND ${import} "/" slash_position REVERSE)
|
||||
if (slash_position EQUAL -1)
|
||||
|
@ -986,6 +987,8 @@ function(_qt_internal_target_generate_qmldir target)
|
|||
|
||||
_qt_internal_qmldir_item_list(import QT_QML_MODULE_IMPORTS)
|
||||
_qt_internal_qmldir_item_list("optional import" QT_QML_MODULE_OPTIONAL_IMPORTS)
|
||||
_qt_internal_qmldir_item_list("default import" QT_QML_MODULE_DEFAULT_IMPORTS)
|
||||
|
||||
_qt_internal_qmldir_item_list(depends QT_QML_MODULE_DEPENDENCIES)
|
||||
|
||||
get_target_property(prefix ${target} QT_QML_MODULE_RESOURCE_PREFIX)
|
||||
|
|
|
@ -52,6 +52,7 @@ qt_add_qml_module(
|
|||
[TYPEINFO typeinfo]
|
||||
[IMPORTS ...]
|
||||
[OPTIONAL_IMPORTS ...]
|
||||
[DEFAULT_IMPORTS ...]
|
||||
[DEPENDENCIES ...]
|
||||
[IMPORT_PATH ...]
|
||||
[SOURCES ...]
|
||||
|
@ -469,6 +470,15 @@ like \c qmllint. Versions can be specified in the same way as for \c IMPORTS.
|
|||
Each module listed here will be added as an \c{optional import} entry in the
|
||||
generated \l{Module Definition qmldir Files}{qmldir} file.
|
||||
|
||||
\c DEFAULT_IMPORTS specifies which of the optional imports are the default entries
|
||||
that should be loaded by tooling. One entry should be specified for every group of
|
||||
\c OPTIONAL_IMPORTS in the module. As optional imports are only resolved at runtime,
|
||||
tooling like qmllint cannot in general know which of the optional imports should
|
||||
be resolved. To remedy this, you can specify one of the optional imports as the
|
||||
default import; tooling will then pick it. If you have one optional import that
|
||||
gets used at runtime without any further configuration, that is an ideal candidate
|
||||
for the default import.
|
||||
|
||||
\c DEPENDENCIES provides a list of other QML modules that this module depends
|
||||
on, but doesn't necessarily import. It would typically be used for dependencies
|
||||
that only exist at the C++ level, such as a module registering a class to QML
|
||||
|
|
|
@ -241,6 +241,23 @@ bool QQmlDirParser::parse(const QString &source)
|
|||
"not %1.").arg(sections[1]));
|
||||
continue;
|
||||
}
|
||||
} else if (sections[0] == QLatin1String("default")) {
|
||||
if (sectionCount < 2) {
|
||||
reportError(lineNumber, 0,
|
||||
QStringLiteral("default directive requires further "
|
||||
"arguments, but none were provided."));
|
||||
continue;
|
||||
}
|
||||
if (sections[1] == QLatin1String("import")) {
|
||||
if (!readImport(sections + 1, sectionCount - 1,
|
||||
Import::Flags({ Import::Optional, Import::OptionalDefault })))
|
||||
continue;
|
||||
} else {
|
||||
reportError(lineNumber, 0,
|
||||
QStringLiteral("only optional imports can have a a defaultl, "
|
||||
"not %1.")
|
||||
.arg(sections[1]));
|
||||
}
|
||||
} else if (sections[0] == QLatin1String("classname")) {
|
||||
if (sectionCount < 2) {
|
||||
reportError(lineNumber, 0,
|
||||
|
|
|
@ -134,9 +134,11 @@ 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
|
||||
Default = 0x0,
|
||||
Auto = 0x1, // forward the version of the importing module
|
||||
Optional = 0x2, // is not automatically imported but only a tooling hint
|
||||
OptionalDefault =
|
||||
0x4, // tooling hint only, denotes this entry should be imported by tooling
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
|
|
|
@ -271,11 +271,29 @@ void QQmlJSImporter::importDependencies(const QQmlJSImporter::Import &import,
|
|||
for (auto const &dependency : qAsConst(import.dependencies))
|
||||
importHelper(dependency.module, types, QString(), dependency.version, true);
|
||||
|
||||
bool hasOptionalImports = false;
|
||||
for (auto const &import : qAsConst(import.imports)) {
|
||||
if (import.flags & QQmlDirParser::Import::Optional) {
|
||||
hasOptionalImports = true;
|
||||
if (!m_useOptionalImports) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(import.flags & QQmlDirParser::Import::OptionalDefault))
|
||||
continue;
|
||||
}
|
||||
|
||||
importHelper(import.module, types, isDependency ? QString() : prefix,
|
||||
(import.flags & QQmlDirParser::Import::Auto) ? version : import.version,
|
||||
isDependency);
|
||||
}
|
||||
|
||||
if (hasOptionalImports && !m_useOptionalImports) {
|
||||
m_warnings.append(
|
||||
{ u"%1 uses optional imports which are not supported. Some types might not be found."_qs
|
||||
.arg(import.name),
|
||||
QtCriticalMsg, QQmlJS::SourceLocation() });
|
||||
}
|
||||
}
|
||||
|
||||
static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry,
|
||||
|
|
|
@ -50,10 +50,12 @@ class QQmlJSImporter
|
|||
public:
|
||||
using ImportedTypes = QHash<QString, QQmlJSImportedScope>;
|
||||
|
||||
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper)
|
||||
: m_importPaths(importPaths)
|
||||
, m_builtins({})
|
||||
, m_mapper(mapper)
|
||||
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
|
||||
bool useOptionalImports = false)
|
||||
: m_importPaths(importPaths),
|
||||
m_builtins({}),
|
||||
m_mapper(mapper),
|
||||
m_useOptionalImports(useOptionalImports)
|
||||
{}
|
||||
|
||||
QQmlJSResourceFileMapper *resourceFileMapper() { return m_mapper; }
|
||||
|
@ -153,6 +155,7 @@ private:
|
|||
QList<QQmlJS::DiagnosticMessage> m_warnings;
|
||||
AvailableTypes m_builtins;
|
||||
QQmlJSResourceFileMapper *m_mapper = nullptr;
|
||||
bool m_useOptionalImports;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -69,7 +69,7 @@ private:
|
|||
};
|
||||
|
||||
QQmlJSLinter::QQmlJSLinter(const QStringList &importPaths, bool useAbsolutePath)
|
||||
: m_useAbsolutePath(useAbsolutePath), m_importer(importPaths, nullptr)
|
||||
: m_useAbsolutePath(useAbsolutePath), m_importer(importPaths, nullptr, true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,14 @@ qt_internal_add_qml_module(QuickControls2
|
|||
IMPORTS
|
||||
QtQuick.Controls.impl/auto
|
||||
OPTIONAL_IMPORTS
|
||||
QtQuick.Controls.Basic/auto
|
||||
QtQuick.Controls.Fusion/auto
|
||||
QtQuick.Controls.Material/auto
|
||||
QtQuick.Controls.Imagine/auto
|
||||
QtQuick.Controls.Universal/auto
|
||||
QtQuick.Controls.Windows/auto
|
||||
QtQuick.Controls.macOS/auto
|
||||
DEFAULT_IMPORTS
|
||||
QtQuick.Controls.Basic/auto
|
||||
NO_PLUGIN_OPTIONAL
|
||||
NO_GENERATE_PLUGIN_SOURCE
|
||||
SOURCES
|
||||
|
|
|
@ -3,4 +3,4 @@ Something 1.0 SomethingElse.qml
|
|||
typeinfo plugins.qmltypes
|
||||
depends QtQuick 2.0
|
||||
import QtQml 2.0
|
||||
optional import QtQuick.LocalStorage auto
|
||||
default import QtQuick.LocalStorage auto
|
||||
|
|
|
@ -939,7 +939,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");
|
||||
QTest::newRow("defaultImport") << QStringLiteral("defaultImport.qml");
|
||||
QTest::newRow("goodAliasObject") << QStringLiteral("goodAliasObject.qml");
|
||||
QTest::newRow("jsmoduleimport") << QStringLiteral("jsmoduleimport.qml");
|
||||
QTest::newRow("overridescript") << QStringLiteral("overridescript.qml");
|
||||
|
|
Loading…
Reference in New Issue