File 0001-qmlcachegen-fix-crash-on-unresolved-type-with-requir.patch of Package qt6-declarative

From 79079a0c6df5e02c4c47003fb88656c37aaf3d0a Mon Sep 17 00:00:00 2001
From: Sami Shalayel <sami.shalayel@qt.io>
Date: Thu, 5 Jun 2025 10:51:46 +0200
Subject: [PATCH] qmlcachegen: fix crash on unresolved type with required
 property
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

qmlcachegen can't resolve all types when importing QtQuick.Controls, so
scopes from QtQuick.Controls might be unresolved.
Check the scope before creating a fix suggesion when checking the
required properties, and add a test that tests a file with required
properties on an unresolved base type "Tumbler".

This also fixes the crashes from QTBUG-137196 and QTBUG-136998 it seems.

Pick-to: 6.9 6.8 6.5
Fixes: QTBUG-137411
Fixes: QTBUG-137196
Fixes: QTBUG-136998
Change-Id: Ibf461b54abf84ba13bff8c4833940c7359cf2d8e
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit c9713681e8d0ee7b7a69d38c5972ee73e8ee4b78)
---
 src/qmlcompiler/qqmljsimportvisitor.cpp       | 21 ++++----
 .../data/crashes/buggyFixSuggestion.qml       | 25 +++++++++
 .../auto/qml/qmlcachegen/tst_qmlcachegen.cpp  | 54 +++++++++++++++++++
 3 files changed, 90 insertions(+), 10 deletions(-)
 create mode 100644 tests/auto/qml/qmlcachegen/data/crashes/buggyFixSuggestion.qml

diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 2a1f31e..e2371a5 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -1041,16 +1041,17 @@ void QQmlJSImportVisitor::checkRequiredProperties()
                     : u"here"_s;
 
             if (!prevRequiredScope.isNull()) {
-                auto sourceScope = prevRequiredScope->baseType();
-                suggestion = QQmlJSFixSuggestion{
-                    "%1:%2:%3: Property marked as required in %4."_L1
-                            .arg(sourceScope->filePath())
-                            .arg(sourceScope->sourceLocation().startLine)
-                            .arg(sourceScope->sourceLocation().startColumn)
-                            .arg(requiredScopeName),
-                    sourceScope->sourceLocation()
-                };
-                suggestion->setFilename(sourceScope->filePath());
+                if (auto sourceScope = prevRequiredScope->baseType()) {
+                    suggestion = QQmlJSFixSuggestion{
+                        "%1:%2:%3: Property marked as required in %4."_L1
+                                .arg(sourceScope->filePath())
+                                .arg(sourceScope->sourceLocation().startLine)
+                                .arg(sourceScope->sourceLocation().startColumn)
+                                .arg(requiredScopeName),
+                        sourceScope->sourceLocation()
+                    };
+                    suggestion->setFilename(sourceScope->filePath());
+                }
             } else {
                 message += " (marked as required by %1)"_L1.arg(requiredScopeName);
             }
diff --git a/tests/auto/qml/qmlcachegen/data/crashes/buggyFixSuggestion.qml b/tests/auto/qml/qmlcachegen/data/crashes/buggyFixSuggestion.qml
new file mode 100644
index 0000000..f435d2e
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/crashes/buggyFixSuggestion.qml
@@ -0,0 +1,25 @@
+import QtQuick
+
+Item {
+    id: root
+
+    Item {
+        id: inner
+
+        Tumbler {
+            id: year
+
+            delegate: Rectangle {
+                required property var modelData
+            }
+        }
+
+        Tumbler {
+            id: month
+
+            delegate: Rectangle {
+                required property var modelData
+            }
+        }
+    }
+}
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 3c602f5..bb8fc5c 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -73,6 +73,9 @@ private slots:
     void aotstatsSerialization();
     void aotstatsGeneration_data();
     void aotstatsGeneration();
+
+    void crash_data();
+    void crash();
 };
 
 // A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -121,6 +124,36 @@ static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr
     return proc.exitCode() == 0;
 }
 
+static bool generateCpp(const QString &qmlFileName, QByteArray *capturedStderr = nullptr)
+{
+#if defined(QTEST_CROSS_COMPILED)
+    QTest::qFail("You cannot call qmlcachegen on the target.", __FILE__, __LINE__);
+    return false;
+#endif
+    QProcess proc;
+    if (capturedStderr == nullptr)
+        proc.setProcessChannelMode(QProcess::ForwardedChannels);
+    proc.setProgram(QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath)
+                    + QLatin1String("/qmlcachegen"));
+    QTemporaryDir outputDir;
+    const QString outputFile = outputDir.filePath("output.cpp"_L1);
+    proc.setArguments(QStringList{ "--resource-path"_L1, "qrc:/qt/qml/Crashes/testFile.qml"_L1,
+                                   "-o"_L1, outputFile, qmlFileName });
+    proc.start();
+    if (!proc.waitForFinished())
+        return false;
+
+    if (capturedStderr)
+        *capturedStderr = proc.readAllStandardError();
+
+    if (!QFile::exists(outputFile))
+        return false;
+
+    if (proc.exitStatus() != QProcess::NormalExit)
+        return false;
+    return proc.exitCode() == 0;
+}
+
 tst_qmlcachegen::tst_qmlcachegen()
     : QQmlDataTest(QT_QMLTEST_DATADIR)
 {
@@ -1023,6 +1056,27 @@ void tst_qmlcachegen::aotstatsGeneration()
     }
 }
 
+void tst_qmlcachegen::crash_data()
+{
+    QTest::addColumn<QString>("fileName");
+
+    QTest::addRow("buggyFixSuggestion") << u"buggyFixSuggestion.qml"_s;
+}
+
+void tst_qmlcachegen::crash()
+{
+#if defined(QTEST_CROSS_COMPILED)
+    QSKIP("Cannot call qmlcachegen on cross-compiled target.");
+#endif
+
+    QFETCH(QString, fileName);
+    const QString filePath = testFile("crashes/" + fileName);
+
+    QFile file(filePath);
+    QVERIFY(file.exists());
+    QVERIFY(generateCpp(filePath));
+}
+
 const QQmlScriptString &ScriptStringProps::undef() const
 {
     return m_undef;
-- 
2.49.0

openSUSE Build Service is sponsored by