51 if (token == COLON || token == LBRACE)
53 if (token == SEMIC || token == RANGLE)
60 if (!test(IDENTIFIER))
62 QByteArray name = lexem();
68 if (!test(IDENTIFIER))
71 }
else if (test(IDENTIFIER)) {
72 const QByteArrayView lex = lexemView();
73 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
79 def->qualified += name;
81 def->qualified += lexemView();
82 if (test(IDENTIFIER)) {
84 def->qualified += name;
87 def->classname = name;
88 def->lineNumber = symbol().lineNum;
90 if (test(IDENTIFIER)) {
91 const QByteArrayView lex = lexemView();
92 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
104 else if (test(PROTECTED))
109 const Type type = parseType();
114 def->superclassList.push_back({type.name, toFullyQualified(type.name), access});
116 }
while (test(COMMA));
118 if (!def->superclassList.isEmpty()
119 && knownGadgets.contains(def->superclassList.constFirst().classname)) {
121 knownGadgets.insert(def->classname, def->qualified);
122 knownGadgets.insert(def->qualified, def->qualified);
127 def->begin = index - 1;
128 bool foundRBrace =
until(RBRACE
);
130 index = def->begin + 1;
137 bool hasSignedOrUnsigned =
false;
139 type.firstToken = lookup();
145 hasSignedOrUnsigned =
true;
149 type.name += lexemView();
151 if (lookup(0) == VOLATILE)
152 type.isVolatile =
true;
154 case Q_MOC_COMPAT_TOKEN:
155 case Q_INVOKABLE_TOKEN:
156 case Q_SCRIPTABLE_TOKEN:
157 case Q_SIGNALS_TOKEN:
161 type.name += lexemView();
184 if (hasSignedOrUnsigned) {
193 type.name += lexemView();
195 if (test(LONG) || test(INT) || test(DOUBLE)) {
206 type.name += lexemView();
207 isVoid |= (lookup(0) == VOID);
216 if (type.name.isEmpty()) {
220 type.name += lexemUntil(RANGLE);
223 type.name += lexemView();
224 type.isScoped =
true;
229 while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
230 || test(STAR) || test(AND) || test(ANDAND)) {
232 type.name += lexemView();
233 if (lookup(0) == AND)
234 type.referenceType = Type::Reference;
235 else if (lookup(0) == ANDAND)
236 type.referenceType = Type::RValueReference;
237 else if (lookup(0) == STAR)
238 type.referenceType = Type::Pointer;
240 type.rawName = type.name;
242 if (isVoid && type.referenceType == Type::NoReference) {
319 arg.type = parseType();
320 if (arg.type.name ==
"void")
322 if (test(IDENTIFIER))
324 while (test(LBRACK)) {
325 arg.rightType += lexemUntil(RBRACK);
327 if (test(CONST) || test(VOLATILE)) {
328 arg.rightType +=
' ';
329 arg.rightType += lexemView();
331 arg.normalizedType = normalizeType(QByteArray(arg.type.name +
' ' + arg.rightType));
334 def->arguments += arg;
339 if (!def->arguments.isEmpty()
340 && def->arguments.constLast().normalizedType ==
"QPrivateSignal") {
341 def->arguments.removeLast();
344 if (def->arguments.size() == 1
345 && def->arguments.constLast().normalizedType ==
"QMethodRawArguments") {
346 def->arguments.removeLast();
350 if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<
int>::max()))
351 error(
"number of function arguments exceeds std::numeric_limits<int>::max()");
398 QByteArray revisionString = lexemUntil(RPAREN);
399 revisionString.remove(0, 1);
400 revisionString.chop(1);
401 const QList<QByteArray> majorMinor = revisionString.split(
',');
402 switch (majorMinor.size()) {
405 const int revision = revisionString.toInt(&ok);
406 if (!ok || !QTypeRevision::isValidSegment(revision))
407 error(
"Invalid revision");
412 const int major = majorMinor[0].toInt(&ok);
413 if (!ok || !QTypeRevision::isValidSegment(major))
414 error(
"Invalid major version");
415 const int minor = majorMinor[1].toInt(&ok);
416 if (!ok || !QTypeRevision::isValidSegment(minor))
417 error(
"Invalid minor version");
421 error(
"Invalid revision");
445 bool templateFunction = (lookup() == TEMPLATE);
446 def->type = parseType();
447 if (def->type.name.isEmpty()) {
448 if (templateFunction)
449 error(
"Template function as signal or slot");
453 bool scopedFunctionName =
false;
458 Type tempType = parseType();
459 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
460 if (testFunctionAttribute(def->type.firstToken, def))
462 else if (def->type.firstToken == Q_SIGNALS_TOKEN)
464 else if (def->type.firstToken == Q_SLOTS_TOKEN)
467 if (!def->tag.isEmpty())
469 def->tag += def->type.name;
471 def->type = tempType;
472 tempType = parseType();
474 next(LPAREN,
"Not a signal or slot declaration");
475 def->name = tempType.name;
478 scopedFunctionName = tempType.isScoped;
486 while (test(IDENTIFIER))
491 while (test(IDENTIFIER))
503 if (def->type.name ==
"auto" && test(ARROW))
504 def->type = parseType();
517 if (scopedFunctionName) {
518 const QByteArray msg =
"Function declaration " + def->name
519 +
" contains extra qualification. Ignoring as signal or slot.";
520 warning(msg.constData());
524 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(
' ');
525 if (typeNameParts.contains(
"auto")) {
527 error(
"Function declared with auto as return type but missing trailing return type. "
528 "Return type deduction is not supported.");
532 if (def->type.referenceType == Type::Reference) {
533 QByteArray rawName = def->type.rawName;
534 def->type = Type(
"void");
535 def->type.rawName = rawName;
538 def->normalizedType = normalizeType(def->type.name);
557 bool tilde = test(TILDE);
558 def->type = parseType();
559 if (def->type.name.isEmpty())
561 bool scopedFunctionName =
false;
563 def->name = def->type.name;
565 scopedFunctionName = def->type.isScoped;
566 if (def->name == cdef->classname) {
579 Type tempType = parseType();
580 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
581 if (testFunctionAttribute(def->type.firstToken, def))
583 else if (def->type.name ==
"Q_SIGNAL")
585 else if (def->type.name ==
"Q_SLOT")
588 if (!def->tag.isEmpty())
590 def->tag += def->type.name;
592 def->type = tempType;
593 tempType = parseType();
597 def->name = tempType.name;
599 scopedFunctionName = tempType.isScoped;
610 while (test(IDENTIFIER))
618 if (def->type.name ==
"auto" && test(ARROW))
619 def->type = parseType();
621 if (scopedFunctionName
623 const QByteArray msg =
"parsemaybe: Function declaration " + def->name
624 +
" contains extra qualification. Ignoring as signal or slot.";
625 warning(msg.constData());
630 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(
' ');
631 if (typeNameParts.contains(
"auto")) {
633 error(
"Function declared with auto as return type but missing trailing return type. "
634 "Return type deduction is not supported.");
638 if (def->type.referenceType == Type::Reference) {
639 QByteArray rawName = def->type.rawName;
640 def->type = Type(
"void");
641 def->type.rawName = rawName;
644 def->normalizedType = normalizeType(def->type.name);
672 if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<
int>::max()))
673 error(
"number of signals defined in parent class(es) exceeds "
674 "std::numeric_limits<int>::max().");
676 if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<
int>::max()))
677 error(
"number of bindable properties exceeds std::numeric_limits<int>::max().");
679 if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<
int>::max()))
680 error(
"number of times Q_CLASSINFO macro is used exceeds "
681 "std::numeric_limits<int>::max().");
683 if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<
int>::max()))
684 error(
"number of enumerations exceeds std::numeric_limits<int>::max().");
686 if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<
int>::max()))
687 error(
"number of super classes exceeds std::numeric_limits<int>::max().");
689 if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<
int>::max()))
690 error(
"number of constructor parameters exceeds std::numeric_limits<int>::max().");
692 if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<
int>::max()))
693 error(
"number of signals exceeds std::numeric_limits<int>::max().");
695 if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<
int>::max()))
696 error(
"number of declared slots exceeds std::numeric_limits<int>::max().");
698 if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<
int>::max()))
699 error(
"number of methods exceeds std::numeric_limits<int>::max().");
701 if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<
int>::max()))
702 error(
"number of public functions declared in this class exceeds "
703 "std::numeric_limits<int>::max().");
709 bool templateClass =
false;
714 qsizetype rewind = index;
715 if (test(IDENTIFIER)) {
716 QByteArray nsName = lexem();
717 QByteArrayList nested;
718 while (test(SCOPE)) {
720
721
722
723
726 nested.append(nsName);
732 }
else if (test(LPAREN)) {
735 }
else if (!test(SEMIC)) {
737 def.classname = nsName;
738 def.lineNumber = symbol().lineNum;
739 def.doGenerate = currentFilenames.size() <= 1;
742 def.begin = index - 1;
745 index = def.begin + 1;
749 for (
const QByteArray &ns : nested) {
750 NamespaceDef parentNs;
751 parentNs.classname = ns;
752 parentNs.qualified = def.qualified;
753 def.qualified += ns +
"::";
754 parentNs.begin = def.begin;
755 parentNs.end = def.end;
756 namespaceList += parentNs;
762 if (test(IDENTIFIER)) {
763 while (test(SCOPE)) {
770 }
else if (!test(SEMIC)) {
775 case Q_NAMESPACE_TOKEN:
778 case Q_NAMESPACE_EXPORT_TOKEN:
780 while (test(IDENTIFIER))
786 case Q_ENUM_NS_TOKEN:
790 error(
"Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
793 case Q_FLAG_NS_TOKEN:
797 error(
"Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
799 case Q_DECLARE_FLAGS_TOKEN:
802 case Q_CLASSINFO_TOKEN:
803 parseClassInfo(&def);
805 case Q_MOC_INCLUDE_TOKEN:
813 def.enumList += enumDef;
826 namespaceList += def;
828 if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
829 error(
"Namespace declaration lacks Q_NAMESPACE macro.");
836 templateClass =
false;
839 templateClass =
true;
841 case MOC_INCLUDE_BEGIN:
842 currentFilenames.push(symbol().unquotedLexem());
844 case MOC_INCLUDE_END:
845 currentFilenames.pop();
847 case Q_DECLARE_INTERFACE_TOKEN:
850 case Q_DECLARE_METATYPE_TOKEN:
853 case Q_MOC_INCLUDE_TOKEN:
857 if (test(NAMESPACE)) {
858 while (test(SCOPE) || test(IDENTIFIER))
868 if (currentFilenames.size() <= 1)
880 case Q_GADGET_EXPORT_TOKEN:
882 while (test(IDENTIFIER))
898 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
899 classHash.insert(def.classname, def.qualified);
900 classHash.insert(def.qualified, def.qualified);
905 if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
909 Symbol qmlRegistrationMacroSymbol =
{};
914 switch ((t = next())) {
917 if (test(Q_SIGNALS_TOKEN))
918 error(
"Signals cannot have access specifier");
922 if (test(Q_SIGNALS_TOKEN))
923 error(
"Signals cannot have access specifier");
927 if (test(Q_SIGNALS_TOKEN))
928 error(
"Signals cannot have access specifier");
936 if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
937 error(
"Meta object features not supported for nested classes");
941 case Q_SIGNALS_TOKEN:
945 switch (lookup(-1)) {
952 error(
"Missing access specifier for slots");
958 error(
"Template classes not supported by Q_OBJECT");
959 if (def.classname !=
"Qt" && def.classname !=
"QObject" && def.superclassList.isEmpty())
960 error(
"Class contains Q_OBJECT macro but does not inherit from QObject");
962 case Q_GADGET_EXPORT_TOKEN:
964 while (test(IDENTIFIER))
971 error(
"Template classes not supported by Q_GADGET");
973 case Q_PROPERTY_TOKEN:
976 case QT_ANONYMOUS_PROPERTY_TOKEN:
979 case Q_PLUGIN_METADATA_TOKEN:
986 case Q_ENUM_NS_TOKEN:
987 error(
"Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
993 case Q_FLAG_NS_TOKEN:
994 error(
"Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
996 case Q_DECLARE_FLAGS_TOKEN:
999 case Q_CLASSINFO_TOKEN:
1002 case Q_MOC_INCLUDE_TOKEN:
1005 case Q_INTERFACES_TOKEN:
1008 case Q_PRIVATE_SLOT_TOKEN:
1011 case Q_PRIVATE_PROPERTY_TOKEN:
1014 case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
1020 def.enumList += enumDef;
1027 const QByteArrayView lex = lexemView();
1028 if (lex.startsWith(
"QML_")) {
1029 if ( lex ==
"QML_ELEMENT" || lex ==
"QML_NAMED_ELEMENT"
1030 || lex ==
"QML_ANONYMOUS" || lex ==
"QML_VALUE_TYPE") {
1031 qmlRegistrationMacroSymbol = symbol();
1039 qsizetype rewind = index--;
1043 def.constructorList += funcDef;
1044 handleDefaultArguments(&def.constructorList, funcDef);
1050 def.publicList += funcDef;
1052 def.slotList += funcDef;
1053 handleDefaultArguments(&def.slotList, funcDef);
1057 def.signalList += funcDef;
1058 handleDefaultArguments(&def.signalList, funcDef);
1062 def.methodList += funcDef;
1063 handleDefaultArguments(&def.methodList, funcDef);
1077
1078
1079
1081 QByteArray msg(
"Potential QML registration macro was found, but no header containing it was included.\n"
1082 "This might cause runtime errors in QML applications\n"
1083 "Include <QtQmlIntegration/qqmlintegration.h> or <QtQml/qqmlregistration.h> to fix this.");
1084 if (qmlMacroWarningIsFatal)
1085 error(qmlRegistrationMacroSymbol, msg.constData());
1087 warning(qmlRegistrationMacroSymbol, msg.constData());
1091 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
1095 if (!def.hasQObject && !def.hasQGadget)
1096 error(
"Class declaration lacks Q_OBJECT macro.");
1099 if (!def.pluginData.iid.isEmpty())
1100 def.pluginData.metaArgs = metaArgs;
1102 if (def
.hasQObject && !def.superclassList.isEmpty())
1110 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
1111 classHash.insert(def.classname, def.qualified);
1112 classHash.insert(def.qualified, def.qualified);
1115 for (
const auto &n : std::as_const(namespaceList)) {
1116 if (!n.hasQNamespace)
1119 static_cast<BaseDef &>(def) =
static_cast<BaseDef>(n);
1120 def.qualified += def.classname;
1121 def.hasQNamespace =
true;
1122 auto it = std::find_if(classList.begin(), classList.end(), [&def](
const ClassDef &val) {
1123 return def.classname == val.classname && def.qualified == val.qualified;
1126 if (it != classList.end()) {
1127 it->classInfoList += def.classInfoList;
1128 Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<
int>::max());
1129 it->enumDeclarations.insert(def.enumDeclarations);
1130 it->enumList += def.enumList;
1131 Q_ASSERT(it->enumList.size() <= std::numeric_limits<
int>::max());
1132 it->flagAliases.insert(def.flagAliases);
1134 knownGadgets.insert(def.classname, def.qualified);
1135 knownGadgets.insert(def.qualified, def.qualified);
1190 static const QByteArrayList candidates = make_candidates();
1192 QByteArrayList required;
1193 required.reserve(candidates.size());
1195 bool needsQProperty =
false;
1197 for (
const auto &candidate : candidates) {
1198 const QByteArray pattern = candidate +
'<';
1200 for (
const auto &c : classes) {
1201 for (
const auto &p : c.propertyList)
1202 needsQProperty |= !p.bind.isEmpty();
1203 if (any_type_contains(c.propertyList, pattern) ||
1204 any_arg_contains(c.slotList, pattern) ||
1205 any_arg_contains(c.signalList, pattern) ||
1206 any_arg_contains(c.methodList, pattern)) {
1207 required.push_back(candidate);
1214 required.push_back(
"QProperty");
1239 QByteArrayView fn = strippedFileName();
1241 fprintf(out,
"/****************************************************************************\n"
1242 "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
1243 fprintf(out,
"** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" ,
mocOutputRevision, QT_VERSION_STR);
1244 fprintf(out,
"** WARNING! All changes made in this file will be lost!\n"
1245 "*****************************************************************************/\n\n");
1251 if (includePath.size() && !includePath.endsWith(
'/'))
1253 for (QByteArray inc : std::as_const(includeFiles)) {
1254 if (!inc.isEmpty() && inc.at(0) !=
'<' && inc.at(0) !=
'"') {
1255 if (includePath.size() && includePath !=
"./")
1256 inc.prepend(includePath);
1257 inc =
'\"' + inc +
'\"';
1259 fprintf(out,
"#include %s\n", inc.constData());
1262 if (classList.size() && classList.constFirst().classname ==
"Qt")
1263 fprintf(out,
"#include <QtCore/qobject.h>\n");
1265 fprintf(out,
"#include <QtCore/qmetatype.h>\n");
1267 fprintf(out,
"#include <QtCore/qplugin.h>\n");
1269 const auto qtContainers = requiredQtContainers(classList);
1270 for (
const QByteArray &qtContainer : qtContainers)
1271 fprintf(out,
"#include <QtCore/%s>\n", qtContainer.constData());
1273 fprintf(out,
"\n#include <QtCore/qtmochelpers.h>\n");
1275 fprintf(out,
"\n#include <memory>\n\n");
1276 fprintf(out,
"\n#include <QtCore/qxptype_traits.h>\n");
1278 fprintf(out,
"#if !defined(Q_MOC_OUTPUT_REVISION)\n"
1279 "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
1281 fprintf(out,
"#error \"This file was generated using the moc from %s."
1282 " It\"\n#error \"cannot be used with the include files from"
1283 " this version of Qt.\"\n#error \"(The moc has changed too"
1284 " much.)\"\n", QT_VERSION_STR);
1285 fprintf(out,
"#endif\n\n");
1287#if QT_VERSION <= QT_VERSION_CHECK(7
, 0
, 0
)
1288 fprintf(out,
"#ifndef Q_CONSTINIT\n"
1289 "#define Q_CONSTINIT\n"
1294 for (ClassDef &cdef : classList) {
1295 QList<EnumDef> enumList;
1296 for (EnumDef def : std::as_const(cdef.enumList)) {
1297 if (cdef.enumDeclarations.contains(def.name)) {
1300 def.enumName = def.name;
1301 QByteArray alias = cdef.flagAliases.value(def.name);
1302 if (cdef.enumDeclarations.contains(alias)) {
1304 def.flags |= cdef.enumDeclarations[alias];
1308 cdef.enumList = enumList;
1311 fprintf(out,
"QT_WARNING_PUSH\n");
1312 fprintf(out,
"QT_WARNING_DISABLE_DEPRECATED\n");
1313 fprintf(out,
"QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
1315 QHash<QByteArray, QJsonObject> classDefJsonObjects;
1316 QHash<QByteArray, QByteArray> metaObjectHashes;
1317 for (
const ClassDef &def : std::as_const(classList)) {
1318 const QJsonObject jsonObject = def.toJson();
1319 classDefJsonObjects.insert(def.qualified, jsonObject);
1320 metaObjectHashes.insert(def.qualified, classDefJsonObjectHash(jsonObject));
1324 for (
const ClassDef &def : std::as_const(classList)) {
1325 Generator generator(
this, &def, metaTypes, knownQObjectClasses, knownGadgets,
1326 metaObjectHashes, out, requireCompleteTypes);
1327 generator.generateCode();
1330 if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<
int>::max())) {
1331 error(
"internal limit exceeded: number of parsed strings is too big.");
1337 fprintf(out,
"QT_WARNING_POP\n");
1340 QJsonObject mocData;
1341 mocData[
"outputRevision"_L1] = mocOutputRevision;
1342 mocData[
"inputFile"_L1] = QLatin1StringView(fn.constData());
1344 QJsonArray classesJsonFormatted;
1345 QJsonObject hashesJsonObject;
1347 for (
const ClassDef &cdef : std::as_const(classList)) {
1348 classesJsonFormatted.append(classDefJsonObjects[cdef.qualified]);
1349 hashesJsonObject.insert(QString::fromLatin1(cdef.qualified),
1350 QString::fromLatin1(metaObjectHashes[cdef.qualified]));
1353 if (!classesJsonFormatted.isEmpty())
1354 mocData[
"classes"_L1] = classesJsonFormatted;
1356 if (!hashesJsonObject.isEmpty())
1357 mocData[
"hashes"_L1] = hashesJsonObject;
1360 fputs(jsonDoc.toJson().constData(), jsonOutput);
1491 auto checkIsFunction = [&](
const QByteArray &def,
const char *name) {
1492 if (def.endsWith(
')')) {
1493 QByteArray msg =
"Providing a function for ";
1495 msg +=
" in a property declaration is not be supported in Qt 6.";
1496 error(msg.constData());
1500 while (test(IDENTIFIER)) {
1501 const Symbol &lsym = symbol();
1502 const QByteArrayView l = lsym.lexemView();
1503 if (l[0] ==
'C' && l ==
"CONSTANT") {
1506 }
else if (l[0] ==
'F' && l ==
"FINAL") {
1509 }
else if (l[0] ==
'N' && l ==
"NAME") {
1511 propDef.name = lexem();
1513 }
else if (l[0] ==
'O' && l ==
"OVERRIDE") {
1516 }
else if (l[0] ==
'R' && l ==
"REQUIRED") {
1519 }
else if (l[0] ==
'R' && l ==
"REVISION" && test(LPAREN)) {
1523 }
else if (l[0] ==
'V' && l ==
"VIRTUAL") {
1530 v = lexemUntil(RPAREN);
1531 v = v.mid(1, v.size() - 2);
1532 }
else if (test(INTEGER_LITERAL)) {
1534 if (l !=
"REVISION")
1536 }
else if (test(DEFAULT)) {
1538 if (l !=
"READ" && l !=
"WRITE")
1544 v2 = lexemUntil(RPAREN);
1545 else if (v !=
"true" && v !=
"false")
1558 else if (l ==
"RESET")
1560 else if (l ==
"REVISION") {
1562 const int minor = v.toInt(&ok);
1563 if (!ok || !QTypeRevision::isValidSegment(minor))
1570 if (l ==
"SCRIPTABLE") {
1571 propDef.scriptable = v + v2;
1572 checkIsFunction(propDef.scriptable,
"SCRIPTABLE");
1573 }
else if (l ==
"STORED") {
1574 propDef.stored = v + v2;
1575 checkIsFunction(propDef.stored,
"STORED");
1579 case 'W':
if (l !=
"WRITE") error(lsym);
1582 case 'B':
if (l !=
"BINDABLE") error(lsym);
1585 case 'D':
if (l !=
"DESIGNABLE") error(lsym);
1586 propDef.designable = v + v2;
1587 checkIsFunction(propDef.designable,
"DESIGNABLE");
1589 case 'N':
if (l !=
"NOTIFY") error(lsym);
1592 case 'U':
if (l !=
"USER") error(lsym);
1593 propDef.user = v + v2;
1594 checkIsFunction(propDef.user,
"USER");
1600 if (propDef
.constant && !propDef.write.isNull()) {
1601 const QByteArray msg =
"Property declaration " + propDef.name
1602 +
" is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1604 warning(msg.constData());
1606 if (propDef
.constant && !propDef.notify.isNull()) {
1607 const QByteArray msg =
"Property declaration " + propDef.name
1608 +
" is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1610 warning(msg.constData());
1612 if (propDef
.constant && !propDef.bind.isNull()) {
1613 const QByteArray msg =
"Property declaration " + propDef.name
1614 +
" is both BINDable and CONSTANT. CONSTANT will be ignored.";
1616 warning(msg.constData());
1618 if (propDef.read ==
"default" && propDef.bind.isNull()) {
1619 const QByteArray msg =
"Property declaration " + propDef.name
1620 +
" is not BINDable but default-READable. READ will be ignored.";
1622 warning(msg.constData());
1624 if (propDef.write ==
"default" && propDef.bind.isNull()) {
1625 const QByteArray msg =
"Property declaration " + propDef.name
1626 +
" is not BINDable but default-WRITEable. WRITE will be ignored.";
1628 warning(msg.constData());
1631 const QByteArray msg =
"Issue with property declaration " + propDef.name
1632 +
": VIRTUAL is redundant when overriding a property. The OVERRIDE "
1633 "must only be used when actually overriding an existing property; using it on a "
1634 "new property is an error.";
1635 error(msg.constData());
1638 const QByteArray msg =
"Issue with property declaration " + propDef.name
1639 +
": OVERRIDE is redundant when property is marked FINAL";
1640 error(msg.constData());
1643 const QByteArray msg =
"Issue with property declaration " + propDef.name
1644 +
": The VIRTUAL cannot be combined with FINAL, as these attributes are mutually "
1646 error(msg.constData());
1663 QByteArray metaData;
1664 while (test(IDENTIFIER)) {
1665 QByteArray l = lexem();
1667 next(STRING_LITERAL);
1668 def->pluginData.iid = unquotedLexem();
1669 }
else if (l ==
"URI") {
1670 next(STRING_LITERAL);
1671 def->pluginData.uri = unquotedLexem();
1672 }
else if (l ==
"FILE") {
1673 next(STRING_LITERAL);
1674 QByteArrayView metaDataFile = unquotedLexemView();
1675 QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
1676 QString::fromLocal8Bit(metaDataFile));
1677 for (
const IncludePath &p : std::as_const(includes)) {
1680 if (p.isFrameworkPath)
1683 fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(metaDataFile));
1691 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1692 +
" does not exist. Declaration will be ignored";
1693 error(msg.constData());
1696 QFile file(fi.canonicalFilePath());
1697 if (!file.open(QFile::ReadOnly)) {
1698 QByteArray msg =
"Plugin Metadata file " + lexemView() +
" could not be opened: "
1699 + file.errorString().toUtf8();
1700 error(msg.constData());
1703 parsedPluginMetadataFiles.append(fi.canonicalFilePath());
1704 metaData = file.readAll();
1708 if (!metaData.isEmpty()) {
1709 def->pluginData.metaData = QJsonDocument::fromJson(metaData);
1710 if (!def->pluginData.metaData.isObject()) {
1711 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1712 +
" does not contain a valid JSON object. Declaration will be ignored";
1713 warning(msg.constData());
1714 def->pluginData.iid = QByteArray();
1715 def->pluginData.uri = QByteArray();
1830 while (test(IDENTIFIER)) {
1832 iface += ClassDef::Interface(lexem());
1833 while (test(SCOPE)) {
1834 iface.last().className += lexemView();
1836 iface.last().className += lexemView();
1838 while (test(COLON)) {
1840 iface += ClassDef::Interface(lexem());
1841 while (test(SCOPE)) {
1842 iface.last().className += lexemView();
1844 iface.last().className += lexemView();
1848 for (qsizetype i = 0; i < iface.size(); ++i) {
1849 const QByteArray iid = interface2IdMap.value(iface.at(i).className);
1851 error(
"Undefined interface");
1853 iface[i].interfaceId = iid;
1855 def->interfaceList += iface;
1949 switch(symbols.at(index-1).token) {
1950 case LBRACE: ++braceCount;
break;
1951 case LBRACK: ++brackCount;
break;
1952 case LPAREN: ++parenCount;
break;
1953 case LANGLE: ++angleCount;
break;
1961 qsizetype possible = -1;
1963 while (index < symbols.size()) {
1964 Token t = symbols.at(index++).token;
1966 case LBRACE: ++braceCount;
break;
1967 case RBRACE: --braceCount;
break;
1968 case LBRACK: ++brackCount;
break;
1969 case RBRACK: --brackCount;
break;
1970 case LPAREN: ++parenCount;
break;
1971 case RPAREN: --parenCount;
break;
1973 if (parenCount == 0 && braceCount == 0)
1977 if (parenCount == 0 && braceCount == 0)
1981 if (parenCount == 0 && braceCount == 0) {
1992 && (target != RANGLE || angleCount <= 0)) {
1993 if (target != COMMA || angleCount <= 0)
1998 if (target == COMMA && t == EQ && possible != -1) {
2003 if (braceCount < 0 || brackCount < 0 || parenCount < 0
2004 || (target == RANGLE && angleCount < 0)) {
2009 if (braceCount <= 0 && t == SEMIC) {
2015 if (target == COMMA && angleCount != 0 && possible != -1) {
2025 Q_ASSERT(!def->superclassList.isEmpty());
2026 const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
2028 if (!knownQObjectClasses.contains(firstSuperclass)) {
2031 const QByteArray msg
2034 +
" contains the Q_OBJECT macro and inherits from "
2035 + def->superclassList.value(0)
2036 +
" but that is not a known QObject subclass. You may get compilation errors.";
2037 warning(msg.constData());
2042 auto isRegisteredInterface = [&def](QByteArrayView super) {
2043 auto matchesSuperClass = [&super](
const auto &ifaces) {
2044 return !ifaces.isEmpty() && ifaces.first().className == super;
2046 return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
2049 const auto end = def->superclassList.cend();
2050 auto it = def->superclassList.cbegin() + 1;
2051 for (; it != end; ++it) {
2052 const QByteArray &superClass = it->classname;
2053 if (knownQObjectClasses.contains(superClass)) {
2054 const QByteArray msg
2057 +
" inherits from two QObject subclasses "
2061 +
". This is not supported!";
2062 warning(msg.constData());
2065 if (interface2IdMap.contains(superClass)) {
2066 if (!isRegisteredInterface(superClass)) {
2067 const QByteArray msg
2070 +
" implements the interface "
2072 +
" but does not list it in Q_INTERFACES. qobject_cast to "
2074 +
" will not work!";
2075 warning(msg.constData());
2087 QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
2088 auto hasNoAttributes = [&](
const PropertyDef &p) {
2089 if (definedProperties.hasSeen(p.name)) {
2090 QByteArray msg =
"The property '" + p.name +
"' is defined multiple times in class " + cdef->classname +
".";
2091 warning(msg.constData());
2094 if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
2095 QByteArray msg =
"Property declaration " + p.name +
" has neither an associated QProperty<> member"
2096 ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
2097 const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
2098 warning(sym, msg.constData());
2099 if (p.write.isEmpty())
2104 cdef->propertyList.removeIf(hasNoAttributes);
2106 for (PropertyDef &p : cdef->propertyList) {
2107 for (
const FunctionDef &f : std::as_const(cdef->publicList)) {
2108 if (f.name != p.read)
2112 if (f.arguments.size())
2114 PropertyDef::Specification spec = PropertyDef::ValueSpec;
2115 QByteArray tmp = f.normalizedType;
2116 if (p.type ==
"QByteArray" && tmp ==
"const char *")
2118 if (tmp.left(6) ==
"const ")
2120 if (p.type != tmp && tmp.endsWith(
'*')) {
2122 spec = PropertyDef::PointerSpec;
2123 }
else if (f.type.name.endsWith(
'&')) {
2124 spec = PropertyDef::ReferenceSpec;
2131 if (!p.notify.isEmpty()) {
2133 for (
int j = 0; j <
int(cdef->signalList.size()); ++j) {
2134 const FunctionDef &f = cdef->signalList.at(j);
2135 if (f.name != p.notify) {
2142 p.notifyId = notifyId;
2143 if (notifyId == -1) {
2144 const int index =
int(cdef->nonClassSignalList.indexOf(p.notify));
2146 cdef->nonClassSignalList << p.notify;
2147 p.notifyId =
int(-1 - cdef->nonClassSignalList.size());
2149 p.notifyId =
int(-2 - index);
2159 cls[
"className"_L1] = QString::fromUtf8(classname.constData());
2160 cls[
"qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
2161 cls[
"lineNumber"_L1] = lineNumber;
2163 cls[
"final"_L1] =
true;
2165 QJsonArray classInfos;
2166 for (
const auto &info: std::as_const(classInfoList)) {
2167 QJsonObject infoJson;
2168 infoJson[
"name"_L1] = QString::fromUtf8(info.name);
2169 infoJson[
"value"_L1] = QString::fromUtf8(info.value);
2170 classInfos.append(infoJson);
2173 if (classInfos.size())
2174 cls[
"classInfos"_L1] = classInfos;
2176 int methodIndex = 0;
2177 const auto appendFunctions
2178 = [&cls, &methodIndex](
const QString &type,
const QList<
FunctionDef> &funcs) {
2179 QJsonArray jsonFuncs;
2181 for (
const FunctionDef &fdef: funcs)
2182 jsonFuncs.append(fdef.toJson(methodIndex++));
2184 if (!jsonFuncs.isEmpty())
2185 cls[type] = jsonFuncs;
2189 appendFunctions(
"signals"_L1, signalList);
2190 appendFunctions(
"slots"_L1, slotList);
2191 appendFunctions(
"methods"_L1, methodList);
2195 appendFunctions(
"constructors"_L1, constructorList);
2199 for (
const PropertyDef &propDef: std::as_const(propertyList))
2200 props.append(propDef.toJson());
2202 if (!props.isEmpty())
2203 cls[
"properties"_L1] = props;
2206 cls[
"object"_L1] =
true;
2208 cls[
"gadget"_L1] =
true;
2210 cls[
"namespace"_L1] =
true;
2212 QJsonArray superClasses;
2214 for (
const auto &super: std::as_const(superclassList)) {
2215 QJsonObject superCls;
2216 superCls[
"name"_L1] = QString::fromUtf8(super.classname);
2217 if (super.classname != super.qualified)
2218 superCls[
"fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
2219 FunctionDef::accessToJson(&superCls, super.access);
2220 superClasses.append(superCls);
2223 if (!superClasses.isEmpty())
2224 cls[
"superClasses"_L1] = superClasses;
2227 for (
const EnumDef &enumDef: std::as_const(enumList))
2228 enums.append(enumDef.toJson(*
this));
2229 if (!enums.isEmpty())
2230 cls[
"enums"_L1] = enums;
2233 for (
const QList<Interface> &ifaceList : interfaceList) {
2234 QJsonArray jsonList;
2235 for (
const Interface &iface: ifaceList) {
2236 QJsonObject ifaceJson;
2237 ifaceJson[
"id"_L1] = QString::fromUtf8(iface.interfaceId);
2238 ifaceJson[
"className"_L1] = QString::fromUtf8(iface.className);
2239 jsonList.append(ifaceJson);
2241 ifaces.append(jsonList);
2243 if (!ifaces.isEmpty())
2244 cls[
"interfaces"_L1] = ifaces;