summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/CMakeLists.txt4
-rw-r--r--src/tools/moc/cbordevice.h2
-rw-r--r--src/tools/moc/generator.cpp369
-rw-r--r--src/tools/moc/generator.h7
-rw-r--r--src/tools/moc/main.cpp93
-rw-r--r--src/tools/moc/moc.cpp333
-rw-r--r--src/tools/moc/moc.h27
-rw-r--r--src/tools/moc/parser.cpp76
-rw-r--r--src/tools/moc/parser.h11
-rw-r--r--src/tools/moc/preprocessor.cpp99
-rw-r--r--src/tools/moc/preprocessor.h9
-rw-r--r--src/tools/moc/symbols.h107
-rwxr-xr-xsrc/tools/moc/util/generate.sh4
-rw-r--r--src/tools/moc/util/licenseheader.cpp.in (renamed from src/tools/moc/util/licenseheader.txt)0
-rw-r--r--src/tools/moc/utils.h42
15 files changed, 626 insertions, 557 deletions
diff --git a/src/tools/moc/CMakeLists.txt b/src/tools/moc/CMakeLists.txt
index 4302992bad..b98b7ab4e9 100644
--- a/src/tools/moc/CMakeLists.txt
+++ b/src/tools/moc/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_get_tool_target_name(target_name moc)
qt_internal_add_tool(${target_name}
+ TRY_RUN
CORE_LIBRARY Bootstrap
TARGET_DESCRIPTION "Qt Meta Object Compiler"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
@@ -20,7 +21,6 @@ qt_internal_add_tool(${target_name}
outputrevision.h
parser.cpp parser.h
preprocessor.cpp preprocessor.h
- # qdatetime_p.h special case remove
symbols.h
token.cpp token.h
utils.h
@@ -29,6 +29,8 @@ qt_internal_add_tool(${target_name}
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_FROM_BYTEARRAY
QT_NO_FOREACH
+ QT_NO_QPAIR
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
../../3rdparty/tinycbor/src
diff --git a/src/tools/moc/cbordevice.h b/src/tools/moc/cbordevice.h
index f221968911..7668e4c0be 100644
--- a/src/tools/moc/cbordevice.h
+++ b/src/tools/moc/cbordevice.h
@@ -4,6 +4,8 @@
#ifndef CBORDEVICE_H
#define CBORDEVICE_H
+#include <QtCore/qtypes.h>
+
#include <memory>
#include <stdio.h>
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index ca6a4181b6..1c6604a96e 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -23,6 +23,8 @@
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
uint nameToBuiltinType(const QByteArray &name)
{
if (name.isEmpty())
@@ -55,11 +57,12 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
return nullptr;
}
- Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile,
bool requireCompleteTypes)
- : out(outfile),
+ : parser(moc),
+ out(outfile),
cdef(classDef),
metaTypes(metaTypes),
knownQObjectClasses(knownQObjectClasses),
@@ -67,24 +70,24 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
requireCompleteTypes(requireCompleteTypes)
{
if (cdef->superclassList.size())
- purestSuperClass = cdef->superclassList.constFirst().first;
+ purestSuperClass = cdef->superclassList.constFirst().classname;
}
-static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
+static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i)
{
if (s.at(i) != '\\' || i >= s.size() - 1)
return 1;
- const int startPos = i;
+ const qsizetype startPos = i;
++i;
char ch = s.at(i);
if (ch == 'x') {
++i;
- while (i < s.size() && is_hex_char(s.at(i)))
+ while (i < s.size() && isHexDigit(s.at(i)))
++i;
- } else if (is_octal_char(ch)) {
+ } else if (isOctalDigit(ch)) {
while (i < startPos + 4
&& i < s.size()
- && is_octal_char(s.at(i))) {
+ && isOctalDigit(s.at(i))) {
++i;
}
} else { // single character escape sequence
@@ -93,36 +96,23 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos;
}
-static inline uint lengthOfEscapedString(const QByteArray &str)
-{
- int extra = 0;
- for (int j = 0; j < str.size(); ++j) {
- if (str.at(j) == '\\') {
- int cnt = lengthOfEscapeSequence(str, j) - 1;
- extra += cnt;
- j += cnt;
- }
- }
- return str.size() - extra;
-}
-
// Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
// opening and closing quotes are NOT included (it's up to the caller).
static void printStringWithIndentation(FILE *out, const QByteArray &s)
{
static constexpr int ColumnWidth = 72;
- int len = s.size();
- int idx = 0;
+ const qsizetype len = s.size();
+ qsizetype idx = 0;
do {
- int spanLen = qMin(ColumnWidth - 2, len - idx);
+ qsizetype spanLen = qMin(ColumnWidth - 2, len - idx);
// don't cut escape sequences at the end of a line
- int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
+ const qsizetype backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
- int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
+ const qsizetype escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, len - idx);
}
- fprintf(out, "\n \"%.*s\"", spanLen, s.constData() + idx);
+ fprintf(out, "\n \"%.*s\"", int(spanLen), s.constData() + idx);
idx += spanLen;
} while (idx < len);
}
@@ -135,7 +125,7 @@ void Generator::strreg(const QByteArray &s)
int Generator::stridx(const QByteArray &s)
{
- int i = strings.indexOf(s);
+ int i = int(strings.indexOf(s));
Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
return i;
}
@@ -146,8 +136,8 @@ int Generator::stridx(const QByteArray &s)
static int aggregateParameterCount(const QList<FunctionDef> &list)
{
int sum = 0;
- for (int i = 0; i < list.size(); ++i)
- sum += list.at(i).arguments.size() + 1; // +1 for return type
+ for (const FunctionDef &def : list)
+ sum += int(def.arguments.size()) + 1; // +1 for return type
return sum;
}
@@ -184,14 +174,14 @@ bool Generator::registerableMetaType(const QByteArray &propertyType)
#undef STREAM_1ARG_TEMPLATE
;
for (const QByteArray &oneArgTemplateType : oneArgTemplates) {
- QByteArray ba = oneArgTemplateType + "<";
+ const QByteArray ba = oneArgTemplateType + "<";
if (propertyType.startsWith(ba) && propertyType.endsWith(">")) {
- const int argumentSize = propertyType.size() - oneArgTemplateType.size() - 1
+ const qsizetype argumentSize = propertyType.size() - ba.size()
// The closing '>'
- 1
// templates inside templates have an extra whitespace char to strip.
- (propertyType.at(propertyType.size() - 2) == ' ' ? 1 : 0 );
- const QByteArray templateArg = propertyType.mid(oneArgTemplateType.size() + 1, argumentSize);
+ const QByteArray templateArg = propertyType.sliced(ba.size(), argumentSize);
return isBuiltinType(templateArg) || registerableMetaType(templateArg);
}
}
@@ -204,7 +194,7 @@ static bool qualifiedNameEquals(const QByteArray &qualifiedName, const QByteArra
{
if (qualifiedName == name)
return true;
- int index = qualifiedName.indexOf("::");
+ const qsizetype index = qualifiedName.indexOf("::");
if (index == -1)
return false;
return qualifiedNameEquals(qualifiedName.mid(index+2), name);
@@ -234,8 +224,7 @@ void Generator::generateCode()
// filter out undeclared enumerators and sets
{
QList<EnumDef> enumList;
- for (int i = 0; i < cdef->enumList.size(); ++i) {
- EnumDef def = cdef->enumList.at(i);
+ for (EnumDef def : std::as_const(cdef->enumList)) {
if (cdef->enumDeclarations.contains(def.name)) {
enumList += def;
}
@@ -277,7 +266,7 @@ void Generator::generateCode()
fprintf(out, "\n#ifdef QT_MOC_HAS_STRINGDATA\n"
"struct qt_meta_stringdata_%s_t {};\n"
- "static constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
+ "constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
{
char comma = 0;
@@ -289,61 +278,9 @@ void Generator::generateCode()
}
}
fprintf(out, "\n);\n"
- "#else // !QT_MOC_HAS_STRING_DATA\n");
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
+ "#else // !QT_MOC_HAS_STRINGDATA\n");
fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n");
-#else
-//
-// Build stringdata struct
-//
-
- fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
- fprintf(out, " uint offsetsAndSizes[%d];\n", int(strings.size() * 2));
- for (int i = 0; i < strings.size(); ++i) {
- int thisLength = lengthOfEscapedString(strings.at(i)) + 1;
- fprintf(out, " char stringdata%d[%d];\n", i, thisLength);
- }
- fprintf(out, "};\n");
-
- // Macro that simplifies the string data listing. The offset is calculated
- // from the top of the stringdata object (i.e., past the uints).
- fprintf(out, "#define QT_MOC_LITERAL(ofs, len) \\\n"
- " uint(sizeof(qt_meta_stringdata_%s_t::offsetsAndSizes) + ofs), len \n",
- qualifiedClassNameIdentifier.constData());
-
- fprintf(out, "Q_CONSTINIT static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
- qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
- fprintf(out, " {");
- {
- int idx = 0;
- for (int i = 0; i < strings.size(); ++i) {
- const QByteArray &str = strings.at(i);
- const QByteArray comment = str.size() > 32 ? str.left(29) + "..." : str;
- const char *comma = (i != strings.size() - 1 ? "," : " ");
- int len = lengthOfEscapedString(str);
- fprintf(out, "\n QT_MOC_LITERAL(%d, %d)%s // \"%s\"", idx, len, comma,
- comment.constData());
-
- idx += len + 1;
- }
- fprintf(out, "\n }");
- }
-
-//
-// Build stringdata arrays
-//
- for (const QByteArray &s : std::as_const(strings)) {
- fputc(',', out);
- printStringWithIndentation(out, s);
- }
-
-// Terminate stringdata struct
- fprintf(out, "\n};\n");
- fprintf(out, "#undef QT_MOC_LITERAL\n");
-#endif // Qt 6.9
-
- fprintf(out, "#endif // !QT_MOC_HAS_STRING_DATA\n");
+ fprintf(out, "#endif // !QT_MOC_HAS_STRINGDATA\n");
fprintf(out, "} // unnamed namespace\n\n");
//
@@ -358,8 +295,14 @@ void Generator::generateCode()
fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0));
index += cdef->classInfoList.size() * 2;
- int methodCount = cdef->signalList.size() + cdef->slotList.size() + cdef->methodList.size();
- fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
+ qsizetype methodCount = 0;
+ if (qAddOverflow(cdef->signalList.size(), cdef->slotList.size(), &methodCount)
+ || qAddOverflow(cdef->methodList.size(), methodCount, &methodCount)) {
+ parser->error("internal limit exceeded: the total number of member functions"
+ " (including signals and slots) is too big.");
+ }
+
+ fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0);
index += methodCount * QMetaObjectPrivate::IntsPerMethod;
if (cdef->revisionedMethods)
index += methodCount;
@@ -370,15 +313,16 @@ void Generator::generateCode()
+ aggregateParameterCount(cdef->constructorList);
index += totalParameterCount * 2 // types and parameter names
- methodCount // return "parameters" don't have names
- - cdef->constructorList.size(); // "this" parameters don't have names
+ - int(cdef->constructorList.size()); // "this" parameters don't have names
fprintf(out, " %4d, %4d, // properties\n", int(cdef->propertyList.size()), int(cdef->propertyList.size() ? index : 0));
index += cdef->propertyList.size() * QMetaObjectPrivate::IntsPerProperty;
fprintf(out, " %4d, %4d, // enums/sets\n", int(cdef->enumList.size()), cdef->enumList.size() ? index : 0);
int enumsIndex = index;
- for (int i = 0; i < cdef->enumList.size(); ++i)
- index += 5 + (cdef->enumList.at(i).values.size() * 2);
+ for (const EnumDef &def : std::as_const(cdef->enumList))
+ index += QMetaObjectPrivate::IntsPerEnum + (def.values.size() * 2);
+
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.size()) : 0,
isConstructible ? index : 0);
@@ -397,8 +341,14 @@ void Generator::generateCode()
//
generateClassInfos();
- // all property metatypes, + 1 for the type of the current class itself
- int initialMetaTypeOffset = cdef->propertyList.size() + 1;
+ qsizetype propEnumCount = 0;
+ // all property metatypes + all enum metatypes + 1 for the type of the current class itself
+ if (qAddOverflow(cdef->propertyList.size(), cdef->enumList.size(), &propEnumCount)
+ || qAddOverflow(propEnumCount, qsizetype(1), &propEnumCount)
+ || propEnumCount >= std::numeric_limits<int>::max()) {
+ parser->error("internal limit exceeded: number of property and enum metatypes is too big.");
+ }
+ int initialMetaTypeOffset = int(propEnumCount);
//
// Build signals array first, otherwise the signal indices would be wrong
@@ -461,15 +411,14 @@ void Generator::generateCode()
QMultiHash<QByteArray, QByteArray> knownExtraMetaObject(knownGadgets);
knownExtraMetaObject.unite(knownQObjectClasses);
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
if (isBuiltinType(p.type))
continue;
if (p.type.contains('*') || p.type.contains('<') || p.type.contains('>'))
continue;
- int s = p.type.lastIndexOf("::");
+ const qsizetype s = p.type.lastIndexOf("::");
if (s <= 0)
continue;
@@ -480,7 +429,7 @@ void Generator::generateCode()
QByteArray thisScope = cdef->qualified;
do {
- int s = thisScope.lastIndexOf("::");
+ const qsizetype s = thisScope.lastIndexOf("::");
thisScope = thisScope.left(s);
QByteArray currentScope = thisScope.isEmpty() ? unqualifiedScope : thisScope + "::" + unqualifiedScope;
scopeIt = knownExtraMetaObject.constFind(currentScope);
@@ -506,7 +455,7 @@ void Generator::generateCode()
for (auto it = cdef->enumDeclarations.keyBegin(),
end = cdef->enumDeclarations.keyEnd(); it != end; ++it) {
const QByteArray &enumKey = *it;
- int s = enumKey.lastIndexOf("::");
+ const qsizetype s = enumKey.lastIndexOf("::");
if (s > 0) {
QByteArray scope = enumKey.left(s);
if (scope != "Qt" && !qualifiedNameEquals(cdef->qualified, scope) && !extraList.contains(scope))
@@ -521,9 +470,9 @@ void Generator::generateCode()
if (!extraList.isEmpty()) {
fprintf(out, "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n",
qualifiedClassNameIdentifier.constData());
- for (int i = 0; i < extraList.size(); ++i) {
- fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", extraList.at(i).constData());
- }
+ for (const QByteArray &ba : std::as_const(extraList))
+ fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", ba.constData());
+
fprintf(out, " nullptr\n};\n\n");
}
@@ -569,13 +518,19 @@ void Generator::generateCode()
fprintf(out, " qt_metaTypeArray<");
}
// metatypes for properties
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
fprintf(out, "%s\n // property '%s'\n %s",
comma, p.name.constData(), stringForType(p.type, true).constData());
comma = ",";
}
+ // metatypes for enums
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ fprintf(out, "%s\n // enum '%s'\n %s",
+ comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData());
+ comma = ",";
+ }
+
// type name for the Q_OJBECT/GADGET itself, void for namespaces
auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void";
fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s",
@@ -584,10 +539,9 @@ void Generator::generateCode()
// metatypes for all exposed methods
// because we definitely printed something above, this section doesn't need comma control
- for (const QList<FunctionDef> &methodContainer :
- { cdef->signalList, cdef->slotList, cdef->methodList }) {
- for (int i = 0; i< methodContainer.size(); ++i) {
- const FunctionDef& fdef = methodContainer.at(i);
+ const auto allMethods = {&cdef->signalList, &cdef->slotList, &cdef->methodList};
+ for (const QList<FunctionDef> *methodContainer : allMethods) {
+ for (const FunctionDef &fdef : *methodContainer) {
fprintf(out, ",\n // method '%s'\n %s",
fdef.name.constData(), stringForType(fdef.type.name, false).constData());
for (const auto &argument: fdef.arguments)
@@ -596,8 +550,7 @@ void Generator::generateCode()
}
// but constructors have no return types, so this needs comma control again
- for (int i = 0; i< cdef->constructorList.size(); ++i) {
- const FunctionDef& fdef = cdef->constructorList.at(i);
+ for (const FunctionDef &fdef : std::as_const(cdef->constructorList)) {
if (fdef.arguments.isEmpty())
continue;
@@ -634,18 +587,24 @@ void Generator::generateCode()
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
" return static_cast<void*>(this);\n",
qualifiedClassNameIdentifier.constData());
- for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
- if (cdef->superclassList.at(i).second == FunctionDef::Private)
- continue;
- const char *cname = cdef->superclassList.at(i).first.constData();
- fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
- cname, cname);
+
+ // for all superclasses but the first one
+ if (cdef->superclassList.size() > 1) {
+ auto it = cdef->superclassList.cbegin() + 1;
+ const auto end = cdef->superclassList.cend();
+ for (; it != end; ++it) {
+ if (it->access == FunctionDef::Private)
+ continue;
+ const char *cname = it->classname.constData();
+ fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
+ cname, cname);
+ }
}
- for (int i = 0; i < cdef->interfaceList.size(); ++i) {
- const QList<ClassDef::Interface> &iface = cdef->interfaceList.at(i);
- for (int j = 0; j < iface.size(); ++j) {
+
+ for (const QList<ClassDef::Interface> &iface : std::as_const(cdef->interfaceList)) {
+ for (qsizetype j = 0; j < iface.size(); ++j) {
fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData());
- for (int k = j; k >= 0; --k)
+ for (qsizetype k = j; k >= 0; --k)
fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData());
fprintf(out, "this%s;\n", QByteArray(j + 1, ')').constData());
}
@@ -666,8 +625,8 @@ void Generator::generateCode()
//
// Generate internal signal functions
//
- for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
- generateSignal(&cdef->signalList[signalindex], signalindex);
+ for (int signalindex = 0; signalindex < int(cdef->signalList.size()); ++signalindex)
+ generateSignal(&cdef->signalList.at(signalindex), signalindex);
//
// Generate plugin meta data
@@ -678,12 +637,29 @@ void Generator::generateCode()
// Generate function to make sure the non-class signals exist in the parent classes
//
if (!cdef->nonClassSignalList.isEmpty()) {
- fprintf(out, "// If you get a compile error in this function it can be because either\n");
- fprintf(out, "// a) You are using a NOTIFY signal that does not exist. Fix it.\n");
- fprintf(out, "// b) You are using a NOTIFY signal that does exist (in a parent class) but has a non-empty parameter list. This is a moc limitation.\n");
- fprintf(out, "[[maybe_unused]] static void checkNotifySignalValidity_%s(%s *t) {\n", qualifiedClassNameIdentifier.constData(), cdef->qualified.constData());
- for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList))
- fprintf(out, " t->%s();\n", nonClassSignal.constData());
+ fprintf(out, "namespace CheckNotifySignalValidity_%s {\n", qualifiedClassNameIdentifier.constData());
+ for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList)) {
+ const auto propertyIt = std::find_if(cdef->propertyList.constBegin(),
+ cdef->propertyList.constEnd(),
+ [&nonClassSignal](const PropertyDef &p) {
+ return nonClassSignal == p.notify;
+ });
+ // must find something, otherwise checkProperties wouldn't have inserted an entry into nonClassSignalList
+ Q_ASSERT(propertyIt != cdef->propertyList.constEnd());
+ fprintf(out, "template<typename T> using has_nullary_%s = decltype(std::declval<T>().%s());\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData());
+ const auto &propertyType = propertyIt->type;
+ fprintf(out, "template<typename T> using has_unary_%s = decltype(std::declval<T>().%s(std::declval<%s>()));\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData(),
+ propertyType.constData());
+ fprintf(out, "static_assert(qxp::is_detected_v<has_nullary_%s, %s> || qxp::is_detected_v<has_unary_%s, %s>,\n"
+ " \"NOTIFY signal %s does not exist in class (or is private in its parent)\");\n",
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData());
+ }
fprintf(out, "}\n");
}
}
@@ -691,8 +667,7 @@ void Generator::generateCode()
void Generator::registerClassInfoStrings()
{
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList)) {
strreg(c.name);
strreg(c.value);
}
@@ -705,25 +680,19 @@ void Generator::generateClassInfos()
fprintf(out, "\n // classinfo: key, value\n");
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList))
fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
- }
}
void Generator::registerFunctionStrings(const QList<FunctionDef> &list)
{
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
-
+ for (const FunctionDef &f : list) {
strreg(f.name);
if (!isBuiltinType(f.normalizedType))
strreg(f.normalizedType);
strreg(f.tag);
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
+ for (const ArgumentDef &a : f.arguments) {
if (!isBuiltinType(a.normalizedType))
strreg(a.normalizedType);
strreg(a.name);
@@ -744,9 +713,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu
return;
fprintf(out, "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
-
+ for (const FunctionDef &f : list) {
QByteArray comment;
uint flags = type;
if (f.access == FunctionDef::Private) {
@@ -781,7 +748,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu
comment.append(" | MethodIsConst ");
}
- int argc = f.arguments.size();
+ const int argc = int(f.arguments.size());
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n",
stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, initialMetatypeOffset, comment.constData());
@@ -795,10 +762,8 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef> &list, const
{
if (list.size())
fprintf(out, "\n // %ss: revision\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list)
fprintf(out, " %4d,\n", f.revision);
- }
}
void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const char *functype)
@@ -806,25 +771,22 @@ void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: parameters\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list) {
fprintf(out, " ");
// Types
- int argsCount = f.arguments.size();
- for (int j = -1; j < argsCount; ++j) {
- if (j > -1)
- fputc(' ', out);
- const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
- generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor);
+ const bool allowEmptyName = f.isConstructor;
+ generateTypeInfo(f.normalizedType, allowEmptyName);
+ fputc(',', out);
+ for (const ArgumentDef &arg : f.arguments) {
+ fputc(' ', out);
+ generateTypeInfo(arg.normalizedType, allowEmptyName);
fputc(',', out);
}
// Parameter names
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &arg = f.arguments.at(j);
+ for (const ArgumentDef &arg : f.arguments)
fprintf(out, " %4d,", stridx(arg.name));
- }
fprintf(out, "\n");
}
@@ -857,8 +819,7 @@ void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName
void Generator::registerPropertyStrings()
{
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
strreg(p.name);
if (!isBuiltinType(p.type))
strreg(p.type);
@@ -872,9 +833,8 @@ void Generator::generateProperties()
//
if (cdef->propertyList.size())
- fprintf(out, "\n // properties: name, type, flags\n");
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ fprintf(out, "\n // properties: name, type, flags, notifyId, revision\n");
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
uint flags = Invalid;
if (!isBuiltinType(p.type))
flags |= EnumOrFlag;
@@ -918,7 +878,7 @@ void Generator::generateProperties()
int notifyId = p.notifyId;
if (p.notifyId < -1) {
// signal is in parent class
- const int indexInStrings = strings.indexOf(p.notify);
+ const int indexInStrings = int(strings.indexOf(p.notify));
notifyId = indexInStrings | IsUnresolvedSignal;
}
fprintf(out, ", 0x%.8x, uint(%d), %d,\n", flags, notifyId, p.revision);
@@ -927,13 +887,12 @@ void Generator::generateProperties()
void Generator::registerEnumStrings()
{
- for (int i = 0; i < cdef->enumList.size(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
strreg(e.name);
if (!e.enumName.isNull())
strreg(e.enumName);
- for (int j = 0; j < e.values.size(); ++j)
- strreg(e.values.at(j));
+ for (const QByteArray &val : e.values)
+ strreg(val);
}
}
@@ -943,7 +902,7 @@ void Generator::generateEnums(int index)
return;
fprintf(out, "\n // enums: name, alias, flags, count, data\n");
- index += 5 * cdef->enumList.size();
+ index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size();
int i;
for (i = 0; i < cdef->enumList.size(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
@@ -962,10 +921,8 @@ void Generator::generateEnums(int index)
}
fprintf(out, "\n // enum data: key, value\n");
- for (i = 0; i < cdef->enumList.size(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
- for (int j = 0; j < e.values.size(); ++j) {
- const QByteArray &val = e.values.at(j);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ for (const QByteArray &val : e.values) {
QByteArray code = cdef->qualified.constData();
if (e.isEnumClass)
code += "::" + (e.enumName.isNull() ? e.name : e.enumName);
@@ -1042,7 +999,7 @@ void Generator::generateMetacall()
QMultiMap<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
{
QMultiMap<QByteArray, int> automaticPropertyMetaTypes;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
+ for (int i = 0; i < int(cdef->propertyList.size()); ++i) {
const QByteArray propertyType = cdef->propertyList.at(i).type;
if (registerableMetaType(propertyType) && !isBuiltinType(propertyType))
automaticPropertyMetaTypes.insert(propertyType, i);
@@ -1078,10 +1035,11 @@ void Generator::generateStaticMetacall()
Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed
int offset = 1;
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ",");
fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))",
a.typeNameForCast.constData(), offset++);
@@ -1091,7 +1049,7 @@ void Generator::generateStaticMetacall()
if (!cdef->constructorList.isEmpty()) {
fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
fprintf(out, " switch (_id) {\n");
- const int ctorend = cdef->constructorList.size();
+ const int ctorend = int(cdef->constructorList.size());
for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
cdef->classname.constData(), cdef->classname.constData());
@@ -1153,16 +1111,17 @@ void Generator::generateStaticMetacall()
if (f.isRawSlot) {
fprintf(out, "QMethodRawArguments{ _a }");
} else {
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ",");
fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
isUsed_a = true;
}
if (f.isPrivateSignal) {
- if (argsCount > 0)
+ if (!f.arguments.isEmpty())
fprintf(out, ", ");
fprintf(out, "%s", "QPrivateSignal()");
}
@@ -1215,7 +1174,7 @@ void Generator::generateStaticMetacall()
fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n");
fprintf(out, " int *result = reinterpret_cast<int *>(_a[0]);\n");
bool anythingUsed = false;
- for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
+ for (int methodindex = 0; methodindex < int(cdef->signalList.size()); ++methodindex) {
const FunctionDef &f = cdef->signalList.at(methodindex);
if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic)
continue;
@@ -1223,15 +1182,16 @@ void Generator::generateStaticMetacall()
fprintf(out, " {\n");
fprintf(out, " using _t = %s (%s::*)(",f.type.rawName.constData() , cdef->classname.constData());
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ", ");
fprintf(out, "%s", QByteArray(a.type.name + ' ' + a.rightType).constData());
}
if (f.isPrivateSignal) {
- if (argsCount > 0)
+ if (!f.arguments.isEmpty())
fprintf(out, ", ");
fprintf(out, "%s", "QPrivateSignal");
}
@@ -1282,8 +1242,7 @@ void Generator::generateStaticMetacall()
bool needSet = false;
bool needReset = false;
bool hasBindableProperties = false;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
needGet |= !p.read.isEmpty() || !p.member.isEmpty();
if (!p.read.isEmpty() || !p.member.isEmpty())
needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
@@ -1314,7 +1273,7 @@ void Generator::generateStaticMetacall()
if (needTempVarForGet)
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.read.isEmpty() && p.member.isEmpty())
continue;
@@ -1355,7 +1314,7 @@ void Generator::generateStaticMetacall()
setupMemberAccess();
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.constant)
continue;
@@ -1408,7 +1367,7 @@ void Generator::generateStaticMetacall()
if (needReset) {
setupMemberAccess();
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.reset.isEmpty())
continue;
@@ -1429,7 +1388,7 @@ void Generator::generateStaticMetacall()
if (hasBindableProperties) {
setupMemberAccess();
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.bind.isEmpty())
continue;
@@ -1465,7 +1424,7 @@ void Generator::generateStaticMetacall()
fprintf(out, "}\n");
}
-void Generator::generateSignal(FunctionDef *def,int index)
+void Generator::generateSignal(const FunctionDef *def, int index)
{
if (def->wasCloned || def->isAbstract)
return;
@@ -1489,9 +1448,11 @@ void Generator::generateSignal(FunctionDef *def,int index)
}
int offset = 1;
- for (int j = 0; j < def->arguments.size(); ++j) {
- const ArgumentDef &a = def->arguments.at(j);
- if (j)
+ const auto begin = def->arguments.cbegin();
+ const auto end = def->arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fputs(", ", out);
if (a.type.name.size())
fputs(a.type.name.constData(), out);
@@ -1633,7 +1594,7 @@ void Generator::generatePluginMetaData()
};
// 'Use' all namespaces.
- int pos = cdef->qualified.indexOf("::");
+ qsizetype pos = cdef->qualified.indexOf("::");
for ( ; pos != -1 ; pos = cdef->qualified.indexOf("::", pos + 2) )
fprintf(out, "using namespace %s;\n", cdef->qualified.left(pos).constData());
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index fa651f04a0..2d4d69ca05 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -10,16 +10,19 @@ QT_BEGIN_NAMESPACE
class Generator
{
+ Moc *parser = nullptr;
FILE *out;
ClassDef *cdef;
QList<uint> meta_data;
public:
- Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr,
bool requireCompleteTypes = false);
void generateCode();
+ qsizetype registeredStringsCount() { return strings.size(); };
+
private:
bool registerableMetaType(const QByteArray &propertyType);
void registerClassInfoStrings();
@@ -37,7 +40,7 @@ private:
void generateProperties();
void generateMetacall();
void generateStaticMetacall();
- void generateSignal(FunctionDef *def, int index);
+ void generateSignal(const FunctionDef *def, int index);
void generatePluginMetaData();
QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
QMap<int, QMultiMap<QByteArray, int>>
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index eb359f4dbb..89fb367ca7 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -19,7 +19,8 @@
#include <qcoreapplication.h>
#include <qcommandlineoption.h>
#include <qcommandlineparser.h>
-#include <qscopedpointer.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -58,10 +59,21 @@ void error(const char *msg = "Invalid argument")
fprintf(stderr, "moc: %s\n", msg);
}
-struct ScopedPointerFileCloser
+static auto openFileForWriting(const QString &name)
{
- static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
-};
+ struct Closer { void operator()(FILE *handle) const { fclose(handle); } };
+ using R = std::unique_ptr<FILE, Closer>;
+
+#ifdef _MSC_VER
+ FILE *file;
+ if (_wfopen_s(&file, reinterpret_cast<const wchar_t *>(name.utf16()), L"w") != 0)
+ return R{};
+ return R{file};
+#else
+ return R{fopen(QFile::encodeName(name).constData(), "w")};
+#endif
+}
+using File = decltype(openFileForWriting({}));
static inline bool hasNext(const Symbols &symbols, int i)
{ return (i < symbols.size()); }
@@ -178,7 +190,7 @@ int runMoc(int argc, char **argv)
QString filename;
QString output;
QFile in;
- FILE *out = nullptr;
+ File out;
// Note that moc isn't translated.
// If you use this code as an example for a translated app, make sure to translate the strings.
@@ -399,7 +411,7 @@ int runMoc(int argc, char **argv)
for (const QString &arg : defines) {
QByteArray name = arg.toLocal8Bit();
QByteArray value("1");
- int eq = name.indexOf('=');
+ const qsizetype eq = name.indexOf('=');
if (eq >= 0) {
value = name.mid(eq + 1);
name = name.left(eq);
@@ -449,11 +461,14 @@ int runMoc(int argc, char **argv)
if (filename.isEmpty()) {
filename = QStringLiteral("standard input");
- in.open(stdin, QIODevice::ReadOnly);
+ if (!in.open(stdin, QIODevice::ReadOnly)) {
+ fprintf(stderr, "moc: cannot open standard input: %s\n", qPrintable(in.errorString()));
+ return 1;
+ }
} else {
in.setFileName(filename);
if (!in.open(QIODevice::ReadOnly)) {
- fprintf(stderr, "moc: %s: No such file\n", qPrintable(filename));
+ fprintf(stderr, "moc: cannot open %s: %s\n", qPrintable(filename), qPrintable(in.errorString()));
return 1;
}
moc.filename = filename.toLocal8Bit();
@@ -525,51 +540,45 @@ int runMoc(int argc, char **argv)
// 3. and output meta object code
- QScopedPointer<FILE, ScopedPointerFileCloser> jsonOutput;
+ File 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)
-#else
- out = fopen(QFile::encodeName(output).constData(), "w"); // create output file
+ out = openFileForWriting(output);
if (!out)
-#endif
{
- fprintf(stderr, "moc: Cannot create %s\n", QFile::encodeName(output).constData());
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create %s. Error: %s\n",
+ QFile::encodeName(output).constData(),
+ strerror(fopen_errno));
return 1;
}
if (parser.isSet(jsonOption)) {
const QString jsonOutputFileName = output + ".json"_L1;
- 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",
+ jsonOutput = openFileForWriting(jsonOutputFileName);
+ if (!jsonOutput) {
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n",
QFile::encodeName(jsonOutputFileName).constData(),
- strerror(errno));
- jsonOutput.reset(f);
+ strerror(fopen_errno));
+ }
}
} else { // use stdout
- out = stdout;
+ out.reset(stdout);
outputToFile = false;
}
if (pp.preprocessOnly) {
- fprintf(out, "%s\n", composePreprocessorOutput(moc.symbols).constData());
+ fprintf(out.get(), "%s\n", composePreprocessorOutput(moc.symbols).constData());
} else {
if (moc.classList.isEmpty())
moc.note("No relevant classes found. No output generated.");
else
- moc.generate(out, jsonOutput.data());
+ moc.generate(out.get(), jsonOutput.get());
}
- if (output.size())
- fclose(out);
+ out.reset();
if (parser.isSet(depFileOption)) {
// 4. write a Make-style dependency file (can also be consumed by Ninja).
@@ -587,23 +596,17 @@ int runMoc(int argc, char **argv)
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",
+ File depFileHandle = openFileForWriting(depOutputFileName);
+ if (!depFileHandle) {
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n",
QFile::encodeName(depOutputFileName).constData(),
- strerror(errno));
- depFileHandle.reset(depFileHandleRaw);
+ strerror(fopen_errno));
+ }
- if (!depFileHandle.isNull()) {
+ if (depFileHandle) {
// First line is the path to the generated file.
- fprintf(depFileHandle.data(), "%s: ",
+ fprintf(depFileHandle.get(), "%s: ",
escapeAndEncodeDependencyPath(depRuleName).constData());
QByteArrayList dependencies;
@@ -635,7 +638,7 @@ int runMoc(int argc, char **argv)
// Join dependencies, output them, and output a final new line.
const auto dependenciesJoined = dependencies.join(QByteArrayLiteral(" \\\n "));
- fprintf(depFileHandle.data(), "%s\n", dependenciesJoined.constData());
+ fprintf(depFileHandle.get(), "%s\n", dependenciesJoined.constData());
}
}
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 64e98ae63b..3cbe331f14 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -26,6 +26,15 @@ 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
@@ -87,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);
@@ -243,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;
@@ -318,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)
@@ -409,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();
@@ -421,31 +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();
}
+ next(LPAREN, "Not a signal or slot declaration");
+ def->name = tempType.name;
+ scopedFunctionName = tempType.isScoped;
if (!test(RPAREN)) {
parseFunctionArguments(def);
@@ -509,14 +518,20 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
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();
@@ -531,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
@@ -593,6 +613,52 @@ inline void handleDefaultArguments(QList<FunctionDef> *functionList, FunctionDef
}
}
+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()
{
QList<NamespaceDef> namespaceList;
@@ -601,7 +667,7 @@ void Moc::parse()
Token t = next();
switch (t) {
case NAMESPACE: {
- int rewind = index;
+ qsizetype rewind = index;
if (test(IDENTIFIER)) {
QByteArray nsName = lexem();
QByteArrayList nested;
@@ -633,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;
@@ -652,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);
@@ -783,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);
@@ -798,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:
@@ -916,7 +978,7 @@ 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) {
@@ -965,9 +1027,13 @@ 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);
@@ -987,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);
@@ -1066,12 +1134,13 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
void Moc::generate(FILE *out, FILE *jsonOutput)
{
- QByteArray fn = filename;
- int i = filename.size()-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);
@@ -1084,9 +1153,8 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
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 + '\"';
@@ -1105,18 +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%s#include <QtCore/qtmochelpers.h>\n%s\n",
-#if QT_VERSION <= QT_VERSION_CHECK(6, 9, 0)
- "#if __has_include(<QtCore/qtmochelpers.h>)\n",
- "#else\n"
- "QT_BEGIN_MOC_NAMESPACE\n"
- "#endif\n"
-#else
- "", ""
-#endif
- );
+ 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());
@@ -1138,9 +1198,16 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
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);
@@ -1300,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;
@@ -1327,11 +1395,11 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
} 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(1);
+ error(lsym);
} else {
next(IDENTIFIER);
v = lexem();
@@ -1345,7 +1413,7 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
if (l == "MEMBER")
propDef.member = v;
else
- error(2);
+ error(lsym);
break;
case 'R':
if (l == "READ")
@@ -1356,10 +1424,10 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
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") {
@@ -1369,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()) {
@@ -1449,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;
@@ -1620,7 +1690,7 @@ void Moc::parseInterfaces(ClassDef *def)
}
}
// resolve from classnames to interface ids
- for (int i = 0; i < iface.size(); ++i) {
+ for (qsizetype i = 0; i < iface.size(); ++i) {
const QByteArray iid = interface2IdMap.value(iface.at(i).className);
if (iid.isEmpty())
error("Undefined interface");
@@ -1697,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) {
@@ -1733,7 +1803,7 @@ bool Moc::until(Token target) {
//when searching commas within the default argument, we should take care of template depth (anglecount)
// 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;
@@ -1797,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
@@ -1812,8 +1883,18 @@ void Moc::checkSuperClasses(ClassDef *def)
#endif
return;
}
- for (int i = 1; i < def->superclassList.size(); ++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 "
@@ -1827,14 +1908,7 @@ void Moc::checkSuperClasses(ClassDef *def)
}
if (interface2IdMap.contains(superClass)) {
- bool registeredInterface = false;
- for (int i = 0; i < def->interfaceList.size(); ++i)
- if (def->interfaceList.at(i).constFirst().className == superClass) {
- registeredInterface = true;
- break;
- }
-
- if (!registeredInterface) {
+ if (!isRegisteredInterface(superClass)) {
const QByteArray msg
= "Class "
+ def->classname
@@ -1856,30 +1930,26 @@ void Moc::checkProperties(ClassDef *cdef)
// returning pointers, or const char * for QByteArray.
//
QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- PropertyDef &p = cdef->propertyList[i];
+ 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.size(); ++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
@@ -1905,7 +1975,7 @@ void Moc::checkProperties(ClassDef *cdef)
}
if (!p.notify.isEmpty()) {
int notifyId = -1;
- for (int j = 0; j < cdef->signalList.size(); ++j) {
+ for (int j = 0; j < int(cdef->signalList.size()); ++j) {
const FunctionDef &f = cdef->signalList.at(j);
if (f.name != p.notify) {
continue;
@@ -1916,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.size();
+ p.notifyId = int(-1 - cdef->nonClassSignalList.size());
} else {
- p.notifyId = -2 - index;
+ p.notifyId = int(-2 - index);
}
}
}
@@ -1978,11 +2048,11 @@ QJsonObject ClassDef::toJson() const
QJsonArray superClasses;
for (const auto &super: std::as_const(superclassList)) {
- const auto name = super.first;
- const auto access = super.second;
QJsonObject superCls;
- superCls["name"_L1] = 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);
}
@@ -2107,6 +2177,8 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const
def["name"_L1] = QString::fromUtf8(name);
if (!enumName.isEmpty())
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;
@@ -2119,4 +2191,23 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const
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
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index edeac03b82..c1759fb0a3 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -7,11 +7,10 @@
#include "parser.h"
#include <qstringlist.h>
#include <qmap.h>
-#include <qpair.h>
#include <qjsondocument.h>
#include <qjsonarray.h>
#include <qjsonobject.h>
-#include <qversionnumber.h>
+#include <qtyperevision.h>
#include <stdio.h>
#include <private/qtools_p.h>
@@ -43,10 +42,12 @@ struct EnumDef
{
QByteArray name;
QByteArray enumName;
+ QByteArray type;
QList<QByteArray> values;
bool isEnumClass; // c++11 enum class
EnumDef() : isEnumClass(false) {}
QJsonObject toJson(const ClassDef &cdef) const;
+ QByteArray qualifiedType(const ClassDef *cdef) const;
};
Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE);
@@ -120,7 +121,7 @@ struct PropertyDef
bool required = false;
int relativeIndex = -1; // property index in current metaobject
- int location = -1; // token index, used for error reporting
+ qsizetype location = -1; // token index, used for error reporting
QJsonObject toJson() const;
};
@@ -150,12 +151,19 @@ struct BaseDef {
QMap<QByteArray, bool> enumDeclarations;
QList<EnumDef> enumList;
QMap<QByteArray, QByteArray> flagAliases;
- int begin = 0;
- int end = 0;
+ qsizetype begin = 0;
+ qsizetype end = 0;
};
+struct SuperClass {
+ QByteArray classname;
+ QByteArray qualified;
+ FunctionDef::Access access;
+};
+Q_DECLARE_TYPEINFO(SuperClass, Q_RELOCATABLE_TYPE);
+
struct ClassDef : BaseDef {
- QList<QPair<QByteArray, FunctionDef::Access>> superclassList;
+ QList<SuperClass> superclassList;
struct Interface
{
@@ -233,6 +241,10 @@ public:
return index > def->begin && index < def->end - 1;
}
+ const QByteArray &toFullyQualified(const QByteArray &name) const noexcept;
+
+ void prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const;
+
Type parseType();
bool parseEnum(EnumDef *def);
@@ -277,6 +289,9 @@ public:
void checkSuperClasses(ClassDef *def);
void checkProperties(ClassDef* cdef);
+ bool testForFunctionModifiers(FunctionDef *def);
+
+ void checkListSizes(const ClassDef &def);
};
inline QByteArray noRef(const QByteArray &type)
diff --git a/src/tools/moc/parser.cpp b/src/tools/moc/parser.cpp
index 6fa0e645d3..1cfb8ce486 100644
--- a/src/tools/moc/parser.cpp
+++ b/src/tools/moc/parser.cpp
@@ -8,42 +8,80 @@
QT_BEGIN_NAMESPACE
-#ifdef USE_LEXEM_STORE
-Symbol::LexemStore Symbol::lexemStore;
-#endif
-
static const char *error_msg = nullptr;
+/*! \internal
+ Base implementation for printing diagnostic messages.
+
+ For example:
+ "/path/to/file:line:column: error: %s\n"
+ '%s' is replaced by \a msg. (Currently "column" is always 1).
+
+ If sym.lineNum is -1, the line and column parts aren't printed:
+ "/path/to/file: error: %s\n"
+
+ \a formatStringSuffix specifies the type of the message e.g.:
+ "error: %s\n"
+ "warning: %s\n"
+ "note: %s\n"
+ "Parse error at %s\n" (from defaultErrorMsg())
+*/
+void Parser::printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym)
+{
+ if (sym.lineNum != -1) {
#ifdef Q_CC_MSVC
-#define ErrorFormatString "%s(%d:%d): "
+ QByteArray formatString = "%s(%d:%d): " + formatStringSuffix;
#else
-#define ErrorFormatString "%s:%d:%d: "
+ QByteArray formatString = "%s:%d:%d: " + formatStringSuffix;
#endif
+ fprintf(stderr, formatString.constData(),
+ currentFilenames.top().constData(), sym.lineNum, 1, msg.data());
+ } else {
+ QByteArray formatString = "%s: " + formatStringSuffix;
+ fprintf(stderr, formatString.constData(),
+ currentFilenames.top().constData(), msg.data());
+ }
+}
+
+void Parser::defaultErrorMsg(const Symbol &sym)
+{
+ if (sym.lineNum != -1)
+ printMsg("error: Parse error at \"%s\"\n", sym.lexem().data(), sym);
+ else
+ printMsg("error: could not parse file\n", "", sym);
+}
-void Parser::error(int rollback) {
- index -= rollback;
- error();
+void Parser::error(const Symbol &sym)
+{
+ defaultErrorMsg(sym);
+ exit(EXIT_FAILURE);
}
-void Parser::error(const char *msg) {
+
+void Parser::error(const char *msg)
+{
if (msg || error_msg)
- fprintf(stderr, ErrorFormatString "error: %s\n",
- currentFilenames.top().constData(), symbol().lineNum, 1, msg?msg:error_msg);
+ printMsg("error: %s\n",
+ msg ? msg : error_msg,
+ index > 0 ? symbol() : Symbol{});
else
- fprintf(stderr, ErrorFormatString "error: Parse error at \"%s\"\n",
- currentFilenames.top().constData(), symbol().lineNum, 1, symbol().lexem().data());
+ defaultErrorMsg(symbol());
+
exit(EXIT_FAILURE);
}
+void Parser::warning(const Symbol &sym, QByteArrayView msg)
+{
+ if (displayWarnings)
+ printMsg("warning: %s\n", msg, sym);
+}
+
void Parser::warning(const char *msg) {
- if (displayWarnings && msg)
- fprintf(stderr, ErrorFormatString "warning: %s\n",
- currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
+ warning(index > 0 ? symbol() : Symbol{}, msg);
}
void Parser::note(const char *msg) {
if (displayNotes && msg)
- fprintf(stderr, ErrorFormatString "note: %s\n",
- currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
+ printMsg("note: %s\n", msg, index > 0 ? symbol() : Symbol{});
}
QT_END_NAMESPACE
diff --git a/src/tools/moc/parser.h b/src/tools/moc/parser.h
index 5f754d9b19..6fe982a1ce 100644
--- a/src/tools/moc/parser.h
+++ b/src/tools/moc/parser.h
@@ -5,6 +5,7 @@
#define PARSER_H
#include "symbols.h"
+#include <QtCore/qbytearrayview.h>
#include <stack>
@@ -15,7 +16,7 @@ class Parser
public:
Parser():index(0), displayWarnings(true), displayNotes(true) {}
Symbols symbols;
- int index;
+ qsizetype index;
bool displayWarnings;
bool displayNotes;
@@ -43,11 +44,15 @@ public:
inline QByteArray lexem() { return symbols.at(index-1).lexem();}
inline QByteArray unquotedLexem() { return symbols.at(index-1).unquotedLexem();}
inline const Symbol &symbol() { return symbols.at(index-1);}
+ inline const Symbol &symbolAt(qsizetype idx) { return symbols.at(idx); }
- Q_NORETURN void error(int rollback);
+ Q_NORETURN void error(const Symbol &symbol);
Q_NORETURN void error(const char *msg = nullptr);
void warning(const char * = nullptr);
+ void warning(const Symbol &sym, QByteArrayView msg);
void note(const char * = nullptr);
+ void defaultErrorMsg(const Symbol &sym);
+ void printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym);
};
@@ -62,7 +67,7 @@ inline bool Parser::test(Token token)
inline Token Parser::lookup(int k)
{
- const int l = index - 1 + k;
+ const qsizetype l = index - 1 + k;
return l < symbols.size() ? symbols.at(l).token : NOTOKEN;
}
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 0958e26be3..11ea8d417e 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -12,6 +12,8 @@
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
#include "ppkeywords.cpp"
#include "keywords.cpp"
@@ -212,7 +214,9 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
data -= 2;
break;
case DIGIT:
- while (is_digit_char(*data) || *data == '\'')
+ {
+ bool hasSeenTokenSeparator = false;;
+ while (isAsciiDigit(*data) || (hasSeenTokenSeparator = *data == '\''))
++data;
if (!*data || *data != '.') {
token = INTEGER_LITERAL;
@@ -221,22 +225,30 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
|| *data == 'b' || *data == 'B')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data) || *data == '\'')
+ while (isHexDigit(*data) || (hasSeenTokenSeparator = *data == '\''))
+ ++data;
+ } else if (*data == 'L') // TODO: handle other suffixes
+ ++data;
+ if (!hasSeenTokenSeparator) {
+ while (is_ident_char(*data)) {
++data;
+ token = IDENTIFIER;
+ }
}
break;
}
token = FLOATING_LITERAL;
++data;
Q_FALLTHROUGH();
+ }
case FLOATING_LITERAL:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -315,16 +327,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
continue; //ignore
}
}
-#ifdef USE_LEXEM_STORE
- if (!Preprocessor::preprocessOnly
- && token != IDENTIFIER
- && token != STRING_LITERAL
- && token != FLOATING_LITERAL
- && token != INTEGER_LITERAL)
- symbols += Symbol(lineNum, token);
- else
-#endif
- symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
+ symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
} else { // Preprocessor
@@ -390,7 +393,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
token = PP_CHARACTER_LITERAL;
break;
case PP_DIGIT:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (!*data || *data != '.') {
token = PP_INTEGER_LITERAL;
@@ -398,22 +401,23 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
(*data == 'x' || *data == 'X')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data) || *data == '\'')
+ while (isHexDigit(*data) || *data == '\'')
++data;
- }
+ } else if (*data == 'L') // TODO: handle other suffixes
+ ++data;
break;
}
token = PP_FLOATING_LITERAL;
++data;
Q_FALLTHROUGH();
case PP_FLOATING_LITERAL:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -495,22 +499,14 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
}
if (mode == PreparePreprocessorStatement)
continue;
-#ifdef USE_LEXEM_STORE
- if (token != PP_IDENTIFIER
- && token != PP_STRING_LITERAL
- && token != PP_FLOATING_LITERAL
- && token != PP_INTEGER_LITERAL)
- symbols += Symbol(lineNum, token);
- else
-#endif
- symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
+ symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
}
}
symbols += Symbol(); // eof symbol
return symbols;
}
-void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index,
+void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, qsizetype &index,
int lineNum, bool one, const QSet<QByteArray> &excludeSymbols)
{
SymbolStack symbols;
@@ -618,19 +614,22 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
HashHash
} mode = Normal;
- for (int i = 0; i < macro.symbols.size(); ++i) {
- const Symbol &s = macro.symbols.at(i);
+ const auto end = macro.symbols.cend();
+ auto it = macro.symbols.cbegin();
+ const auto lastSym = std::prev(macro.symbols.cend(), !macro.symbols.isEmpty() ? 1 : 0);
+ for (; it != end; ++it) {
+ const Symbol &s = *it;
if (s.token == HASH || s.token == PP_HASHHASH) {
mode = (s.token == HASH ? Hash : HashHash);
continue;
}
- int index = macro.arguments.indexOf(s);
+ const qsizetype index = macro.arguments.indexOf(s);
if (mode == Normal) {
if (index >= 0 && index < arguments.size()) {
// each argument undoergoes macro expansion if it's not used as part of a # or ##
- if (i == macro.symbols.size() - 1 || macro.symbols.at(i + 1).token != PP_HASHHASH) {
+ if (it == lastSym || std::next(it)->token != PP_HASHHASH) {
Symbols arg = arguments.at(index);
- int idx = 1;
+ qsizetype idx = 1;
macroExpand(&expansion, that, arg, idx, lineNum, false, symbols.excludeSymbols());
} else {
expansion += arguments.at(index);
@@ -649,9 +648,9 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
const Symbols &arg = arguments.at(index);
QByteArray stringified;
- for (int i = 0; i < arg.size(); ++i) {
- stringified += arg.at(i).lexem();
- }
+ for (const Symbol &sym : arg)
+ stringified += sym.lexem();
+
stringified.replace('"', "\\\"");
stringified.prepend('"');
stringified.append('"');
@@ -685,8 +684,8 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
if (index >= 0 && index < arguments.size()) {
const Symbols &arg = arguments.at(index);
- for (int i = 1; i < arg.size(); ++i)
- expansion += arg.at(i);
+ if (!arg.isEmpty())
+ expansion.append(arg.cbegin() + 1, arg.cend());
}
}
mode = Normal;
@@ -927,7 +926,11 @@ int PP_Expression::primary_expression()
test(PP_RPAREN);
} else {
next();
- value = lexem().toInt(nullptr, 0);
+ const QByteArray &lex = lexem();
+ auto lexView = QByteArrayView(lex);
+ if (lex.endsWith('L'))
+ lexView.chop(1);
+ value = lexView.toInt(nullptr, 0);
}
return value;
}
@@ -966,7 +969,7 @@ static void mergeStringLiterals(Symbols *_symbols)
for (Symbols::iterator i = symbols.begin(); i != symbols.end(); ++i) {
if (i->token == STRING_LITERAL) {
Symbols::Iterator mergeSymbol = i;
- int literalsLength = mergeSymbol->len;
+ qsizetype literalsLength = mergeSymbol->len;
while (++i != symbols.end() && i->token == STRING_LITERAL)
literalsLength += i->len - 2; // no quotes
@@ -1000,10 +1003,12 @@ static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepa
fprintf(stderr, "debug-includes: searching for '%s'\n", include.constData());
}
- for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) {
- const Parser::IncludePath &p = includepaths.at(j);
+ for (const Parser::IncludePath &p : includepaths) {
+ if (fi.exists())
+ break;
+
if (p.isFrameworkPath) {
- const int slashPos = include.indexOf('/');
+ const qsizetype slashPos = include.indexOf('/');
if (slashPos == -1)
continue;
fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"),
@@ -1099,7 +1104,7 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
continue;
Symbols saveSymbols = symbols;
- int saveIndex = index;
+ qsizetype saveIndex = index;
// phase 1: get rid of backslash-newlines
input = cleaned(input);
@@ -1134,14 +1139,14 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
} else {
macro.isFunction = false;
}
- int start = index;
+ qsizetype start = index;
until(PP_NEWLINE);
macro.symbols.reserve(index - start - 1);
// remove whitespace where there shouldn't be any:
// Before and after the macro, after a # and around ##
Token lastToken = HASH; // skip shitespace at the beginning
- for (int i = start; i < index - 1; ++i) {
+ for (qsizetype i = start; i < index - 1; ++i) {
Token token = symbols.at(i).token;
if (token == WHITESPACE) {
if (lastToken == PP_HASH || lastToken == HASH ||
diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h
index 84186fec9e..3509e83dce 100644
--- a/src/tools/moc/preprocessor.h
+++ b/src/tools/moc/preprocessor.h
@@ -20,11 +20,7 @@ struct Macro
Symbols symbols;
};
-#ifdef USE_LEXEM_STORE
-typedef QByteArray MacroName;
-#else
typedef SubArray MacroName;
-#endif
typedef QHash<MacroName, Macro> Macros;
class QFile;
@@ -48,8 +44,9 @@ public:
void substituteUntilNewline(Symbols &substituted);
static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName);
- static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, int lineNum, bool one,
- const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
+ static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand,
+ qsizetype &index, int lineNum, bool one,
+ const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
int evaluateCondition();
diff --git a/src/tools/moc/symbols.h b/src/tools/moc/symbols.h
index cde01cf11d..869f7c793f 100644
--- a/src/tools/moc/symbols.h
+++ b/src/tools/moc/symbols.h
@@ -7,7 +7,7 @@
#include "token.h"
#include <qdebug.h>
-#include <qhash.h>
+#include <qhashfunctions.h>
#include <qlist.h>
#include <qstack.h>
#include <qstring.h>
@@ -15,73 +15,48 @@
QT_BEGIN_NAMESPACE
-//#define USE_LEXEM_STORE
-
struct SubArray
{
- inline SubArray():from(0),len(-1){}
+ inline SubArray() = default;
inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){}
inline SubArray(const char *s):array(s),from(0) { len = array.size(); }
- inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){}
+ SubArray(const QByteArray &a, qsizetype from, qsizetype len)
+ : array(a), from(from), len(len)
+ {
+ }
QByteArray array;
- int from, len;
+ qsizetype from = 0;
+ qsizetype len = -1;
inline bool operator==(const SubArray &other) const {
if (len != other.len)
return false;
- for (int i = 0; i < len; ++i)
- if (array.at(from + i) != other.array.at(other.from + i))
- return false;
- return true;
+ const auto begin = array.cbegin() + from;
+ const auto end = begin + len;
+ const auto other_begin = other.array.cbegin() + other.from;
+ return std::equal(begin, end, other_begin);
}
};
-inline size_t qHash(const SubArray &key)
+inline size_t qHash(const SubArray &key, size_t seed = 0)
{
- return qHash(QLatin1StringView(key.array.constData() + key.from, key.len));
+ return qHash(QLatin1StringView(key.array.constData() + key.from, key.len), seed);
}
struct Symbol
{
-
-#ifdef USE_LEXEM_STORE
- typedef QHash<SubArray, QHashDummyValue> LexemStore;
- static LexemStore lexemStore;
-
- inline Symbol() : lineNum(-1),token(NOTOKEN){}
- inline Symbol(int lineNum, Token token):
- lineNum(lineNum), token(token){}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem):
- lineNum(lineNum), token(token),lex(lexem){}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
- lineNum(lineNum), token(token){
- LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len));
-
- if (it != lexemStore.constEnd()) {
- lex = it.key().array;
- } else {
- lex = lexem.mid(from, len);
- lexemStore.insert(lex, QHashDummyValue());
- }
+ inline Symbol() = default;
+ inline Symbol(int lineNum, Token token) : lineNum(lineNum), token(token) { }
+ inline Symbol(int lineNum, Token token, const QByteArray &lexem)
+ : lineNum(lineNum), token(token), lex(lexem), len(lex.size())
+ {
}
- int lineNum;
- Token token;
- inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); }
- inline QByteArray lexem() const { return lex; }
- inline operator QByteArray() const { return lex; }
- QByteArray lex;
-
-#else
-
- inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {}
- inline Symbol(int lineNum, Token token):
- lineNum(lineNum), token(token), from(0), len(-1) {}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem):
- lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); }
- inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
- lineNum(lineNum), token(token),lex(lexem),from(from), len(len){}
- int lineNum;
- Token token;
+ Symbol(int lineNum, Token token, const QByteArray &lexem, qsizetype from, qsizetype len)
+ : lineNum(lineNum), token(token), lex(lexem), from(from), len(len)
+ {
+ }
+ int lineNum = -1;
+ Token token = NOTOKEN;
inline QByteArray lexem() const { return lex.mid(from, len); }
inline QByteArray unquotedLexem() const { return lex.mid(from+1, len-2); }
inline operator SubArray() const { return SubArray(lex, from, len); }
@@ -90,9 +65,8 @@ struct Symbol
return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len);
}
QByteArray lex;
- int from, len;
-
-#endif
+ qsizetype from = 0;
+ qsizetype len = -1;
};
Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE);
@@ -102,7 +76,7 @@ struct SafeSymbols {
Symbols symbols;
QByteArray expandedMacro;
QSet<QByteArray> excludedSymbols;
- int index;
+ qsizetype index;
};
Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE);
@@ -127,13 +101,13 @@ public:
inline QByteArray lexem() const { return symbol().lexem(); }
inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); }
- bool dontReplaceSymbol(const QByteArray &name);
- QSet<QByteArray> excludeSymbols();
+ bool dontReplaceSymbol(const QByteArray &name) const;
+ QSet<QByteArray> excludeSymbols() const;
};
inline bool SymbolStack::test(Token token)
{
- int stackPos = size() - 1;
+ qsizetype stackPos = size() - 1;
while (stackPos >= 0 && at(stackPos).index >= at(stackPos).symbols.size())
--stackPos;
if (stackPos < 0)
@@ -145,21 +119,20 @@ inline bool SymbolStack::test(Token token)
return false;
}
-inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name)
+inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) const
{
- for (int i = 0; i < size(); ++i) {
- if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name))
- return true;
- }
- return false;
+ auto matchesName = [&name](const SafeSymbols &sf) {
+ return name == sf.expandedMacro || sf.excludedSymbols.contains(name);
+ };
+ return std::any_of(cbegin(), cend(), matchesName);
}
-inline QSet<QByteArray> SymbolStack::excludeSymbols()
+inline QSet<QByteArray> SymbolStack::excludeSymbols() const
{
QSet<QByteArray> set;
- for (int i = 0; i < size(); ++i) {
- set << at(i).expandedMacro;
- set += at(i).excludedSymbols;
+ for (const SafeSymbols &sf : *this) {
+ set << sf.expandedMacro;
+ set += sf.excludedSymbols;
}
return set;
}
diff --git a/src/tools/moc/util/generate.sh b/src/tools/moc/util/generate.sh
index 4514ca4930..6be06e5a91 100755
--- a/src/tools/moc/util/generate.sh
+++ b/src/tools/moc/util/generate.sh
@@ -6,7 +6,7 @@ set -ex
qmake
make
-cat licenseheader.txt > ../keywords.cpp
-cat licenseheader.txt > ../ppkeywords.cpp
+cat licenseheader.cpp.in > ../keywords.cpp
+cat licenseheader.cpp.in > ../ppkeywords.cpp
./generate_keywords >> ../keywords.cpp
./generate_keywords preprocessor >> ../ppkeywords.cpp
diff --git a/src/tools/moc/util/licenseheader.txt b/src/tools/moc/util/licenseheader.cpp.in
index 42958a66f5..42958a66f5 100644
--- a/src/tools/moc/util/licenseheader.txt
+++ b/src/tools/moc/util/licenseheader.cpp.in
diff --git a/src/tools/moc/utils.h b/src/tools/moc/utils.h
index 358780a33d..0b0d70f462 100644
--- a/src/tools/moc/utils.h
+++ b/src/tools/moc/utils.h
@@ -5,6 +5,9 @@
#define UTILS_H
#include <QtCore/qglobal.h>
+#include <private/qtools_p.h>
+
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -20,49 +23,20 @@ inline bool is_space(char s)
inline bool is_ident_start(char s)
{
- return ((s >= 'a' && s <= 'z')
- || (s >= 'A' && s <= 'Z')
- || s == '_' || s == '$'
- );
+ using namespace QtMiscUtils;
+ return isAsciiLower(s) || isAsciiUpper(s) || s == '_' || s == '$';
}
inline bool is_ident_char(char s)
{
- return ((s >= 'a' && s <= 'z')
- || (s >= 'A' && s <= 'Z')
- || (s >= '0' && s <= '9')
- || s == '_' || s == '$'
- );
+ return QtMiscUtils::isAsciiLetterOrNumber(s) || s == '_' || s == '$';
}
-inline bool is_identifier(const char *s, int len)
+inline bool is_identifier(const char *s, qsizetype len)
{
if (len < 1)
return false;
- if (!is_ident_start(*s))
- return false;
- for (int i = 1; i < len; ++i)
- if (!is_ident_char(s[i]))
- return false;
- return true;
-}
-
-inline bool is_digit_char(char s)
-{
- return (s >= '0' && s <= '9');
-}
-
-inline bool is_octal_char(char s)
-{
- return (s >= '0' && s <= '7');
-}
-
-inline bool is_hex_char(char s)
-{
- return ((s >= 'a' && s <= 'f')
- || (s >= 'A' && s <= 'F')
- || (s >= '0' && s <= '9')
- );
+ return std::all_of(s, s + len, is_ident_char);
}
inline const char *skipQuote(const char *data)