summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/collectjson.cpp103
-rw-r--r--src/tools/moc/collectjson.h42
-rw-r--r--src/tools/moc/generator.cpp8
-rw-r--r--src/tools/moc/main.cpp172
-rw-r--r--src/tools/moc/moc.cpp205
-rw-r--r--src/tools/moc/moc.h13
-rw-r--r--src/tools/moc/moc.pri7
-rw-r--r--src/tools/moc/parser.cpp2
-rw-r--r--src/tools/moc/preprocessor.cpp2
9 files changed, 541 insertions, 13 deletions
diff --git a/src/tools/moc/collectjson.cpp b/src/tools/moc/collectjson.cpp
new file mode 100644
index 0000000000..4029bca5e9
--- /dev/null
+++ b/src/tools/moc/collectjson.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite 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 <qfile.h>
+#include <qjsonarray.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qhashfunctions.h>
+#include <qstringlist.h>
+#include <cstdlib>
+
+static bool readFromDevice(QIODevice *device, QJsonArray *allMetaObjects)
+{
+ const QByteArray contents = device->readAll();
+ if (contents.isEmpty())
+ return true;
+
+ QJsonParseError error {};
+ QJsonDocument metaObjects = QJsonDocument::fromJson(contents, &error);
+ if (error.error != QJsonParseError::NoError) {
+ fprintf(stderr, "%s at %d\n", error.errorString().toUtf8().constData(), error.offset);
+ return false;
+ }
+
+ allMetaObjects->append(metaObjects.object());
+ return true;
+}
+
+int collectJson(const QStringList &jsonFiles, const QString &outputFile)
+{
+ qSetGlobalQHashSeed(0);
+
+ QFile output;
+ if (outputFile.isEmpty()) {
+ if (!output.open(stdout, QIODevice::WriteOnly)) {
+ fprintf(stderr, "Error opening stdout for writing\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ output.setFileName(outputFile);
+ if (!output.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, "Error opening %s for writing\n", qPrintable(outputFile));
+ return EXIT_FAILURE;
+ }
+ }
+
+ QJsonArray allMetaObjects;
+ if (jsonFiles.isEmpty()) {
+ QFile f;
+ if (!f.open(stdin, QIODevice::ReadOnly)) {
+ fprintf(stderr, "Error opening stdin for reading\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!readFromDevice(&f, &allMetaObjects)) {
+ fprintf(stderr, "Error parsing data from stdin\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ for (const QString &jsonFile: jsonFiles) {
+ QFile f(jsonFile);
+ if (!f.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Error opening %s for reading\n", qPrintable(jsonFile));
+ return EXIT_FAILURE;
+ }
+
+ if (!readFromDevice(&f, &allMetaObjects)) {
+ fprintf(stderr, "Error parsing %s\n", qPrintable(jsonFile));
+ return EXIT_FAILURE;
+ }
+ }
+
+ QJsonDocument doc(allMetaObjects);
+ output.write(doc.toJson());
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/tools/moc/collectjson.h b/src/tools/moc/collectjson.h
new file mode 100644
index 0000000000..9d329c96ca
--- /dev/null
+++ b/src/tools/moc/collectjson.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications 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 COLLECTJSON_H
+#define COLLECTJSON_H
+
+#include <qglobal.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+int collectJson(const QStringList &jsonFiles, const QString &outputFile);
+
+QT_END_NAMESPACE
+
+#endif // COLLECTOJSON_H
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index 6a74e739e6..034e846918 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -77,7 +77,7 @@ static const char *metaTypeEnumValueString(int type)
QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
}
#undef RETURN_METATYPENAME_STRING
- return 0;
+ return nullptr;
}
Generator::Generator(ClassDef *classDef, const QVector<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile)
@@ -462,7 +462,7 @@ void Generator::generateCode()
// Build extra array
//
QVector<QByteArray> extraList;
- QHash<QByteArray, QByteArray> knownExtraMetaObject = knownGadgets;
+ QMultiHash<QByteArray, QByteArray> knownExtraMetaObject = knownGadgets;
knownExtraMetaObject.unite(knownQObjectClasses);
for (int i = 0; i < cdef->propertyList.count(); ++i) {
@@ -541,8 +541,10 @@ void Generator::generateCode()
if (isQObject)
fprintf(out, " nullptr,\n");
- else if (cdef->superclassList.size() && (!cdef->hasQGadget || knownGadgets.contains(purestSuperClass)))
+ else if (cdef->superclassList.size() && !cdef->hasQGadget) // for qobject, we know the super class must have a static metaobject
fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData());
+ else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it
+ fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData());
else
fprintf(out, " nullptr,\n");
fprintf(out, " qt_meta_stringdata_%s.data,\n"
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index ba559b572f..b8c2d7f594 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -30,6 +30,7 @@
#include "preprocessor.h"
#include "moc.h"
#include "outputrevision.h"
+#include "collectjson.h"
#include <qfile.h>
#include <qfileinfo.h>
@@ -37,10 +38,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include <qcoreapplication.h>
#include <qcommandlineoption.h>
#include <qcommandlineparser.h>
+#include <qscopedpointer.h>
QT_BEGIN_NAMESPACE
@@ -77,6 +80,10 @@ void error(const char *msg = "Invalid argument")
fprintf(stderr, "moc: %s\n", msg);
}
+struct ScopedPointerFileCloser
+{
+ static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
+};
static inline bool hasNext(const Symbols &symbols, int i)
{ return (i < symbols.size()); }
@@ -168,6 +175,49 @@ static QStringList argumentsFromCommandLineAndFile(const QStringList &arguments)
return allArguments;
}
+// Escape characters in given path. Dependency paths are Make-style, not NMake/Jom style.
+// The paths can also be consumed by Ninja.
+// "$" replaced by "$$"
+// "#" replaced by "\#"
+// " " replaced by "\ "
+// "\#" replaced by "\\#"
+// "\ " replaced by "\\\ "
+//
+// The escape rules are according to what clang / llvm escapes when generating a Make-style
+// dependency file.
+// Is a template function, because input param can be either a QString or a QByteArray.
+template <typename T> struct CharType;
+template <> struct CharType<QString> { using type = QLatin1Char; };
+template <> struct CharType<QByteArray> { using type = char; };
+template <typename StringType>
+StringType escapeDependencyPath(const StringType &path)
+{
+ using CT = typename CharType<StringType>::type;
+ StringType escapedPath;
+ int size = path.size();
+ escapedPath.reserve(size);
+ for (int i = 0; i < size; ++i) {
+ if (path[i] == CT('$')) {
+ escapedPath.append(CT('$'));
+ } else if (path[i] == CT('#')) {
+ escapedPath.append(CT('\\'));
+ } else if (path[i] == CT(' ')) {
+ escapedPath.append(CT('\\'));
+ int backwards_it = i - 1;
+ while (backwards_it > 0 && path[backwards_it] == CT('\\')) {
+ escapedPath.append(CT('\\'));
+ --backwards_it;
+ }
+ }
+ escapedPath.append(path[i]);
+ }
+ return escapedPath;
+}
+
+QByteArray escapeAndEncodeDependencyPath(const QString &path)
+{
+ return QFile::encodeName(escapeDependencyPath(path));
+}
int runMoc(int argc, char **argv)
{
@@ -293,10 +343,36 @@ int runMoc(int argc, char **argv)
ignoreConflictsOption.setDescription(QStringLiteral("Ignore all options that conflict with compilers, like -pthread conflicting with moc's -p option."));
parser.addOption(ignoreConflictsOption);
+ QCommandLineOption jsonOption(QStringLiteral("output-json"));
+ jsonOption.setDescription(QStringLiteral("In addition to generating C++ code, create a machine-readable JSON file in a file that matches the output file and an extra .json extension."));
+ parser.addOption(jsonOption);
+
+ QCommandLineOption collectOption(QStringLiteral("collect-json"));
+ collectOption.setDescription(QStringLiteral("Instead of processing C++ code, collect previously generated JSON output into a single file."));
+ parser.addOption(collectOption);
+
+ QCommandLineOption depFileOption(QStringLiteral("output-dep-file"));
+ depFileOption.setDescription(
+ QStringLiteral("Output a Make-style dep file for build system consumption."));
+ parser.addOption(depFileOption);
+
+ QCommandLineOption depFilePathOption(QStringLiteral("dep-file-path"));
+ depFilePathOption.setDescription(QStringLiteral("Path where to write the dep file."));
+ depFilePathOption.setValueName(QStringLiteral("file"));
+ parser.addOption(depFilePathOption);
+
+ QCommandLineOption depFileRuleNameOption(QStringLiteral("dep-file-rule-name"));
+ depFileRuleNameOption.setDescription(
+ QStringLiteral("The rule name (first line) of the dep file."));
+ depFileRuleNameOption.setValueName(QStringLiteral("rule name"));
+ parser.addOption(depFileRuleNameOption);
+
parser.addPositionalArgument(QStringLiteral("[header-file]"),
QStringLiteral("Header file to read from, otherwise stdin."));
parser.addPositionalArgument(QStringLiteral("[@option-file]"),
QStringLiteral("Read additional options from option-file."));
+ parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
+ QStringLiteral("MOC generated json output"));
const QStringList arguments = argumentsFromCommandLineAndFile(app.arguments());
if (arguments.isEmpty())
@@ -305,6 +381,10 @@ int runMoc(int argc, char **argv)
parser.process(arguments);
const QStringList files = parser.positionalArguments();
+ output = parser.value(outputOption);
+ if (parser.isSet(collectOption))
+ return collectJson(files, output);
+
if (files.count() > 1) {
error(qPrintable(QLatin1String("Too many input files specified: '") + files.join(QLatin1String("' '")) + QLatin1Char('\'')));
parser.showHelp(1);
@@ -313,7 +393,6 @@ int runMoc(int argc, char **argv)
}
const bool ignoreConflictingOptions = parser.isSet(ignoreConflictsOption);
- output = parser.value(outputOption);
pp.preprocessOnly = parser.isSet(preprocessOption);
if (parser.isSet(noIncludeOption)) {
moc.noInclude = true;
@@ -456,6 +535,7 @@ int runMoc(int argc, char **argv)
// 1. preprocess
const auto includeFiles = parser.values(includeOption);
+ QStringList validIncludesFiles;
for (const QString &includeName : includeFiles) {
QByteArray rawName = pp.resolveInclude(QFile::encodeName(includeName), moc.filename);
if (rawName.isEmpty()) {
@@ -468,6 +548,7 @@ int runMoc(int argc, char **argv)
moc.symbols += Symbol(0, MOC_INCLUDE_BEGIN, rawName);
moc.symbols += pp.preprocessed(rawName, &f);
moc.symbols += Symbol(0, MOC_INCLUDE_END, rawName);
+ validIncludesFiles.append(includeName);
} else {
fprintf(stderr, "Warning: Cannot open %s included by moc file %s: %s\n",
rawName.constData(),
@@ -485,6 +566,9 @@ int runMoc(int argc, char **argv)
// 3. and output meta object code
+ QScopedPointer<FILE, ScopedPointerFileCloser> jsonOutput;
+
+ bool outputToFile = true;
if (output.size()) { // output file specified
#if defined(_MSC_VER)
if (_wfopen_s(&out, reinterpret_cast<const wchar_t *>(output.utf16()), L"w") != 0)
@@ -496,8 +580,24 @@ int runMoc(int argc, char **argv)
fprintf(stderr, "moc: Cannot create %s\n", QFile::encodeName(output).constData());
return 1;
}
+
+ if (parser.isSet(jsonOption)) {
+ const QString jsonOutputFileName = output + QLatin1String(".json");
+ FILE *f;
+#if defined(_MSC_VER)
+ if (_wfopen_s(&f, reinterpret_cast<const wchar_t *>(jsonOutputFileName.utf16()), L"w") != 0)
+#else
+ f = fopen(QFile::encodeName(jsonOutputFileName).constData(), "w");
+ if (!f)
+#endif
+ fprintf(stderr, "moc: Cannot create JSON output file %s. %s\n",
+ QFile::encodeName(jsonOutputFileName).constData(),
+ strerror(errno));
+ jsonOutput.reset(f);
+ }
} else { // use stdout
out = stdout;
+ outputToFile = false;
}
if (pp.preprocessOnly) {
@@ -506,12 +606,80 @@ int runMoc(int argc, char **argv)
if (moc.classList.isEmpty())
moc.note("No relevant classes found. No output generated.");
else
- moc.generate(out);
+ moc.generate(out, jsonOutput.data());
}
if (output.size())
fclose(out);
+ if (parser.isSet(depFileOption)) {
+ // 4. write a Make-style dependency file (can also be consumed by Ninja).
+ QString depOutputFileName;
+ QString depRuleName = output;
+
+ if (parser.isSet(depFileRuleNameOption))
+ depRuleName = parser.value(depFileRuleNameOption);
+
+ if (parser.isSet(depFilePathOption)) {
+ depOutputFileName = parser.value(depFilePathOption);
+ } else if (outputToFile) {
+ depOutputFileName = output + QLatin1String(".d");
+ } else {
+ fprintf(stderr, "moc: Writing to stdout, but no depfile path specified.\n");
+ }
+
+ QScopedPointer<FILE, ScopedPointerFileCloser> depFileHandle;
+ FILE *depFileHandleRaw;
+#if defined(_MSC_VER)
+ if (_wfopen_s(&depFileHandleRaw,
+ reinterpret_cast<const wchar_t *>(depOutputFileName.utf16()), L"w") != 0)
+#else
+ depFileHandleRaw = fopen(QFile::encodeName(depOutputFileName).constData(), "w");
+ if (!depFileHandleRaw)
+#endif
+ fprintf(stderr, "moc: Cannot create dep output file '%s'. %s\n",
+ QFile::encodeName(depOutputFileName).constData(),
+ strerror(errno));
+ depFileHandle.reset(depFileHandleRaw);
+
+ if (!depFileHandle.isNull()) {
+ // First line is the path to the generated file.
+ fprintf(depFileHandle.data(), "%s: ",
+ escapeAndEncodeDependencyPath(depRuleName).constData());
+
+ QByteArrayList dependencies;
+
+ // If there's an input file, it's the first dependency.
+ if (!filename.isEmpty()) {
+ dependencies.append(escapeAndEncodeDependencyPath(filename).constData());
+ }
+
+ // Additional passed-in includes are dependencies (like moc_predefs.h).
+ for (const QString &includeName : validIncludesFiles) {
+ dependencies.append(escapeAndEncodeDependencyPath(includeName).constData());
+ }
+
+ // Plugin metadata json files discovered via Q_PLUGIN_METADATA macros are also
+ // dependencies.
+ for (const QString &pluginMetadataFile : moc.parsedPluginMetadataFiles) {
+ dependencies.append(escapeAndEncodeDependencyPath(pluginMetadataFile).constData());
+ }
+
+ // All pre-processed includes are dependnecies.
+ // Sort the entries for easier human consumption.
+ auto includeList = pp.preprocessedIncludes.values();
+ std::sort(includeList.begin(), includeList.end());
+
+ for (QByteArray &includeName : includeList) {
+ dependencies.append(escapeDependencyPath(includeName));
+ }
+
+ // Join dependencies, output them, and output a final new line.
+ const auto dependenciesJoined = dependencies.join(QByteArrayLiteral(" \\\n "));
+ fprintf(depFileHandle.data(), "%s\n", dependenciesJoined.constData());
+ }
+ }
+
return 0;
}
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 50946443be..d7a1af0a18 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -35,6 +35,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
+#include <QtCore/qjsondocument.h>
// for normalizeTypeInternal
#include <private/qmetaobject_moc_p.h>
@@ -929,9 +930,9 @@ void Moc::parse()
if (it != classList.end()) {
it->classInfoList += def.classInfoList;
- it->enumDeclarations.unite(def.enumDeclarations);
+ it->enumDeclarations.insert(def.enumDeclarations);
it->enumList += def.enumList;
- it->flagAliases.unite(def.flagAliases);
+ it->flagAliases.insert(def.flagAliases);
} else {
knownGadgets.insert(def.classname, def.qualified);
knownGadgets.insert(def.qualified, def.qualified);
@@ -999,7 +1000,7 @@ static QByteArrayList requiredQtContainers(const QVector<ClassDef> &classes)
return required;
}
-void Moc::generate(FILE *out)
+void Moc::generate(FILE *out, FILE *jsonOutput)
{
QByteArray fn = filename;
int i = filename.length()-1;
@@ -1062,6 +1063,23 @@ void Moc::generate(FILE *out)
fprintf(out, "QT_WARNING_POP\n");
fprintf(out, "QT_END_MOC_NAMESPACE\n");
+
+ if (jsonOutput) {
+ QJsonObject mocData;
+ mocData[QLatin1String("outputRevision")] = mocOutputRevision;
+ mocData[QLatin1String("inputFile")] = QLatin1String(fn.constData());
+
+ QJsonArray classesJsonFormatted;
+
+ for (const ClassDef &cdef: qAsConst(classList))
+ classesJsonFormatted.append(cdef.toJson());
+
+ if (!classesJsonFormatted.isEmpty())
+ mocData[QLatin1String("classes")] = classesJsonFormatted;
+
+ QJsonDocument jsonDoc(mocData);
+ fputs(jsonDoc.toJson().constData(), jsonOutput);
+ }
}
void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
@@ -1364,6 +1382,7 @@ void Moc::parsePluginData(ClassDef *def)
error(msg.constData());
return;
}
+ parsedPluginMetadataFiles.append(fi.canonicalFilePath());
metaData = file.readAll();
}
}
@@ -1784,6 +1803,186 @@ void Moc::checkProperties(ClassDef *cdef)
}
}
+QJsonObject ClassDef::toJson() const
+{
+ QJsonObject cls;
+ cls[QLatin1String("className")] = QString::fromUtf8(classname.constData());
+ cls[QLatin1String("qualifiedClassName")] = QString::fromUtf8(qualified.constData());
+
+ QJsonArray classInfos;
+ for (const auto &info: qAsConst(classInfoList)) {
+ QJsonObject infoJson;
+ infoJson[QLatin1String("name")] = QString::fromUtf8(info.name);
+ infoJson[QLatin1String("value")] = QString::fromUtf8(info.value);
+ classInfos.append(infoJson);
+ }
+
+ if (classInfos.size())
+ cls[QLatin1String("classInfos")] = classInfos;
+
+ const auto appendFunctions = [&cls](const QString &type, const QVector<FunctionDef> &funcs) {
+ QJsonArray jsonFuncs;
+
+ for (const FunctionDef &fdef: funcs)
+ jsonFuncs.append(fdef.toJson());
+
+ if (!jsonFuncs.isEmpty())
+ cls[type] = jsonFuncs;
+ };
+
+ appendFunctions(QLatin1String("signals"), signalList);
+ appendFunctions(QLatin1String("slots"), slotList);
+ appendFunctions(QLatin1String("constructors"), constructorList);
+ appendFunctions(QLatin1String("methods"), methodList);
+
+ QJsonArray props;
+
+ for (const PropertyDef &propDef: qAsConst(propertyList))
+ props.append(propDef.toJson());
+
+ if (!props.isEmpty())
+ cls[QLatin1String("properties")] = props;
+
+ if (hasQGadget)
+ cls[QLatin1String("gadget")] = true;
+
+ QJsonArray superClasses;
+
+ for (const auto &super: qAsConst(superclassList)) {
+ const auto name = super.first;
+ const auto access = super.second;
+ QJsonObject superCls;
+ superCls[QLatin1String("name")] = QString::fromUtf8(name);
+ FunctionDef::accessToJson(&superCls, access);
+ superClasses.append(superCls);
+ }
+
+ if (!superClasses.isEmpty())
+ cls[QLatin1String("superClasses")] = superClasses;
+
+ QJsonArray enums;
+ for (const EnumDef &enumDef: qAsConst(enumList))
+ enums.append(enumDef.toJson(*this));
+ if (!enums.isEmpty())
+ cls[QLatin1String("enums")] = enums;
+
+ QJsonArray ifaces;
+ for (const QVector<Interface> &ifaceList: interfaceList) {
+ QJsonArray jsonList;
+ for (const Interface &iface: ifaceList) {
+ QJsonObject ifaceJson;
+ ifaceJson[QLatin1String("id")] = QString::fromUtf8(iface.interfaceId);
+ ifaceJson[QLatin1String("className")] = QString::fromUtf8(iface.className);
+ jsonList.append(ifaceJson);
+ }
+ ifaces.append(jsonList);
+ }
+ if (!ifaces.isEmpty())
+ cls[QLatin1String("interfaces")] = ifaces;
+
+ return cls;
+}
+
+QJsonObject FunctionDef::toJson() const
+{
+ QJsonObject fdef;
+ fdef[QLatin1String("name")] = QString::fromUtf8(name);
+ if (!tag.isEmpty())
+ fdef[QLatin1String("tag")] = QString::fromUtf8(tag);
+ fdef[QLatin1String("returnType")] = QString::fromUtf8(normalizedType);
+ QJsonArray args;
+ for (const ArgumentDef &arg: arguments)
+ args.append(arg.toJson());
+
+ if (!args.isEmpty())
+ fdef[QLatin1String("arguments")] = args;
+
+ accessToJson(&fdef, access);
+
+ if (revision > 0)
+ fdef[QLatin1String("revision")] = revision;
+
+ return fdef;
+}
+
+void FunctionDef::accessToJson(QJsonObject *obj, FunctionDef::Access acs)
+{
+ switch (acs) {
+ case Private: (*obj)[QLatin1String("access")] = QLatin1String("private"); break;
+ case Public: (*obj)[QLatin1String("access")] = QLatin1String("public"); break;
+ case Protected: (*obj)[QLatin1String("access")] = QLatin1String("protected"); break;
+ }
+}
+
+QJsonObject ArgumentDef::toJson() const
+{
+ QJsonObject arg;
+ arg[QLatin1String("type")] = QString::fromUtf8(normalizedType);
+ if (!name.isEmpty())
+ arg[QLatin1String("name")] = QString::fromUtf8(name);
+ return arg;
+}
+
+QJsonObject PropertyDef::toJson() const
+{
+ QJsonObject prop;
+ prop[QLatin1String("name")] = QString::fromUtf8(name);
+ prop[QLatin1String("type")] = QString::fromUtf8(type);
+
+ const auto jsonify = [&prop](const char *str, const QByteArray &member) {
+ if (!member.isEmpty())
+ prop[QLatin1String(str)] = QString::fromUtf8(member);
+ };
+
+ jsonify("member", member);
+ jsonify("read", read);
+ jsonify("write", write);
+ jsonify("reset", reset);
+ jsonify("notify", notify);
+ jsonify("privateClass", inPrivateClass);
+
+ const auto jsonifyBoolOrString = [&prop](const char *str, const QByteArray &boolOrString) {
+ QJsonValue value;
+ if (boolOrString == "true")
+ value = true;
+ else if (boolOrString == "false")
+ value = false;
+ else
+ value = QString::fromUtf8(boolOrString); // function name to query at run-time
+ prop[QLatin1String(str)] = value;
+ };
+
+ jsonifyBoolOrString("designable", designable);
+ jsonifyBoolOrString("scriptable", scriptable);
+ jsonifyBoolOrString("stored", stored);
+ jsonifyBoolOrString("user", user);
+
+ prop[QLatin1String("constant")] = constant;
+ prop[QLatin1String("final")] = final;
+
+ if (revision > 0)
+ prop[QLatin1String("revision")] = revision;
+
+ return prop;
+}
+
+QJsonObject EnumDef::toJson(const ClassDef &cdef) const
+{
+ QJsonObject def;
+ def[QLatin1String("name")] = QString::fromUtf8(name);
+ if (!enumName.isEmpty())
+ def[QLatin1String("alias")] = QString::fromUtf8(enumName);
+ def[QLatin1String("isFlag")] = cdef.enumDeclarations.value(name);
+ def[QLatin1String("isClass")] = isEnumClass;
+
+ QJsonArray valueArr;
+ for (const QByteArray &value: values)
+ valueArr.append(QString::fromUtf8(value));
+ if (!valueArr.isEmpty())
+ def[QLatin1String("values")] = valueArr;
+
+ return def;
+}
QT_END_NAMESPACE
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index bb1c9501fe..5d1ae0ad6d 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -61,6 +61,7 @@ struct Type
};
Q_DECLARE_TYPEINFO(Type, Q_MOVABLE_TYPE);
+struct ClassDef;
struct EnumDef
{
QByteArray name;
@@ -68,6 +69,7 @@ struct EnumDef
QVector<QByteArray> values;
bool isEnumClass; // c++11 enum class
EnumDef() : isEnumClass(false) {}
+ QJsonObject toJson(const ClassDef &cdef) const;
};
Q_DECLARE_TYPEINFO(EnumDef, Q_MOVABLE_TYPE);
@@ -78,6 +80,8 @@ struct ArgumentDef
QByteArray rightType, normalizedType, name;
QByteArray typeNameForCast; // type name to be used in cast from void * in metacall
bool isDefault;
+
+ QJsonObject toJson() const;
};
Q_DECLARE_TYPEINFO(ArgumentDef, Q_MOVABLE_TYPE);
@@ -111,6 +115,9 @@ struct FunctionDef
bool isConstructor = false;
bool isDestructor = false;
bool isAbstract = false;
+
+ QJsonObject toJson() const;
+ static void accessToJson(QJsonObject *obj, Access acs);
};
Q_DECLARE_TYPEINFO(FunctionDef, Q_MOVABLE_TYPE);
@@ -130,6 +137,8 @@ struct PropertyDef
int revision = 0;
bool constant = false;
bool final = false;
+
+ QJsonObject toJson() const;
};
Q_DECLARE_TYPEINFO(PropertyDef, Q_MOVABLE_TYPE);
@@ -183,6 +192,7 @@ struct ClassDef : BaseDef {
bool hasQObject = false;
bool hasQGadget = false;
+ QJsonObject toJson() const;
};
Q_DECLARE_TYPEINFO(ClassDef, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(ClassDef::Interface, Q_MOVABLE_TYPE);
@@ -213,9 +223,10 @@ public:
QHash<QByteArray, QByteArray> knownQObjectClasses;
QHash<QByteArray, QByteArray> knownGadgets;
QMap<QString, QJsonArray> metaArgs;
+ QVector<QString> parsedPluginMetadataFiles;
void parse();
- void generate(FILE *out);
+ void generate(FILE *out, FILE *jsonOutput);
bool parseClassHead(ClassDef *def);
inline bool inClass(const ClassDef *def) const {
diff --git a/src/tools/moc/moc.pri b/src/tools/moc/moc.pri
index 90839a445b..278d5607cd 100644
--- a/src/tools/moc/moc.pri
+++ b/src/tools/moc/moc.pri
@@ -10,9 +10,12 @@ HEADERS = $$PWD/moc.h \
$$PWD/utils.h \
$$PWD/generator.h \
$$PWD/outputrevision.h \
- $$PWD/cbordevice.h
+ $$PWD/cbordevice.h \
+ $$PWD/collectjson.h
+
SOURCES = $$PWD/moc.cpp \
$$PWD/preprocessor.cpp \
$$PWD/generator.cpp \
$$PWD/parser.cpp \
- $$PWD/token.cpp
+ $$PWD/token.cpp \
+ $$PWD/collectjson.cpp
diff --git a/src/tools/moc/parser.cpp b/src/tools/moc/parser.cpp
index b7aefae1ec..068f75d4bd 100644
--- a/src/tools/moc/parser.cpp
+++ b/src/tools/moc/parser.cpp
@@ -37,7 +37,7 @@ QT_BEGIN_NAMESPACE
Symbol::LexemStore Symbol::lexemStore;
#endif
-static const char *error_msg = 0;
+static const char *error_msg = nullptr;
#ifdef Q_CC_MSVC
#define ErrorFormatString "%s(%d): "
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index d135bddb4c..a99b8cc80c 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -943,7 +943,7 @@ int PP_Expression::primary_expression()
test(PP_RPAREN);
} else {
next();
- value = lexem().toInt(0, 0);
+ value = lexem().toInt(nullptr, 0);
}
return value;
}