diff options
Diffstat (limited to 'src/tools/moc/generator.cpp')
-rw-r--r-- | src/tools/moc/generator.cpp | 778 |
1 files changed, 388 insertions, 390 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 37797ef7db..1c6604a96e 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com> -** Copyright (C) 2018 Intel Corporation. -** 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) 2020 The Qt Company Ltd. +// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com> +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "generator.h" #include "cbordevice.h" @@ -48,6 +23,8 @@ QT_BEGIN_NAMESPACE +using namespace QtMiscUtils; + uint nameToBuiltinType(const QByteArray &name) { if (name.isEmpty()) @@ -80,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), @@ -92,32 +70,53 @@ 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.length() - 1) + 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.length() && 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.length() - && is_octal_char(s.at(i))) { + && i < s.size() + && isOctalDigit(s.at(i))) { ++i; } } else { // single character escape sequence - i = qMin(i + 1, s.length()); + i = qMin(i + 1, s.size()); } return i - startPos; } +// 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; + const qsizetype len = s.size(); + qsizetype idx = 0; + + do { + qsizetype spanLen = qMin(ColumnWidth - 2, len - idx); + // don't cut escape sequences at the end of a line + const qsizetype backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1); + if (backSlashPos >= idx) { + const qsizetype escapeLen = lengthOfEscapeSequence(s, backSlashPos); + spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, len - idx); + } + fprintf(out, "\n \"%.*s\"", int(spanLen), s.constData() + idx); + idx += spanLen; + } while (idx < len); +} + void Generator::strreg(const QByteArray &s) { if (!strings.contains(s)) @@ -126,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; } @@ -137,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.count(); ++i) - sum += list.at(i).arguments.count() + 1; // +1 for return type + for (const FunctionDef &def : list) + sum += int(def.arguments.size()) + 1; // +1 for return type return sum; } @@ -175,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); } } @@ -195,12 +194,28 @@ 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); } +static QByteArray generateQualifiedClassNameIdentifier(const QByteArray &identifier) +{ + QByteArray qualifiedClassNameIdentifier = identifier; + + // Remove ':'s in the name, but be sure not to create any illegal + // identifiers in the process. (Don't replace with '_', because + // that will create problems with things like NS_::_class.) + qualifiedClassNameIdentifier.replace("::", "SCOPE"); + + // Also, avoid any leading/trailing underscores (we'll concatenate + // the generated name with other prefixes/suffixes, and these latter + // may already include an underscore, leading to two underscores) + qualifiedClassNameIdentifier = "CLASS" + qualifiedClassNameIdentifier + "ENDCLASS"; + return qualifiedClassNameIdentifier; +} + void Generator::generateCode() { bool isQObject = (cdef->classname == "QObject"); @@ -209,8 +224,7 @@ void Generator::generateCode() // filter out undeclared enumerators and sets { QList<EnumDef> enumList; - for (int i = 0; i < cdef->enumList.count(); ++i) { - EnumDef def = cdef->enumList.at(i); + for (EnumDef def : std::as_const(cdef->enumList)) { if (cdef->enumDeclarations.contains(def.name)) { enumList += def; } @@ -237,128 +251,58 @@ void Generator::generateCode() registerPropertyStrings(); registerEnumStrings(); - QByteArray qualifiedClassNameIdentifier = cdef->qualified; - qualifiedClassNameIdentifier.replace(':', '_'); + const bool hasStaticMetaCall = + (cdef->hasQObject || !cdef->methodList.isEmpty() + || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); + + const QByteArray qualifiedClassNameIdentifier = generateQualifiedClassNameIdentifier(cdef->qualified); + + // ensure the qt_meta_stringdata_XXXX_t type is local + fprintf(out, "namespace {\n"); // -// Build stringdata struct +// Build the strings using QtMocHelpers::StringData // - const int constCharArraySizeLimit = 65535; - fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData()); - fprintf(out, " const uint offsetsAndSize[%d];\n", int(strings.size()*2)); - { - int stringDataLength = 0; - int stringDataCounter = 0; - for (int i = 0; i < strings.size(); ++i) { - int thisLength = strings.at(i).length() + 1; - stringDataLength += thisLength; - if (stringDataLength / constCharArraySizeLimit) { - // save previous stringdata and start computing the next one. - fprintf(out, " char stringdata%d[%d];\n", stringDataCounter++, stringDataLength - thisLength); - stringDataLength = thisLength; - } - } - fprintf(out, " char stringdata%d[%d];\n", stringDataCounter, stringDataLength); - } - fprintf(out, "};\n"); - - // Macro that expands into a QByteArrayData. The offset member is - // calculated from 1) the offset of the actual characters in the - // stringdata.stringdata member, and 2) the stringdata.data index of the - // QByteArrayData being defined. This calculation relies on the - // QByteArrayData::data() implementation returning simply "this + offset". - fprintf(out, "#define QT_MOC_LITERAL(ofs, len) \\\n" - " uint(offsetof(qt_meta_stringdata_%s_t, stringdata0) + ofs), len \n", - qualifiedClassNameIdentifier.constData()); - - fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n", + fprintf(out, "\n#ifdef QT_MOC_HAS_STRINGDATA\n" + "struct qt_meta_stringdata_%s_t {};\n" + "constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(", qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); - fprintf(out, " {\n"); { - int idx = 0; - for (int i = 0; i < strings.size(); ++i) { - const QByteArray &str = strings.at(i); - fprintf(out, "QT_MOC_LITERAL(%d, %d)", idx, int(str.length())); - if (i != strings.size() - 1) - fputc(',', out); - const QByteArray comment = str.length() > 32 ? str.left(29) + "..." : str; - fprintf(out, " // \"%s\"\n", comment.size() ? comment.constData() : ""); - idx += str.length() + 1; - for (int j = 0; j < str.length(); ++j) { - if (str.at(j) == '\\') { - int cnt = lengthOfEscapeSequence(str, j) - 1; - idx -= cnt; - j += cnt; - } - } - } - fprintf(out, "\n },\n"); - } - -// -// Build stringdata array -// - fprintf(out, " \""); - int col = 0; - int len = 0; - int stringDataLength = 0; - for (int i = 0; i < strings.size(); ++i) { - QByteArray s = strings.at(i); - len = s.length(); - stringDataLength += len + 1; - if (stringDataLength >= constCharArraySizeLimit) { - fprintf(out, "\",\n \""); - stringDataLength = len + 1; - col = 0; - } else if (i) - fputs("\\0", out); // add \0 at the end of each string - - if (col && col + len >= 72) { - fprintf(out, "\"\n \""); - col = 0; - } else if (len && s.at(0) >= '0' && s.at(0) <= '9') { - fprintf(out, "\"\""); - len += 2; - } - int idx = 0; - while (idx < s.length()) { - if (idx > 0) { - col = 0; - fprintf(out, "\"\n \""); - } - int spanLen = qMin(70, s.length() - idx); - // don't cut escape sequences at the end of a line - int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1); - if (backSlashPos >= idx) { - int escapeLen = lengthOfEscapeSequence(s, backSlashPos); - spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx); - } - fprintf(out, "%.*s", spanLen, s.constData() + idx); - idx += spanLen; - col += spanLen; + char comma = 0; + for (const QByteArray &str : strings) { + if (comma) + fputc(comma, out); + printStringWithIndentation(out, str); + comma = ','; } - col += len + 2; } - -// Terminate stringdata struct - fprintf(out, "\"\n};\n"); - fprintf(out, "#undef QT_MOC_LITERAL\n\n"); + fprintf(out, "\n);\n" + "#else // !QT_MOC_HAS_STRINGDATA\n"); + fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n"); + fprintf(out, "#endif // !QT_MOC_HAS_STRINGDATA\n"); + fprintf(out, "} // unnamed namespace\n\n"); // // build the data array // int index = MetaObjectPrivateFieldCount; - fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData()); + fprintf(out, "Q_CONSTINIT static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData()); fprintf(out, "\n // content:\n"); fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision)); fprintf(out, " %4d, // classname\n", stridx(cdef->qualified)); - fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.count()), int(cdef->classInfoList.count() ? index : 0)); - index += cdef->classInfoList.count() * 2; + fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0)); + index += cdef->classInfoList.size() * 2; + + 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."); + } - int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count(); - fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0); + fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0); index += methodCount * QMetaObjectPrivate::IntsPerMethod; if (cdef->revisionedMethods) index += methodCount; @@ -369,16 +313,17 @@ void Generator::generateCode() + aggregateParameterCount(cdef->constructorList); index += totalParameterCount * 2 // types and parameter names - methodCount // return "parameters" don't have names - - cdef->constructorList.count(); // "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.count()), int(cdef->propertyList.count() ? index : 0)); - index += cdef->propertyList.count() * QMetaObjectPrivate::IntsPerProperty; - fprintf(out, " %4d, %4d, // enums/sets\n", int(cdef->enumList.count()), cdef->enumList.count() ? index : 0); + 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.count(); ++i) - index += 5 + (cdef->enumList.at(i).values.count() * 2); - fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.count()) : 0, + 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); int flags = 0; @@ -388,7 +333,7 @@ void Generator::generateCode() flags |= PropertyAccessInStaticMetaCall; } fprintf(out, " %4d, // flags\n", flags); - fprintf(out, " %4d, // signalCount\n", int(cdef->signalList.count())); + fprintf(out, " %4d, // signalCount\n", int(cdef->signalList.size())); // @@ -396,8 +341,14 @@ void Generator::generateCode() // generateClassInfos(); - // all property metatypes, + 1 for the type of the current class itself - int initialMetaTypeOffset = cdef->propertyList.count() + 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 @@ -454,30 +405,20 @@ void Generator::generateCode() fprintf(out, "\n 0 // eod\n};\n\n"); // -// Generate internal qt_static_metacall() function -// - const bool hasStaticMetaCall = - (cdef->hasQObject || !cdef->methodList.isEmpty() - || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); - if (hasStaticMetaCall) - generateStaticMetacall(); - -// // Build extra array // QList<QByteArray> extraList; QMultiHash<QByteArray, QByteArray> knownExtraMetaObject(knownGadgets); knownExtraMetaObject.unite(knownQObjectClasses); - for (int i = 0; i < cdef->propertyList.count(); ++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; @@ -488,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); @@ -514,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)) @@ -527,28 +468,29 @@ void Generator::generateCode() // if (!extraList.isEmpty()) { - fprintf(out, "static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n", + fprintf(out, "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n", qualifiedClassNameIdentifier.constData()); - for (int i = 0; i < extraList.count(); ++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"); } // // Finally create and initialize the static meta object // - fprintf(out, "const QMetaObject %s::staticMetaObject = { {\n", cdef->qualified.constData()); + fprintf(out, "Q_CONSTINIT const QMetaObject %s::staticMetaObject = { {\n", + cdef->qualified.constData()); if (isQObject) fprintf(out, " nullptr,\n"); else if (cdef->superclassList.size() && !cdef->hasQGadget && !cdef->hasQNamespace) // for qobject, we know the super class must have a static metaobject fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData()); else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it - fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData()); + fprintf(out, " QtPrivate::MetaObjectForType<%s>::value,\n", purestSuperClass.constData()); else fprintf(out, " nullptr,\n"); - fprintf(out, " qt_meta_stringdata_%s.offsetsAndSize,\n" + fprintf(out, " qt_meta_stringdata_%s.offsetsAndSizes,\n" " qt_meta_data_%s,\n", qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); if (hasStaticMetaCall) @@ -561,63 +503,75 @@ void Generator::generateCode() else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); - bool needsComma = false; + const char *comma = ""; const bool requireCompleteness = requireCompleteTypes || cdef->requireCompleteMethodTypes; + auto stringForType = [requireCompleteness](const QByteArray &type, bool forceComplete) -> QByteArray { + const char *forceCompleteType = forceComplete ? ", std::true_type>" : ", std::false_type>"; + if (requireCompleteness) + return type; + return "QtPrivate::TypeAndForceComplete<" % type % forceCompleteType; + }; if (!requireCompleteness) { - fprintf(out, "qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t\n", qualifiedClassNameIdentifier.constData()); - needsComma = true; + fprintf(out, " qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t", qualifiedClassNameIdentifier.constData()); + comma = ","; } else { - fprintf(out, "qt_metaTypeArray<\n"); + fprintf(out, " qt_metaTypeArray<"); } // metatypes for properties - for (int i = 0; i < cdef->propertyList.count(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); - if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", p.type.data()); - else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", p.type.data()); - needsComma = true; + 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"; - if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", ownType); - else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", ownType); + fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s", + comma, stringForType(ownType, true).constData()); + comma = ","; // metatypes for all exposed methods - // no need to check for needsComma any longer, as we always need one due to the classname being present - for (const QList<FunctionDef> &methodContainer : - { cdef->signalList, cdef->slotList, cdef->methodList }) { - for (int i = 0; i< methodContainer.count(); ++i) { - const FunctionDef& fdef = methodContainer.at(i); - if (requireCompleteness) - fprintf(out, ", %s", fdef.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", fdef.type.name.data()); - for (const auto &argument: fdef.arguments) { - if (requireCompleteness) - fprintf(out, ", %s", argument.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); - } + // because we definitely printed something above, this section doesn't need comma control + 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) + fprintf(out, ",\n %s", stringForType(argument.type.name, false).constData()); } - fprintf(out, "\n"); } - for (int i = 0; i< cdef->constructorList.count(); ++i) { - const FunctionDef& fdef = cdef->constructorList.at(i); + + // but constructors have no return types, so this needs comma control again + for (const FunctionDef &fdef : std::as_const(cdef->constructorList)) { + if (fdef.arguments.isEmpty()) + continue; + + fprintf(out, "%s\n // constructor '%s'", comma, fdef.name.constData()); + comma = ""; for (const auto &argument: fdef.arguments) { - if (requireCompleteness) - fprintf(out, ", %s", argument.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); + fprintf(out, "%s\n %s", comma, + stringForType(argument.type.name, false).constData()); + comma = ","; } } - fprintf(out, "\n"); - fprintf(out, ">,\n"); + fprintf(out, "\n >,\n"); fprintf(out, " nullptr\n} };\n\n"); +// +// Generate internal qt_static_metacall() function +// + if (hasStaticMetaCall) + generateStaticMetacall(); + if (!cdef->hasQObject) return; @@ -633,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()); } @@ -665,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 @@ -677,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 : qAsConst(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"); } } @@ -690,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); } @@ -704,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.count(); ++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.count(); - 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); @@ -743,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.count(); ++i) { - const FunctionDef &f = list.at(i); - + for (const FunctionDef &f : list) { QByteArray comment; uint flags = type; if (f.access == FunctionDef::Private) { @@ -780,7 +748,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu comment.append(" | MethodIsConst "); } - int argc = f.arguments.count(); + 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()); @@ -792,12 +760,10 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu void Generator::generateFunctionRevisions(const QList<FunctionDef> &list, const char *functype) { - if (list.count()) + if (list.size()) fprintf(out, "\n // %ss: revision\n", functype); - for (int i = 0; i < list.count(); ++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) @@ -805,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.count(); ++i) { - const FunctionDef &f = list.at(i); + for (const FunctionDef &f : list) { fprintf(out, " "); // Types - int argsCount = f.arguments.count(); - 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"); } @@ -856,8 +819,7 @@ void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName void Generator::registerPropertyStrings() { - for (int i = 0; i < cdef->propertyList.count(); ++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); @@ -870,10 +832,9 @@ void Generator::generateProperties() // Create meta data // - if (cdef->propertyList.count()) - fprintf(out, "\n // properties: name, type, flags\n"); - for (int i = 0; i < cdef->propertyList.count(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); + if (cdef->propertyList.size()) + 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; @@ -917,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); @@ -926,13 +887,12 @@ void Generator::generateProperties() void Generator::registerEnumStrings() { - for (int i = 0; i < cdef->enumList.count(); ++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.count(); ++j) - strreg(e.values.at(j)); + for (const QByteArray &val : e.values) + strreg(val); } } @@ -942,9 +902,9 @@ void Generator::generateEnums(int index) return; fprintf(out, "\n // enums: name, alias, flags, count, data\n"); - index += 5 * cdef->enumList.count(); + index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size(); int i; - for (i = 0; i < cdef->enumList.count(); ++i) { + for (i = 0; i < cdef->enumList.size(); ++i) { const EnumDef &e = cdef->enumList.at(i); int flags = 0; if (cdef->enumDeclarations.value(e.name)) @@ -955,16 +915,14 @@ void Generator::generateEnums(int index) stridx(e.name), e.enumName.isNull() ? stridx(e.name) : stridx(e.enumName), flags, - int(e.values.count()), + int(e.values.size()), index); - index += e.values.count() * 2; + index += e.values.size() * 2; } fprintf(out, "\n // enum data: key, value\n"); - for (i = 0; i < cdef->enumList.count(); ++i) { - const EnumDef &e = cdef->enumList.at(i); - for (int j = 0; j < e.values.count(); ++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); @@ -1022,8 +980,6 @@ void Generator::generateMetacall() } if (cdef->propertyList.size()) { - - fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); if (needElse) fprintf(out, "else "); fprintf(out, @@ -1031,8 +987,7 @@ void Generator::generateMetacall() " || _c == QMetaObject::ResetProperty || _c == QMetaObject::BindableProperty\n" " || _c == QMetaObject::RegisterPropertyMetaType) {\n" " qt_static_metacall(this, _c, _id, _a);\n" - " _id -= %d;\n }", int(cdef->propertyList.count())); - fprintf(out, "\n#endif // QT_NO_PROPERTIES"); + " _id -= %d;\n }", int(cdef->propertyList.size())); } if (methodList.size() || cdef->propertyList.size()) fprintf(out, "\n "); @@ -1040,10 +995,11 @@ void Generator::generateMetacall() } +// ### Qt 7 (6.x?): remove 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); @@ -1057,7 +1013,7 @@ Generator::methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList) QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypes; for (int i = 0; i < methodList.size(); ++i) { const FunctionDef &f = methodList.at(i); - for (int j = 0; j < f.arguments.count(); ++j) { + for (int j = 0; j < f.arguments.size(); ++j) { const QByteArray argType = f.arguments.at(j).normalizedType; if (registerableMetaType(argType) && !isBuiltinType(argType)) methodsWithAutomaticTypes[i].insert(argType, j); @@ -1074,33 +1030,46 @@ void Generator::generateStaticMetacall() bool needElse = false; bool isUsed_a = false; + const auto generateCtorArguments = [&](int ctorindex) { + const FunctionDef &f = cdef->constructorList.at(ctorindex); + Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed + int offset = 1; + + 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++); + } + }; + if (!cdef->constructorList.isEmpty()) { fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n"); fprintf(out, " switch (_id) {\n"); - for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) { + 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()); - const FunctionDef &f = cdef->constructorList.at(ctorindex); - int offset = 1; - - int argsCount = f.arguments.count(); - for (int j = 0; j < argsCount; ++j) { - const ArgumentDef &a = f.arguments.at(j); - if (j) - fprintf(out, ","); - fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++); - } - if (f.isPrivateSignal) { - if (argsCount > 0) - fprintf(out, ", "); - fprintf(out, "%s", QByteArray("QPrivateSignal()").constData()); - } + generateCtorArguments(ctorindex); fprintf(out, ");\n"); fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n", (cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject"); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); + fprintf(out, " } else if (_c == QMetaObject::ConstructInPlace) {\n"); + fprintf(out, " switch (_id) {\n"); + for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) { + fprintf(out, " case %d: { new (_a[0]) %s(", + ctorindex, cdef->classname.constData()); + generateCtorArguments(ctorindex); + fprintf(out, "); } break;\n"); + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); fprintf(out, " }"); needElse = true; isUsed_a = true; @@ -1142,16 +1111,17 @@ void Generator::generateStaticMetacall() if (f.isRawSlot) { fprintf(out, "QMethodRawArguments{ _a }"); } else { - int argsCount = f.arguments.count(); - 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()"); } @@ -1204,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; @@ -1212,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.count(); - 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"); } @@ -1228,7 +1199,7 @@ void Generator::generateStaticMetacall() fprintf(out, ") const;\n"); else fprintf(out, ");\n"); - fprintf(out, " if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&%s::%s)) {\n", + fprintf(out, " if (_t _q_method = &%s::%s; *reinterpret_cast<_t *>(_a[1]) == _q_method) {\n", cdef->classname.constData(), f.name.constData()); fprintf(out, " *result = %d;\n", methodindex); fprintf(out, " return;\n"); @@ -1260,7 +1231,7 @@ void Generator::generateStaticMetacall() fprintf(out, " *reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< %s >(); break;\n", lastKey.constData()); } fprintf(out, " }\n"); - fprintf(out, " }\n"); + fprintf(out, " } "); isUsed_a = true; needElse = true; } @@ -1271,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 @@ -1282,10 +1252,8 @@ void Generator::generateStaticMetacall() needReset |= !p.reset.isEmpty(); hasBindableProperties |= !p.bind.isEmpty(); } - fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); - if (needElse) - fprintf(out, "else "); + fprintf(out, " else "); fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n"); auto setupMemberAccess = [this]() { @@ -1305,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; @@ -1323,6 +1291,9 @@ void Generator::generateStaticMetacall() else if (cdef->enumDeclarations.value(p.type, false)) fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n", propindex, prefix.constData(), p.read.constData()); + else if (p.read == "default") + fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s().value(); break;\n", + propindex, p.type.constData(), prefix.constData(), p.bind.constData()); else if (!p.read.isEmpty()) fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n", propindex, p.type.constData(), prefix.constData(), p.read.constData()); @@ -1343,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; @@ -1356,6 +1327,12 @@ void Generator::generateStaticMetacall() if (cdef->enumDeclarations.value(p.type, false)) { fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n", propindex, prefix.constData(), p.write.constData()); + } else if (p.write == "default") { + fprintf(out, " case %d: {\n", propindex); + fprintf(out, " %s%s().setValue(*reinterpret_cast< %s*>(_v));\n", + prefix.constData(), p.bind.constData(), p.type.constData()); + fprintf(out, " break;\n"); + fprintf(out, " }\n"); } else if (!p.write.isEmpty()) { fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n", propindex, prefix.constData(), p.write.constData(), p.type.constData()); @@ -1390,15 +1367,15 @@ 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.endsWith(')')) + if (p.reset.isEmpty()) continue; QByteArray prefix = "_t->"; if (p.inPrivateClass.size()) { prefix += p.inPrivateClass + "->"; } - fprintf(out, " case %d: %s%s; break;\n", + fprintf(out, " case %d: %s%s(); break;\n", propindex, prefix.constData(), p.reset.constData()); } fprintf(out, " default: break;\n"); @@ -1411,17 +1388,23 @@ 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; - fprintf(out, " case %d: *static_cast<QUntypedBindable *>(_a[0]) = _t->%s(); break;\n", propindex, p.bind.constData()); + QByteArray prefix = "_t->"; + if (p.inPrivateClass.size()) { + prefix += p.inPrivateClass + "->"; + } + fprintf(out, + " case %d: *static_cast<QUntypedBindable *>(_a[0]) = %s%s(); " + "break;\n", + propindex, prefix.constData(), p.bind.constData()); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, " }"); - fprintf(out, "\n#endif // QT_NO_PROPERTIES"); needElse = true; } @@ -1438,10 +1421,10 @@ void Generator::generateStaticMetacall() if (!isUsed_a) fprintf(out, " (void)_a;\n"); - fprintf(out, "}\n\n"); + fprintf(out, "}\n"); } -void Generator::generateSignal(FunctionDef *def,int index) +void Generator::generateSignal(const FunctionDef *def, int index) { if (def->wasCloned || def->isAbstract) return; @@ -1465,9 +1448,11 @@ void Generator::generateSignal(FunctionDef *def,int index) } int offset = 1; - for (int j = 0; j < def->arguments.count(); ++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); @@ -1498,7 +1483,7 @@ void Generator::generateSignal(FunctionDef *def,int index) } int i; for (i = 1; i < offset; ++i) - if (i <= def->arguments.count() && def->arguments.at(i - 1).type.isVolatile) + if (i <= def->arguments.size() && def->arguments.at(i - 1).type.isVolatile) fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(std::addressof(_t%d)))", i); else fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t%d)))", i); @@ -1557,8 +1542,7 @@ static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v) return cbor_encode_double(parent, d); } } - Q_UNREACHABLE(); - return CborUnknownError; + Q_UNREACHABLE_RETURN(CborUnknownError); } void Generator::generatePluginMetaData() @@ -1566,62 +1550,76 @@ void Generator::generatePluginMetaData() if (cdef->pluginData.iid.isEmpty()) return; - fprintf(out, "\nQT_PLUGIN_METADATA_SECTION\n" - "static constexpr unsigned char qt_pluginMetaData_%s[] = {\n" - " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n" - " // metadata version, Qt version, architectural requirements\n" - " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", - cdef->classname.constData()); - + auto outputCborData = [this]() { + CborDevice dev(out); + CborEncoder enc; + cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); - CborDevice dev(out); - CborEncoder enc; - cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); + CborEncoder map; + cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); - CborEncoder map; - cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); - - dev.nextItem("\"IID\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); - cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); + dev.nextItem("\"IID\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); + cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); - dev.nextItem("\"className\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); - cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); + dev.nextItem("\"className\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); + cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); - QJsonObject o = cdef->pluginData.metaData.object(); - if (!o.isEmpty()) { - dev.nextItem("\"MetaData\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); - jsonObjectToCbor(&map, o); - } + QJsonObject o = cdef->pluginData.metaData.object(); + if (!o.isEmpty()) { + dev.nextItem("\"MetaData\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); + jsonObjectToCbor(&map, o); + } - if (!cdef->pluginData.uri.isEmpty()) { - dev.nextItem("\"URI\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::URI)); - cbor_encode_text_string(&map, cdef->pluginData.uri.constData(), cdef->pluginData.uri.size()); - } + if (!cdef->pluginData.uri.isEmpty()) { + dev.nextItem("\"URI\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::URI)); + cbor_encode_text_string(&map, cdef->pluginData.uri.constData(), cdef->pluginData.uri.size()); + } - // Add -M args from the command line: - for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) { - const QJsonArray &a = it.value(); - QByteArray key = it.key().toUtf8(); - dev.nextItem(QByteArray("command-line \"" + key + "\"").constData()); - cbor_encode_text_string(&map, key.constData(), key.size()); - jsonArrayToCbor(&map, a); - } + // Add -M args from the command line: + for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) { + const QJsonArray &a = it.value(); + QByteArray key = it.key().toUtf8(); + dev.nextItem(QByteArray("command-line \"" + key + "\"").constData()); + cbor_encode_text_string(&map, key.constData(), key.size()); + jsonArrayToCbor(&map, a); + } - // Close the CBOR map manually - dev.nextItem(); - cbor_encoder_close_container(&enc, &map); - fputs("\n};\n", out); + // Close the CBOR map manually + dev.nextItem(); + cbor_encoder_close_container(&enc, &map); + }; // '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()); - fprintf(out, "QT_MOC_EXPORT_PLUGIN(%s, %s)\n\n", + + fputs("\n#ifdef QT_MOC_EXPORT_PLUGIN_V2", out); + + // Qt 6.3+ output + fprintf(out, "\nstatic constexpr unsigned char qt_pluginMetaDataV2_%s[] = {", + cdef->classname.constData()); + outputCborData(); + fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN_V2(%s, %s, qt_pluginMetaDataV2_%s)\n", + cdef->qualified.constData(), cdef->classname.constData(), cdef->classname.constData()); + + // compatibility with Qt 6.0-6.2 + fprintf(out, "#else\nQT_PLUGIN_METADATA_SECTION\n" + "Q_CONSTINIT static constexpr unsigned char qt_pluginMetaData_%s[] = {\n" + " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n" + " // metadata version, Qt version, architectural requirements\n" + " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),", + cdef->classname.constData()); + outputCborData(); + fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN(%s, %s)\n" + "#endif // QT_MOC_EXPORT_PLUGIN_V2\n", cdef->qualified.constData(), cdef->classname.constData()); + + fputs("\n", out); } QT_WARNING_DISABLE_GCC("-Wunused-function") |