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 QByteArrayView lex = lexemView();
69 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
73 def->qualified += name;
75 def->qualified += lexemView();
76 if (test(IDENTIFIER)) {
78 def->qualified += name;
81 def->classname = name;
82 def->lineNumber = symbol().lineNum;
84 if (test(IDENTIFIER)) {
85 const QByteArrayView lex = lexemView();
86 if (lex !=
"final" && lex !=
"sealed" && lex !=
"Q_DECL_FINAL")
96 else if (test(PROTECTED))
101 const Type type = parseType();
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;
129 bool hasSignedOrUnsigned =
false;
131 type.firstToken = lookup();
137 hasSignedOrUnsigned =
true;
141 type.name += lexemView();
143 if (lookup(0) == VOLATILE)
144 type.isVolatile =
true;
146 case Q_MOC_COMPAT_TOKEN:
147 case Q_INVOKABLE_TOKEN:
148 case Q_SCRIPTABLE_TOKEN:
149 case Q_SIGNALS_TOKEN:
153 type.name += lexemView();
176 if (hasSignedOrUnsigned) {
185 type.name += lexemView();
187 if (test(LONG) || test(INT) || test(DOUBLE)) {
198 type.name += lexemView();
199 isVoid |= (lookup(0) == VOID);
208 if (type.name.isEmpty()) {
212 type.name += lexemUntil(RANGLE);
215 type.name += lexemView();
216 type.isScoped =
true;
221 while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
222 || test(STAR) || test(AND) || test(ANDAND)) {
224 type.name += lexemView();
225 if (lookup(0) == AND)
226 type.referenceType = Type::Reference;
227 else if (lookup(0) == ANDAND)
228 type.referenceType = Type::RValueReference;
229 else if (lookup(0) == STAR)
230 type.referenceType = Type::Pointer;
232 type.rawName = type.name;
234 if (isVoid && type.referenceType == Type::NoReference) {
311 arg.type = parseType();
312 if (arg.type.name ==
"void")
314 if (test(IDENTIFIER))
316 while (test(LBRACK)) {
317 arg.rightType += lexemUntil(RBRACK);
319 if (test(CONST) || test(VOLATILE)) {
320 arg.rightType +=
' ';
321 arg.rightType += lexemView();
323 arg.normalizedType = normalizeType(QByteArray(arg.type.name +
' ' + arg.rightType));
326 def->arguments += arg;
331 if (!def->arguments.isEmpty()
332 && def->arguments.constLast().normalizedType ==
"QPrivateSignal") {
333 def->arguments.removeLast();
336 if (def->arguments.size() == 1
337 && def->arguments.constLast().normalizedType ==
"QMethodRawArguments") {
338 def->arguments.removeLast();
342 if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<
int>::max()))
343 error(
"number of function arguments exceeds std::numeric_limits<int>::max()");
390 QByteArray revisionString = lexemUntil(RPAREN);
391 revisionString.remove(0, 1);
392 revisionString.chop(1);
393 const QList<QByteArray> majorMinor = revisionString.split(
',');
394 switch (majorMinor.size()) {
397 const int revision = revisionString.toInt(&ok);
398 if (!ok || !QTypeRevision::isValidSegment(revision))
399 error(
"Invalid revision");
404 const int major = majorMinor[0].toInt(&ok);
405 if (!ok || !QTypeRevision::isValidSegment(major))
406 error(
"Invalid major version");
407 const int minor = majorMinor[1].toInt(&ok);
408 if (!ok || !QTypeRevision::isValidSegment(minor))
409 error(
"Invalid minor version");
413 error(
"Invalid revision");
437 bool templateFunction = (lookup() == TEMPLATE);
438 def->type = parseType();
439 if (def->type.name.isEmpty()) {
440 if (templateFunction)
441 error(
"Template function as signal or slot");
445 bool scopedFunctionName =
false;
450 Type tempType = parseType();
451 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
452 if (testFunctionAttribute(def->type.firstToken, def))
454 else if (def->type.firstToken == Q_SIGNALS_TOKEN)
456 else if (def->type.firstToken == Q_SLOTS_TOKEN)
459 if (!def->tag.isEmpty())
461 def->tag += def->type.name;
463 def->type = tempType;
464 tempType = parseType();
466 next(LPAREN,
"Not a signal or slot declaration");
467 def->name = tempType.name;
470 scopedFunctionName = tempType.isScoped;
478 while (test(IDENTIFIER))
483 while (test(IDENTIFIER))
495 if (def->type.name ==
"auto" && test(ARROW))
496 def->type = parseType();
509 if (scopedFunctionName) {
510 const QByteArray msg =
"Function declaration " + def->name
511 +
" contains extra qualification. Ignoring as signal or slot.";
512 warning(msg.constData());
516 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(
' ');
517 if (typeNameParts.contains(
"auto")) {
519 error(
"Function declared with auto as return type but missing trailing return type. "
520 "Return type deduction is not supported.");
524 if (def->type.referenceType == Type::Reference) {
525 QByteArray rawName = def->type.rawName;
526 def->type = Type(
"void");
527 def->type.rawName = rawName;
530 def->normalizedType = normalizeType(def->type.name);
549 bool tilde = test(TILDE);
550 def->type = parseType();
551 if (def->type.name.isEmpty())
553 bool scopedFunctionName =
false;
555 def->name = def->type.name;
557 scopedFunctionName = def->type.isScoped;
558 if (def->name == cdef->classname) {
571 Type tempType = parseType();
572 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
573 if (testFunctionAttribute(def->type.firstToken, def))
575 else if (def->type.name ==
"Q_SIGNAL")
577 else if (def->type.name ==
"Q_SLOT")
580 if (!def->tag.isEmpty())
582 def->tag += def->type.name;
584 def->type = tempType;
585 tempType = parseType();
589 def->name = tempType.name;
591 scopedFunctionName = tempType.isScoped;
595 if (def->type.referenceType == Type::Reference) {
596 QByteArray rawName = def->type.rawName;
597 def->type = Type(
"void");
598 def->type.rawName = rawName;
601 def->normalizedType = normalizeType(def->type.name);
609 if (scopedFunctionName
611 const QByteArray msg =
"parsemaybe: Function declaration " + def->name
612 +
" contains extra qualification. Ignoring as signal or slot.";
613 warning(msg.constData());
643 if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<
int>::max()))
644 error(
"number of signals defined in parent class(es) exceeds "
645 "std::numeric_limits<int>::max().");
647 if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<
int>::max()))
648 error(
"number of bindable properties exceeds std::numeric_limits<int>::max().");
650 if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<
int>::max()))
651 error(
"number of times Q_CLASSINFO macro is used exceeds "
652 "std::numeric_limits<int>::max().");
654 if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<
int>::max()))
655 error(
"number of enumerations exceeds std::numeric_limits<int>::max().");
657 if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<
int>::max()))
658 error(
"number of super classes exceeds std::numeric_limits<int>::max().");
660 if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<
int>::max()))
661 error(
"number of constructor parameters exceeds std::numeric_limits<int>::max().");
663 if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<
int>::max()))
664 error(
"number of signals exceeds std::numeric_limits<int>::max().");
666 if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<
int>::max()))
667 error(
"number of declared slots exceeds std::numeric_limits<int>::max().");
669 if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<
int>::max()))
670 error(
"number of methods exceeds std::numeric_limits<int>::max().");
672 if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<
int>::max()))
673 error(
"number of public functions declared in this class exceeds "
674 "std::numeric_limits<int>::max().");
680 bool templateClass =
false;
685 qsizetype rewind = index;
686 if (test(IDENTIFIER)) {
687 QByteArray nsName = lexem();
688 QByteArrayList nested;
689 while (test(SCOPE)) {
691
692
693
694
697 nested.append(nsName);
703 }
else if (test(LPAREN)) {
706 }
else if (!test(SEMIC)) {
708 def.classname = nsName;
709 def.lineNumber = symbol().lineNum;
710 def.doGenerate = currentFilenames.size() <= 1;
713 def.begin = index - 1;
716 index = def.begin + 1;
720 for (
const QByteArray &ns : nested) {
721 NamespaceDef parentNs;
722 parentNs.classname = ns;
723 parentNs.qualified = def.qualified;
724 def.qualified += ns +
"::";
725 parentNs.begin = def.begin;
726 parentNs.end = def.end;
727 namespaceList += parentNs;
733 if (test(IDENTIFIER)) {
734 while (test(SCOPE)) {
741 }
else if (!test(SEMIC)) {
746 case Q_NAMESPACE_TOKEN:
749 case Q_NAMESPACE_EXPORT_TOKEN:
751 while (test(IDENTIFIER))
757 case Q_ENUM_NS_TOKEN:
761 error(
"Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
764 case Q_FLAG_NS_TOKEN:
765 parseEnumOrFlag(&def, EnumIsFlag);
768 error(
"Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
770 case Q_DECLARE_FLAGS_TOKEN:
773 case Q_CLASSINFO_TOKEN:
774 parseClassInfo(&def);
776 case Q_MOC_INCLUDE_TOKEN:
784 def.enumList += enumDef;
797 namespaceList += def;
799 if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
800 error(
"Namespace declaration lacks Q_NAMESPACE macro.");
807 templateClass =
false;
810 templateClass =
true;
812 case MOC_INCLUDE_BEGIN:
813 currentFilenames.push(symbol().unquotedLexem());
815 case MOC_INCLUDE_END:
816 currentFilenames.pop();
818 case Q_DECLARE_INTERFACE_TOKEN:
821 case Q_DECLARE_METATYPE_TOKEN:
824 case Q_MOC_INCLUDE_TOKEN:
828 if (test(NAMESPACE)) {
829 while (test(SCOPE) || test(IDENTIFIER))
839 if (currentFilenames.size() <= 1)
851 case Q_GADGET_EXPORT_TOKEN:
853 while (test(IDENTIFIER))
869 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
870 classHash.insert(def.classname, def.qualified);
871 classHash.insert(def.qualified, def.qualified);
876 if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
880 Symbol qmlRegistrationMacroSymbol =
{};
885 switch ((t = next())) {
888 if (test(Q_SIGNALS_TOKEN))
889 error(
"Signals cannot have access specifier");
893 if (test(Q_SIGNALS_TOKEN))
894 error(
"Signals cannot have access specifier");
898 if (test(Q_SIGNALS_TOKEN))
899 error(
"Signals cannot have access specifier");
907 if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
908 error(
"Meta object features not supported for nested classes");
912 case Q_SIGNALS_TOKEN:
916 switch (lookup(-1)) {
923 error(
"Missing access specifier for slots");
929 error(
"Template classes not supported by Q_OBJECT");
930 if (def.classname !=
"Qt" && def.classname !=
"QObject" && def.superclassList.isEmpty())
931 error(
"Class contains Q_OBJECT macro but does not inherit from QObject");
933 case Q_GADGET_EXPORT_TOKEN:
935 while (test(IDENTIFIER))
942 error(
"Template classes not supported by Q_GADGET");
944 case Q_PROPERTY_TOKEN:
947 case QT_ANONYMOUS_PROPERTY_TOKEN:
950 case Q_PLUGIN_METADATA_TOKEN:
957 case Q_ENUM_NS_TOKEN:
958 error(
"Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
962 parseEnumOrFlag(&def, EnumIsFlag);
964 case Q_FLAG_NS_TOKEN:
965 error(
"Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
967 case Q_DECLARE_FLAGS_TOKEN:
970 case Q_CLASSINFO_TOKEN:
973 case Q_MOC_INCLUDE_TOKEN:
976 case Q_INTERFACES_TOKEN:
979 case Q_PRIVATE_SLOT_TOKEN:
982 case Q_PRIVATE_PROPERTY_TOKEN:
985 case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
991 def.enumList += enumDef;
998 const QByteArrayView lex = lexemView();
999 if (lex.startsWith(
"QML_")) {
1000 if ( lex ==
"QML_ELEMENT" || lex ==
"QML_NAMED_ELEMENT"
1001 || lex ==
"QML_ANONYMOUS" || lex ==
"QML_VALUE_TYPE") {
1002 qmlRegistrationMacroSymbol = symbol();
1010 qsizetype rewind = index--;
1014 def.constructorList += funcDef;
1015 handleDefaultArguments(&def.constructorList, funcDef);
1021 def.publicList += funcDef;
1023 def.slotList += funcDef;
1024 handleDefaultArguments(&def.slotList, funcDef);
1028 def.signalList += funcDef;
1029 handleDefaultArguments(&def.signalList, funcDef);
1033 def.methodList += funcDef;
1034 handleDefaultArguments(&def.methodList, funcDef);
1048
1049
1050
1052 QByteArray msg(
"Potential QML registration macro was found, but no header containing it was included.\n"
1053 "This might cause runtime errors in QML applications\n"
1054 "Include <QtQmlIntegration/qqmlintegration.h> or <QtQml/qqmlregistration.h> to fix this.");
1055 if (qmlMacroWarningIsFatal)
1056 error(qmlRegistrationMacroSymbol, msg.constData());
1058 warning(qmlRegistrationMacroSymbol, msg.constData());
1062 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
1066 if (!def.hasQObject && !def.hasQGadget)
1067 error(
"Class declaration lacks Q_OBJECT macro.");
1070 if (!def.pluginData.iid.isEmpty())
1071 def.pluginData.metaArgs = metaArgs;
1073 if (def
.hasQObject && !def.superclassList.isEmpty())
1081 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
1082 classHash.insert(def.classname, def.qualified);
1083 classHash.insert(def.qualified, def.qualified);
1086 for (
const auto &n : std::as_const(namespaceList)) {
1087 if (!n.hasQNamespace)
1090 static_cast<BaseDef &>(def) =
static_cast<BaseDef>(n);
1091 def.qualified += def.classname;
1092 def.hasQNamespace =
true;
1093 auto it = std::find_if(classList.begin(), classList.end(), [&def](
const ClassDef &val) {
1094 return def.classname == val.classname && def.qualified == val.qualified;
1097 if (it != classList.end()) {
1098 it->classInfoList += def.classInfoList;
1099 Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<
int>::max());
1100 it->enumDeclarations.insert(def.enumDeclarations);
1101 it->enumList += def.enumList;
1102 Q_ASSERT(it->enumList.size() <= std::numeric_limits<
int>::max());
1103 it->flagAliases.insert(def.flagAliases);
1105 knownGadgets.insert(def.classname, def.qualified);
1106 knownGadgets.insert(def.qualified, def.qualified);
1161 static const QByteArrayList candidates = make_candidates();
1163 QByteArrayList required;
1164 required.reserve(candidates.size());
1166 bool needsQProperty =
false;
1168 for (
const auto &candidate : candidates) {
1169 const QByteArray pattern = candidate +
'<';
1171 for (
const auto &c : classes) {
1172 for (
const auto &p : c.propertyList)
1173 needsQProperty |= !p.bind.isEmpty();
1174 if (any_type_contains(c.propertyList, pattern) ||
1175 any_arg_contains(c.slotList, pattern) ||
1176 any_arg_contains(c.signalList, pattern) ||
1177 any_arg_contains(c.methodList, pattern)) {
1178 required.push_back(candidate);
1185 required.push_back(
"QProperty");
1192 QByteArrayView fn = strippedFileName();
1194 fprintf(out,
"/****************************************************************************\n"
1195 "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
1196 fprintf(out,
"** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
1197 fprintf(out,
"** WARNING! All changes made in this file will be lost!\n"
1198 "*****************************************************************************/\n\n");
1204 if (includePath.size() && !includePath.endsWith(
'/'))
1206 for (QByteArray inc : std::as_const(includeFiles)) {
1207 if (!inc.isEmpty() && inc.at(0) !=
'<' && inc.at(0) !=
'"') {
1208 if (includePath.size() && includePath !=
"./")
1209 inc.prepend(includePath);
1210 inc =
'\"' + inc +
'\"';
1212 fprintf(out,
"#include %s\n", inc.constData());
1215 if (classList.size() && classList.constFirst().classname ==
"Qt")
1216 fprintf(out,
"#include <QtCore/qobject.h>\n");
1218 fprintf(out,
"#include <QtCore/qmetatype.h>\n");
1220 fprintf(out,
"#include <QtCore/qplugin.h>\n");
1222 const auto qtContainers = requiredQtContainers(classList);
1223 for (
const QByteArray &qtContainer : qtContainers)
1224 fprintf(out,
"#include <QtCore/%s>\n", qtContainer.constData());
1226 fprintf(out,
"\n#include <QtCore/qtmochelpers.h>\n");
1228 fprintf(out,
"\n#include <memory>\n\n");
1229 fprintf(out,
"\n#include <QtCore/qxptype_traits.h>\n");
1231 fprintf(out,
"#if !defined(Q_MOC_OUTPUT_REVISION)\n"
1232 "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
1234 fprintf(out,
"#error \"This file was generated using the moc from %s."
1235 " It\"\n#error \"cannot be used with the include files from"
1236 " this version of Qt.\"\n#error \"(The moc has changed too"
1237 " much.)\"\n", QT_VERSION_STR);
1238 fprintf(out,
"#endif\n\n");
1240#if QT_VERSION <= QT_VERSION_CHECK(7
, 0
, 0
)
1241 fprintf(out,
"#ifndef Q_CONSTINIT\n"
1242 "#define Q_CONSTINIT\n"
1246 fprintf(out,
"QT_WARNING_PUSH\n");
1247 fprintf(out,
"QT_WARNING_DISABLE_DEPRECATED\n");
1248 fprintf(out,
"QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
1251 for (ClassDef &def : classList) {
1252 Generator generator(
this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
1253 requireCompleteTypes);
1254 generator.generateCode();
1257 if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<
int>::max())) {
1258 error(
"internal limit exceeded: number of parsed strings is too big.");
1264 fprintf(out,
"QT_WARNING_POP\n");
1267 QJsonObject mocData;
1268 mocData[
"outputRevision"_L1] = mocOutputRevision;
1269 mocData[
"inputFile"_L1] = QLatin1StringView(fn.constData());
1271 QJsonArray classesJsonFormatted;
1273 for (
const ClassDef &cdef: std::as_const(classList))
1274 classesJsonFormatted.append(cdef.toJson());
1276 if (!classesJsonFormatted.isEmpty())
1277 mocData[
"classes"_L1] = classesJsonFormatted;
1280 fputs(jsonDoc.toJson().constData(), jsonOutput);
1411 auto checkIsFunction = [&](
const QByteArray &def,
const char *name) {
1412 if (def.endsWith(
')')) {
1413 QByteArray msg =
"Providing a function for ";
1415 msg +=
" in a property declaration is not be supported in Qt 6.";
1416 error(msg.constData());
1420 while (test(IDENTIFIER)) {
1421 const Symbol &lsym = symbol();
1422 const QByteArrayView l = lsym.lexemView();
1423 if (l[0] ==
'C' && l ==
"CONSTANT") {
1426 }
else if (l[0] ==
'F' && l ==
"FINAL") {
1429 }
else if (l[0] ==
'N' && l ==
"NAME") {
1431 propDef.name = lexem();
1433 }
else if (l[0] ==
'R' && l ==
"REQUIRED") {
1436 }
else if (l[0] ==
'R' && l ==
"REVISION" && test(LPAREN)) {
1444 v = lexemUntil(RPAREN);
1445 v = v.mid(1, v.size() - 2);
1446 }
else if (test(INTEGER_LITERAL)) {
1448 if (l !=
"REVISION")
1450 }
else if (test(DEFAULT)) {
1452 if (l !=
"READ" && l !=
"WRITE")
1458 v2 = lexemUntil(RPAREN);
1459 else if (v !=
"true" && v !=
"false")
1472 else if (l ==
"RESET")
1474 else if (l ==
"REVISION") {
1476 const int minor = v.toInt(&ok);
1477 if (!ok || !QTypeRevision::isValidSegment(minor))
1484 if (l ==
"SCRIPTABLE") {
1485 propDef.scriptable = v + v2;
1486 checkIsFunction(propDef.scriptable,
"SCRIPTABLE");
1487 }
else if (l ==
"STORED") {
1488 propDef.stored = v + v2;
1489 checkIsFunction(propDef.stored,
"STORED");
1493 case 'W':
if (l !=
"WRITE") error(lsym);
1496 case 'B':
if (l !=
"BINDABLE") error(lsym);
1499 case 'D':
if (l !=
"DESIGNABLE") error(lsym);
1500 propDef.designable = v + v2;
1501 checkIsFunction(propDef.designable,
"DESIGNABLE");
1503 case 'N':
if (l !=
"NOTIFY") error(lsym);
1506 case 'U':
if (l !=
"USER") error(lsym);
1507 propDef.user = v + v2;
1508 checkIsFunction(propDef.user,
"USER");
1514 if (propDef
.constant && !propDef.write.isNull()) {
1515 const QByteArray msg =
"Property declaration " + propDef.name
1516 +
" is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1518 warning(msg.constData());
1520 if (propDef
.constant && !propDef.notify.isNull()) {
1521 const QByteArray msg =
"Property declaration " + propDef.name
1522 +
" is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1524 warning(msg.constData());
1526 if (propDef
.constant && !propDef.bind.isNull()) {
1527 const QByteArray msg =
"Property declaration " + propDef.name
1528 +
" is both BINDable and CONSTANT. CONSTANT will be ignored.";
1530 warning(msg.constData());
1532 if (propDef.read ==
"default" && propDef.bind.isNull()) {
1533 const QByteArray msg =
"Property declaration " + propDef.name
1534 +
" is not BINDable but default-READable. READ will be ignored.";
1536 warning(msg.constData());
1538 if (propDef.write ==
"default" && propDef.bind.isNull()) {
1539 const QByteArray msg =
"Property declaration " + propDef.name
1540 +
" is not BINDable but default-WRITEable. WRITE will be ignored.";
1542 warning(msg.constData());
1559 QByteArray metaData;
1560 while (test(IDENTIFIER)) {
1561 QByteArray l = lexem();
1563 next(STRING_LITERAL);
1564 def->pluginData.iid = unquotedLexem();
1565 }
else if (l ==
"URI") {
1566 next(STRING_LITERAL);
1567 def->pluginData.uri = unquotedLexem();
1568 }
else if (l ==
"FILE") {
1569 next(STRING_LITERAL);
1570 QByteArrayView metaDataFile = unquotedLexemView();
1571 QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
1572 QString::fromLocal8Bit(metaDataFile));
1573 for (
const IncludePath &p : std::as_const(includes)) {
1576 if (p.isFrameworkPath)
1579 fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(metaDataFile));
1587 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1588 +
" does not exist. Declaration will be ignored";
1589 error(msg.constData());
1592 QFile file(fi.canonicalFilePath());
1593 if (!file.open(QFile::ReadOnly)) {
1594 QByteArray msg =
"Plugin Metadata file " + lexemView() +
" could not be opened: "
1595 + file.errorString().toUtf8();
1596 error(msg.constData());
1599 parsedPluginMetadataFiles.append(fi.canonicalFilePath());
1600 metaData = file.readAll();
1604 if (!metaData.isEmpty()) {
1605 def->pluginData.metaData = QJsonDocument::fromJson(metaData);
1606 if (!def->pluginData.metaData.isObject()) {
1607 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1608 +
" does not contain a valid JSON object. Declaration will be ignored";
1609 warning(msg.constData());
1610 def->pluginData.iid = QByteArray();
1611 def->pluginData.uri = QByteArray();
1845 switch(symbols.at(index-1).token) {
1846 case LBRACE: ++braceCount;
break;
1847 case LBRACK: ++brackCount;
break;
1848 case LPAREN: ++parenCount;
break;
1849 case LANGLE: ++angleCount;
break;
1857 qsizetype possible = -1;
1859 while (index < symbols.size()) {
1860 Token t = symbols.at(index++).token;
1862 case LBRACE: ++braceCount;
break;
1863 case RBRACE: --braceCount;
break;
1864 case LBRACK: ++brackCount;
break;
1865 case RBRACK: --brackCount;
break;
1866 case LPAREN: ++parenCount;
break;
1867 case RPAREN: --parenCount;
break;
1869 if (parenCount == 0 && braceCount == 0)
1873 if (parenCount == 0 && braceCount == 0)
1877 if (parenCount == 0 && braceCount == 0) {
1888 && (target != RANGLE || angleCount <= 0)) {
1889 if (target != COMMA || angleCount <= 0)
1894 if (target == COMMA && t == EQ && possible != -1) {
1899 if (braceCount < 0 || brackCount < 0 || parenCount < 0
1900 || (target == RANGLE && angleCount < 0)) {
1905 if (braceCount <= 0 && t == SEMIC) {
1911 if (target == COMMA && angleCount != 0 && possible != -1) {
1921 Q_ASSERT(!def->superclassList.isEmpty());
1922 const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
1924 if (!knownQObjectClasses.contains(firstSuperclass)) {
1927 const QByteArray msg
1930 +
" contains the Q_OBJECT macro and inherits from "
1931 + def->superclassList.value(0)
1932 +
" but that is not a known QObject subclass. You may get compilation errors.";
1933 warning(msg.constData());
1938 auto isRegisteredInterface = [&def](QByteArrayView super) {
1939 auto matchesSuperClass = [&super](
const auto &ifaces) {
1940 return !ifaces.isEmpty() && ifaces.first().className == super;
1942 return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
1945 const auto end = def->superclassList.cend();
1946 auto it = def->superclassList.cbegin() + 1;
1947 for (; it != end; ++it) {
1948 const QByteArray &superClass = it->classname;
1949 if (knownQObjectClasses.contains(superClass)) {
1950 const QByteArray msg
1953 +
" inherits from two QObject subclasses "
1957 +
". This is not supported!";
1958 warning(msg.constData());
1961 if (interface2IdMap.contains(superClass)) {
1962 if (!isRegisteredInterface(superClass)) {
1963 const QByteArray msg
1966 +
" implements the interface "
1968 +
" but does not list it in Q_INTERFACES. qobject_cast to "
1970 +
" will not work!";
1971 warning(msg.constData());
1983 QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
1984 auto hasNoAttributes = [&](
const PropertyDef &p) {
1985 if (definedProperties.hasSeen(p.name)) {
1986 QByteArray msg =
"The property '" + p.name +
"' is defined multiple times in class " + cdef->classname +
".";
1987 warning(msg.constData());
1990 if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
1991 QByteArray msg =
"Property declaration " + p.name +
" has neither an associated QProperty<> member"
1992 ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
1993 const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
1994 warning(sym, msg.constData());
1995 if (p.write.isEmpty())
2000 cdef->propertyList.removeIf(hasNoAttributes);
2002 for (PropertyDef &p : cdef->propertyList) {
2003 for (
const FunctionDef &f : std::as_const(cdef->publicList)) {
2004 if (f.name != p.read)
2008 if (f.arguments.size())
2010 PropertyDef::Specification spec = PropertyDef::ValueSpec;
2011 QByteArray tmp = f.normalizedType;
2012 if (p.type ==
"QByteArray" && tmp ==
"const char *")
2014 if (tmp.left(6) ==
"const ")
2016 if (p.type != tmp && tmp.endsWith(
'*')) {
2018 spec = PropertyDef::PointerSpec;
2019 }
else if (f.type.name.endsWith(
'&')) {
2020 spec = PropertyDef::ReferenceSpec;
2027 if (!p.notify.isEmpty()) {
2029 for (
int j = 0; j <
int(cdef->signalList.size()); ++j) {
2030 const FunctionDef &f = cdef->signalList.at(j);
2031 if (f.name != p.notify) {
2038 p.notifyId = notifyId;
2039 if (notifyId == -1) {
2040 const int index =
int(cdef->nonClassSignalList.indexOf(p.notify));
2042 cdef->nonClassSignalList << p.notify;
2043 p.notifyId =
int(-1 - cdef->nonClassSignalList.size());
2045 p.notifyId =
int(-2 - index);
2055 cls[
"className"_L1] = QString::fromUtf8(classname.constData());
2056 cls[
"qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
2057 cls[
"lineNumber"_L1] = lineNumber;
2059 QJsonArray classInfos;
2060 for (
const auto &info: std::as_const(classInfoList)) {
2061 QJsonObject infoJson;
2062 infoJson[
"name"_L1] = QString::fromUtf8(info.name);
2063 infoJson[
"value"_L1] = QString::fromUtf8(info.value);
2064 classInfos.append(infoJson);
2067 if (classInfos.size())
2068 cls[
"classInfos"_L1] = classInfos;
2070 int methodIndex = 0;
2071 const auto appendFunctions
2072 = [&cls, &methodIndex](
const QString &type,
const QList<
FunctionDef> &funcs) {
2073 QJsonArray jsonFuncs;
2075 for (
const FunctionDef &fdef: funcs)
2076 jsonFuncs.append(fdef.toJson(methodIndex++));
2078 if (!jsonFuncs.isEmpty())
2079 cls[type] = jsonFuncs;
2083 appendFunctions(
"signals"_L1, signalList);
2084 appendFunctions(
"slots"_L1, slotList);
2085 appendFunctions(
"methods"_L1, methodList);
2089 appendFunctions(
"constructors"_L1, constructorList);
2093 for (
const PropertyDef &propDef: std::as_const(propertyList))
2094 props.append(propDef.toJson());
2096 if (!props.isEmpty())
2097 cls[
"properties"_L1] = props;
2100 cls[
"object"_L1] =
true;
2102 cls[
"gadget"_L1] =
true;
2104 cls[
"namespace"_L1] =
true;
2106 QJsonArray superClasses;
2108 for (
const auto &super: std::as_const(superclassList)) {
2109 QJsonObject superCls;
2110 superCls[
"name"_L1] = QString::fromUtf8(super.classname);
2111 if (super.classname != super.qualified)
2112 superCls[
"fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
2113 FunctionDef::accessToJson(&superCls, super.access);
2114 superClasses.append(superCls);
2117 if (!superClasses.isEmpty())
2118 cls[
"superClasses"_L1] = superClasses;
2121 for (
const EnumDef &enumDef: std::as_const(enumList))
2122 enums.append(enumDef.toJson(*
this));
2123 if (!enums.isEmpty())
2124 cls[
"enums"_L1] = enums;
2127 for (
const QList<Interface> &ifaceList : interfaceList) {
2128 QJsonArray jsonList;
2129 for (
const Interface &iface: ifaceList) {
2130 QJsonObject ifaceJson;
2131 ifaceJson[
"id"_L1] = QString::fromUtf8(iface.interfaceId);
2132 ifaceJson[
"className"_L1] = QString::fromUtf8(iface.className);
2133 jsonList.append(ifaceJson);
2135 ifaces.append(jsonList);
2137 if (!ifaces.isEmpty())
2138 cls[
"interfaces"_L1] = ifaces;