diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-06 12:33:51 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-06 22:41:51 +0100 |
commit | 421ad80dee10e7b5eff352aecb2986c370f0e487 (patch) | |
tree | 152b155b255ac99e9dd34f36dc64d047e89ceb57 | |
parent | 68b9ab7b93320a975c2f20c09eddccf0fdb275b7 (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>
-rw-r--r-- | src/qmltyperegistrar/.prev_CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/qmltyperegistrar/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/qmltyperegistrar/metatypesjsonprocessor.cpp | 335 | ||||
-rw-r--r-- | src/qmltyperegistrar/metatypesjsonprocessor.h | 76 | ||||
-rw-r--r-- | src/qmltyperegistrar/qmltyperegistrar.cpp | 298 | ||||
-rw-r--r-- | src/qmltyperegistrar/qmltyperegistrar.pro | 7 |
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 |