aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2022-11-23 17:20:47 +0100
committerUlf Hermann <ulf.hermann@qt.io>2022-11-25 00:04:02 +0100
commit6e640a0218b9860f7af79494d87b64690805a1ed (patch)
treef93a52a0382737d0d5baf30df44db930b6eb4111
parent60a18929027cca06fb81d007e81c056465507946 (diff)
QmlCompiler: Store imported types in a QList
The same type can be exported multiple times with different attributes, even in the same module. This requires us to fix directory imports as qmllint otherwise complains about SegFault.bad.qml and SegFault.qml being the same type (which they obviously aren't). Task-number: QTCREATORBUG-27590 Change-Id: I295d927b9a07acbb715055a6883ac44b50129c2d Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp51
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h4
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp5
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader_p.h4
-rw-r--r--src/qmldom/qqmldomtypesreader.cpp2
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/multiforeign.h51
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/multiforeign.qml10
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp11
9 files changed, 115 insertions, 25 deletions
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index f8adeb79c2..c491e6d86e 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -35,7 +35,7 @@ static QQmlDirParser createQmldirParserForFile(const QString &filename)
}
void QQmlJSImporter::readQmltypes(
- const QString &filename, QHash<QString, QQmlJSExportedScope> *objects,
+ const QString &filename, QList<QQmlJSExportedScope> *objects,
QList<QQmlDirParser::Import> *dependencies)
{
const QFileInfo fileInfo(filename);
@@ -198,7 +198,7 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
reader.typeNamespace(), it.key(), it->version, QTypeRevision()));
}
for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
- result.objects.insert(it.key(), it.value());
+ result.objects.append(it.value());
const auto scripts = reader.scripts();
for (const auto &script : scripts) {
@@ -224,7 +224,7 @@ QQmlJSImporter::Import QQmlJSImporter::readDirectory(const QString &directory)
for (const auto &entry : resources) {
const QString name = QFileInfo(entry.resourcePath).baseName();
if (name.front().isUpper()) {
- import.objects.insert(name, {
+ import.objects.append({
localFile2ScopeTree(entry.filePath),
{ QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
});
@@ -244,12 +244,21 @@ QQmlJSImporter::Import QQmlJSImporter::readDirectory(const QString &directory)
QDir::NoFilter
};
while (it.hasNext()) {
- it.next();
- if (!it.fileName().front().isUpper())
- continue; // Non-uppercase names cannot be imported anyway.
+ QString name = it.nextFileInfo().completeBaseName();
- const QString name = QFileInfo(it.filePath()).baseName();
- import.objects.insert(name, {
+ // Non-uppercase names cannot be imported anyway.
+ if (!name.front().isUpper())
+ continue;
+
+ // .ui.qml is fine
+ if (name.endsWith(u".ui"))
+ name = name.chopped(3);
+
+ // Names with dots in them cannot be imported either.
+ if (name.contains(u'.'))
+ continue;
+
+ import.objects.append({
localFile2ScopeTree(it.filePath()),
{ QQmlJSScope::Export(QString(), name, QTypeRevision(), QTypeRevision()) }
});
@@ -415,9 +424,7 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
}
// add objects
- for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
- const auto &val = it.value();
-
+ for (const auto &val : import.objects) {
const QString cppName = isComposite(val.scope)
? prefixedName(anonPrefix, internalName(val.scope))
: internalName(val.scope);
@@ -470,9 +477,7 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
}
}
- for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
- const auto &val = it.value();
-
+ for (const auto &val : qAsConst(import.objects)) {
// Otherwise we have already done it in localFile2ScopeTree()
if (!val.scope.factory() && val.scope->baseType().isNull()) {
@@ -546,10 +551,22 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
const QQmlJSScope::Import builtinImport(
QString(), QStringLiteral("QML"), QTypeRevision::fromVersion(1, 0), false, true);
- const QQmlJSScope::ConstPtr intType = result.objects[u"int"_s].scope;
- Q_ASSERT(intType);
+ QQmlJSScope::ConstPtr intType;
+ QQmlJSScope::ConstPtr arrayType;
+
+ for (const QQmlJSExportedScope &exported : result.objects) {
+ if (exported.scope->internalName() == u"int"_s) {
+ intType = exported.scope;
+ if (!arrayType.isNull())
+ break;
+ } else if (exported.scope->internalName() == u"Array"_s) {
+ arrayType = exported.scope;
+ if (!intType.isNull())
+ break;
+ }
+ }
- const QQmlJSScope::ConstPtr arrayType = result.objects[u"Array"_s].scope;
+ Q_ASSERT(intType);
Q_ASSERT(arrayType);
m_builtins = AvailableTypes(ImportedTypes(
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h
index 017917d3cf..792e26a291 100644
--- a/src/qmlcompiler/qqmljsimporter_p.h
+++ b/src/qmlcompiler/qqmljsimporter_p.h
@@ -115,7 +115,7 @@ private:
bool isStaticModule = false;
bool isSystemModule = false;
- QHash<QString, QQmlJSExportedScope> objects;
+ QList<QQmlJSExportedScope> objects;
QHash<QString, QQmlJSExportedScope> scripts;
QList<QQmlDirParser::Import> imports;
QList<QQmlDirParser::Import> dependencies;
@@ -130,7 +130,7 @@ private:
void importDependencies(const QQmlJSImporter::Import &import, AvailableTypes *types,
const QString &prefix = QString(),
QTypeRevision version = QTypeRevision(), bool isDependency = false);
- void readQmltypes(const QString &filename, QHash<QString, QQmlJSExportedScope> *objects,
+ void readQmltypes(const QString &filename, QList<QQmlJSExportedScope> *objects,
QList<QQmlDirParser::Import> *dependencies);
Import readQmldir(const QString &dirname);
Import readDirectory(const QString &directory);
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
index 8c6368dfde..9360119c5c 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp
+++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
@@ -31,8 +31,7 @@ QString toString(const UiQualifiedId *qualifiedId, QChar delimiter = QLatin1Char
}
bool QQmlJSTypeDescriptionReader::operator()(
- QHash<QString, QQmlJSExportedScope> *objects,
- QStringList *dependencies)
+ QList<QQmlJSExportedScope> *objects, QStringList *dependencies)
{
Engine engine;
@@ -260,7 +259,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
if (metaObjectRevisions)
checkMetaObjectRevisions(metaObjectRevisions, &exports);
- m_objects->insert(scope->internalName(), {scope, exports});
+ m_objects->append({scope, exports});
}
void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod,
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader_p.h b/src/qmlcompiler/qqmljstypedescriptionreader_p.h
index 58a01d6fb8..37dd388308 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader_p.h
+++ b/src/qmlcompiler/qqmljstypedescriptionreader_p.h
@@ -33,7 +33,7 @@ public:
explicit QQmlJSTypeDescriptionReader(QString fileName, QString data)
: m_fileName(std::move(fileName)), m_source(std::move(data)) {}
- bool operator()(QHash<QString, QQmlJSExportedScope> *objects, QStringList *dependencies);
+ bool operator()(QList<QQmlJSExportedScope> *objects, QStringList *dependencies);
QString errorMessage() const { return m_errorMessage; }
QString warningMessage() const { return m_warningMessage; }
@@ -73,7 +73,7 @@ private:
QString m_source;
QString m_errorMessage;
QString m_warningMessage;
- QHash<QString, QQmlJSExportedScope> *m_objects = nullptr;
+ QList<QQmlJSExportedScope> *m_objects = nullptr;
QStringList *m_dependencies = nullptr;
};
diff --git a/src/qmldom/qqmldomtypesreader.cpp b/src/qmldom/qqmldomtypesreader.cpp
index 355ef99eba..69fba60047 100644
--- a/src/qmldom/qqmldomtypesreader.cpp
+++ b/src/qmldom/qqmldomtypesreader.cpp
@@ -246,7 +246,7 @@ bool QmltypesReader::parse()
QQmlJSTypeDescriptionReader reader(qmltypesFilePtr()->canonicalFilePath(),
qmltypesFilePtr()->code());
QStringList dependencies;
- QHash<QString, QQmlJSExportedScope> objects;
+ QList<QQmlJSExportedScope> objects;
m_isValid = reader(&objects, &dependencies);
for (const auto &obj : std::as_const(objects))
insertComponent(obj.scope, obj.exports);
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index b7f8f28aeb..5bb30f1969 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -8,6 +8,7 @@ set(cpp_sources
dynamicmeta.h
gadgetwithenum.h
invisible.h
+ multiforeign.h
objectwithmethod.h
person.cpp person.h
state.h
@@ -119,6 +120,7 @@ set(qml_files
methods.qml
modulePrefix.qml
moveRegVoid.qml
+ multiforeign.qml
noBindingLoop.qml
noQQmlData.qml
nonNotifyable.qml
diff --git a/tests/auto/qml/qmlcppcodegen/data/multiforeign.h b/tests/auto/qml/qmlcppcodegen/data/multiforeign.h
new file mode 100644
index 0000000000..290b6370f5
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/multiforeign.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef MULTIFOREIGN_H
+#define MULTIFOREIGN_H
+
+#include <QtCore/qobject.h>
+#include <QtQml/qqml.h>
+
+class Autochthon : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString location READ location WRITE setLocation NOTIFY locationChanged FINAL)
+
+public:
+ const QString &location() const
+ {
+ return m_location;
+ }
+
+ void setLocation(const QString &newLocation)
+ {
+ if (m_location == newLocation)
+ return;
+ m_location = newLocation;
+ emit locationChanged();
+ }
+
+signals:
+ void locationChanged();
+
+private:
+ QString m_location;
+};
+
+struct Foreign1
+{
+ Q_GADGET
+ QML_FOREIGN(Autochthon)
+ QML_ELEMENT
+};
+
+struct Foreign2
+{
+ Q_GADGET
+ QML_FOREIGN(Autochthon)
+ QML_ELEMENT
+};
+
+
+#endif // MULTIFOREIGN_H
diff --git a/tests/auto/qml/qmlcppcodegen/data/multiforeign.qml b/tests/auto/qml/qmlcppcodegen/data/multiforeign.qml
new file mode 100644
index 0000000000..0db62fe875
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/multiforeign.qml
@@ -0,0 +1,10 @@
+pragma Strict
+import TestTypes
+import QtQml
+
+QtObject {
+ objectName: f1.location + " and " + f2.location
+ property Foreign1 f1: Foreign1 { location: "not here" }
+ property Foreign2 f2: Foreign2 { location: "not there" }
+
+}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 4b4cc6042a..1dd4c0fcf0 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -147,6 +147,7 @@ private slots:
void callWithSpread();
void nullComparison();
void consoleObject();
+ void multiForeign();
};
void tst_QmlCppCodegen::initTestCase()
@@ -2859,6 +2860,16 @@ void tst_QmlCppCodegen::consoleObject()
QVERIFY(!o.isNull());
}
+void tst_QmlCppCodegen::multiForeign()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, QUrl(u"qrc:/qt/qml/TestTypes/multiforeign.qml"_s));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QCOMPARE(o->objectName(), u"not here and not there"_s);
+}
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"