aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-03-16 14:50:24 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-03-19 16:37:44 +0100
commitf726d237277de0f4c8f276d20a5bb1b6a8cd007c (patch)
treeb6e089eb68027297447bcd2cfd633830679855f5
parent266dbbef1fdc34a9740458e86f0a0ee3fffa3f98 (diff)
qmllint: Break inheritance cycles
Previously we would run into infinite loops on those. Mind that qmllint will reject a file called Window.qml that imports QtQuick.Window and then instantiates a Window {}. Such a thing is bad style. Task-number: QTBUG-82817 Change-Id: I6db82ca1794c3020dcb7d7e837fe44f72bca5029 Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--tests/auto/qml/qmllint/data/Cycle1.qml2
-rw-r--r--tests/auto/qml/qmllint/data/Cycle2.qml2
-rw-r--r--tests/auto/qml/qmllint/data/Cycle3.qml2
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp4
-rw-r--r--tools/qmllint/findunqualified.cpp17
5 files changed, 27 insertions, 0 deletions
diff --git a/tests/auto/qml/qmllint/data/Cycle1.qml b/tests/auto/qml/qmllint/data/Cycle1.qml
new file mode 100644
index 0000000000..8095e9f732
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Cycle1.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+Cycle2 {}
diff --git a/tests/auto/qml/qmllint/data/Cycle2.qml b/tests/auto/qml/qmllint/data/Cycle2.qml
new file mode 100644
index 0000000000..90c376fcda
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Cycle2.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+Cycle3 {}
diff --git a/tests/auto/qml/qmllint/data/Cycle3.qml b/tests/auto/qml/qmllint/data/Cycle3.qml
new file mode 100644
index 0000000000..f4cba68653
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/Cycle3.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+Cycle1 {}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index ed968d6623..8697495a6f 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -164,6 +164,10 @@ void TestQmllint::dirtyQmlCode_data()
<< QStringLiteral("incompleteQmltypes.qml")
<< QString("Warning: Type \"QPalette\" of member \"palette\" not found at 5:26")
<< QString();
+ QTest::newRow("inheritanceCylce")
+ << QStringLiteral("Cycle1.qml")
+ << QString("Warning: Cycle2 is part of an inheritance cycle: Cycle2 -> Cycle3 -> Cycle1 -> Cycle2")
+ << QString();
}
void TestQmllint::dirtyQmlCode()
diff --git a/tools/qmllint/findunqualified.cpp b/tools/qmllint/findunqualified.cpp
index 5bb9b62529..9bb9395015 100644
--- a/tools/qmllint/findunqualified.cpp
+++ b/tools/qmllint/findunqualified.cpp
@@ -367,11 +367,28 @@ void FindUnqualifiedIDVisitor::importFileOrDirectory(const QString &fileOrDirect
void FindUnqualifiedIDVisitor::importExportedNames(const QStringRef &prefix, QString name)
{
+ QList<ScopeTree::ConstPtr> scopes;
for (;;) {
ScopeTree::ConstPtr scope = m_exportedName2Scope.value(m_exportedName2Scope.contains(name)
? name
: prefix + QLatin1Char('.') + name);
if (scope) {
+ if (scopes.contains(scope)) {
+ QString inheritenceCycle = name;
+ for (const auto seen: qAsConst(scopes)) {
+ inheritenceCycle.append(QLatin1String(" -> "));
+ inheritenceCycle.append(seen->superclassName());
+ }
+
+ m_colorOut.write(QLatin1String("Warning: "), Warning);
+ m_colorOut.write(QString::fromLatin1("%1 is part of an inheritance cycle: %2\n")
+ .arg(name)
+ .arg(inheritenceCycle));
+ m_unknownImports.insert(name);
+ m_visitFailed = true;
+ break;
+ }
+ scopes.append(scope);
const auto properties = scope->properties();
for (auto property : properties) {
property.setType(m_exportedName2Scope.value(property.typeName()).get());