diff options
author | Sami Shalayel <[email protected]> | 2025-01-27 15:41:40 +0100 |
---|---|---|
committer | Sami Shalayel <[email protected]> | 2025-03-06 19:23:04 +0100 |
commit | 313d473d700e2dfda8e060d3ce577b598314d0d3 (patch) | |
tree | f8c3438f611f56c6fed3d572e4d7607eeda0fdfa | |
parent | 7d3b8d0c649aa8a2846ae7a2546e9c751c3b2d98 (diff) |
qdslintplugin: add UnsupportedRootTypeInQmlUi warning
Implement ErrUnsupportedTypeInQmlUi that warns about unsupported root
types in .ui.qml files. Also reuse the same warning message.
Task-number: QTBUG-129308
Change-Id: I83a2cb39367ea3fe6ac65ab1e0b16c04cf467d73
Reviewed-by: Ulf Hermann <[email protected]>
5 files changed, 83 insertions, 15 deletions
diff --git a/src/plugins/qmllint/qds/plugin.json b/src/plugins/qmllint/qds/plugin.json index a77ef0398b..9d9d482510 100644 --- a/src/plugins/qmllint/qds/plugin.json +++ b/src/plugins/qmllint/qds/plugin.json @@ -29,6 +29,11 @@ "name": "InvalidIdeInVisualDesigner", "settingsName": "InvalidIdeInVisualDesigner", "description": "Warn about ambiguous id names in ui.qml files" + }, + { + "name": "UnsupportedRootTypeInQmlUi", + "settingsName": "UnsupportedRootTypeInQmlUi", + "description": "Warn about unsupported root types in ui.qml files" } ] } diff --git a/src/plugins/qmllint/qds/qdslintplugin.cpp b/src/plugins/qmllint/qds/qdslintplugin.cpp index 04a5620c33..9855ac3a52 100644 --- a/src/plugins/qmllint/qds/qdslintplugin.cpp +++ b/src/plugins/qmllint/qds/qdslintplugin.cpp @@ -7,6 +7,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtCore/qhash.h> #include <QtCore/qset.h> +#include <QtCore/qspan.h> QT_BEGIN_NAMESPACE @@ -29,6 +30,9 @@ static constexpr LoggerWarningId ErrUnsupportedTypeInQmlUi{ static constexpr LoggerWarningId ErrInvalidIdeInVisualDesigner{ "QtDesignStudio.InvalidIdeInVisualDesigner" }; +static constexpr LoggerWarningId ErrUnsupportedRootTypeInQmlUi{ + "QtDesignStudio.UnsupportedRootTypeInQmlUi" +}; class FunctionCallValidator : public PropertyPass { @@ -71,7 +75,16 @@ private: std::make_pair("QtQml.Models"_L1, "Package"_L1), std::make_pair("QtQuick"_L1, "ShaderEffect"_L1), }; + using UnsupportedName = decltype(s_unsupportedElementNames)::value_type; std::array<Element, s_unsupportedElementNames.size()> m_unsupportedElements; + + static constexpr std::array s_unsupportedRootNames = { + std::make_pair("QtQml.Models"_L1, "ListModel"_L1), + std::make_pair("QtQml.Models"_L1, "Package"_L1), + std::make_pair("QtQml"_L1, "Timer"_L1), + }; + std::array<Element, s_unsupportedRootNames.size()> m_unsupportedRootElements; + Element m_qtObject; }; void QdsBindingValidator::onRead(const QQmlSA::Element &element, const QString &propertyName, @@ -216,25 +229,49 @@ void FunctionCallValidator::onCall(const Element &element, const QString &proper QdsElementValidator::QdsElementValidator(PassManager *manager) : ElementPass(manager) { - for (qsizetype i = 0; i < qsizetype(s_unsupportedElementNames.size()); ++i) { - if (!manager->hasImportedModule(s_unsupportedElementNames[i].first)) - continue; - m_unsupportedElements[i] = resolveType(s_unsupportedElementNames[i].first, - s_unsupportedElementNames[i].second); - } + auto loadTypes = [&manager, this](QSpan<const UnsupportedName> names, QSpan<Element> output) { + for (qsizetype i = 0; i < qsizetype(names.size()); ++i) { + if (!manager->hasImportedModule(names[i].first)) + continue; + output[i] = resolveType(names[i].first, names[i].second); + } + }; + loadTypes(s_unsupportedElementNames, m_unsupportedElements); + loadTypes(s_unsupportedRootNames, m_unsupportedRootElements); + m_qtObject = resolveType("QtQml"_L1, "QtObject"_L1); } void QdsElementValidator::run(const Element &element) { - for (const auto &unsupportedElement : m_unsupportedElements) { - if (!unsupportedElement || !element.inherits(unsupportedElement)) - continue; - - emitWarning(u"This type (%1) is not supported in a UI file (.ui.qml)."_s.arg( - element.baseTypeName()), - ErrUnsupportedTypeInQmlUi, element.sourceLocation()); - break; - } + enum WarningType { ForElements, ForRootElements }; + auto warnIfElementIsUnsupported = [this, &element](WarningType warningType) { + QSpan<const Element> unsupportedComponents = warningType == ForElements + ? QSpan<const Element>(m_unsupportedElements) + : QSpan<const Element>(m_unsupportedRootElements); + const QStringView message = warningType == ForElements + ? u"This type (%1) is not supported in a UI file (.ui.qml)." + : u"This type (%1) is not supported as a root element of a UI file (.ui.qml)."; + const LoggerWarningId &id = warningType == ForElements ? ErrUnsupportedTypeInQmlUi + : ErrUnsupportedRootTypeInQmlUi; + + for (const auto &unsupportedElement : unsupportedComponents) { + if (!unsupportedElement || !element.inherits(unsupportedElement)) + continue; + + emitWarning(message.arg(element.baseTypeName()), id, element.sourceLocation()); + break; + } + + // special case: we don't want to warn on types indirectly inheriting from QtObject, for + // example Item. + if (warningType == ForRootElements && element.baseType() == m_qtObject) + emitWarning(message.arg(element.baseTypeName()), id, element.sourceLocation()); + }; + + if (element.isFileRootComponent()) + warnIfElementIsUnsupported(ForRootElements); + warnIfElementIsUnsupported(ForElements); + if (QString id = resolveElementToId(element, element); !id.isEmpty()) { static constexpr std::array unsupportedNames = { "action"_L1, "alias"_L1, "anchors"_L1, "as"_L1, "baseState"_L1, diff --git a/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement.ui.qml b/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement.ui.qml new file mode 100644 index 0000000000..4611af3533 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement.ui.qml @@ -0,0 +1,3 @@ +import QtQuick + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement2.ui.qml b/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement2.ui.qml new file mode 100644 index 0000000000..46c1db7a61 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qdsPlugin/UnsupportedRootElement2.ui.qml @@ -0,0 +1,7 @@ +import QtQuick +import QtQml.Models + +ListModel { + +} + diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 7ca19a029b..93994a2926 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -2612,6 +2612,22 @@ void TestQmllint::qdsPlugin_data() QTest::addRow("SupportedElements") << u"qdsPlugin/SupportedElements.ui.qml"_s << Result::clean(); + + QTest::addRow("UnsupportedRootElement") + << u"qdsPlugin/UnsupportedRootElement.ui.qml"_s + << Result{ { + Message{ + u"This type (QtObject) is not supported as a root element of a UI file (.ui.qml)."_s, + 3, 1 }, + } }; + + QTest::addRow("UnsupportedRootElement2") + << u"qdsPlugin/UnsupportedRootElement2.ui.qml"_s + << Result{ { + Message{ + u"This type (ListModel) is not supported as a root element of a UI file (.ui.qml)."_s, + 4, 1 }, + } }; } void TestQmllint::qdsPlugin() |