aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-05-11 17:36:08 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2021-05-14 16:39:40 +0200
commit04c2546b82d0609fcaab2e792e2b1e0794dca9eb (patch)
tree807df2b256daab607af986e55c4731dbd5caf3bd
parentf3ed98bf09885795de160468fd615c9e07d5ed5d (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.cpp23
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h3
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp3
-rw-r--r--src/qmlcompiler/qqmljslogger_p.h3
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h5
-rw-r--r--tests/auto/qml/qmllint/data/inlineComponent.qml14
-rw-r--r--tests/auto/qml/qmllint/data/nestedInlineComponents.qml7
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp4
-rw-r--r--tools/qmllint/findwarnings.cpp8
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);