133 bool hasSignedOrUnsigned =
false;
135 type.firstToken = lookup();
141 hasSignedOrUnsigned =
true;
145 type.name += lexemView();
147 if (lookup(0) == VOLATILE)
148 type.isVolatile =
true;
150 case Q_MOC_COMPAT_TOKEN:
151 case Q_INVOKABLE_TOKEN:
152 case Q_SCRIPTABLE_TOKEN:
153 case Q_SIGNALS_TOKEN:
157 type.name += lexemView();
180 if (hasSignedOrUnsigned) {
189 type.name += lexemView();
191 if (test(LONG) || test(INT) || test(DOUBLE)) {
202 type.name += lexemView();
203 isVoid |= (lookup(0) == VOID);
212 if (type.name.isEmpty()) {
216 type.name += lexemUntil(RANGLE);
219 type.name += lexemView();
220 type.isScoped =
true;
225 while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
226 || test(STAR) || test(AND) || test(ANDAND)) {
228 type.name += lexemView();
229 if (lookup(0) == AND)
230 type.referenceType = Type::Reference;
231 else if (lookup(0) == ANDAND)
232 type.referenceType = Type::RValueReference;
233 else if (lookup(0) == STAR)
234 type.referenceType = Type::Pointer;
236 type.rawName = type.name;
238 if (isVoid && type.referenceType == Type::NoReference) {
441 bool templateFunction = (lookup() == TEMPLATE);
442 def->type = parseType();
443 if (def->type.name.isEmpty()) {
444 if (templateFunction)
445 error(
"Template function as signal or slot");
449 bool scopedFunctionName =
false;
454 Type tempType = parseType();
455 while (!tempType.name.isEmpty() && lookup() != LPAREN) {
456 if (testFunctionAttribute(def->type.firstToken, def))
458 else if (def->type.firstToken == Q_SIGNALS_TOKEN)
460 else if (def->type.firstToken == Q_SLOTS_TOKEN)
463 if (!def->tag.isEmpty())
465 def->tag += def->type.name;
467 def->type = tempType;
468 tempType = parseType();
470 next(LPAREN,
"Not a signal or slot declaration");
471 def->name = tempType.name;
474 scopedFunctionName = tempType.isScoped;
482 while (test(IDENTIFIER))
487 while (test(IDENTIFIER))
499 if (def->type.name ==
"auto" && test(ARROW))
500 def->type = parseType();
513 if (scopedFunctionName) {
514 const QByteArray msg =
"Function declaration " + def->name
515 +
" contains extra qualification. Ignoring as signal or slot.";
516 warning(msg.constData());
520 QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(
' ');
521 if (typeNameParts.contains(
"auto")) {
523 error(
"Function declared with auto as return type but missing trailing return type. "
524 "Return type deduction is not supported.");
528 if (def->type.referenceType == Type::Reference) {
529 QByteArray rawName = def->type.rawName;
530 def->type = Type(
"void");
531 def->type.rawName = rawName;
534 def->normalizedType = normalizeType(def->type.name);
778 bool templateClass =
false;
783 qsizetype rewind = index;
784 if (test(IDENTIFIER)) {
785 QByteArray nsName = lexem();
786 QByteArrayList nested;
787 while (test(SCOPE)) {
789
790
791
792
795 nested.append(nsName);
801 }
else if (test(LPAREN)) {
804 }
else if (!test(SEMIC)) {
806 def.classname = nsName;
807 def.lineNumber = symbol().lineNum;
808 def.doGenerate = currentFilenames.size() <= 1;
811 def.begin = index - 1;
814 index = def.begin + 1;
818 for (
const QByteArray &ns : nested) {
819 NamespaceDef parentNs;
820 parentNs.classname = ns;
821 parentNs.qualified = def.qualified;
822 def.qualified += ns +
"::";
823 parentNs.begin = def.begin;
824 parentNs.end = def.end;
825 namespaceList += parentNs;
831 if (test(IDENTIFIER)) {
832 while (test(SCOPE)) {
839 }
else if (!test(SEMIC)) {
844 case Q_NAMESPACE_EXPORT_TOKEN:
846 while (test(IDENTIFIER))
850 case Q_NAMESPACE_TOKEN:
852 if (moduleUnitKind == ModuleUnitKind::ImplementationUnit)
853 error(
"Q_NAMESPACE is not supported in a module implementation unit");
854 if (inPrivateModuleFragment)
855 error(
"Q_NAMESPACE is not supported in a private module fragment");
858 case Q_ENUM_NS_TOKEN:
862 error(
"Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
865 case Q_FLAG_NS_TOKEN:
869 error(
"Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
871 case Q_DECLARE_FLAGS_TOKEN:
874 case Q_CLASSINFO_TOKEN:
875 parseClassInfo(&def);
877 case Q_MOC_INCLUDE_TOKEN:
885 def.enumList += enumDef;
898 namespaceList += def;
900 if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
901 error(
"Namespace declaration lacks Q_NAMESPACE macro.");
908 templateClass =
false;
911 templateClass =
true;
913 case MOC_INCLUDE_BEGIN:
919 if (hasGlobalModuleFragment && moduleUnitKind == ModuleUnitKind::NotAModule
920 && currentFilenames.size() == 1) {
921 moduleFragmentIncludes += symbol().lexem();
924 currentFilenames.push(symbol().unquotedLexem());
926 case MOC_INCLUDE_END:
927 currentFilenames.pop();
929 case Q_DECLARE_INTERFACE_TOKEN:
932 case Q_DECLARE_METATYPE_TOKEN:
935 case Q_MOC_INCLUDE_TOKEN:
939 if (test(NAMESPACE)) {
940 while (test(SCOPE) || test(IDENTIFIER))
950 if (currentFilenames.size() <= 1)
962 case Q_GADGET_EXPORT_TOKEN:
964 while (test(IDENTIFIER))
980 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
981 classHash.insert(def.classname, def.qualified);
982 classHash.insert(def.qualified, def.qualified);
986 const qsizetype afterExport = index;
987 if (currentFilenames.size() == 1 && test(IDENTIFIER) && lexem() ==
"module")
988 parseModuleDeclaration(index,
true);
994 if (currentFilenames.size() == 1 && lexem() ==
"module") {
995 const qsizetype afterModule = index;
999 parsePrivateModuleFragment(afterModule);
1003 const qsizetype afterModuleInSource =
1004 afterModule - firstSourceSymbolIndex;
1005 const bool precededByBareModuleFragment =
1006 afterModuleInSource == 3
1007 && symbols.at(afterModule - 2).token == SEMIC
1008 && symbols.at(afterModule - 3).token == IDENTIFIER
1009 && symbols.at(afterModule - 3).lexem() ==
"module";
1010 const bool isModuleCandidate = afterModuleInSource < 2
1011 || precededByBareModuleFragment
1012 || (hasGlobalModuleFragment
1013 && symbols.at(afterModule - 2).token == MOC_INCLUDE_END);
1014 if (isModuleCandidate)
1015 parseModuleDeclaration(afterModule,
false);
1021 if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
1025 Symbol qmlRegistrationMacroSymbol =
{};
1030 switch ((t = next())) {
1033 if (test(Q_SIGNALS_TOKEN))
1034 error(
"Signals cannot have access specifier");
1038 if (test(Q_SIGNALS_TOKEN))
1039 error(
"Signals cannot have access specifier");
1043 if (test(Q_SIGNALS_TOKEN))
1044 error(
"Signals cannot have access specifier");
1052 if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
1053 error(
"Meta object features not supported for nested classes");
1057 case Q_SIGNALS_TOKEN:
1061 switch (lookup(-1)) {
1068 error(
"Missing access specifier for slots");
1071 case Q_OBJECT_TOKEN:
1074 error(
"Template classes not supported by Q_OBJECT");
1075 if (def.classname !=
"Qt" && def.classname !=
"QObject" && def.superclassList.isEmpty())
1076 error(
"Class contains Q_OBJECT macro but does not inherit from QObject");
1077 if (moduleUnitKind == ModuleUnitKind::ImplementationUnit)
1078 error(
"Q_OBJECT is not supported in a module implementation unit");
1079 if (inPrivateModuleFragment)
1080 error(
"Q_OBJECT is not supported in a private module fragment");
1082 case Q_GADGET_EXPORT_TOKEN:
1084 while (test(IDENTIFIER))
1088 case Q_GADGET_TOKEN:
1091 error(
"Template classes not supported by Q_GADGET");
1092 if (moduleUnitKind == ModuleUnitKind::ImplementationUnit)
1093 error(
"Q_GADGET is not supported in a module implementation unit");
1094 if (inPrivateModuleFragment)
1095 error(
"Q_GADGET is not supported in a private module fragment");
1097 case Q_PROPERTY_TOKEN:
1100 case QT_ANONYMOUS_PROPERTY_TOKEN:
1103 case Q_PLUGIN_METADATA_TOKEN:
1110 case Q_ENUM_NS_TOKEN:
1111 error(
"Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
1117 case Q_FLAG_NS_TOKEN:
1118 error(
"Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
1120 case Q_DECLARE_FLAGS_TOKEN:
1123 case Q_CLASSINFO_TOKEN:
1126 case Q_MOC_INCLUDE_TOKEN:
1129 case Q_INTERFACES_TOKEN:
1132 case Q_PRIVATE_SLOT_TOKEN:
1135 case Q_PRIVATE_PROPERTY_TOKEN:
1138 case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
1144 def.enumList += enumDef;
1151 const QByteArrayView lex = lexemView();
1152 if (lex.startsWith(
"QML_")) {
1153 if ( lex ==
"QML_ELEMENT" || lex ==
"QML_NAMED_ELEMENT"
1154 || lex ==
"QML_ANONYMOUS" || lex ==
"QML_VALUE_TYPE") {
1155 qmlRegistrationMacroSymbol = symbol();
1163 qsizetype rewind = index--;
1167 def.constructorList += funcDef;
1168 handleDefaultArguments(&def.constructorList, funcDef);
1174 def.publicList += funcDef;
1176 def.slotList += funcDef;
1177 handleDefaultArguments(&def.slotList, funcDef);
1181 def.signalList += funcDef;
1182 handleDefaultArguments(&def.signalList, funcDef);
1186 def.methodList += funcDef;
1187 handleDefaultArguments(&def.methodList, funcDef);
1201
1202
1203
1205 QByteArray msg(
"Potential QML registration macro was found, but no header containing it was included.\n"
1206 "This might cause runtime errors in QML applications\n"
1207 "Include <QtQmlIntegration/qqmlintegration.h> or <QtQml/qqmlregistration.h> to fix this.");
1208 if (qmlMacroWarningIsFatal)
1209 error(qmlRegistrationMacroSymbol, msg.constData());
1211 warning(qmlRegistrationMacroSymbol, msg.constData());
1215 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
1219 if (!def.hasQObject && !def.hasQGadget)
1220 error(
"Class declaration lacks Q_OBJECT macro.");
1223 if (!def.pluginData.iid.isEmpty())
1224 def.pluginData.metaArgs = metaArgs;
1226 if (def
.hasQObject && !def.superclassList.isEmpty())
1234 QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
1235 classHash.insert(def.classname, def.qualified);
1236 classHash.insert(def.qualified, def.qualified);
1239 for (
const auto &n : std::as_const(namespaceList)) {
1240 if (!n.hasQNamespace)
1243 static_cast<BaseDef &>(def) =
static_cast<BaseDef>(n);
1244 def.qualified += def.classname;
1245 def.hasQNamespace =
true;
1246 auto it = std::find_if(classList.begin(), classList.end(), [&def](
const ClassDef &val) {
1247 return def.classname == val.classname && def.qualified == val.qualified;
1250 if (it != classList.end()) {
1251 it->classInfoList += def.classInfoList;
1252 Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<
int>::max());
1253 it->enumDeclarations.insert(def.enumDeclarations);
1254 it->enumList += def.enumList;
1255 Q_ASSERT(it->enumList.size() <= std::numeric_limits<
int>::max());
1256 it->flagAliases.insert(def.flagAliases);
1258 knownGadgets.insert(def.classname, def.qualified);
1259 knownGadgets.insert(def.qualified, def.qualified);
1345 QByteArrayView fn = strippedFileName();
1347 fprintf(out,
"/****************************************************************************\n"
1348 "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
1349 fprintf(out,
"** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
1350 fprintf(out,
"** WARNING! All changes made in this file will be lost!\n"
1351 "*****************************************************************************/\n\n");
1358 fprintf(out,
"module;\n\n");
1359 for (
const QByteArray &inc : std::as_const(moduleFragmentIncludes))
1360 fprintf(out,
"#include \"%s\"\n", inc.constData());
1365 if (includePath.size() && !includePath.endsWith(
'/'))
1367 for (QByteArray inc : std::as_const(includeFiles)) {
1368 if (!inc.isEmpty() && inc.at(0) !=
'<' && inc.at(0) !=
'"') {
1369 if (includePath.size() && includePath !=
"./")
1370 inc.prepend(includePath);
1371 inc =
'\"' + inc +
'\"';
1373 fprintf(out,
"#include %s\n", inc.constData());
1376 if (classList.size() && classList.constFirst().classname ==
"Qt")
1377 fprintf(out,
"#include <QtCore/qobject.h>\n");
1379 fprintf(out,
"#include <QtCore/qmetatype.h>\n");
1381 fprintf(out,
"#include <QtCore/qplugin.h>\n");
1383 const auto qtContainers = requiredQtContainers(classList);
1384 for (
const QByteArray &qtContainer : qtContainers)
1385 fprintf(out,
"#include <QtCore/%s>\n", qtContainer.constData());
1387 fprintf(out,
"\n#include <QtCore/qtmochelpers.h>\n");
1389 fprintf(out,
"\n#include <memory>\n\n");
1390 fprintf(out,
"\n#include <QtCore/qxptype_traits.h>\n");
1393 fprintf(out,
"\nmodule %s;\n", moduleName.constData());
1401 fprintf(out,
"import :%s;\n", modulePartitionName.constData());
1407 fprintf(out,
"#if !defined(Q_MOC_OUTPUT_REVISION)\n"
1408 "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
1409 fprintf(out,
"#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
1410 fprintf(out,
"#error \"This file was generated using the moc from %s."
1411 " It\"\n#error \"cannot be used with the include files from"
1412 " this version of Qt.\"\n#error \"(The moc has changed too"
1413 " much.)\"\n", QT_VERSION_STR);
1414 fprintf(out,
"#endif\n\n");
1416#if QT_VERSION <= QT_VERSION_CHECK(7
, 0
, 0
)
1417 fprintf(out,
"#ifndef Q_CONSTINIT\n"
1418 "#define Q_CONSTINIT\n"
1423 for (ClassDef &cdef : classList) {
1424 QList<EnumDef> enumList;
1425 for (EnumDef def : std::as_const(cdef.enumList)) {
1426 if (cdef.enumDeclarations.contains(def.name)) {
1429 def.enumName = def.name;
1430 QByteArray alias = cdef.flagAliases.value(def.name);
1431 if (cdef.enumDeclarations.contains(alias)) {
1433 def.flags |= cdef.enumDeclarations[alias];
1437 cdef.enumList = enumList;
1440 fprintf(out,
"QT_WARNING_PUSH\n");
1441 fprintf(out,
"QT_WARNING_DISABLE_DEPRECATED\n");
1442 fprintf(out,
"QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
1445 for (
const ClassDef &def : std::as_const(classList)) {
1446 Generator generator(
this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
1447 requireCompleteTypes);
1448 generator.generateCode();
1451 if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<
int>::max())) {
1452 error(
"internal limit exceeded: number of parsed strings is too big.");
1458 fprintf(out,
"QT_WARNING_POP\n");
1461 QJsonObject mocData;
1462 mocData[
"outputRevision"_L1] = mocOutputRevision;
1463 mocData[
"inputFile"_L1] = QLatin1StringView(fn.constData());
1466 QByteArray moduleId = moduleName;
1467 if (!modulePartitionName.isEmpty())
1468 moduleId +=
':' + modulePartitionName;
1469 mocData[
"module"_L1] = QLatin1StringView(moduleId.constData(), moduleId.size());
1472 QJsonArray classesJsonFormatted;
1474 for (
const ClassDef &cdef: std::as_const(classList))
1475 classesJsonFormatted.append(cdef.toJson());
1477 if (!classesJsonFormatted.isEmpty())
1478 mocData[
"classes"_L1] = classesJsonFormatted;
1481 fputs(jsonDoc.toJson().constData(), jsonOutput);
1612 auto checkIsFunction = [&](
const QByteArray &def,
const char *name) {
1613 if (def.endsWith(
')')) {
1614 QByteArray msg =
"Providing a function for ";
1616 msg +=
" in a property declaration is not be supported in Qt 6.";
1617 error(msg.constData());
1621 while (test(IDENTIFIER)) {
1622 const Symbol &lsym = symbol();
1623 const QByteArrayView l = lsym.lexemView();
1624 if (l[0] ==
'C' && l ==
"CONSTANT") {
1627 }
else if (l[0] ==
'F' && l ==
"FINAL") {
1630 }
else if (l[0] ==
'N' && l ==
"NAME") {
1632 propDef.name = lexem();
1634 }
else if (l[0] ==
'O' && l ==
"OVERRIDE") {
1637 }
else if (l[0] ==
'R' && l ==
"REQUIRED") {
1640 }
else if (l[0] ==
'R' && l ==
"REVISION" && test(LPAREN)) {
1644 }
else if (l[0] ==
'V' && l ==
"VIRTUAL") {
1651 v = lexemUntil(RPAREN);
1652 v = v.mid(1, v.size() - 2);
1653 }
else if (test(INTEGER_LITERAL)) {
1655 if (l !=
"REVISION")
1657 }
else if (test(DEFAULT)) {
1659 if (l !=
"READ" && l !=
"WRITE")
1665 v2 = lexemUntil(RPAREN);
1666 else if (v !=
"true" && v !=
"false")
1679 else if (l ==
"RESET")
1681 else if (l ==
"REVISION") {
1683 const int minor = v.toInt(&ok);
1684 if (!ok || !QTypeRevision::isValidSegment(minor))
1691 if (l ==
"SCRIPTABLE") {
1692 propDef.scriptable = v + v2;
1693 checkIsFunction(propDef.scriptable,
"SCRIPTABLE");
1694 }
else if (l ==
"STORED") {
1695 propDef.stored = v + v2;
1696 checkIsFunction(propDef.stored,
"STORED");
1700 case 'W':
if (l !=
"WRITE") error(lsym);
1703 case 'B':
if (l !=
"BINDABLE") error(lsym);
1706 case 'D':
if (l !=
"DESIGNABLE") error(lsym);
1707 propDef.designable = v + v2;
1708 checkIsFunction(propDef.designable,
"DESIGNABLE");
1710 case 'N':
if (l !=
"NOTIFY") error(lsym);
1713 case 'U':
if (l !=
"USER") error(lsym);
1714 propDef.user = v + v2;
1715 checkIsFunction(propDef.user,
"USER");
1721 if (propDef
.constant && !propDef.write.isNull()) {
1722 const QByteArray msg =
"Property declaration " + propDef.name
1723 +
" is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1725 warning(msg.constData());
1727 if (propDef
.constant && !propDef.notify.isNull()) {
1728 const QByteArray msg =
"Property declaration " + propDef.name
1729 +
" is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1731 warning(msg.constData());
1733 if (propDef
.constant && !propDef.bind.isNull()) {
1734 const QByteArray msg =
"Property declaration " + propDef.name
1735 +
" is both BINDable and CONSTANT. CONSTANT will be ignored.";
1737 warning(msg.constData());
1739 if (propDef.read ==
"default" && propDef.bind.isNull()) {
1740 const QByteArray msg =
"Property declaration " + propDef.name
1741 +
" is not BINDable but default-READable. READ will be ignored.";
1743 warning(msg.constData());
1745 if (propDef.write ==
"default" && propDef.bind.isNull()) {
1746 const QByteArray msg =
"Property declaration " + propDef.name
1747 +
" is not BINDable but default-WRITEable. WRITE will be ignored.";
1749 warning(msg.constData());
1752 const QByteArray msg =
"Issue with property declaration " + propDef.name
1753 +
": VIRTUAL is redundant when overriding a property. The OVERRIDE "
1754 "must only be used when actually overriding an existing property; using it on a "
1755 "new property is an error.";
1756 error(msg.constData());
1759 const QByteArray msg =
"Issue with property declaration " + propDef.name
1760 +
": OVERRIDE is redundant when property is marked FINAL";
1761 error(msg.constData());
1764 const QByteArray msg =
"Issue with property declaration " + propDef.name
1765 +
": The VIRTUAL cannot be combined with FINAL, as these attributes are mutually "
1767 error(msg.constData());
1784 QByteArray metaData;
1785 while (test(IDENTIFIER)) {
1786 QByteArray l = lexem();
1788 next(STRING_LITERAL);
1789 def->pluginData.iid = unquotedLexem();
1790 }
else if (l ==
"URI") {
1791 next(STRING_LITERAL);
1792 def->pluginData.uri = unquotedLexem();
1793 }
else if (l ==
"FILE") {
1794 next(STRING_LITERAL);
1795 QByteArrayView metaDataFile = unquotedLexemView();
1796 QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
1797 QString::fromLocal8Bit(metaDataFile));
1798 for (
const IncludePath &p : std::as_const(includes)) {
1801 if (p.isFrameworkPath)
1804 fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(metaDataFile));
1812 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1813 +
" does not exist. Declaration will be ignored";
1814 error(msg.constData());
1817 QFile file(fi.canonicalFilePath());
1818 if (!file.open(QFile::ReadOnly)) {
1819 QByteArray msg =
"Plugin Metadata file " + lexemView() +
" could not be opened: "
1820 + file.errorString().toUtf8();
1821 error(msg.constData());
1824 parsedPluginMetadataFiles.append(fi.canonicalFilePath());
1825 metaData = file.readAll();
1829 if (!metaData.isEmpty()) {
1830 def->pluginData.metaData = QJsonDocument::fromJson(metaData);
1831 if (!def->pluginData.metaData.isObject()) {
1832 const QByteArray msg =
"Plugin Metadata file " + lexemView()
1833 +
" does not contain a valid JSON object. Declaration will be ignored";
1834 warning(msg.constData());
1835 def->pluginData.iid = QByteArray();
1836 def->pluginData.uri = QByteArray();
2146 Q_ASSERT(!def->superclassList.isEmpty());
2147 const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
2149 if (!knownQObjectClasses.contains(firstSuperclass)) {
2152 const QByteArray msg
2155 +
" contains the Q_OBJECT macro and inherits from "
2156 + def->superclassList.value(0)
2157 +
" but that is not a known QObject subclass. You may get compilation errors.";
2158 warning(msg.constData());
2163 auto isRegisteredInterface = [&def](QByteArrayView super) {
2164 auto matchesSuperClass = [&super](
const auto &ifaces) {
2165 return !ifaces.isEmpty() && ifaces.first().className == super;
2167 return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
2170 const auto end = def->superclassList.cend();
2171 auto it = def->superclassList.cbegin() + 1;
2172 for (; it != end; ++it) {
2173 const QByteArray &superClass = it->classname;
2174 if (knownQObjectClasses.contains(superClass)) {
2175 const QByteArray msg
2178 +
" inherits from two QObject subclasses "
2182 +
". This is not supported!";
2183 warning(msg.constData());
2186 if (interface2IdMap.contains(superClass)) {
2187 if (!isRegisteredInterface(superClass)) {
2188 const QByteArray msg
2191 +
" implements the interface "
2193 +
" but does not list it in Q_INTERFACES. qobject_cast to "
2195 +
" will not work!";
2196 warning(msg.constData());
2208 QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
2209 auto hasNoAttributes = [&](
const PropertyDef &p) {
2210 if (definedProperties.hasSeen(p.name)) {
2211 QByteArray msg =
"The property '" + p.name +
"' is defined multiple times in class " + cdef->classname +
".";
2212 warning(msg.constData());
2215 if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
2216 QByteArray msg =
"Property declaration " + p.name +
" has neither an associated QProperty<> member"
2217 ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
2218 const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
2219 warning(sym, msg.constData());
2220 if (p.write.isEmpty())
2225 cdef->propertyList.removeIf(hasNoAttributes);
2227 for (PropertyDef &p : cdef->propertyList) {
2228 for (
const FunctionDef &f : std::as_const(cdef->publicList)) {
2229 if (f.name != p.read)
2233 if (f.arguments.size())
2235 PropertyDef::Specification spec = PropertyDef::ValueSpec;
2236 QByteArray tmp = f.normalizedType;
2237 if (p.type ==
"QByteArray" && tmp ==
"const char *")
2239 if (tmp.left(6) ==
"const ")
2241 if (p.type != tmp && tmp.endsWith(
'*')) {
2243 spec = PropertyDef::PointerSpec;
2244 }
else if (f.type.name.endsWith(
'&')) {
2245 spec = PropertyDef::ReferenceSpec;
2252 if (!p.notify.isEmpty()) {
2254 for (
int j = 0; j <
int(cdef->signalList.size()); ++j) {
2255 const FunctionDef &f = cdef->signalList.at(j);
2256 if (f.name != p.notify) {
2263 p.notifyId = notifyId;
2264 if (notifyId == -1) {
2265 const int index =
int(cdef->nonClassSignalList.indexOf(p.notify));
2267 cdef->nonClassSignalList << p.notify;
2268 p.notifyId =
int(-1 - cdef->nonClassSignalList.size());
2270 p.notifyId =
int(-2 - index);
2280 cls[
"className"_L1] = QString::fromUtf8(classname.constData());
2281 cls[
"qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
2282 cls[
"lineNumber"_L1] = lineNumber;
2284 cls[
"final"_L1] =
true;
2286 QJsonArray classInfos;
2287 for (
const auto &info: std::as_const(classInfoList)) {
2288 QJsonObject infoJson;
2289 infoJson[
"name"_L1] = QString::fromUtf8(info.name);
2290 infoJson[
"value"_L1] = QString::fromUtf8(info.value);
2291 classInfos.append(infoJson);
2294 if (classInfos.size())
2295 cls[
"classInfos"_L1] = classInfos;
2297 int methodIndex = 0;
2298 const auto appendFunctions
2299 = [&cls, &methodIndex](
const QString &type,
const QList<
FunctionDef> &funcs) {
2300 QJsonArray jsonFuncs;
2302 for (
const FunctionDef &fdef: funcs)
2303 jsonFuncs.append(fdef.toJson(methodIndex++));
2305 if (!jsonFuncs.isEmpty())
2306 cls[type] = jsonFuncs;
2310 appendFunctions(
"signals"_L1, signalList);
2311 appendFunctions(
"slots"_L1, slotList);
2312 appendFunctions(
"methods"_L1, methodList);
2316 appendFunctions(
"constructors"_L1, constructorList);
2320 for (
const PropertyDef &propDef: std::as_const(propertyList))
2321 props.append(propDef.toJson());
2323 if (!props.isEmpty())
2324 cls[
"properties"_L1] = props;
2327 cls[
"object"_L1] =
true;
2329 cls[
"gadget"_L1] =
true;
2331 cls[
"namespace"_L1] =
true;
2333 QJsonArray superClasses;
2335 for (
const auto &super: std::as_const(superclassList)) {
2336 QJsonObject superCls;
2337 superCls[
"name"_L1] = QString::fromUtf8(super.classname);
2338 if (super.classname != super.qualified)
2339 superCls[
"fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
2340 FunctionDef::accessToJson(&superCls, super.access);
2341 superClasses.append(superCls);
2344 if (!superClasses.isEmpty())
2345 cls[
"superClasses"_L1] = superClasses;
2348 for (
const EnumDef &enumDef: std::as_const(enumList))
2349 enums.append(enumDef.toJson(*
this));
2350 if (!enums.isEmpty())
2351 cls[
"enums"_L1] = enums;
2354 for (
const QList<Interface> &ifaceList : interfaceList) {
2355 QJsonArray jsonList;
2356 for (
const Interface &iface: ifaceList) {
2357 QJsonObject ifaceJson;
2358 ifaceJson[
"id"_L1] = QString::fromUtf8(iface.interfaceId);
2359 ifaceJson[
"className"_L1] = QString::fromUtf8(iface.className);
2360 jsonList.append(ifaceJson);
2362 ifaces.append(jsonList);
2364 if (!ifaces.isEmpty())
2365 cls[
"interfaces"_L1] = ifaces;