47 if (token == COLON || token == LBRACE)
49 if (token == SEMIC || token == RANGLE)
56 if (!test(IDENTIFIER))
58 QByteArray name = lexem();
64 if (!test(IDENTIFIER))
67 }
else if (test(IDENTIFIER)) {
68 const QByteArray lex = lexem();
69 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
73 def->qualified += name;
75 def->qualified += lexem();
76 if (test(IDENTIFIER)) {
78 def->qualified += name;
81 def->classname = name;
82 def->lineNumber = symbol().lineNum;
84 if (test(IDENTIFIER)) {
85 const QByteArray lex = lexem();
86 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
96 else if (test(PROTECTED))
106 def->superclassList.push_back({type.name, toFullyQualified(type.name), access});
108 }
while (test(COMMA));
110 if (!def->superclassList.isEmpty()
111 && knownGadgets.contains(def->superclassList.constFirst().classname)) {
113 knownGadgets.insert(def->classname, def->qualified);
114 knownGadgets.insert(def->qualified, def->qualified);
119 def->begin = index - 1;
120 bool foundRBrace =
until(RBRACE
);
122 index = def->begin + 1;
302 if (arg.type.name ==
"void")
304 if (test(IDENTIFIER))
306 while (test(LBRACK)) {
307 arg.rightType += lexemUntil(RBRACK);
309 if (test(CONST) || test(VOLATILE)) {
310 arg.rightType +=
' ';
311 arg.rightType += lexem();
313 arg.normalizedType = normalizeType(QByteArray(arg.type.name +
' ' + arg.rightType));
314 arg.typeNameForCast = QByteArray(
"std::add_pointer_t<"+arg.normalizedType+
">");
317 def->arguments += arg;
322 if (!def->arguments.isEmpty()
323 && def->arguments.constLast().normalizedType ==
"QPrivateSignal") {
324 def->arguments.removeLast();
327 if (def->arguments.size() == 1
328 && def->arguments.constLast().normalizedType ==
"QMethodRawArguments") {
329 def->arguments.removeLast();
333 if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<
int>::max()))
334 error(
"number of function arguments exceeds std::numeric_limits<int>::max()");
381 QByteArray revisionString = lexemUntil(RPAREN);
382 revisionString.remove(0, 1);
383 revisionString.chop(1);
384 const QList<QByteArray> majorMinor = revisionString.split(
',');
385 switch (majorMinor.size()) {
388 const int revision = revisionString.toInt(&ok);
389 if (!ok || !QTypeRevision::isValidSegment(revision))
390 error(
"Invalid revision");
395 const int major = majorMinor[0].toInt(&ok);
396 if (!ok || !QTypeRevision::isValidSegment(major))
397 error(
"Invalid major version");
398 const int minor = majorMinor[1].toInt(&ok);
399 if (!ok || !QTypeRevision::isValidSegment(minor))
400 error(
"Invalid minor version");
404 error(
"Invalid revision");
428 bool templateFunction = (lookup() == TEMPLATE);
430 if (def->type.name.isEmpty()) {
431 if (templateFunction)
432 error(
"Template function as signal or slot");
436 bool scopedFunctionName =
false;
442 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
443 if (testFunctionAttribute(def->type.firstToken, def))
445 else if (def->type.firstToken == Q_SIGNALS_TOKEN)
447 else if (def->type.firstToken == Q_SLOTS_TOKEN)
450 if (!def->tag.isEmpty())
452 def->tag += def->type.name;
454 def->type = tempType;
457 next(LPAREN,
"Not a signal or slot declaration");
458 def->name = tempType.name;
467 while (test(IDENTIFIER))
472 while (test(IDENTIFIER))
484 if (def->type.name ==
"auto" && test(ARROW))
498 if (scopedFunctionName) {
499 const QByteArray msg =
"Function declaration " + def->name
500 +
" contains extra qualification. Ignoring as signal or slot.";
501 warning(msg.constData());
505 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(
' ');
506 if (typeNameParts.contains(
"auto")) {
508 error(
"Function declared with auto as return type but missing trailing return type. "
509 "Return type deduction is not supported.");
514 QByteArray rawName = def->type.rawName;
515 def->type = Type(
"void");
516 def->type.rawName = rawName;
519 def->normalizedType = normalizeType(def->type.name);
538 bool tilde = test(TILDE);
540 if (def->type.name.isEmpty())
542 bool scopedFunctionName =
false;
544 def->name = def->type.name;
545 scopedFunctionName = def->type.isScoped;
546 if (def->name == cdef->classname) {
560 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
561 if (testFunctionAttribute(def->type.firstToken, def))
563 else if (def->type.name ==
"Q_SIGNAL")
565 else if (def->type.name ==
"Q_SLOT")
568 if (!def->tag.isEmpty())
570 def->tag += def->type.name;
572 def->type = tempType;
577 def->name = tempType.name;
583 QByteArray rawName = def->type.rawName;
584 def->type = Type(
"void");
585 def->type.rawName = rawName;
588 def->normalizedType = normalizeType(def->type.name);
596 if (scopedFunctionName
598 const QByteArray msg =
"parsemaybe: Function declaration " + def->name
599 +
" contains extra qualification. Ignoring as signal or slot.";
600 warning(msg.constData());
630 if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<
int>::max()))
631 error(
"number of signals defined in parent class(es) exceeds "
632 "std::numeric_limits<int>::max().");
634 if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<
int>::max()))
635 error(
"number of bindable properties exceeds std::numeric_limits<int>::max().");
637 if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<
int>::max()))
638 error(
"number of times Q_CLASSINFO macro is used exceeds "
639 "std::numeric_limits<int>::max().");
641 if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<
int>::max()))
642 error(
"number of enumerations exceeds std::numeric_limits<int>::max().");
644 if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<
int>::max()))
645 error(
"number of super classes exceeds std::numeric_limits<int>::max().");
647 if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<
int>::max()))
648 error(
"number of constructor parameters exceeds std::numeric_limits<int>::max().");
650 if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<
int>::max()))
651 error(
"number of signals exceeds std::numeric_limits<int>::max().");
653 if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<
int>::max()))
654 error(
"number of declared slots exceeds std::numeric_limits<int>::max().");
656 if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<
int>::max()))
657 error(
"number of methods exceeds std::numeric_limits<int>::max().");
659 if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<
int>::max()))
660 error(
"number of public functions declared in this class exceeds "
661 "std::numeric_limits<int>::max().");
667 bool templateClass =
false;
672 qsizetype rewind = index;
673 if (test(IDENTIFIER)) {
674 QByteArray nsName = lexem();
675 QByteArrayList nested;
676 while (test(SCOPE)) {
678
679
680
681
684 nested.append(nsName);
690 }
else if (test(LPAREN)) {
693 }
else if (!test(SEMIC)) {
695 def.classname = nsName;
696 def.lineNumber = symbol().lineNum;
697 def.doGenerate = currentFilenames.size() <= 1;
700 def.begin = index - 1;
703 index = def.begin + 1;
707 for (
const QByteArray &ns : nested) {
708 NamespaceDef parentNs;
709 parentNs.classname = ns;
710 parentNs.qualified = def.qualified;
711 def.qualified += ns +
"::";
712 parentNs.begin = def.begin;
713 parentNs.end = def.end;
714 namespaceList += parentNs;
720 if (test(IDENTIFIER)) {
721 while (test(SCOPE)) {
728 }
else if (!test(SEMIC)) {
733 case Q_NAMESPACE_TOKEN:
736 case Q_NAMESPACE_EXPORT_TOKEN:
738 while (test(IDENTIFIER))
744 case Q_ENUM_NS_TOKEN:
748 error(
"Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
751 case Q_FLAG_NS_TOKEN:
752 parseEnumOrFlag(&def, EnumIsFlag);
755 error(
"Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
757 case Q_DECLARE_FLAGS_TOKEN:
760 case Q_CLASSINFO_TOKEN:
761 parseClassInfo(&def);
763 case Q_MOC_INCLUDE_TOKEN:
771 def.enumList += enumDef;
784 namespaceList += def;
786 if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
787 error(
"Namespace declaration lacks Q_NAMESPACE macro.");
794 templateClass =
false;
797 templateClass =
true;
799 case MOC_INCLUDE_BEGIN:
800 currentFilenames.push(symbol().unquotedLexem());
802 case MOC_INCLUDE_END:
803 currentFilenames.pop();
805 case Q_DECLARE_INTERFACE_TOKEN:
808 case Q_DECLARE_METATYPE_TOKEN:
811 case Q_MOC_INCLUDE_TOKEN:
815 if (test(NAMESPACE)) {
816 while (test(SCOPE) || test(IDENTIFIER))
826 if (currentFilenames.size() <= 1)
838 case Q_GADGET_EXPORT_TOKEN:
840 while (test(IDENTIFIER))
856 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
857 classHash.insert(def.classname, def.qualified);
858 classHash.insert(def.qualified, def.qualified);
863 if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
871 switch ((t = next())) {
874 if (test(Q_SIGNALS_TOKEN))
875 error(
"Signals cannot have access specifier");
879 if (test(Q_SIGNALS_TOKEN))
880 error(
"Signals cannot have access specifier");
884 if (test(Q_SIGNALS_TOKEN))
885 error(
"Signals cannot have access specifier");
893 if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
894 error(
"Meta object features not supported for nested classes");
898 case Q_SIGNALS_TOKEN:
902 switch (lookup(-1)) {
909 error(
"Missing access specifier for slots");
915 error(
"Template classes not supported by Q_OBJECT");
916 if (def.classname !=
"Qt" && def.classname !=
"QObject" && def.superclassList.isEmpty())
917 error(
"Class contains Q_OBJECT macro but does not inherit from QObject");
919 case Q_GADGET_EXPORT_TOKEN:
921 while (test(IDENTIFIER))
928 error(
"Template classes not supported by Q_GADGET");
930 case Q_PROPERTY_TOKEN:
933 case QT_ANONYMOUS_PROPERTY_TOKEN:
936 case Q_PLUGIN_METADATA_TOKEN:
943 case Q_ENUM_NS_TOKEN:
944 error(
"Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
948 parseEnumOrFlag(&def, EnumIsFlag);
950 case Q_FLAG_NS_TOKEN:
951 error(
"Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
953 case Q_DECLARE_FLAGS_TOKEN:
956 case Q_CLASSINFO_TOKEN:
959 case Q_MOC_INCLUDE_TOKEN:
962 case Q_INTERFACES_TOKEN:
965 case Q_PRIVATE_SLOT_TOKEN:
968 case Q_PRIVATE_PROPERTY_TOKEN:
971 case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
977 def.enumList += enumDef;
985 qsizetype rewind = index--;
989 def.constructorList += funcDef;
990 handleDefaultArguments(&def.constructorList, funcDef);
996 def.publicList += funcDef;
998 def.slotList += funcDef;
999 handleDefaultArguments(&def.slotList, funcDef);
1003 def.signalList += funcDef;
1004 handleDefaultArguments(&def.signalList, funcDef);
1008 def.methodList += funcDef;
1009 handleDefaultArguments(&def.methodList, funcDef);
1023 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
1027 if (!def.hasQObject && !def.hasQGadget)
1028 error(
"Class declaration lacks Q_OBJECT macro.");
1031 if (!def.pluginData.iid.isEmpty())
1032 def.pluginData.metaArgs = metaArgs;
1034 if (def
.hasQObject && !def.superclassList.isEmpty())
1042 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
1043 classHash.insert(def.classname, def.qualified);
1044 classHash.insert(def.qualified, def.qualified);
1047 for (
const auto &n : std::as_const(namespaceList)) {
1048 if (!n.hasQNamespace)
1051 static_cast<BaseDef &>(def) =
static_cast<BaseDef>(n);
1052 def.qualified += def.classname;
1053 def.hasQNamespace =
true;
1054 auto it = std::find_if(classList.begin(), classList.end(), [&def](
const ClassDef &val) {
1055 return def.classname == val.classname && def.qualified == val.qualified;
1058 if (it != classList.end()) {
1059 it->classInfoList += def.classInfoList;
1060 Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<
int>::max());
1061 it->enumDeclarations.insert(def.enumDeclarations);
1062 it->enumList += def.enumList;
1063 Q_ASSERT(it->enumList.size() <= std::numeric_limits<
int>::max());
1064 it->flagAliases.insert(def.flagAliases);
1066 knownGadgets.insert(def.classname, def.qualified);
1067 knownGadgets.insert(def.qualified, def.qualified);
1110 static const QByteArrayList candidates = make_candidates();
1112 QByteArrayList required;
1113 required.reserve(candidates.size());
1115 bool needsQProperty =
false;
1117 for (
const auto &candidate : candidates) {
1118 const QByteArray pattern = candidate +
'<';
1120 for (
const auto &c : classes) {
1121 for (
const auto &p : c.propertyList)
1122 needsQProperty |= !p.bind.isEmpty();
1123 if (any_type_contains(c.propertyList, pattern) ||
1124 any_arg_contains(c.slotList, pattern) ||
1125 any_arg_contains(c.signalList, pattern) ||
1126 any_arg_contains(c.methodList, pattern)) {
1127 required.push_back(candidate);
1134 required.push_back(
"QProperty");
1141 QByteArrayView fn = QByteArrayView(filename);
1143 auto isSlash = [](
char ch) {
return ch ==
'/' || ch ==
'\\'; };
1144 auto rit =
std::find_if(fn.crbegin(), fn.crend(), isSlash);
1145 if (rit != fn.crend())
1146 fn = fn.last(rit - fn.crbegin());
1148 fprintf(out,
"/****************************************************************************\n"
1149 "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
1150 fprintf(out,
"** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
1151 fprintf(out,
"** WARNING! All changes made in this file will be lost!\n"
1152 "*****************************************************************************/\n\n");
1158 if (includePath.size() && !includePath.endsWith(
'/'))
1160 for (QByteArray inc : std::as_const(includeFiles)) {
1161 if (!inc.isEmpty() && inc.at(0) !=
'<' && inc.at(0) !=
'"') {
1162 if (includePath.size() && includePath !=
"./")
1163 inc.prepend(includePath);
1164 inc =
'\"' + inc +
'\"';
1166 fprintf(out,
"#include %s\n", inc.constData());
1169 if (classList.size() && classList.constFirst().classname ==
"Qt")
1170 fprintf(out,
"#include <QtCore/qobject.h>\n");
1172 fprintf(out,
"#include <QtCore/qmetatype.h>\n");
1174 fprintf(out,
"#include <QtCore/qplugin.h>\n");
1176 const auto qtContainers = requiredQtContainers(classList);
1177 for (
const QByteArray &qtContainer : qtContainers)
1178 fprintf(out,
"#include <QtCore/%s>\n", qtContainer.constData());
1180 fprintf(out,
"\n#include <QtCore/qtmochelpers.h>\n");
1182 fprintf(out,
"\n#include <memory>\n\n");
1183 fprintf(out,
"\n#include <QtCore/qxptype_traits.h>\n");
1185 fprintf(out,
"#if !defined(Q_MOC_OUTPUT_REVISION)\n"
1186 "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
1187 fprintf(out,
"#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
1188 fprintf(out,
"#error \"This file was generated using the moc from %s."
1189 " It\"\n#error \"cannot be used with the include files from"
1190 " this version of Qt.\"\n#error \"(The moc has changed too"
1191 " much.)\"\n", QT_VERSION_STR);
1192 fprintf(out,
"#endif\n\n");
1194#if QT_VERSION <= QT_VERSION_CHECK(7
, 0
, 0
)
1195 fprintf(out,
"#ifndef Q_CONSTINIT\n"
1196 "#define Q_CONSTINIT\n"
1200 fprintf(out,
"QT_WARNING_PUSH\n");
1201 fprintf(out,
"QT_WARNING_DISABLE_DEPRECATED\n");
1202 fprintf(out,
"QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
1205 for (ClassDef &def : classList) {
1206 Generator generator(
this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
1207 requireCompleteTypes);
1208 generator.generateCode();
1211 if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<
int>::max())) {
1212 error(
"internal limit exceeded: number of parsed strings is too big.");
1218 fprintf(out,
"QT_WARNING_POP\n");
1222 mocData[
"outputRevision"_L1] = mocOutputRevision;
1223 mocData[
"inputFile"_L1] = QLatin1StringView(fn.constData());
1227 for (
const ClassDef &cdef: std::as_const(classList))
1228 classesJsonFormatted.append(cdef.toJson());
1230 if (!classesJsonFormatted.isEmpty())
1231 mocData[
"classes"_L1] = classesJsonFormatted;
1234 fputs(jsonDoc.toJson().constData(), jsonOutput);
1362 auto checkIsFunction = [&](
const QByteArray &def,
const char *name) {
1363 if (def.endsWith(
')')) {
1364 QByteArray msg =
"Providing a function for ";
1366 msg +=
" in a property declaration is not be supported in Qt 6.";
1367 error(msg.constData());
1371 while (test(IDENTIFIER)) {
1372 const Symbol &lsym = symbol();
1373 const QByteArray l = lsym.lexem();
1374 if (l[0] ==
'C' && l ==
"CONSTANT") {
1377 }
else if (l[0] ==
'F' && l ==
"FINAL") {
1380 }
else if (l[0] ==
'N' && l ==
"NAME") {
1382 propDef.name = lexem();
1384 }
else if (l[0] ==
'R' && l ==
"REQUIRED") {
1387 }
else if (l[0] ==
'R' && l ==
"REVISION" && test(LPAREN)) {
1395 v = lexemUntil(RPAREN);
1396 v = v.mid(1, v.size() - 2);
1397 }
else if (test(INTEGER_LITERAL)) {
1399 if (l !=
"REVISION")
1401 }
else if (test(DEFAULT)) {
1403 if (l !=
"READ" && l !=
"WRITE")
1409 v2 = lexemUntil(RPAREN);
1410 else if (v !=
"true" && v !=
"false")
1423 else if (l ==
"RESET")
1425 else if (l ==
"REVISION") {
1427 const int minor = v.toInt(&ok);
1428 if (!ok || !QTypeRevision::isValidSegment(minor))
1435 if (l ==
"SCRIPTABLE") {
1436 propDef.scriptable = v + v2;
1437 checkIsFunction(propDef.scriptable,
"SCRIPTABLE");
1438 }
else if (l ==
"STORED") {
1439 propDef.stored = v + v2;
1440 checkIsFunction(propDef.stored,
"STORED");
1444 case 'W':
if (l !=
"WRITE") error(lsym);
1447 case 'B':
if (l !=
"BINDABLE") error(lsym);
1450 case 'D':
if (l !=
"DESIGNABLE") error(lsym);
1451 propDef.designable = v + v2;
1452 checkIsFunction(propDef.designable,
"DESIGNABLE");
1454 case 'N':
if (l !=
"NOTIFY") error(lsym);
1457 case 'U':
if (l !=
"USER") error(lsym);
1458 propDef.user = v + v2;
1459 checkIsFunction(propDef.user,
"USER");
1465 if (propDef
.constant && !propDef.write.isNull()) {
1466 const QByteArray msg =
"Property declaration " + propDef.name
1467 +
" is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1469 warning(msg.constData());
1471 if (propDef
.constant && !propDef.notify.isNull()) {
1472 const QByteArray msg =
"Property declaration " + propDef.name
1473 +
" is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1475 warning(msg.constData());
1477 if (propDef
.constant && !propDef.bind.isNull()) {
1478 const QByteArray msg =
"Property declaration " + propDef.name
1479 +
" is both BINDable and CONSTANT. CONSTANT will be ignored.";
1481 warning(msg.constData());
1483 if (propDef.read ==
"default" && propDef.bind.isNull()) {
1484 const QByteArray msg =
"Property declaration " + propDef.name
1485 +
" is not BINDable but default-READable. READ will be ignored.";
1487 warning(msg.constData());
1489 if (propDef.write ==
"default" && propDef.bind.isNull()) {
1490 const QByteArray msg =
"Property declaration " + propDef.name
1491 +
" is not BINDable but default-WRITEable. WRITE will be ignored.";
1493 warning(msg.constData());
1510 QByteArray metaData;
1511 while (test(IDENTIFIER)) {
1512 QByteArray l = lexem();
1514 next(STRING_LITERAL);
1515 def->pluginData.iid = unquotedLexem();
1516 }
else if (l ==
"URI") {
1517 next(STRING_LITERAL);
1518 def->pluginData.uri = unquotedLexem();
1519 }
else if (l ==
"FILE") {
1520 next(STRING_LITERAL);
1521 QByteArray metaDataFile = unquotedLexem();
1522 QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
1523 QString::fromLocal8Bit(metaDataFile));
1524 for (
const IncludePath &p : std::as_const(includes)) {
1527 if (p.isFrameworkPath)
1530 fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(metaDataFile.constData()));
1538 const QByteArray msg =
"Plugin Metadata file " + lexem()
1539 +
" does not exist. Declaration will be ignored";
1540 error(msg.constData());
1543 QFile file(fi.canonicalFilePath());
1544 if (!file.open(QFile::ReadOnly)) {
1545 QByteArray msg =
"Plugin Metadata file " + lexem() +
" could not be opened: "
1546 + file.errorString().toUtf8();
1547 error(msg.constData());
1550 parsedPluginMetadataFiles.append(fi.canonicalFilePath());
1551 metaData = file.readAll();
1555 if (!metaData.isEmpty()) {
1556 def->pluginData.metaData = QJsonDocument::fromJson(metaData);
1557 if (!def->pluginData.metaData.isObject()) {
1558 const QByteArray msg =
"Plugin Metadata file " + lexem()
1559 +
" does not contain a valid JSON object. Declaration will be ignored";
1560 warning(msg.constData());
1561 def->pluginData.iid = QByteArray();
1562 def->pluginData.uri = QByteArray();
1677 while (test(IDENTIFIER)) {
1679 iface += ClassDef::Interface(lexem());
1680 while (test(SCOPE)) {
1681 iface.last().className += lexem();
1683 iface.last().className += lexem();
1685 while (test(COLON)) {
1687 iface += ClassDef::Interface(lexem());
1688 while (test(SCOPE)) {
1689 iface.last().className += lexem();
1691 iface.last().className += lexem();
1695 for (qsizetype i = 0; i < iface.size(); ++i) {
1696 const QByteArray iid = interface2IdMap.value(iface.at(i).className);
1698 error(
"Undefined interface");
1700 iface[i].interfaceId = iid;
1702 def->interfaceList += iface;
1796 switch(symbols.at(index-1).token) {
1797 case LBRACE: ++braceCount;
break;
1798 case LBRACK: ++brackCount;
break;
1799 case LPAREN: ++parenCount;
break;
1800 case LANGLE: ++angleCount;
break;
1808 qsizetype possible = -1;
1810 while (index < symbols.size()) {
1811 Token t = symbols.at(index++).token;
1813 case LBRACE: ++braceCount;
break;
1814 case RBRACE: --braceCount;
break;
1815 case LBRACK: ++brackCount;
break;
1816 case RBRACK: --brackCount;
break;
1817 case LPAREN: ++parenCount;
break;
1818 case RPAREN: --parenCount;
break;
1820 if (parenCount == 0 && braceCount == 0)
1824 if (parenCount == 0 && braceCount == 0)
1828 if (parenCount == 0 && braceCount == 0) {
1839 && (target != RANGLE || angleCount <= 0)) {
1840 if (target != COMMA || angleCount <= 0)
1845 if (target == COMMA && t == EQ && possible != -1) {
1850 if (braceCount < 0 || brackCount < 0 || parenCount < 0
1851 || (target == RANGLE && angleCount < 0)) {
1856 if (braceCount <= 0 && t == SEMIC) {
1862 if (target == COMMA && angleCount != 0 && possible != -1) {
1872 Q_ASSERT(!def->superclassList.isEmpty());
1873 const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
1875 if (!knownQObjectClasses.contains(firstSuperclass)) {
1878 const QByteArray msg
1881 +
" contains the Q_OBJECT macro and inherits from "
1882 + def->superclassList.value(0)
1883 +
" but that is not a known QObject subclass. You may get compilation errors.";
1884 warning(msg.constData());
1889 auto isRegisteredInterface = [&def](QByteArrayView super) {
1890 auto matchesSuperClass = [&super](
const auto &ifaces) {
1891 return !ifaces.isEmpty() && ifaces.first().className == super;
1893 return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
1896 const auto end = def->superclassList.cend();
1897 auto it = def->superclassList.cbegin() + 1;
1898 for (; it != end; ++it) {
1899 const QByteArray &superClass = it->classname;
1900 if (knownQObjectClasses.contains(superClass)) {
1901 const QByteArray msg
1904 +
" inherits from two QObject subclasses "
1908 +
". This is not supported!";
1909 warning(msg.constData());
1912 if (interface2IdMap.contains(superClass)) {
1913 if (!isRegisteredInterface(superClass)) {
1914 const QByteArray msg
1917 +
" implements the interface "
1919 +
" but does not list it in Q_INTERFACES. qobject_cast to "
1921 +
" will not work!";
1922 warning(msg.constData());
1934 QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
1935 auto hasNoAttributes = [&](
const PropertyDef &p) {
1936 if (definedProperties.hasSeen(p.name)) {
1937 QByteArray msg =
"The property '" + p.name +
"' is defined multiple times in class " + cdef->classname +
".";
1938 warning(msg.constData());
1941 if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
1942 QByteArray msg =
"Property declaration " + p.name +
" has neither an associated QProperty<> member"
1943 ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
1944 const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
1945 warning(sym, msg.constData());
1946 if (p.write.isEmpty())
1951 cdef->propertyList.removeIf(hasNoAttributes);
1953 for (PropertyDef &p : cdef->propertyList) {
1954 for (
const FunctionDef &f : std::as_const(cdef->publicList)) {
1955 if (f.name != p.read)
1959 if (f.arguments.size())
1961 PropertyDef::Specification spec = PropertyDef::ValueSpec;
1962 QByteArray tmp = f.normalizedType;
1963 if (p.type ==
"QByteArray" && tmp ==
"const char *")
1965 if (tmp.left(6) ==
"const ")
1967 if (p.type != tmp && tmp.endsWith(
'*')) {
1969 spec = PropertyDef::PointerSpec;
1970 }
else if (f.type.name.endsWith(
'&')) {
1971 spec = PropertyDef::ReferenceSpec;
1978 if (!p.notify.isEmpty()) {
1980 for (
int j = 0; j <
int(cdef->signalList.size()); ++j) {
1981 const FunctionDef &f = cdef->signalList.at(j);
1982 if (f.name != p.notify) {
1989 p.notifyId = notifyId;
1990 if (notifyId == -1) {
1991 const int index =
int(cdef->nonClassSignalList.indexOf(p.notify));
1993 cdef->nonClassSignalList << p.notify;
1994 p.notifyId =
int(-1 - cdef->nonClassSignalList.size());
1996 p.notifyId =
int(-2 - index);
2006 cls[
"className"_L1] = QString::fromUtf8(classname.constData());
2007 cls[
"qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
2008 cls[
"lineNumber"_L1] = lineNumber;
2011 for (
const auto &info: std::as_const(classInfoList)) {
2012 QJsonObject infoJson;
2013 infoJson[
"name"_L1] = QString::fromUtf8(info.name);
2014 infoJson[
"value"_L1] = QString::fromUtf8(info.value);
2015 classInfos.append(infoJson);
2018 if (classInfos.size())
2019 cls[
"classInfos"_L1] = classInfos;
2021 int methodIndex = 0;
2022 const auto appendFunctions
2023 = [&cls, &methodIndex](
const QString &type,
const QList<
FunctionDef> &funcs) {
2026 for (
const FunctionDef &fdef: funcs)
2027 jsonFuncs.append(fdef.toJson(methodIndex++));
2029 if (!jsonFuncs.isEmpty())
2030 cls[type] = jsonFuncs;
2034 appendFunctions(
"signals"_L1, signalList);
2035 appendFunctions(
"slots"_L1, slotList);
2036 appendFunctions(
"methods"_L1, methodList);
2040 appendFunctions(
"constructors"_L1, constructorList);
2044 for (
const PropertyDef &propDef: std::as_const(propertyList))
2045 props.append(propDef.toJson());
2047 if (!props.isEmpty())
2048 cls[
"properties"_L1] = props;
2051 cls[
"object"_L1] =
true;
2053 cls[
"gadget"_L1] =
true;
2055 cls[
"namespace"_L1] =
true;
2059 for (
const auto &super: std::as_const(superclassList)) {
2060 QJsonObject superCls;
2061 superCls[
"name"_L1] = QString::fromUtf8(super.classname);
2062 if (super.classname != super.qualified)
2063 superCls[
"fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
2064 FunctionDef::accessToJson(&superCls, super.access);
2065 superClasses.append(superCls);
2068 if (!superClasses.isEmpty())
2069 cls[
"superClasses"_L1] = superClasses;
2072 for (
const EnumDef &enumDef: std::as_const(enumList))
2073 enums.append(enumDef.toJson(*
this));
2074 if (!enums.isEmpty())
2075 cls[
"enums"_L1] = enums;
2078 for (
const QList<Interface> &ifaceList : interfaceList) {
2079 QJsonArray jsonList;
2080 for (
const Interface &iface: ifaceList) {
2081 QJsonObject ifaceJson;
2082 ifaceJson[
"id"_L1] = QString::fromUtf8(iface.interfaceId);
2083 ifaceJson[
"className"_L1] = QString::fromUtf8(iface.className);
2084 jsonList.append(ifaceJson);
2086 ifaces.append(jsonList);
2088 if (!ifaces.isEmpty())
2089 cls[
"interfaces"_L1] = ifaces;