diff options
author | Maximilian Goldstein <max.goldstein@qt.io> | 2021-05-11 17:36:08 +0200 |
---|---|---|
committer | Maximilian Goldstein <max.goldstein@qt.io> | 2021-05-14 16:39:40 +0200 |
commit | 04c2546b82d0609fcaab2e792e2b1e0794dca9eb (patch) | |
tree | 807df2b256daab607af986e55c4731dbd5caf3bd | |
parent | f3ed98bf09885795de160468fd615c9e07d5ed5d (diff) |
qmllint: Add inline component support
Adds support for inline components for qmllint with a few things not working yet:
- Two inline components referencing each other
- Using inline components before they are declared
These two issues require a larger overhaul of qmllint as a whole and will be addressed in a different change.
Change-Id: I2834702c21a8eb728db4709d6f475c33796b3e4d
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 23 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor_p.h | 3 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljslogger.cpp | 3 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljslogger_p.h | 3 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 5 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/inlineComponent.qml | 14 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/data/nestedInlineComponents.qml | 7 | ||||
-rw-r--r-- | tests/auto/qml/qmllint/tst_qmllint.cpp | 4 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 8 |
9 files changed, 64 insertions, 6 deletions
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index e3ecd54714..a41faf5557 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -342,6 +342,11 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) m_currentScope->setAnnotations(parseAnnotations(definition->annotations)); + if (!m_inlineComponentName.isNull()) { + m_currentScope->setIsInlineComponent(true); + m_rootScopeImports.insert(m_inlineComponentName.toString(), m_currentScope); + } + QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); return true; } @@ -349,9 +354,27 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition) void QQmlJSImportVisitor::endVisit(UiObjectDefinition *) { QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes); + leaveEnvironment(); } +bool QQmlJSImportVisitor::visit(UiInlineComponent *component) +{ + if (!m_inlineComponentName.isNull()) { + m_logger.log(u"Nested inline components are not supported"_qs, Log_Syntax, + component->firstSourceLocation()); + return true; + } + + m_inlineComponentName = component->name; + return true; +} + +void QQmlJSImportVisitor::endVisit(UiInlineComponent *) +{ + m_inlineComponentName = QStringView(); +} + bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember) { switch (publicMember->type) { diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h index 0aa9a18b55..a2bdf86f9e 100644 --- a/src/qmlcompiler/qqmljsimportvisitor_p.h +++ b/src/qmlcompiler/qqmljsimportvisitor_p.h @@ -75,6 +75,8 @@ protected: void endVisit(QQmlJS::AST::UiProgram *) override; bool visit(QQmlJS::AST::UiObjectDefinition *) override; void endVisit(QQmlJS::AST::UiObjectDefinition *) override; + bool visit(QQmlJS::AST::UiInlineComponent *) override; + void endVisit(QQmlJS::AST::UiInlineComponent *) override; bool visit(QQmlJS::AST::UiPublicMember *) override; bool visit(QQmlJS::AST::UiRequired *required) override; bool visit(QQmlJS::AST::UiScriptBinding *) override; @@ -123,6 +125,7 @@ protected: void throwRecursionDepthError() override; QString m_implicitImportDirectory; + QStringView m_inlineComponentName; QStringList m_qmltypesFiles; QQmlJSScope::Ptr m_currentScope; QQmlJSScope::Ptr m_exportedRootScope; diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp index d6ef349d83..496e62fe80 100644 --- a/src/qmlcompiler/qqmljslogger.cpp +++ b/src/qmlcompiler/qqmljslogger.cpp @@ -87,8 +87,9 @@ QQmlJSLogger::QQmlJSLogger(const QString &fileName, const QString &code, bool si m_categoryDisabled[it.value().m_category] = it.value().m_disabled; } - // This has to be set up manually since we don't expose it as an option + // These have to be set up manually since we don't expose it as an option m_categoryLevels[Log_RecursionDepthError] = QtCriticalMsg; + m_categoryLevels[Log_Syntax] = QtCriticalMsg; // setup color output m_output.insertMapping(QtCriticalMsg, QColorOutput::RedForeground); diff --git a/src/qmlcompiler/qqmljslogger_p.h b/src/qmlcompiler/qqmljslogger_p.h index dd8338b669..66e53b4a90 100644 --- a/src/qmlcompiler/qqmljslogger_p.h +++ b/src/qmlcompiler/qqmljslogger_p.h @@ -100,7 +100,8 @@ enum QQmlJSLoggerCategory { Log_UnqualifiedAccess, Log_UnusedImport, Log_MultilineString, - QQmlJSLoggerCategory_Last = Log_MultilineString + Log_Syntax, + QQmlJSLoggerCategory_Last = Log_Syntax }; class QQmlJSLogger diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index e3463c5192..f61cd7b2eb 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -114,7 +114,8 @@ public: Singleton = 0x4, Script = 0x8, CustomParser = 0x10, - Array = 0x20 + Array = 0x20, + InlineComponent = 0x40 }; Q_DECLARE_FLAGS(Flags, Flag) Q_FLAGS(Flags); @@ -274,6 +275,7 @@ public: bool isScript() const { return m_flags & Script; } bool hasCustomParser() const { return m_flags & CustomParser; } bool isArrayScope() const { return m_flags & Array; } + bool isInlineComponent() const { return m_flags & InlineComponent; } void setIsSingleton(bool v) { m_flags.setFlag(Singleton, v); } void setIsCreatable(bool v) { m_flags.setFlag(Creatable, v); } void setIsComposite(bool v) { m_flags.setFlag(Composite, v); } @@ -283,6 +285,7 @@ public: m_flags.setFlag(CustomParser, v);; } void setIsArrayScope(bool v) { m_flags.setFlag(Array, v); } + void setIsInlineComponent(bool v) { m_flags.setFlag(InlineComponent, v); } void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; } AccessSemantics accessSemantics() const { return m_semantics; } diff --git a/tests/auto/qml/qmllint/data/inlineComponent.qml b/tests/auto/qml/qmllint/data/inlineComponent.qml new file mode 100644 index 0000000000..ce6998a980 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inlineComponent.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + component IC : QtObject {} + QtObject { + component IC2: QtObject {} + + property IC ic: IC {} + property IC2 ic2: IC2 {} + } + + property IC ic : IC {} + property IC2 ic2: IC2 {} +} diff --git a/tests/auto/qml/qmllint/data/nestedInlineComponents.qml b/tests/auto/qml/qmllint/data/nestedInlineComponents.qml new file mode 100644 index 0000000000..e2a32df092 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nestedInlineComponents.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + component IC: QtObject { + component IC2: QtObject {} + } +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index d6f5088a9d..330ca0b8f1 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -615,6 +615,9 @@ void TestQmllint::dirtyQmlCode_data() << QStringLiteral("unresolvedAttachedType.qml") << QStringLiteral("unknown attached property scope UnresolvedAttachedType.") << QStringLiteral("Property \"property\" is invalid or does not exist") << false; + QTest::newRow("nestedInlineComponents") + << QStringLiteral("nestedInlineComponents.qml") + << QStringLiteral("Nested inline components are not supported") << QString() << false; } void TestQmllint::dirtyQmlCode() @@ -748,6 +751,7 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("QVariant") << QStringLiteral("qvariant.qml"); QTest::newRow("Accessible") << QStringLiteral("accessible.qml"); QTest::newRow("qjsroot") << QStringLiteral("qjsroot.qml"); + QTest::newRow("InlineComponent") << QStringLiteral("inlineComponent.qml"); } void TestQmllint::cleanQmlCode() diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp index 4041cac8df..ce78d8285b 100644 --- a/tools/qmllint/findwarnings.cpp +++ b/tools/qmllint/findwarnings.cpp @@ -144,7 +144,8 @@ void FindWarningVisitor::flushPendingSignalParameters() void FindWarningVisitor::checkDefaultProperty(const QQmlJSScope::ConstPtr &scope) { - if (scope == m_exportedRootScope || scope->isArrayScope()) // inapplicable + if (scope == m_exportedRootScope || scope->isArrayScope() + || scope->isInlineComponent()) // inapplicable return; // These warnings do not apply for custom parsers and their children and need to be handled on a @@ -670,8 +671,9 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiPublicMember *uipb) if (uipb->type == QQmlJS::AST::UiPublicMember::Property && uipb->memberType != nullptr && !uipb->memberType->name.isEmpty() && uipb->memberType->name != QLatin1String("alias")) { const auto name = uipb->memberType->name.toString(); - if (m_importTypeLocationMap.contains(name)) { - m_usedTypes.insert(name); + if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].isNull()) { + if (m_importTypeLocationMap.contains(name)) + m_usedTypes.insert(name); } else { m_logger.log(name + QStringLiteral(" was not found. Did you add all import paths?"), Log_Import); |