diff options
Diffstat (limited to 'src/tools/moc/generator.cpp')
-rw-r--r-- | src/tools/moc/generator.cpp | 269 |
1 files changed, 123 insertions, 146 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index d15b6de490..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 qsizetype 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); } } @@ -276,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; @@ -288,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"); // @@ -357,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; @@ -369,7 +313,7 @@ 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; @@ -397,8 +341,14 @@ void Generator::generateCode() // generateClassInfos(); + qsizetype propEnumCount = 0; // all property metatypes + all enum metatypes + 1 for the type of the current class itself - int initialMetaTypeOffset = cdef->propertyList.size() + cdef->enumList.size() + 1; + 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 @@ -577,8 +527,7 @@ void Generator::generateCode() // 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(cdef->classname % "::" % e.name, true).constData()); + comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData()); comma = ","; } @@ -590,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) @@ -639,13 +587,20 @@ 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 (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()); @@ -670,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 @@ -682,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"); } } @@ -776,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()); @@ -803,12 +775,12 @@ void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const 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); } @@ -861,7 +833,7 @@ void Generator::generateProperties() // if (cdef->propertyList.size()) - fprintf(out, "\n // properties: name, type, flags\n"); + 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)) @@ -906,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); @@ -1027,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); @@ -1063,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++); @@ -1076,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()); @@ -1138,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()"); } @@ -1200,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; @@ -1208,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"); } @@ -1298,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; @@ -1339,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; @@ -1392,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; @@ -1413,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; @@ -1449,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; @@ -1473,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); |