aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmltyperegistrar
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-11-06 12:33:51 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-11-06 22:41:51 +0100
commit421ad80dee10e7b5eff352aecb2986c370f0e487 (patch)
tree152b155b255ac99e9dd34f36dc64d047e89ceb57 /src/qmltyperegistrar
parent68b9ab7b93320a975c2f20c09eddccf0fdb275b7 (diff)
qmltyperegistrar: Move JSON processing into separate class
qmltyperegistrar.cpp was getting unwieldy. Change-Id: I2172253d81c0fca724bb0fef4a96d50a93c47428 Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qmltyperegistrar')
-rw-r--r--src/qmltyperegistrar/.prev_CMakeLists.txt1
-rw-r--r--src/qmltyperegistrar/CMakeLists.txt1
-rw-r--r--src/qmltyperegistrar/metatypesjsonprocessor.cpp335
-rw-r--r--src/qmltyperegistrar/metatypesjsonprocessor.h76
-rw-r--r--src/qmltyperegistrar/qmltyperegistrar.cpp298
-rw-r--r--src/qmltyperegistrar/qmltyperegistrar.pro7
6 files changed, 433 insertions, 285 deletions
diff --git a/src/qmltyperegistrar/.prev_CMakeLists.txt b/src/qmltyperegistrar/.prev_CMakeLists.txt
index 7faf074456..0c4a2b89c6 100644
--- a/src/qmltyperegistrar/.prev_CMakeLists.txt
+++ b/src/qmltyperegistrar/.prev_CMakeLists.txt
@@ -9,6 +9,7 @@ qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "QML Types Registrar"
SOURCES
../qmlcompiler/qqmljsstreamwriter.cpp ../qmlcompiler/qqmljsstreamwriter_p.h
+ metatypesjsonprocessor.cpp metatypesjsonprocessor.h
qmltyperegistrar.cpp
qmltypesclassdescription.cpp qmltypesclassdescription.h
qmltypescreator.cpp qmltypescreator.h
diff --git a/src/qmltyperegistrar/CMakeLists.txt b/src/qmltyperegistrar/CMakeLists.txt
index cefb255cc6..9145a298c9 100644
--- a/src/qmltyperegistrar/CMakeLists.txt
+++ b/src/qmltyperegistrar/CMakeLists.txt
@@ -10,6 +10,7 @@ qt_internal_add_tool(${target_name}
TOOLS_TARGET Qml # special case
SOURCES
../qmlcompiler/qqmljsstreamwriter.cpp ../qmlcompiler/qqmljsstreamwriter_p.h
+ metatypesjsonprocessor.cpp metatypesjsonprocessor.h
qmltyperegistrar.cpp
qmltypesclassdescription.cpp qmltypesclassdescription.h
qmltypescreator.cpp qmltypescreator.h
diff --git a/src/qmltyperegistrar/metatypesjsonprocessor.cpp b/src/qmltyperegistrar/metatypesjsonprocessor.cpp
new file mode 100644
index 0000000000..f71a94c67d
--- /dev/null
+++ b/src/qmltyperegistrar/metatypesjsonprocessor.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "metatypesjsonprocessor.h"
+
+#include <QtCore/qfile.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qqueue.h>
+
+
+bool MetaTypesJsonProcessor::processTypes(const QStringList &files)
+{
+ for (const QString &source: files) {
+ QJsonDocument metaObjects;
+ {
+ QFile f(source);
+ if (!f.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Error opening %s for reading\n", qPrintable(source));
+ return false;
+ }
+ QJsonParseError error = {0, QJsonParseError::NoError};
+ metaObjects = QJsonDocument::fromJson(f.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "Error parsing %s\n", qPrintable(source));
+ return false;
+ }
+ }
+
+ if (metaObjects.isArray()) {
+ const QJsonArray metaObjectsArray = metaObjects.array();
+ for (const QJsonValue metaObject : metaObjectsArray) {
+ if (!metaObject.isObject()) {
+ fprintf(stderr, "Error parsing %s: JSON is not an object\n",
+ qPrintable(source));
+ return false;
+ }
+
+ processTypes(metaObject.toObject());
+ }
+ } else if (metaObjects.isObject()) {
+ processTypes(metaObjects.object());
+ } else {
+ fprintf(stderr, "Error parsing %s: JSON is not an object or an array\n",
+ qPrintable(source));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool MetaTypesJsonProcessor::processForeignTypes(const QStringList &foreignTypesFiles)
+{
+ bool success = true;
+
+ for (const QString &types : foreignTypesFiles) {
+ QFile typesFile(types);
+ if (!typesFile.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open foreign types file %s\n", qPrintable(types));
+ success = false;
+ continue;
+ }
+
+ QJsonParseError error = {0, QJsonParseError::NoError};
+ QJsonDocument foreignMetaObjects = QJsonDocument::fromJson(typesFile.readAll(), &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "Error parsing %s\n", qPrintable(types));
+ success = false;
+ continue;
+ }
+
+ const QJsonArray foreignObjectsArray = foreignMetaObjects.array();
+ for (const QJsonValue metaObject : foreignObjectsArray) {
+ if (!metaObject.isObject()) {
+ fprintf(stderr, "Error parsing %s: JSON is not an object\n",
+ qPrintable(types));
+ success = false;
+ continue;
+ }
+
+ processForeignTypes(metaObject.toObject());
+ }
+ }
+ return success;
+}
+
+void MetaTypesJsonProcessor::postProcessTypes()
+{
+ sortTypes(m_types);
+ sortIncludes();
+}
+
+void MetaTypesJsonProcessor::postProcessForeignTypes()
+{
+ sortTypes(m_foreignTypes);
+ m_types += foreignRelatedTypes();
+ sortTypes(m_types);
+}
+
+MetaTypesJsonProcessor::RegistrationMode MetaTypesJsonProcessor::qmlTypeRegistrationMode(
+ const QJsonObject &classDef)
+{
+ const QJsonArray classInfos = classDef[QLatin1String("classInfos")].toArray();
+ for (const QJsonValue info : classInfos) {
+ const QString name = info[QLatin1String("name")].toString();
+ if (name == QLatin1String("QML.Element")) {
+ if (classDef[QLatin1String("object")].toBool())
+ return ObjectRegistration;
+ if (classDef[QLatin1String("gadget")].toBool())
+ return GadgetRegistration;
+ if (classDef[QLatin1String("namespace")].toBool())
+ return NamespaceRegistration;
+ qWarning() << "Not registering classInfo which is neither an object, "
+ "nor a gadget, nor a namespace:"
+ << name;
+ break;
+ }
+ }
+ return NoRegistration;
+}
+
+QVector<QJsonObject> MetaTypesJsonProcessor::foreignRelatedTypes() const
+{
+ const QLatin1String classInfosKey("classInfos");
+ const QLatin1String nameKey("name");
+ const QLatin1String qualifiedClassNameKey("qualifiedClassName");
+ const QLatin1String qmlNamePrefix("QML.");
+ const QLatin1String qmlForeignName("QML.Foreign");
+ const QLatin1String qmlAttachedName("QML.Attached");
+ const QLatin1String valueKey("value");
+ const QLatin1String superClassesKey("superClasses");
+ const QLatin1String accessKey("access");
+ const QLatin1String publicAccess("public");
+
+ QSet<QString> processedRelatedNames;
+ QQueue<QJsonObject> typeQueue;
+ typeQueue.append(m_types);
+ QVector<QJsonObject> relatedTypes;
+
+ // First mark all classes registered from this module as already processed.
+ for (const QJsonObject &type : m_types) {
+ processedRelatedNames.insert(type.value(qualifiedClassNameKey).toString());
+ const auto classInfos = type.value(classInfosKey).toArray();
+ for (const QJsonValue classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlForeignName) {
+ processedRelatedNames.insert(obj.value(valueKey).toString());
+ break;
+ }
+ }
+ }
+
+ // Then mark all classes registered from other modules as already processed.
+ // We don't want to generate them again for this module.
+ for (const QJsonObject &foreignType : m_foreignTypes) {
+ const auto classInfos = foreignType.value(classInfosKey).toArray();
+ bool seenQmlPrefix = false;
+ for (const QJsonValue classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ const QString name = obj.value(nameKey).toString();
+ if (!seenQmlPrefix && name.startsWith(qmlNamePrefix)) {
+ processedRelatedNames.insert(foreignType.value(qualifiedClassNameKey).toString());
+ seenQmlPrefix = true;
+ }
+ if (name == qmlForeignName) {
+ processedRelatedNames.insert(obj.value(valueKey).toString());
+ break;
+ }
+ }
+ }
+
+ auto addType = [&](const QString &typeName) {
+ if (processedRelatedNames.contains(typeName))
+ return;
+ processedRelatedNames.insert(typeName);
+ if (const QJsonObject *other
+ = QmlTypesClassDescription::findType(m_foreignTypes, typeName)) {
+ relatedTypes.append(*other);
+ typeQueue.enqueue(*other);
+ }
+ };
+
+ // Then recursively iterate the super types and attached types, marking the
+ // ones we are interested in as related.
+ while (!typeQueue.isEmpty()) {
+ const QJsonObject classDef = typeQueue.dequeue();
+
+ const auto classInfos = classDef.value(classInfosKey).toArray();
+ for (const QJsonValue classInfo : classInfos) {
+ const QJsonObject obj = classInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlAttachedName) {
+ addType(obj.value(valueKey).toString());
+ } else if (obj.value(nameKey).toString() == qmlForeignName) {
+ const QString foreignClassName = obj.value(valueKey).toString();
+ if (const QJsonObject *other = QmlTypesClassDescription::findType(
+ m_foreignTypes, foreignClassName)) {
+ const auto otherSupers = other->value(superClassesKey).toArray();
+ if (!otherSupers.isEmpty()) {
+ const QJsonObject otherSuperObject = otherSupers.first().toObject();
+ if (otherSuperObject.value(accessKey).toString() == publicAccess)
+ addType(otherSuperObject.value(nameKey).toString());
+ }
+
+ const auto otherClassInfos = other->value(classInfosKey).toArray();
+ for (const QJsonValue otherClassInfo : otherClassInfos) {
+ const QJsonObject obj = otherClassInfo.toObject();
+ if (obj.value(nameKey).toString() == qmlAttachedName) {
+ addType(obj.value(valueKey).toString());
+ break;
+ }
+ // No, you cannot chain QML_FOREIGN declarations. Sorry.
+ }
+ break;
+ }
+ }
+ }
+
+ const auto supers = classDef.value(superClassesKey).toArray();
+ if (!supers.isEmpty()) {
+ const QJsonObject superObject = supers.first().toObject();
+ if (superObject.value(accessKey).toString() == publicAccess)
+ addType(superObject.value(nameKey).toString());
+ }
+ }
+
+ return relatedTypes;
+}
+
+void MetaTypesJsonProcessor::sortTypes(QVector<QJsonObject> &types)
+{
+ const QLatin1String qualifiedClassNameKey("qualifiedClassName");
+ std::sort(types.begin(), types.end(), [&](const QJsonObject &a, const QJsonObject &b) {
+ return a.value(qualifiedClassNameKey).toString() <
+ b.value(qualifiedClassNameKey).toString();
+ });
+}
+
+void MetaTypesJsonProcessor::sortIncludes()
+{
+ std::sort(m_includes.begin(), m_includes.end());
+ const auto newEnd = std::unique(m_includes.begin(), m_includes.end());
+ m_includes.erase(newEnd, m_includes.end());
+}
+
+QString MetaTypesJsonProcessor::resolvedInclude(const QString &include)
+{
+ return (m_privateIncludes && include.endsWith(QLatin1String("_p.h")))
+ ? QLatin1String("private/") + include
+ : include;
+}
+
+void MetaTypesJsonProcessor::processTypes(const QJsonObject &types)
+{
+ const QString include = resolvedInclude(types[QLatin1String("inputFile")].toString());
+ const QJsonArray classes = types[QLatin1String("classes")].toArray();
+ for (const QJsonValue cls : classes) {
+ QJsonObject classDef = cls.toObject();
+ classDef.insert(QLatin1String("inputFile"), include);
+
+ switch (qmlTypeRegistrationMode(classDef)) {
+ case NamespaceRegistration:
+ case GadgetRegistration:
+ case ObjectRegistration: {
+ if (!include.endsWith(QLatin1String(".h"))
+ && !include.endsWith(QLatin1String(".hpp"))
+ && !include.endsWith(QLatin1String(".hxx"))
+ && include.contains(QLatin1Char('.'))) {
+ fprintf(stderr,
+ "Class %s is declared in %s, which appears not to be a header.\n"
+ "The compilation of its registration to QML may fail.\n",
+ qPrintable(classDef.value(QLatin1String("qualifiedClassName"))
+ .toString()),
+ qPrintable(include));
+ }
+ m_includes.append(include);
+ {
+ bool shouldRegister = true;
+ for (const QJsonValue v :
+ classDef.value(QLatin1String("classInfos")).toArray()) {
+ if (v[QLatin1String("name")].toString()
+ == QLatin1String("QML.ManualRegistration")) {
+ shouldRegister = QStringView(u"true").compare(
+ v[QLatin1String("value")].toString(),
+ Qt::CaseInsensitive) != 0;
+ }
+ }
+ classDef.insert(QLatin1String("registerable"), shouldRegister);
+ }
+
+ m_types.append(classDef);
+ break;
+ }
+ case NoRegistration:
+ m_foreignTypes.append(classDef);
+ break;
+ }
+ }
+}
+
+void MetaTypesJsonProcessor::processForeignTypes(const QJsonObject &types)
+{
+ const QString include = types[QLatin1String("inputFile")].toString();
+ const QJsonArray classes = types[QLatin1String("classes")].toArray();
+ for (const QJsonValue cls : classes) {
+ QJsonObject classDef = cls.toObject();
+ classDef.insert(QLatin1String("inputFile"), include);
+ m_foreignTypes.append(classDef);
+ }
+}
diff --git a/src/qmltyperegistrar/metatypesjsonprocessor.h b/src/qmltyperegistrar/metatypesjsonprocessor.h
new file mode 100644
index 0000000000..341a64a98b
--- /dev/null
+++ b/src/qmltyperegistrar/metatypesjsonprocessor.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METATYPESJSONPROCESSOR_H
+#define METATYPESJSONPROCESSOR_H
+
+#include "qmltypesclassdescription.h"
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qjsonobject.h>
+
+class MetaTypesJsonProcessor
+{
+public:
+ MetaTypesJsonProcessor(bool privateIncludes) : m_privateIncludes(privateIncludes) {}
+
+ bool processTypes(const QStringList &files);
+ bool processForeignTypes(const QStringList &foreignTypesFiles);
+
+ void postProcessTypes();
+ void postProcessForeignTypes();
+
+ QVector<QJsonObject> types() const { return m_types; }
+ QVector<QJsonObject> foreignTypes() const { return m_foreignTypes; }
+ QStringList includes() const { return m_includes; }
+
+private:
+ enum RegistrationMode {
+ NoRegistration,
+ ObjectRegistration,
+ GadgetRegistration,
+ NamespaceRegistration
+ };
+
+ static RegistrationMode qmlTypeRegistrationMode(const QJsonObject &classDef);
+ QVector<QJsonObject> foreignRelatedTypes() const;
+
+ void sortTypes(QVector<QJsonObject> &types);
+ void sortIncludes();
+ QString resolvedInclude(const QString &include);;
+ void processTypes(const QJsonObject &types);
+ void processForeignTypes(const QJsonObject &types);
+
+ QStringList m_includes;
+ QVector<QJsonObject> m_types;
+ QVector<QJsonObject> m_foreignTypes;
+ bool m_privateIncludes = false;
+};
+
+#endif // METATYPESJSONPROCESSOR_H
diff --git a/src/qmltyperegistrar/qmltyperegistrar.cpp b/src/qmltyperegistrar/qmltyperegistrar.cpp
index 2f37d3a963..bf3c4c94d4 100644
--- a/src/qmltyperegistrar/qmltyperegistrar.cpp
+++ b/src/qmltyperegistrar/qmltyperegistrar.cpp
@@ -27,18 +27,17 @@
****************************************************************************/
#include "qmltypescreator.h"
+#include "metatypesjsonprocessor.h"
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QtDebug>
-#include <QJsonDocument>
#include <QJsonArray>
-#include <QJsonValue>
#include <QJsonObject>
+#include <QJsonValue>
#include <QFile>
#include <QScopedPointer>
#include <QSaveFile>
-#include <QQueue>
#include <cstdlib>
@@ -47,34 +46,6 @@ struct ScopedPointerFileCloser
static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
};
-enum RegistrationMode {
- NoRegistration,
- ObjectRegistration,
- GadgetRegistration,
- NamespaceRegistration
-};
-
-static RegistrationMode qmlTypeRegistrationMode(const QJsonObject &classDef)
-{
- const QJsonArray classInfos = classDef[QLatin1String("classInfos")].toArray();
- for (const QJsonValue info : classInfos) {
- const QString name = info[QLatin1String("name")].toString();
- if (name == QLatin1String("QML.Element")) {
- if (classDef[QLatin1String("object")].toBool())
- return ObjectRegistration;
- if (classDef[QLatin1String("gadget")].toBool())
- return GadgetRegistration;
- if (classDef[QLatin1String("namespace")].toBool())
- return NamespaceRegistration;
- qWarning() << "Not registering classInfo which is neither an object, "
- "nor a gadget, nor a namespace:"
- << name;
- break;
- }
- }
- return NoRegistration;
-}
-
static bool argumentsFromCommandLineAndFile(QStringList &allArguments, const QStringList &arguments)
{
allArguments.reserve(arguments.size());
@@ -104,113 +75,6 @@ static bool argumentsFromCommandLineAndFile(QStringList &allArguments, const QSt
return true;
}
-static QVector<QJsonObject> foreignRelatedTypes(const QVector<QJsonObject> &types,
- const QVector<QJsonObject> &foreignTypes)
-{
- const QLatin1String classInfosKey("classInfos");
- const QLatin1String nameKey("name");
- const QLatin1String qualifiedClassNameKey("qualifiedClassName");
- const QLatin1String qmlNamePrefix("QML.");
- const QLatin1String qmlForeignName("QML.Foreign");
- const QLatin1String qmlAttachedName("QML.Attached");
- const QLatin1String valueKey("value");
- const QLatin1String superClassesKey("superClasses");
- const QLatin1String accessKey("access");
- const QLatin1String publicAccess("public");
-
- QSet<QString> processedRelatedNames;
- QQueue<QJsonObject> typeQueue;
- typeQueue.append(types.toList());
- QVector<QJsonObject> relatedTypes;
-
- // First mark all classes registered from this module as already processed.
- for (const QJsonObject &type : types) {
- processedRelatedNames.insert(type.value(qualifiedClassNameKey).toString());
- const auto classInfos = type.value(classInfosKey).toArray();
- for (const QJsonValue classInfo : classInfos) {
- const QJsonObject obj = classInfo.toObject();
- if (obj.value(nameKey).toString() == qmlForeignName) {
- processedRelatedNames.insert(obj.value(valueKey).toString());
- break;
- }
- }
- }
-
- // Then mark all classes registered from other modules as already processed.
- // We don't want to generate them again for this module.
- for (const QJsonObject &foreignType : foreignTypes) {
- const auto classInfos = foreignType.value(classInfosKey).toArray();
- bool seenQmlPrefix = false;
- for (const QJsonValue classInfo : classInfos) {
- const QJsonObject obj = classInfo.toObject();
- const QString name = obj.value(nameKey).toString();
- if (!seenQmlPrefix && name.startsWith(qmlNamePrefix)) {
- processedRelatedNames.insert(foreignType.value(qualifiedClassNameKey).toString());
- seenQmlPrefix = true;
- }
- if (name == qmlForeignName) {
- processedRelatedNames.insert(obj.value(valueKey).toString());
- break;
- }
- }
- }
-
- auto addType = [&](const QString &typeName) {
- if (processedRelatedNames.contains(typeName))
- return;
- processedRelatedNames.insert(typeName);
- if (const QJsonObject *other = QmlTypesClassDescription::findType(foreignTypes, typeName)) {
- relatedTypes.append(*other);
- typeQueue.enqueue(*other);
- }
- };
-
- // Then recursively iterate the super types and attached types, marking the
- // ones we are interested in as related.
- while (!typeQueue.isEmpty()) {
- const QJsonObject classDef = typeQueue.dequeue();
-
- const auto classInfos = classDef.value(classInfosKey).toArray();
- for (const QJsonValue classInfo : classInfos) {
- const QJsonObject obj = classInfo.toObject();
- if (obj.value(nameKey).toString() == qmlAttachedName) {
- addType(obj.value(valueKey).toString());
- } else if (obj.value(nameKey).toString() == qmlForeignName) {
- const QString foreignClassName = obj.value(valueKey).toString();
- if (const QJsonObject *other = QmlTypesClassDescription::findType(
- foreignTypes, foreignClassName)) {
- const auto otherSupers = other->value(superClassesKey).toArray();
- if (!otherSupers.isEmpty()) {
- const QJsonObject otherSuperObject = otherSupers.first().toObject();
- if (otherSuperObject.value(accessKey).toString() == publicAccess)
- addType(otherSuperObject.value(nameKey).toString());
- }
-
- const auto otherClassInfos = other->value(classInfosKey).toArray();
- for (const QJsonValue otherClassInfo : otherClassInfos) {
- const QJsonObject obj = otherClassInfo.toObject();
- if (obj.value(nameKey).toString() == qmlAttachedName) {
- addType(obj.value(valueKey).toString());
- break;
- }
- // No, you cannot chain QML_FOREIGN declarations. Sorry.
- }
- break;
- }
- }
- }
-
- const auto supers = classDef.value(superClassesKey).toArray();
- if (!supers.isEmpty()) {
- const QJsonObject superObject = supers.first().toObject();
- if (superObject.value(accessKey).toString() == publicAccess)
- addType(superObject.value(nameKey).toString());
- }
- }
-
- return relatedTypes;
-}
-
int main(int argc, char **argv)
{
// Produce reliably the same output for the same input by disabling QHash's random seeding.
@@ -303,113 +167,16 @@ int main(int argc, char **argv)
"#include <QtQml/qqml.h>\n"
"#include <QtQml/qqmlmoduleregistration.h>\n");
- QStringList includes;
- QVector<QJsonObject> types;
- QVector<QJsonObject> foreignTypes;
-
const QString module = parser.value(importNameOption);
- const QStringList files = parser.positionalArguments();
- for (const QString &source: files) {
- QJsonDocument metaObjects;
- {
- QFile f(source);
- if (!f.open(QIODevice::ReadOnly)) {
- fprintf(stderr, "Error opening %s for reading\n", qPrintable(source));
- return EXIT_FAILURE;
- }
- QJsonParseError error = {0, QJsonParseError::NoError};
- metaObjects = QJsonDocument::fromJson(f.readAll(), &error);
- if (error.error != QJsonParseError::NoError) {
- fprintf(stderr, "Error parsing %s\n", qPrintable(source));
- return EXIT_FAILURE;
- }
- }
-
- const bool privateIncludes = parser.isSet(privateIncludesOption);
- auto resolvedInclude = [&](const QString &include) {
- return (privateIncludes && include.endsWith(QLatin1String("_p.h")))
- ? QLatin1String("private/") + include
- : include;
- };
-
- auto processMetaObject = [&](const QJsonObject &metaObject) {
- const QString include = resolvedInclude(metaObject[QLatin1String("inputFile")].toString());
- const QJsonArray classes = metaObject[QLatin1String("classes")].toArray();
- for (const QJsonValue cls : classes) {
- QJsonObject classDef = cls.toObject();
- classDef.insert(QLatin1String("inputFile"), include);
-
- switch (qmlTypeRegistrationMode(classDef)) {
- case NamespaceRegistration:
- case GadgetRegistration:
- case ObjectRegistration: {
- if (!include.endsWith(QLatin1String(".h"))
- && !include.endsWith(QLatin1String(".hpp"))
- && !include.endsWith(QLatin1String(".hxx"))
- && include.contains(QLatin1Char('.'))) {
- fprintf(stderr,
- "Class %s is declared in %s, which appears not to be a header.\n"
- "The compilation of its registration to QML may fail.\n",
- qPrintable(classDef.value(QLatin1String("qualifiedClassName"))
- .toString()),
- qPrintable(include));
- }
- includes.append(include);
- {
- bool shouldRegister = true;
- for (const QJsonValue v :
- classDef.value(QLatin1String("classInfos")).toArray()) {
- if (v[QLatin1String("name")].toString() == QLatin1String("QML.ManualRegistration"))
- shouldRegister = QStringView(u"true").compare(v[QLatin1String("value")].toString(), Qt::CaseInsensitive) != 0;
- }
- classDef.insert(QLatin1String("registerable"), shouldRegister);
- }
-
- types.append(classDef);
- break;
- }
- case NoRegistration:
- foreignTypes.append(classDef);
- break;
- }
- }
- };
-
- if (metaObjects.isArray()) {
- const QJsonArray metaObjectsArray = metaObjects.array();
- for (const QJsonValue metaObject : metaObjectsArray) {
- if (!metaObject.isObject()) {
- fprintf(stderr, "Error parsing %s: JSON is not an object\n",
- qPrintable(source));
- return EXIT_FAILURE;
- }
-
- processMetaObject(metaObject.toObject());
- }
- } else if (metaObjects.isObject()) {
- processMetaObject(metaObjects.object());
- } else {
- fprintf(stderr, "Error parsing %s: JSON is not an object or an array\n",
- qPrintable(source));
- return EXIT_FAILURE;
- }
- }
- const QLatin1String qualifiedClassNameKey("qualifiedClassName");
- auto sortTypes = [&](QVector<QJsonObject> &types) {
- std::sort(types.begin(), types.end(), [&](const QJsonObject &a, const QJsonObject &b) {
- return a.value(qualifiedClassNameKey).toString() <
- b.value(qualifiedClassNameKey).toString();
- });
- };
-
- sortTypes(types);
+ MetaTypesJsonProcessor processor(parser.isSet(privateIncludesOption));
+ if (!processor.processTypes(parser.positionalArguments()))
+ return EXIT_FAILURE;
- std::sort(includes.begin(), includes.end());
- const auto newEnd = std::unique(includes.begin(), includes.end());
- includes.erase(newEnd, includes.end());
+ processor.postProcessTypes();
- for (const QString &include : qAsConst(includes))
+ const QStringList includes = processor.includes();
+ for (const QString &include : includes)
fprintf(output, "\n#include <%s>", qPrintable(include));
fprintf(output, "\n\n");
@@ -428,7 +195,8 @@ int main(int argc, char **argv)
qPrintable(module), qPrintable(majorVersion));
}
- for (const QJsonObject &classDef : qAsConst(types)) {
+ const QVector<QJsonObject> types = processor.types();
+ for (const QJsonObject &classDef : types) {
if (!classDef.value(QLatin1String("registerable")).toBool())
continue;
@@ -457,50 +225,14 @@ int main(int argc, char **argv)
if (!parser.isSet(pluginTypesOption))
return EXIT_SUCCESS;
- if (parser.isSet(foreignTypesOption)) {
- const QStringList foreignTypesFiles = parser.value(foreignTypesOption)
- .split(QLatin1Char(','));
- for (const QString &types : foreignTypesFiles) {
- QFile typesFile(types);
- if (!typesFile.open(QIODevice::ReadOnly)) {
- fprintf(stderr, "Cannot open foreign types file %s\n", qPrintable(types));
- continue;
- }
-
- QJsonParseError error = {0, QJsonParseError::NoError};
- QJsonDocument foreignMetaObjects = QJsonDocument::fromJson(typesFile.readAll(), &error);
- if (error.error != QJsonParseError::NoError) {
- fprintf(stderr, "Error parsing %s\n", qPrintable(types));
- continue;
- }
-
- const QJsonArray foreignObjectsArray = foreignMetaObjects.array();
- for (const QJsonValue metaObject : foreignObjectsArray) {
- if (!metaObject.isObject()) {
- fprintf(stderr, "Error parsing %s: JSON is not an object\n",
- qPrintable(types));
- continue;
- }
-
- auto const asObject = metaObject.toObject();
- const QString include = asObject[QLatin1String("inputFile")].toString();
- const QJsonArray classes = asObject[QLatin1String("classes")].toArray();
- for (const QJsonValue cls : classes) {
- QJsonObject classDef = cls.toObject();
- classDef.insert(QLatin1String("inputFile"), include);
- foreignTypes.append(classDef);
- }
- }
- }
- }
+ if (parser.isSet(foreignTypesOption))
+ processor.processForeignTypes(parser.value(foreignTypesOption).split(QLatin1Char(',')));
- sortTypes(foreignTypes);
- types += foreignRelatedTypes(types, foreignTypes);
- sortTypes(types);
+ processor.postProcessForeignTypes();
QmlTypesCreator creator;
- creator.setOwnTypes(std::move(types));
- creator.setForeignTypes(std::move(foreignTypes));
+ creator.setOwnTypes(processor.types());
+ creator.setForeignTypes(processor.foreignTypes());
creator.setModule(module);
creator.setVersion(QTypeRevision::fromVersion(parser.value(majorVersionOption).toInt(), 0));
diff --git a/src/qmltyperegistrar/qmltyperegistrar.pro b/src/qmltyperegistrar/qmltyperegistrar.pro
index eaee9b6eb4..006760994f 100644
--- a/src/qmltyperegistrar/qmltyperegistrar.pro
+++ b/src/qmltyperegistrar/qmltyperegistrar.pro
@@ -14,12 +14,15 @@ SOURCES += \
../qmlcompiler/qqmljsstreamwriter.cpp \
qmltyperegistrar.cpp \
qmltypesclassdescription.cpp \
- qmltypescreator.cpp
+ qmltypescreator.cpp \
+ metatypesjsonprocessor.cpp
+
HEADERS += \
../qmlcompiler/qqmljsstreamwriter_p.h \
qmltypesclassdescription.h \
- qmltypescreator.h
+ qmltypescreator.h \
+ metatypesjsonprocessor.h
build_integration.files = qmltypes.prf
build_integration.path = $$[QT_HOST_DATA]/mkspecs/features