summaryrefslogtreecommitdiffstats
path: root/src/tools/moc/moc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/moc/moc.cpp')
-rw-r--r--src/tools/moc/moc.cpp639
1 files changed, 384 insertions, 255 deletions
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index a66eda6f86..3cbe331f14 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -1,31 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "moc.h"
#include "generator.h"
@@ -43,12 +18,23 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// only moc needs this function
static QByteArray normalizeType(const QByteArray &ba)
{
return ba.size() ? normalizeTypeInternal(ba.constBegin(), ba.constEnd()) : ba;
}
+const QByteArray &Moc::toFullyQualified(const QByteArray &name) const noexcept
+{
+ if (auto it = knownQObjectClasses.find(name); it != knownQObjectClasses.end())
+ return it.value();
+ if (auto it = knownGadgets.find(name); it != knownGadgets.end())
+ return it.value();
+ return name;
+}
+
bool Moc::parseClassHead(ClassDef *def)
{
// figure out whether this is a class declaration, or only a
@@ -63,6 +49,9 @@ bool Moc::parseClassHead(ClassDef *def)
return false;
} while (token);
+ // support attributes like "class [[deprecated]]] name"
+ skipCxxAttributes();
+
if (!test(IDENTIFIER)) // typedef struct { ... }
return false;
QByteArray name = lexem();
@@ -107,17 +96,17 @@ bool Moc::parseClassHead(ClassDef *def)
else
test(PUBLIC);
test(VIRTUAL);
- const QByteArray type = parseType().name;
+ const Type type = parseType();
// ignore the 'class Foo : BAR(Baz)' case
if (test(LPAREN)) {
until(RPAREN);
} else {
- def->superclassList += qMakePair(type, access);
+ def->superclassList.push_back({type.name, toFullyQualified(type.name), access});
}
} while (test(COMMA));
if (!def->superclassList.isEmpty()
- && knownGadgets.contains(def->superclassList.constFirst().first)) {
+ && knownGadgets.contains(def->superclassList.constFirst().classname)) {
// Q_GADGET subclasses are treated as Q_GADGETs
knownGadgets.insert(def->classname, def->qualified);
knownGadgets.insert(def->qualified, def->qualified);
@@ -198,6 +187,7 @@ Type Moc::parseType()
case DOUBLE:
case VOID:
case BOOL:
+ case AUTO:
type.name += lexem();
isVoid |= (lookup(0) == VOID);
break;
@@ -262,7 +252,7 @@ bool Moc::parseEnum(EnumDef *def)
}
if (test(COLON)) { // C++11 strongly typed enum
// enum Foo : unsigned long { ... };
- parseType(); //ignore the result
+ def->type = normalizeType(parseType().name);
}
if (!test(LBRACE))
return false;
@@ -284,10 +274,9 @@ bool Moc::parseEnum(EnumDef *def)
return IncludeState::NoInclude;
};
do {
+ handleInclude();
if (lookup() == RBRACE) // accept trailing comma
break;
- if ( handleInclude() == IncludeState::IncludeEnd)
- continue;
next(IDENTIFIER);
def->values += lexem();
handleInclude();
@@ -320,7 +309,7 @@ void Moc::parseFunctionArguments(FunctionDef *def)
arg.rightType += lexem();
}
arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
- arg.typeNameForCast = normalizeType(QByteArray(noRef(arg.type.name) + "(*)" + arg.rightType));
+ arg.typeNameForCast = QByteArray("std::add_pointer_t<"+arg.normalizedType+">");
if (test(EQ))
arg.isDefault = true;
def->arguments += arg;
@@ -338,6 +327,9 @@ void Moc::parseFunctionArguments(FunctionDef *def)
def->arguments.removeLast();
def->isRawSlot = true;
}
+
+ if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<int>::max()))
+ error("number of function arguments exceeds std::numeric_limits<int>::max()");
}
bool Moc::testFunctionAttribute(FunctionDef *def)
@@ -388,7 +380,7 @@ QTypeRevision Moc::parseRevision()
revisionString.remove(0, 1);
revisionString.chop(1);
const QList<QByteArray> majorMinor = revisionString.split(',');
- switch (majorMinor.length()) {
+ switch (majorMinor.size()) {
case 1: {
bool ok = false;
const int revision = revisionString.toInt(&ok);
@@ -429,8 +421,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
def->isVirtual = false;
def->isStatic = false;
//skip modifiers and attributes
- while (test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
- (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
+ while (testForFunctionModifiers(def)
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
bool templateFunction = (lookup() == TEMPLATE);
def->type = parseType();
@@ -441,40 +432,29 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
error();
}
bool scopedFunctionName = false;
- if (test(LPAREN)) {
- def->name = def->type.name;
- scopedFunctionName = def->type.isScoped;
- def->type = Type("int");
- } else {
- Type tempType = parseType();;
- while (!tempType.name.isEmpty() && lookup() != LPAREN) {
- if (testFunctionAttribute(def->type.firstToken, def))
- ; // fine
- else if (def->type.firstToken == Q_SIGNALS_TOKEN)
- error();
- else if (def->type.firstToken == Q_SLOTS_TOKEN)
- error();
- else {
- if (!def->tag.isEmpty())
- def->tag += ' ';
- def->tag += def->type.name;
- }
- def->type = tempType;
- tempType = parseType();
+ // we might have modifiers and attributes after a tag
+ // note that testFunctionAttribute is handled further below,
+ // and revisions and attributes must come first
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();
+ while (!tempType.name.isEmpty() && lookup() != LPAREN) {
+ if (testFunctionAttribute(def->type.firstToken, def))
+ ; // fine
+ else if (def->type.firstToken == Q_SIGNALS_TOKEN)
+ error();
+ else if (def->type.firstToken == Q_SLOTS_TOKEN)
+ error();
+ else {
+ if (!def->tag.isEmpty())
+ def->tag += ' ';
+ def->tag += def->type.name;
}
- next(LPAREN, "Not a signal or slot declaration");
- def->name = tempType.name;
- scopedFunctionName = tempType.isScoped;
+ def->type = tempType;
+ tempType = parseType();
}
-
- // we don't support references as return types, it's too dangerous
- if (def->type.referenceType == Type::Reference) {
- QByteArray rawName = def->type.rawName;
- def->type = Type("void");
- def->type.rawName = rawName;
- }
-
- def->normalizedType = normalizeType(def->type.name);
+ next(LPAREN, "Not a signal or slot declaration");
+ def->name = tempType.name;
+ scopedFunctionName = tempType.isScoped;
if (!test(RPAREN)) {
parseFunctionArguments(def);
@@ -498,6 +478,10 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
next(LPAREN);
until(RPAREN);
}
+
+ if (def->type.name == "auto" && test(ARROW))
+ def->type = parseType(); // Parse trailing return-type
+
if (test(SEMIC))
;
else if ((def->inlineCode = test(LBRACE)))
@@ -515,17 +499,39 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
warning(msg.constData());
return false;
}
+
+ QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(' ');
+ if (typeNameParts.contains("auto")) {
+ // We expected a trailing return type but we haven't seen one
+ error("Function declared with auto as return type but missing trailing return type. "
+ "Return type deduction is not supported.");
+ }
+
+ // we don't support references as return types, it's too dangerous
+ if (def->type.referenceType == Type::Reference) {
+ QByteArray rawName = def->type.rawName;
+ def->type = Type("void");
+ def->type.rawName = rawName;
+ }
+
+ def->normalizedType = normalizeType(def->type.name);
return true;
}
+bool Moc::testForFunctionModifiers(FunctionDef *def)
+{
+ return test(EXPLICIT) || test(INLINE) ||
+ (test(STATIC) && (def->isStatic = true)) ||
+ (test(VIRTUAL) && (def->isVirtual = true));
+}
+
// like parseFunction, but never aborts with an error
bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
{
def->isVirtual = false;
def->isStatic = false;
//skip modifiers and attributes
- while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
- (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
+ while (testForFunctionModifiers(def)
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
bool tilde = test(TILDE);
def->type = parseType();
@@ -540,10 +546,15 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
def->isConstructor = !tilde;
def->type = Type();
} else {
- def->type = Type("int");
+ // missing type name? => Skip
+ return false;
}
} else {
- Type tempType = parseType();;
+ // ### TODO: The condition before testForFunctionModifiers shoulnd't be necessary,
+ // but otherwise we end up with misparses
+ if (def->isSlot || def->isSignal || def->isInvokable)
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
if (testFunctionAttribute(def->type.firstToken, def))
; // fine
@@ -590,6 +601,63 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
return true;
}
+inline void handleDefaultArguments(QList<FunctionDef> *functionList, FunctionDef &function)
+{
+ // support a function with a default argument by pretending there is an
+ // overload without the argument (the original function is the overload with
+ // all arguments present)
+ while (function.arguments.size() > 0 && function.arguments.constLast().isDefault) {
+ function.wasCloned = true;
+ function.arguments.removeLast();
+ *functionList += function;
+ }
+}
+
+void Moc::prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const
+{
+ auto it = namespaceList.crbegin();
+ const auto rend = namespaceList.crend();
+ for (; it != rend; ++it) {
+ if (inNamespace(&*it))
+ def.qualified.prepend(it->classname + "::");
+ }
+}
+
+void Moc::checkListSizes(const ClassDef &def)
+{
+ if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals defined in parent class(es) exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<int>::max()))
+ error("number of bindable properties exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<int>::max()))
+ error("number of times Q_CLASSINFO macro is used exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<int>::max()))
+ error("number of enumerations exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<int>::max()))
+ error("number of super classes exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<int>::max()))
+ error("number of constructor parameters exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<int>::max()))
+ error("number of declared slots exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<int>::max()))
+ error("number of methods exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<int>::max()))
+ error("number of public functions declared in this class exceeds "
+ "std::numeric_limits<int>::max().");
+}
void Moc::parse()
{
@@ -599,11 +667,17 @@ void Moc::parse()
Token t = next();
switch (t) {
case NAMESPACE: {
- int rewind = index;
+ qsizetype rewind = index;
if (test(IDENTIFIER)) {
QByteArray nsName = lexem();
QByteArrayList nested;
while (test(SCOPE)) {
+ /* treat (C++20's) namespace A::inline B {} as A::B
+ this is mostly to not break compilation when encountering such
+ a construct in a header; the interaction of Qt's meta-macros with
+ inline namespaces is still rather poor.
+ */
+ test(INLINE);
next(IDENTIFIER);
nested.append(nsName);
nsName = lexem();
@@ -625,11 +699,8 @@ void Moc::parse()
def.end = index;
index = def.begin + 1;
- for (int i = namespaceList.size() - 1; i >= 0; --i) {
- if (inNamespace(&namespaceList.at(i))) {
- def.qualified.prepend(namespaceList.at(i).classname + "::");
- }
- }
+ prependNamespaces(def, namespaceList);
+
for (const QByteArray &ns : nested) {
NamespaceDef parentNs;
parentNs.classname = ns;
@@ -644,8 +715,10 @@ void Moc::parse()
switch (next()) {
case NAMESPACE:
if (test(IDENTIFIER)) {
- while (test(SCOPE))
+ while (test(SCOPE)) {
+ test(INLINE); // ignore inline namespaces
next(IDENTIFIER);
+ }
if (test(EQ)) {
// namespace Foo = Bar::Baz;
until(SEMIC);
@@ -759,6 +832,12 @@ void Moc::parse()
case Q_OBJECT_TOKEN:
def.hasQObject = true;
break;
+ case Q_GADGET_EXPORT_TOKEN:
+ next(LPAREN);
+ while (test(IDENTIFIER))
+ {}
+ next(RPAREN);
+ Q_FALLTHROUGH();
case Q_GADGET_TOKEN:
def.hasQGadget = true;
break;
@@ -769,9 +848,7 @@ void Moc::parse()
if (!def.hasQObject && !def.hasQGadget)
continue;
- for (int i = namespaceList.size() - 1; i >= 0; --i)
- if (inNamespace(&namespaceList.at(i)))
- def.qualified.prepend(namespaceList.at(i).classname + "::");
+ prependNamespaces(def, namespaceList);
QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
classHash.insert(def.classname, def.qualified);
@@ -784,10 +861,9 @@ void Moc::parse()
continue;
ClassDef def;
if (parseClassHead(&def)) {
+ prependNamespaces(def, namespaceList);
+
FunctionDef::Access access = FunctionDef::Private;
- for (int i = namespaceList.size() - 1; i >= 0; --i)
- if (inNamespace(&namespaceList.at(i)))
- def.qualified.prepend(namespaceList.at(i).classname + "::");
while (inClass(&def) && hasNext()) {
switch ((t = next())) {
case PRIVATE:
@@ -836,13 +912,22 @@ void Moc::parse()
if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
error("Class contains Q_OBJECT macro but does not inherit from QObject");
break;
+ case Q_GADGET_EXPORT_TOKEN:
+ next(LPAREN);
+ while (test(IDENTIFIER))
+ {}
+ next(RPAREN);
+ Q_FALLTHROUGH();
case Q_GADGET_TOKEN:
def.hasQGadget = true;
if (templateClass)
error("Template classes not supported by Q_GADGET");
break;
case Q_PROPERTY_TOKEN:
- parseProperty(&def);
+ parseProperty(&def, Named);
+ break;
+ case QT_ANONYMOUS_PROPERTY_TOKEN:
+ parseProperty(&def, Anonymous);
break;
case Q_PLUGIN_METADATA_TOKEN:
parsePluginData(&def);
@@ -877,7 +962,10 @@ void Moc::parse()
parseSlotInPrivate(&def, access);
break;
case Q_PRIVATE_PROPERTY_TOKEN:
- parsePrivateProperty(&def);
+ parsePrivateProperty(&def, Named);
+ break;
+ case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
+ parsePrivateProperty(&def, Anonymous);
break;
case ENUM: {
EnumDef enumDef;
@@ -890,16 +978,12 @@ void Moc::parse()
default:
FunctionDef funcDef;
funcDef.access = access;
- int rewind = index--;
+ qsizetype rewind = index--;
if (parseMaybeFunction(&def, &funcDef)) {
if (funcDef.isConstructor) {
if ((access == FunctionDef::Public) && funcDef.isInvokable) {
def.constructorList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def.constructorList += funcDef;
- }
+ handleDefaultArguments(&def.constructorList, funcDef);
}
} else if (funcDef.isDestructor) {
// don't care about destructors
@@ -908,29 +992,17 @@ void Moc::parse()
def.publicList += funcDef;
if (funcDef.isSlot) {
def.slotList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def.slotList += funcDef;
- }
+ handleDefaultArguments(&def.slotList, funcDef);
if (funcDef.revision > 0)
++def.revisionedMethods;
} else if (funcDef.isSignal) {
def.signalList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def.signalList += funcDef;
- }
+ handleDefaultArguments(&def.signalList, funcDef);
if (funcDef.revision > 0)
++def.revisionedMethods;
} else if (funcDef.isInvokable) {
def.methodList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def.methodList += funcDef;
- }
+ handleDefaultArguments(&def.methodList, funcDef);
if (funcDef.revision > 0)
++def.revisionedMethods;
}
@@ -955,16 +1027,20 @@ void Moc::parse()
if (!def.pluginData.iid.isEmpty())
def.pluginData.metaArgs = metaArgs;
- checkSuperClasses(&def);
+ if (def.hasQObject && !def.superclassList.isEmpty())
+ checkSuperClasses(&def);
+
checkProperties(&def);
+ checkListSizes(def);
+
classList += def;
QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
classHash.insert(def.classname, def.qualified);
classHash.insert(def.qualified, def.qualified);
}
}
- for (const auto &n : qAsConst(namespaceList)) {
+ for (const auto &n : std::as_const(namespaceList)) {
if (!n.hasQNamespace)
continue;
ClassDef def;
@@ -977,8 +1053,10 @@ void Moc::parse()
if (it != classList.end()) {
it->classInfoList += def.classInfoList;
+ Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<int>::max());
it->enumDeclarations.insert(def.enumDeclarations);
it->enumList += def.enumList;
+ Q_ASSERT(it->enumList.size() <= std::numeric_limits<int>::max());
it->flagAliases.insert(def.flagAliases);
} else {
knownGadgets.insert(def.classname, def.qualified);
@@ -1056,25 +1134,27 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
void Moc::generate(FILE *out, FILE *jsonOutput)
{
- QByteArray fn = filename;
- int i = filename.length()-1;
- while (i > 0 && filename.at(i - 1) != '/' && filename.at(i - 1) != '\\')
- --i; // skip path
- if (i >= 0)
- fn = filename.mid(i);
+ QByteArrayView fn = QByteArrayView(filename);
+
+ auto isSlash = [](char ch) { return ch == '/' || ch == '\\'; };
+ auto rit = std::find_if(fn.crbegin(), fn.crend(), isSlash);
+ if (rit != fn.crend())
+ fn = fn.last(rit - fn.crbegin());
+
fprintf(out, "/****************************************************************************\n"
"** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
fprintf(out, "** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
"*****************************************************************************/\n\n");
- fprintf(out, "#include <memory>\n"); // For std::addressof
+ // include header(s) of user class definitions at _first_ to allow
+ // for preprocessor definitions possibly affecting standard headers.
+ // see https://codereview.qt-project.org/c/qt/qtbase/+/445937
if (!noInclude) {
if (includePath.size() && !includePath.endsWith('/'))
includePath += '/';
- for (int i = 0; i < includeFiles.size(); ++i) {
- QByteArray inc = includeFiles.at(i);
- if (inc.at(0) != '<' && inc.at(0) != '"') {
+ for (QByteArray inc : std::as_const(includeFiles)) {
+ if (!inc.isEmpty() && inc.at(0) != '<' && inc.at(0) != '"') {
if (includePath.size() && includePath != "./")
inc.prepend(includePath);
inc = '\"' + inc + '\"';
@@ -1085,7 +1165,6 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
if (classList.size() && classList.constFirst().classname == "Qt")
fprintf(out, "#include <QtCore/qobject.h>\n");
- fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData
fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
if (mustIncludeQPluginH)
fprintf(out, "#include <QtCore/qplugin.h>\n");
@@ -1094,6 +1173,10 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
for (const QByteArray &qtContainer : qtContainers)
fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
+ fprintf(out, "\n#include <QtCore/qtmochelpers.h>\n");
+
+ fprintf(out, "\n#include <memory>\n\n"); // For std::addressof
+ fprintf(out, "\n#include <QtCore/qxptype_traits.h>\n"); // is_detected
fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
"#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
@@ -1104,32 +1187,44 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
" much.)\"\n", QT_VERSION_STR);
fprintf(out, "#endif\n\n");
- fprintf(out, "QT_BEGIN_MOC_NAMESPACE\n");
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+ fprintf(out, "#ifndef Q_CONSTINIT\n"
+ "#define Q_CONSTINIT\n"
+ "#endif\n\n");
+#endif
+
fprintf(out, "QT_WARNING_PUSH\n");
fprintf(out, "QT_WARNING_DISABLE_DEPRECATED\n");
+ fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
fputs("", out);
- for (i = 0; i < classList.size(); ++i) {
- Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out, requireCompleteTypes);
+ for (ClassDef &def : classList) {
+ Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
+ requireCompleteTypes);
generator.generateCode();
+
+ // generator.generateCode() should have already registered all strings
+ if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<int>::max())) {
+ error("internal limit exceeded: number of parsed strings is too big.");
+ exit(EXIT_FAILURE);
+ }
}
fputs("", 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());
+ mocData["outputRevision"_L1] = mocOutputRevision;
+ mocData["inputFile"_L1] = QLatin1StringView(fn.constData());
QJsonArray classesJsonFormatted;
- for (const ClassDef &cdef: qAsConst(classList))
+ for (const ClassDef &cdef: std::as_const(classList))
classesJsonFormatted.append(cdef.toJson());
if (!classesJsonFormatted.isEmpty())
- mocData[QLatin1String("classes")] = classesJsonFormatted;
+ mocData["classes"_L1] = classesJsonFormatted;
QJsonDocument jsonDoc(mocData);
fputs(jsonDoc.toJson().constData(), jsonOutput);
@@ -1174,11 +1269,7 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
++def->revisionedMethods;
}
def->slotList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def->slotList += funcDef;
- }
+ handleDefaultArguments(&def->slotList, funcDef);
}
}
@@ -1222,17 +1313,14 @@ void Moc::parseSignals(ClassDef *def)
++def->revisionedMethods;
}
def->signalList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def->signalList += funcDef;
- }
+ handleDefaultArguments(&def->signalList, funcDef);
}
}
-void Moc::createPropertyDef(PropertyDef &propDef)
+void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex, Moc::PropertyMode mode)
{
propDef.location = index;
+ propDef.relativeIndex = propertyIndex;
QByteArray type = parseType().name;
if (type.isEmpty())
@@ -1259,8 +1347,10 @@ void Moc::createPropertyDef(PropertyDef &propDef)
propDef.type = type;
- next();
- propDef.name = lexem();
+ if (mode == Moc::Named) {
+ next();
+ propDef.name = lexem();
+ }
parsePropertyAttributes(propDef);
}
@@ -1277,7 +1367,8 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
};
while (test(IDENTIFIER)) {
- const QByteArray l = lexem();
+ const Symbol &lsym = symbol();
+ const QByteArray l = lsym.lexem();
if (l[0] == 'C' && l == "CONSTANT") {
propDef.constant = true;
continue;
@@ -1300,11 +1391,15 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
QByteArray v, v2;
if (test(LPAREN)) {
v = lexemUntil(RPAREN);
- v = v.mid(1, v.length() - 2); // removes the '(' and ')'
+ v = v.mid(1, v.size() - 2); // removes the '(' and ')'
} else if (test(INTEGER_LITERAL)) {
v = lexem();
if (l != "REVISION")
- error(1);
+ error(lsym);
+ } else if (test(DEFAULT)) {
+ v = lexem();
+ if (l != "READ" && l != "WRITE")
+ error(lsym);
} else {
next(IDENTIFIER);
v = lexem();
@@ -1318,21 +1413,21 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
if (l == "MEMBER")
propDef.member = v;
else
- error(2);
+ error(lsym);
break;
case 'R':
if (l == "READ")
propDef.read = v;
else if (l == "RESET")
- propDef.reset = v + v2;
+ propDef.reset = v;
else if (l == "REVISION") {
bool ok = false;
const int minor = v.toInt(&ok);
if (!ok || !QTypeRevision::isValidSegment(minor))
- error(1);
+ error(lsym);
propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>();
} else
- error(2);
+ error(lsym);
break;
case 'S':
if (l == "SCRIPTABLE") {
@@ -1342,27 +1437,27 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
propDef.stored = v + v2;
checkIsFunction(propDef.stored, "STORED");
} else
- error(2);
+ error(lsym);
break;
- case 'W': if (l != "WRITE") error(2);
+ case 'W': if (l != "WRITE") error(lsym);
propDef.write = v;
break;
- case 'B': if (l != "BINDABLE") error(2);
+ case 'B': if (l != "BINDABLE") error(lsym);
propDef.bind = v;
break;
- case 'D': if (l != "DESIGNABLE") error(2);
+ case 'D': if (l != "DESIGNABLE") error(lsym);
propDef.designable = v + v2;
checkIsFunction(propDef.designable, "DESIGNABLE");
break;
- case 'N': if (l != "NOTIFY") error(2);
+ case 'N': if (l != "NOTIFY") error(lsym);
propDef.notify = v;
break;
- case 'U': if (l != "USER") error(2);
+ case 'U': if (l != "USER") error(lsym);
propDef.user = v + v2;
checkIsFunction(propDef.user, "USER");
break;
default:
- error(2);
+ error(lsym);
}
}
if (propDef.constant && !propDef.write.isNull()) {
@@ -1383,13 +1478,25 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
propDef.constant = false;
warning(msg.constData());
}
+ if (propDef.read == "default" && propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is not BINDable but default-READable. READ will be ignored.";
+ propDef.read = "";
+ warning(msg.constData());
+ }
+ if (propDef.write == "default" && propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is not BINDable but default-WRITEable. WRITE will be ignored.";
+ propDef.write = "";
+ warning(msg.constData());
+ }
}
-void Moc::parseProperty(ClassDef *def)
+void Moc::parseProperty(ClassDef *def, Moc::PropertyMode mode)
{
next(LPAREN);
PropertyDef propDef;
- createPropertyDef(propDef);
+ createPropertyDef(propDef, int(def->propertyList.size()), mode);
next(RPAREN);
def->propertyList += propDef;
@@ -1410,9 +1517,11 @@ void Moc::parsePluginData(ClassDef *def)
} else if (l == "FILE") {
next(STRING_LITERAL);
QByteArray metaDataFile = unquotedLexem();
- QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top().constData())).dir(), QString::fromLocal8Bit(metaDataFile.constData()));
- for (int j = 0; j < includes.size() && !fi.exists(); ++j) {
- const IncludePath &p = includes.at(j);
+ QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
+ QString::fromLocal8Bit(metaDataFile));
+ for (const IncludePath &p : std::as_const(includes)) {
+ if (fi.exists())
+ break;
if (p.isFrameworkPath)
continue;
@@ -1475,7 +1584,7 @@ QByteArray Moc::parsePropertyAccessor()
return accessor;
}
-void Moc::parsePrivateProperty(ClassDef *def)
+void Moc::parsePrivateProperty(ClassDef *def, Moc::PropertyMode mode)
{
next(LPAREN);
PropertyDef propDef;
@@ -1483,7 +1592,7 @@ void Moc::parsePrivateProperty(ClassDef *def)
next(COMMA);
- createPropertyDef(propDef);
+ createPropertyDef(propDef, int(def->propertyList.size()), mode);
def->propertyList += propDef;
}
@@ -1581,7 +1690,7 @@ void Moc::parseInterfaces(ClassDef *def)
}
}
// resolve from classnames to interface ids
- for (int i = 0; i < iface.count(); ++i) {
+ for (qsizetype i = 0; i < iface.size(); ++i) {
const QByteArray iid = interface2IdMap.value(iface.at(i).className);
if (iid.isEmpty())
error("Undefined interface");
@@ -1650,11 +1759,7 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
funcDef.access = access;
parseFunction(&funcDef, true);
def->slotList += funcDef;
- while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) {
- funcDef.wasCloned = true;
- funcDef.arguments.removeLast();
- def->slotList += funcDef;
- }
+ handleDefaultArguments(&def->slotList, funcDef);
if (funcDef.revision > 0)
++def->revisionedMethods;
@@ -1662,7 +1767,7 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
QByteArray Moc::lexemUntil(Token target)
{
- int from = index;
+ qsizetype from = index;
until(target);
QByteArray s;
while (from <= index) {
@@ -1696,9 +1801,9 @@ bool Moc::until(Token target) {
}
//when searching commas within the default argument, we should take care of template depth (anglecount)
- // unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or
+ // unfortunately, we do not have enough semantic information to know if '<' is the operator< or
// the beginning of a template type. so we just use heuristics.
- int possible = -1;
+ qsizetype possible = -1;
while (index < symbols.size()) {
Token t = symbols.at(index++).token;
@@ -1762,7 +1867,8 @@ bool Moc::until(Token target) {
void Moc::checkSuperClasses(ClassDef *def)
{
- const QByteArray firstSuperclass = def->superclassList.value(0).first;
+ Q_ASSERT(!def->superclassList.isEmpty());
+ const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
if (!knownQObjectClasses.contains(firstSuperclass)) {
// enable once we /require/ include paths
@@ -1777,8 +1883,18 @@ void Moc::checkSuperClasses(ClassDef *def)
#endif
return;
}
- for (int i = 1; i < def->superclassList.count(); ++i) {
- const QByteArray superClass = def->superclassList.at(i).first;
+
+ auto isRegisteredInterface = [&def](QByteArrayView super) {
+ auto matchesSuperClass = [&super](const auto &ifaces) {
+ return !ifaces.isEmpty() && ifaces.first().className == super;
+ };
+ return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
+ };
+
+ const auto end = def->superclassList.cend();
+ auto it = def->superclassList.cbegin() + 1;
+ for (; it != end; ++it) {
+ const QByteArray &superClass = it->classname;
if (knownQObjectClasses.contains(superClass)) {
const QByteArray msg
= "Class "
@@ -1792,14 +1908,7 @@ void Moc::checkSuperClasses(ClassDef *def)
}
if (interface2IdMap.contains(superClass)) {
- bool registeredInterface = false;
- for (int i = 0; i < def->interfaceList.count(); ++i)
- if (def->interfaceList.at(i).constFirst().className == superClass) {
- registeredInterface = true;
- break;
- }
-
- if (!registeredInterface) {
+ if (!isRegisteredInterface(superClass)) {
const QByteArray msg
= "Class "
+ def->classname
@@ -1817,34 +1926,30 @@ void Moc::checkSuperClasses(ClassDef *def)
void Moc::checkProperties(ClassDef *cdef)
{
//
- // specify get function, for compatibiliy we accept functions
+ // specify get function, for compatibility we accept functions
// returning pointers, or const char * for QByteArray.
//
- QDuplicateTracker<QByteArray> definedProperties;
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- PropertyDef &p = cdef->propertyList[i];
+ QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
+ auto hasNoAttributes = [&](const PropertyDef &p) {
if (definedProperties.hasSeen(p.name)) {
QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + ".";
warning(msg.constData());
}
if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
- const int rewind = index;
- if (p.location >= 0)
- index = p.location;
QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member"
", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
- warning(msg.constData());
- index = rewind;
- if (p.write.isEmpty()) {
- cdef->propertyList.removeAt(i);
- --i;
- }
- continue;
+ const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
+ warning(sym, msg.constData());
+ if (p.write.isEmpty())
+ return true;
}
+ return false;
+ };
+ cdef->propertyList.removeIf(hasNoAttributes);
- for (int j = 0; j < cdef->publicList.count(); ++j) {
- const FunctionDef &f = cdef->publicList.at(j);
+ for (PropertyDef &p : cdef->propertyList) {
+ for (const FunctionDef &f : std::as_const(cdef->publicList)) {
if (f.name != p.read)
continue;
if (!f.isConst) // get functions must be const
@@ -1870,7 +1975,7 @@ void Moc::checkProperties(ClassDef *cdef)
}
if (!p.notify.isEmpty()) {
int notifyId = -1;
- for (int j = 0; j < cdef->signalList.count(); ++j) {
+ for (int j = 0; j < int(cdef->signalList.size()); ++j) {
const FunctionDef &f = cdef->signalList.at(j);
if (f.name != p.notify) {
continue;
@@ -1881,12 +1986,12 @@ void Moc::checkProperties(ClassDef *cdef)
}
p.notifyId = notifyId;
if (notifyId == -1) {
- int index = cdef->nonClassSignalList.indexOf(p.notify);
+ const int index = int(cdef->nonClassSignalList.indexOf(p.notify));
if (index == -1) {
cdef->nonClassSignalList << p.notify;
- p.notifyId = -1 - cdef->nonClassSignalList.count();
+ p.notifyId = int(-1 - cdef->nonClassSignalList.size());
} else {
- p.notifyId = -2 - index;
+ p.notifyId = int(-2 - index);
}
}
}
@@ -1896,19 +2001,19 @@ 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());
+ cls["className"_L1] = QString::fromUtf8(classname.constData());
+ cls["qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
QJsonArray classInfos;
- for (const auto &info: qAsConst(classInfoList)) {
+ for (const auto &info: std::as_const(classInfoList)) {
QJsonObject infoJson;
- infoJson[QLatin1String("name")] = QString::fromUtf8(info.name);
- infoJson[QLatin1String("value")] = QString::fromUtf8(info.value);
+ infoJson["name"_L1] = QString::fromUtf8(info.name);
+ infoJson["value"_L1] = QString::fromUtf8(info.value);
classInfos.append(infoJson);
}
if (classInfos.size())
- cls[QLatin1String("classInfos")] = classInfos;
+ cls["classInfos"_L1] = classInfos;
const auto appendFunctions = [&cls](const QString &type, const QList<FunctionDef> &funcs) {
QJsonArray jsonFuncs;
@@ -1920,59 +2025,59 @@ QJsonObject ClassDef::toJson() const
cls[type] = jsonFuncs;
};
- appendFunctions(QLatin1String("signals"), signalList);
- appendFunctions(QLatin1String("slots"), slotList);
- appendFunctions(QLatin1String("constructors"), constructorList);
- appendFunctions(QLatin1String("methods"), methodList);
+ appendFunctions("signals"_L1, signalList);
+ appendFunctions("slots"_L1, slotList);
+ appendFunctions("constructors"_L1, constructorList);
+ appendFunctions("methods"_L1, methodList);
QJsonArray props;
- for (const PropertyDef &propDef: qAsConst(propertyList))
+ for (const PropertyDef &propDef: std::as_const(propertyList))
props.append(propDef.toJson());
if (!props.isEmpty())
- cls[QLatin1String("properties")] = props;
+ cls["properties"_L1] = props;
if (hasQObject)
- cls[QLatin1String("object")] = true;
+ cls["object"_L1] = true;
if (hasQGadget)
- cls[QLatin1String("gadget")] = true;
+ cls["gadget"_L1] = true;
if (hasQNamespace)
- cls[QLatin1String("namespace")] = true;
+ cls["namespace"_L1] = true;
QJsonArray superClasses;
- for (const auto &super: qAsConst(superclassList)) {
- const auto name = super.first;
- const auto access = super.second;
+ for (const auto &super: std::as_const(superclassList)) {
QJsonObject superCls;
- superCls[QLatin1String("name")] = QString::fromUtf8(name);
- FunctionDef::accessToJson(&superCls, access);
+ superCls["name"_L1] = QString::fromUtf8(super.classname);
+ if (super.classname != super.qualified)
+ superCls["fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
+ FunctionDef::accessToJson(&superCls, super.access);
superClasses.append(superCls);
}
if (!superClasses.isEmpty())
- cls[QLatin1String("superClasses")] = superClasses;
+ cls["superClasses"_L1] = superClasses;
QJsonArray enums;
- for (const EnumDef &enumDef: qAsConst(enumList))
+ for (const EnumDef &enumDef: std::as_const(enumList))
enums.append(enumDef.toJson(*this));
if (!enums.isEmpty())
- cls[QLatin1String("enums")] = enums;
+ cls["enums"_L1] = enums;
QJsonArray ifaces;
for (const QList<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);
+ ifaceJson["id"_L1] = QString::fromUtf8(iface.interfaceId);
+ ifaceJson["className"_L1] = QString::fromUtf8(iface.className);
jsonList.append(ifaceJson);
}
ifaces.append(jsonList);
}
if (!ifaces.isEmpty())
- cls[QLatin1String("interfaces")] = ifaces;
+ cls["interfaces"_L1] = ifaces;
return cls;
}
@@ -1980,22 +2085,25 @@ QJsonObject ClassDef::toJson() const
QJsonObject FunctionDef::toJson() const
{
QJsonObject fdef;
- fdef[QLatin1String("name")] = QString::fromUtf8(name);
+ fdef["name"_L1] = QString::fromUtf8(name);
if (!tag.isEmpty())
- fdef[QLatin1String("tag")] = QString::fromUtf8(tag);
- fdef[QLatin1String("returnType")] = QString::fromUtf8(normalizedType);
+ fdef["tag"_L1] = QString::fromUtf8(tag);
+ fdef["returnType"_L1] = QString::fromUtf8(normalizedType);
QJsonArray args;
for (const ArgumentDef &arg: arguments)
args.append(arg.toJson());
if (!args.isEmpty())
- fdef[QLatin1String("arguments")] = args;
+ fdef["arguments"_L1] = args;
accessToJson(&fdef, access);
if (revision > 0)
- fdef[QLatin1String("revision")] = revision;
+ fdef["revision"_L1] = revision;
+
+ if (wasCloned)
+ fdef["isCloned"_L1] = true;
return fdef;
}
@@ -2003,30 +2111,30 @@ QJsonObject FunctionDef::toJson() const
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;
+ case Private: (*obj)["access"_L1] = "private"_L1; break;
+ case Public: (*obj)["access"_L1] = "public"_L1; break;
+ case Protected: (*obj)["access"_L1] = "protected"_L1; break;
}
}
QJsonObject ArgumentDef::toJson() const
{
QJsonObject arg;
- arg[QLatin1String("type")] = QString::fromUtf8(normalizedType);
+ arg["type"_L1] = QString::fromUtf8(normalizedType);
if (!name.isEmpty())
- arg[QLatin1String("name")] = QString::fromUtf8(name);
+ arg["name"_L1] = QString::fromUtf8(name);
return arg;
}
QJsonObject PropertyDef::toJson() const
{
QJsonObject prop;
- prop[QLatin1String("name")] = QString::fromUtf8(name);
- prop[QLatin1String("type")] = QString::fromUtf8(type);
+ prop["name"_L1] = QString::fromUtf8(name);
+ prop["type"_L1] = QString::fromUtf8(type);
const auto jsonify = [&prop](const char *str, const QByteArray &member) {
if (!member.isEmpty())
- prop[QLatin1String(str)] = QString::fromUtf8(member);
+ prop[QLatin1StringView(str)] = QString::fromUtf8(member);
};
jsonify("member", member);
@@ -2045,7 +2153,7 @@ QJsonObject PropertyDef::toJson() const
value = false;
else
value = QString::fromUtf8(boolOrString); // function name to query at run-time
- prop[QLatin1String(str)] = value;
+ prop[QLatin1StringView(str)] = value;
};
jsonifyBoolOrString("designable", designable);
@@ -2053,12 +2161,12 @@ QJsonObject PropertyDef::toJson() const
jsonifyBoolOrString("stored", stored);
jsonifyBoolOrString("user", user);
- prop[QLatin1String("constant")] = constant;
- prop[QLatin1String("final")] = final;
- prop[QLatin1String("required")] = required;
-
+ prop["constant"_L1] = constant;
+ prop["final"_L1] = final;
+ prop["required"_L1] = required;
+ prop["index"_L1] = relativeIndex;
if (revision > 0)
- prop[QLatin1String("revision")] = revision;
+ prop["revision"_L1] = revision;
return prop;
}
@@ -2066,19 +2174,40 @@ QJsonObject PropertyDef::toJson() const
QJsonObject EnumDef::toJson(const ClassDef &cdef) const
{
QJsonObject def;
- def[QLatin1String("name")] = QString::fromUtf8(name);
+ def["name"_L1] = QString::fromUtf8(name);
if (!enumName.isEmpty())
- def[QLatin1String("alias")] = QString::fromUtf8(enumName);
- def[QLatin1String("isFlag")] = cdef.enumDeclarations.value(name);
- def[QLatin1String("isClass")] = isEnumClass;
+ def["alias"_L1] = QString::fromUtf8(enumName);
+ if (!type.isEmpty())
+ def["type"_L1] = QString::fromUtf8(type);
+ def["isFlag"_L1] = cdef.enumDeclarations.value(name);
+ def["isClass"_L1] = isEnumClass;
QJsonArray valueArr;
for (const QByteArray &value: values)
valueArr.append(QString::fromUtf8(value));
if (!valueArr.isEmpty())
- def[QLatin1String("values")] = valueArr;
+ def["values"_L1] = valueArr;
return def;
}
+QByteArray EnumDef::qualifiedType(const ClassDef *cdef) const
+{
+ if (name == cdef->classname) {
+ // The name of the enclosing namespace is the same as the enum class name
+ if (cdef->qualified.contains("::")) {
+ // QTBUG-112996, fully qualify by using cdef->qualified to disambiguate enum
+ // class name and enclosing namespace, e.g.:
+ // namespace A { namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } }
+ return cdef->qualified % "::" % name;
+ } else {
+ // Just "B"; otherwise the compiler complains about the type "B::B" inside
+ // "B::staticMetaObject" in the generated code; e.g.:
+ // namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) }
+ return name;
+ }
+ }
+ return cdef->classname % "::" % name;
+}
+
QT_END_NAMESPACE