diff options
Diffstat (limited to 'src/tools/moc')
-rw-r--r-- | src/tools/moc/.prev_CMakeLists.txt | 35 | ||||
-rw-r--r-- | src/tools/moc/CMakeLists.txt | 36 | ||||
-rw-r--r-- | src/tools/moc/collectjson.cpp | 4 | ||||
-rw-r--r-- | src/tools/moc/generator.cpp | 138 | ||||
-rw-r--r-- | src/tools/moc/keywords.cpp | 25 | ||||
-rw-r--r-- | src/tools/moc/moc.cpp | 203 | ||||
-rw-r--r-- | src/tools/moc/moc.h | 9 | ||||
-rw-r--r-- | src/tools/moc/token.h | 1 | ||||
-rw-r--r-- | src/tools/moc/util/generate_keywords.cpp | 1 |
9 files changed, 327 insertions, 125 deletions
diff --git a/src/tools/moc/.prev_CMakeLists.txt b/src/tools/moc/.prev_CMakeLists.txt new file mode 100644 index 0000000000..ffadd2e2be --- /dev/null +++ b/src/tools/moc/.prev_CMakeLists.txt @@ -0,0 +1,35 @@ +# Generated from moc.pro. + +##################################################################### +## moc Tool: +##################################################################### + +qt_add_tool(moc + BOOTSTRAP + SOURCES + cbordevice.h + collectjson.cpp collectjson.h + generator.cpp generator.h + main.cpp + moc.cpp moc.h + outputrevision.h + parser.cpp parser.h + preprocessor.cpp preprocessor.h + qdatetime_p.h + symbols.h + token.cpp token.h + utils.h + DEFINES + QT_MOC + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_FROM_BYTEARRAY + QT_NO_COMPRESS + QT_NO_FOREACH + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_SOURCE_DIR} + ../../3rdparty/tinycbor/src +) + +#### Keys ignored in scope 1:.:.:moc.pro:<TRUE>: +# QMAKE_TARGET_DESCRIPTION = "Qt Meta Object Compiler" +# _OPTION = "host_build" diff --git a/src/tools/moc/CMakeLists.txt b/src/tools/moc/CMakeLists.txt new file mode 100644 index 0000000000..c9786674f1 --- /dev/null +++ b/src/tools/moc/CMakeLists.txt @@ -0,0 +1,36 @@ +# Generated from moc.pro. + +##################################################################### +## moc Tool: +##################################################################### + +qt_add_tool(moc + BOOTSTRAP + TOOLS_TARGET Core # special case + SOURCES + cbordevice.h + collectjson.cpp collectjson.h + generator.cpp generator.h + main.cpp + moc.cpp moc.h + outputrevision.h + parser.cpp parser.h + preprocessor.cpp preprocessor.h + # qdatetime_p.h special case remove + symbols.h + token.cpp token.h + utils.h + DEFINES + QT_MOC + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_FROM_BYTEARRAY + QT_NO_COMPRESS + QT_NO_FOREACH + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_SOURCE_DIR} + ../../3rdparty/tinycbor/src +) + +#### Keys ignored in scope 1:.:.:moc.pro:<TRUE>: +# QMAKE_TARGET_DESCRIPTION = "Qt Meta Object Compiler" +# _OPTION = "host_build" diff --git a/src/tools/moc/collectjson.cpp b/src/tools/moc/collectjson.cpp index 4029bca5e9..fe499151cb 100644 --- a/src/tools/moc/collectjson.cpp +++ b/src/tools/moc/collectjson.cpp @@ -83,7 +83,9 @@ int collectJson(const QStringList &jsonFiles, const QString &outputFile) } } - for (const QString &jsonFile: jsonFiles) { + QStringList jsonFilesSorted = jsonFiles; + jsonFilesSorted.sort(); + for (const QString &jsonFile : qAsConst(jsonFilesSorted)) { QFile f(jsonFile); if (!f.open(QIODevice::ReadOnly)) { fprintf(stderr, "Error opening %s for reading\n", qPrintable(jsonFile)); diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 7264b5bf66..c0e1dca748 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -194,7 +194,6 @@ static bool qualifiedNameEquals(const QByteArray &qualifiedName, const QByteArra void Generator::generateCode() { - bool isQt = (cdef->classname == "Qt"); bool isQObject = (cdef->classname == "QObject"); bool isConstructible = !cdef->constructorList.isEmpty(); @@ -237,7 +236,7 @@ void Generator::generateCode() // const int constCharArraySizeLimit = 65535; fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData()); - fprintf(out, " QByteArrayData data[%d];\n", strings.size()); + fprintf(out, " const uint offsetsAndSize[%d];\n", strings.size()*2); { int stringDataLength = 0; int stringDataCounter = 0; @@ -260,11 +259,8 @@ void Generator::generateCode() // stringdata.stringdata member, and 2) the stringdata.data index of the // QByteArrayData being defined. This calculation relies on the // QByteArrayData::data() implementation returning simply "this + offset". - fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) \\\n" - " Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\\n" - " qptrdiff(offsetof(qt_meta_stringdata_%s_t, stringdata0) + ofs \\\n" - " - idx * sizeof(QByteArrayData)) \\\n" - " )\n", + fprintf(out, "#define QT_MOC_LITERAL(ofs, len) \\\n" + " uint(offsetof(qt_meta_stringdata_%s_t, stringdata0) + ofs), len \n", qualifiedClassNameIdentifier.constData()); fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n", @@ -274,7 +270,7 @@ void Generator::generateCode() int idx = 0; for (int i = 0; i < strings.size(); ++i) { const QByteArray &str = strings.at(i); - fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length()); + fprintf(out, "QT_MOC_LITERAL(%d, %d)", idx, str.length()); if (i != strings.size() - 1) fputc(',', out); const QByteArray comment = str.length() > 32 ? str.left(29) + "..." : str; @@ -452,7 +448,7 @@ void Generator::generateCode() // // Generate internal qt_static_metacall() function // - const bool hasStaticMetaCall = !isQt && + const bool hasStaticMetaCall = (cdef->hasQObject || !cdef->methodList.isEmpty() || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); if (hasStaticMetaCall) @@ -480,7 +476,7 @@ void Generator::generateCode() QByteArray unqualifiedScope = p.type.left(s); // The scope may be a namespace for example, so it's only safe to include scopes that are known QObjects (QTBUG-2151) - QHash<QByteArray, QByteArray>::ConstIterator scopeIt; + QMultiHash<QByteArray, QByteArray>::ConstIterator scopeIt; QByteArray thisScope = cdef->qualified; do { @@ -534,10 +530,7 @@ void Generator::generateCode() // // Finally create and initialize the static meta object // - if (isQt) - fprintf(out, "QT_INIT_METAOBJECT const QMetaObject QObject::staticQtMetaObject = { {\n"); - else - fprintf(out, "QT_INIT_METAOBJECT const QMetaObject %s::staticMetaObject = { {\n", cdef->qualified.constData()); + fprintf(out, "QT_INIT_METAOBJECT const QMetaObject %s::staticMetaObject = { {\n", cdef->qualified.constData()); if (isQObject) fprintf(out, " nullptr,\n"); @@ -547,7 +540,7 @@ void Generator::generateCode() fprintf(out, " QtPrivate::MetaObjectForType<%s>::value(),\n", purestSuperClass.constData()); else fprintf(out, " nullptr,\n"); - fprintf(out, " qt_meta_stringdata_%s.data,\n" + fprintf(out, " qt_meta_stringdata_%s.offsetsAndSize,\n" " qt_meta_data_%s,\n", qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); if (hasStaticMetaCall) @@ -559,10 +552,19 @@ void Generator::generateCode() fprintf(out, " nullptr,\n"); else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); - fprintf(out, " nullptr\n} };\n\n"); - if(isQt) - return; + if (cdef->propertyList.isEmpty()) { + fprintf(out, " nullptr,\n"); + } else { + fprintf(out, "qt_metaTypeArray<\n"); + for (int i = 0; i < cdef->propertyList.count(); ++i) { + const PropertyDef &p = cdef->propertyList.at(i); + fprintf(out, "%s%s", i == 0 ? "" : ", ", p.type.data()); + } + fprintf(out, ">,\n"); + } + + fprintf(out, " nullptr\n} };\n\n"); if (!cdef->hasQObject) return; @@ -867,6 +869,9 @@ void Generator::generateProperties() if (p.required) flags |= Required; + if (p.isQProperty) + flags |= IsQProperty; + fprintf(out, " %4d, ", stridx(p.name)); generateTypeInfo(p.type); fprintf(out, ", 0x%.8x,\n", flags); @@ -1015,7 +1020,9 @@ void Generator::generateMetacall() fprintf(out, "else "); fprintf(out, "if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n" - " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {\n" + " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType\n" + " || _c == QMetaObject::RegisterQPropertyObserver\n" + " || _c == QMetaObject::SetQPropertyBinding) {\n" " qt_static_metacall(this, _c, _id, _a);\n" " _id -= %d;\n }", cdef->propertyList.count()); @@ -1221,18 +1228,22 @@ void Generator::generateStaticMetacall() fprintf(out, "%s(", f.name.constData()); int offset = 1; - int argsCount = f.arguments.count(); - for (int j = 0; j < argsCount; ++j) { - const ArgumentDef &a = f.arguments.at(j); - if (j) - fprintf(out, ","); - fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++); - isUsed_a = true; - } - if (f.isPrivateSignal) { - if (argsCount > 0) - fprintf(out, ", "); - fprintf(out, "%s", "QPrivateSignal()"); + if (f.isRawSlot) { + fprintf(out, "QMethodRawArguments{ _a }"); + } else { + int argsCount = f.arguments.count(); + for (int j = 0; j < argsCount; ++j) { + const ArgumentDef &a = f.arguments.at(j); + if (j) + fprintf(out, ","); + fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++); + isUsed_a = true; + } + if (f.isPrivateSignal) { + if (argsCount > 0) + fprintf(out, ", "); + fprintf(out, "%s", "QPrivateSignal()"); + } } fprintf(out, ");"); if (f.normalizedType != "void") { @@ -1348,6 +1359,7 @@ void Generator::generateStaticMetacall() bool needTempVarForGet = false; bool needSet = false; bool needReset = false; + bool haveQProperties = false; for (int i = 0; i < cdef->propertyList.size(); ++i) { const PropertyDef &p = cdef->propertyList.at(i); needGet |= !p.read.isEmpty() || !p.member.isEmpty(); @@ -1357,13 +1369,15 @@ void Generator::generateStaticMetacall() needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant); needReset |= !p.reset.isEmpty(); + haveQProperties |= p.isQProperty; } fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); if (needElse) fprintf(out, "else "); fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n"); - if (needGet) { + + auto setupMemberAccess = [this]() { if (cdef->hasQObject) { #ifndef QT_NO_DEBUG fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); @@ -1373,6 +1387,10 @@ void Generator::generateStaticMetacall() fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData()); } fprintf(out, " Q_UNUSED(_t)\n"); + }; + + if (needGet) { + setupMemberAccess(); if (needTempVarForGet) fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); @@ -1410,15 +1428,7 @@ void Generator::generateStaticMetacall() fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n"); if (needSet) { - if (cdef->hasQObject) { -#ifndef QT_NO_DEBUG - fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); -#endif - fprintf(out, " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData()); - } else { - fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData()); - } - fprintf(out, " Q_UNUSED(_t)\n"); + setupMemberAccess(); fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { @@ -1466,15 +1476,7 @@ void Generator::generateStaticMetacall() fprintf(out, " else "); fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n"); if (needReset) { - if (cdef->hasQObject) { -#ifndef QT_NO_DEBUG - fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n"); -#endif - fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); - } else { - fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData()); - } - fprintf(out, " Q_UNUSED(_t)\n"); + setupMemberAccess(); fprintf(out, " switch (_id) {\n"); for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); @@ -1491,6 +1493,42 @@ void Generator::generateStaticMetacall() fprintf(out, " }\n"); } fprintf(out, " }"); + + fprintf(out, " else "); + fprintf(out, "if (_c == QMetaObject::RegisterQPropertyObserver) {\n"); + if (haveQProperties) { + setupMemberAccess(); + fprintf(out, " QPropertyObserver *observer = reinterpret_cast<QPropertyObserver *>(_a[0]);\n"); + fprintf(out, " switch (_id) {\n"); + for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + const PropertyDef &p = cdef->propertyList.at(propindex); + if (!p.isQProperty) + continue; + fprintf(out, " case %d: observer->setSource(_t->%s); break;\n", + propindex, p.name.constData()); + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); + } + fprintf(out, " }"); + + fprintf(out, " else "); + fprintf(out, "if (_c == QMetaObject::SetQPropertyBinding) {\n"); + if (haveQProperties) { + setupMemberAccess(); + fprintf(out, " switch (_id) {\n"); + for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + const PropertyDef &p = cdef->propertyList.at(propindex); + if (!p.isQProperty) + continue; + fprintf(out, " case %d: _t->%s.setBinding(*reinterpret_cast<QPropertyBinding<%s> *>(_a[0])); break;\n", + propindex, p.name.constData(), p.type.constData()); + } + fprintf(out, " default: break;\n"); + fprintf(out, " }\n"); + } + fprintf(out, " }"); + fprintf(out, "\n#endif // QT_NO_PROPERTIES"); needElse = true; } diff --git a/src/tools/moc/keywords.cpp b/src/tools/moc/keywords.cpp index 7da8d94efc..cc7d747f5b 100644 --- a/src/tools/moc/keywords.cpp +++ b/src/tools/moc/keywords.cpp @@ -30,12 +30,12 @@ // DO NOT EDIT. static const short keyword_trans[][128] = { - {0,0,0,0,0,0,0,0,0,568,565,0,0,0,0,0, + {0,0,0,0,0,0,0,0,0,579,576,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 568,252,566,569,8,38,239,567,25,26,236,234,30,235,27,237, + 579,252,577,580,8,38,239,578,25,26,236,234,30,235,27,237, 22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43, 0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,21,8,8,8,8,8,8,8,8,8,31,571,32,238,8, + 8,21,8,8,8,8,8,8,8,8,8,31,582,32,238,8, 0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13, 14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -177,7 +177,7 @@ static const short keyword_trans[][128] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0, - 574,574,574,574,574,574,574,574,574,574,0,0,0,0,0,0, + 585,585,585,585,585,585,585,585,585,585,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -336,7 +336,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,573,0,0,0,0,572, + 0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,583, 0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -378,7 +378,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,475,424,408,416,380,0,484,0,0,0,0,364,358, + 0,0,0,475,424,408,416,380,0,484,0,0,0,565,364,358, 386,0,557,472,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -1021,11 +1021,22 @@ static const struct {CHARACTER, 0, 79, 563, CHARACTER}, {CHARACTER, 0, 78, 564, CHARACTER}, {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 79, 566, CHARACTER}, + {CHARACTER, 0, 67, 567, CHARACTER}, + {CHARACTER, 0, 95, 568, CHARACTER}, + {CHARACTER, 0, 73, 569, CHARACTER}, + {CHARACTER, 0, 78, 570, CHARACTER}, + {CHARACTER, 0, 67, 571, CHARACTER}, + {CHARACTER, 0, 76, 572, CHARACTER}, + {CHARACTER, 0, 85, 573, CHARACTER}, + {CHARACTER, 0, 68, 574, CHARACTER}, + {CHARACTER, 0, 69, 575, CHARACTER}, + {Q_MOC_INCLUDE_TOKEN, 0, 0, 0, CHARACTER}, {NEWLINE, 0, 0, 0, NOTOKEN}, {QUOTE, 0, 0, 0, NOTOKEN}, {SINGLEQUOTE, 0, 0, 0, NOTOKEN}, {WHITESPACE, 0, 0, 0, NOTOKEN}, - {HASH, 0, 35, 570, HASH}, + {HASH, 0, 35, 581, HASH}, {PP_HASHHASH, 0, 0, 0, NOTOKEN}, {BACKSLASH, 0, 0, 0, NOTOKEN}, {CPP_COMMENT, 0, 0, 0, NOTOKEN}, diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 9dbc22dc2c..edef9d3f04 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -43,30 +43,9 @@ QT_BEGIN_NAMESPACE // only moc needs this function -static QByteArray normalizeType(const QByteArray &ba, bool fixScope = false) +static QByteArray normalizeType(const QByteArray &ba) { - const char *s = ba.constData(); - int len = ba.size(); - char stackbuf[64]; - char *buf = (len >= 64 ? new char[len + 1] : stackbuf); - char *d = buf; - char last = 0; - while(*s && is_space(*s)) - s++; - while (*s) { - while (*s && !is_space(*s)) - last = *d++ = *s++; - while (*s && is_space(*s)) - s++; - if (*s && ((is_ident_char(*s) && is_ident_char(last)) - || ((*s == ':') && (last == '<')))) { - last = *d++ = ' '; - } - } - *d = '\0'; - QByteArray result = normalizeTypeInternal(buf, d, fixScope); - if (buf != stackbuf) - delete [] buf; + QByteArray result = normalizeTypeInternal(ba.constBegin(), ba.constEnd()); return result; } @@ -328,6 +307,11 @@ void Moc::parseFunctionArguments(FunctionDef *def) def->arguments.removeLast(); def->isPrivateSignal = true; } + if (def->arguments.size() == 1 + && def->arguments.constLast().normalizedType == "QMethodRawArguments") { + def->arguments.removeLast(); + def->isRawSlot = true; + } } bool Moc::testFunctionAttribute(FunctionDef *def) @@ -371,17 +355,42 @@ bool Moc::skipCxxAttributes() return false; } -bool Moc::testFunctionRevision(FunctionDef *def) +QTypeRevision Moc::parseRevision() { - if (test(Q_REVISION_TOKEN)) { - next(LPAREN); - QByteArray revision = lexemUntil(RPAREN); - revision.remove(0, 1); - revision.chop(1); + next(LPAREN); + QByteArray revisionString = lexemUntil(RPAREN); + revisionString.remove(0, 1); + revisionString.chop(1); + const QList<QByteArray> majorMinor = revisionString.split(','); + switch (majorMinor.length()) { + case 1: { bool ok = false; - def->revision = revision.toInt(&ok); - if (!ok || def->revision < 0) + const int revision = revisionString.toInt(&ok); + if (!ok || !QTypeRevision::isValidSegment(revision)) error("Invalid revision"); + return QTypeRevision::fromMinorVersion(revision); + } + case 2: { // major.minor + bool ok = false; + const int major = majorMinor[0].toInt(&ok); + if (!ok || !QTypeRevision::isValidSegment(major)) + error("Invalid major version"); + const int minor = majorMinor[1].toInt(&ok); + if (!ok || !QTypeRevision::isValidSegment(minor)) + error("Invalid minor version"); + return QTypeRevision::fromVersion(major, minor); + } + default: + error("Invalid revision"); + return QTypeRevision(); + } +} + +bool Moc::testFunctionRevision(FunctionDef *def) +{ + + if (test(Q_REVISION_TOKEN)) { + def->revision = parseRevision().toEncodedVersion<int>(); return true; } @@ -555,6 +564,32 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) return true; } + +// Try to parse QProperty<MyType> propertName; members +bool Moc::parseMaybeQProperty(ClassDef *def) +{ + if (!test(IDENTIFIER)) + return false; + + if (lexem() != "QProperty") + return false; + + if (!test(LANGLE)) + return false; + + until(RANGLE); + + next(); + const auto propName = lexem(); + + if (!test(SEMIC)) + return false; + + def->qPropertyMembers.insert(propName); + + return true; +} + void Moc::parse() { QVector<NamespaceDef> namespaceList; @@ -648,6 +683,11 @@ void Moc::parse() case Q_CLASSINFO_TOKEN: parseClassInfo(&def); break; + case Q_MOC_INCLUDE_TOKEN: + // skip it, the namespace is parsed twice + next(LPAREN); + lexemUntil(RPAREN); + break; case ENUM: { EnumDef enumDef; if (parseEnum(&enumDef)) @@ -691,6 +731,9 @@ void Moc::parse() case Q_DECLARE_METATYPE_TOKEN: parseDeclareMetatype(); break; + case Q_MOC_INCLUDE_TOKEN: + parseMocInclude(); + break; case USING: if (test(NAMESPACE)) { while (test(SCOPE) || test(IDENTIFIER)) @@ -823,6 +866,9 @@ void Moc::parse() case Q_CLASSINFO_TOKEN: parseClassInfo(&def); break; + case Q_MOC_INCLUDE_TOKEN: + parseMocInclude(); + break; case Q_INTERFACES_TOKEN: parseInterfaces(&def); break; @@ -889,7 +935,9 @@ void Moc::parse() } } } else { - index = rewind; + index = rewind - 1; + if (!parseMaybeQProperty(&def)) + index = rewind; } } } @@ -1084,17 +1132,9 @@ void Moc::generate(FILE *out, FILE *jsonOutput) void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) { - int defaultRevision = -1; - if (test(Q_REVISION_TOKEN)) { - next(LPAREN); - QByteArray revision = lexemUntil(RPAREN); - revision.remove(0, 1); - revision.chop(1); - bool ok = false; - defaultRevision = revision.toInt(&ok); - if (!ok || defaultRevision < 0) - error("Invalid revision"); - } + QTypeRevision defaultRevision; + if (test(Q_REVISION_TOKEN)) + defaultRevision = parseRevision(); next(COLON); while (inClass(def) && hasNext()) { @@ -1123,8 +1163,8 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) continue; if (funcDef.revision > 0) { ++def->revisionedMethods; - } else if (defaultRevision != -1) { - funcDef.revision = defaultRevision; + } else if (defaultRevision.isValid()) { + funcDef.revision = defaultRevision.toEncodedVersion<int>(); ++def->revisionedMethods; } def->slotList += funcDef; @@ -1138,17 +1178,9 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) void Moc::parseSignals(ClassDef *def) { - int defaultRevision = -1; - if (test(Q_REVISION_TOKEN)) { - next(LPAREN); - QByteArray revision = lexemUntil(RPAREN); - revision.remove(0, 1); - revision.chop(1); - bool ok = false; - defaultRevision = revision.toInt(&ok); - if (!ok || defaultRevision < 0) - error("Invalid revision"); - } + QTypeRevision defaultRevision; + if (test(Q_REVISION_TOKEN)) + defaultRevision = parseRevision(); next(COLON); while (inClass(def) && hasNext()) { @@ -1179,8 +1211,8 @@ void Moc::parseSignals(ClassDef *def) error("Not a signal declaration"); if (funcDef.revision > 0) { ++def->revisionedMethods; - } else if (defaultRevision != -1) { - funcDef.revision = defaultRevision; + } else if (defaultRevision.isValid()) { + funcDef.revision = defaultRevision.toEncodedVersion<int>(); ++def->revisionedMethods; } def->signalList += funcDef; @@ -1194,11 +1226,14 @@ void Moc::parseSignals(ClassDef *def) void Moc::createPropertyDef(PropertyDef &propDef) { + propDef.location = index; + QByteArray type = parseType().name; if (type.isEmpty()) error(); propDef.designable = propDef.scriptable = propDef.stored = "true"; propDef.user = "false"; + /* The Q_PROPERTY construct cannot contain any commas, since commas separate macro arguments. We therefore expect users @@ -1230,6 +1265,7 @@ void Moc::createPropertyDef(PropertyDef &propDef) next(); propDef.name = lexem(); + while (test(IDENTIFIER)) { const QByteArray l = lexem(); if (l[0] == 'C' && l == "CONSTANT") { @@ -1241,6 +1277,10 @@ void Moc::createPropertyDef(PropertyDef &propDef) } else if (l[0] == 'R' && l == "REQUIRED") { propDef.required = true; continue; + } else if (l[0] == 'R' && l == "REVISION" && test(LPAREN)) { + prev(); + propDef.revision = parseRevision().toEncodedVersion<int>(); + continue; } QByteArray v, v2; @@ -1273,9 +1313,10 @@ void Moc::createPropertyDef(PropertyDef &propDef) propDef.reset = v + v2; else if (l == "REVISION") { bool ok = false; - propDef.revision = v.toInt(&ok); - if (!ok || propDef.revision < 0) + const int minor = v.toInt(&ok); + if (!ok || !QTypeRevision::isValidSegment(minor)) error(1); + propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>(); } else error(2); break; @@ -1314,11 +1355,6 @@ void Moc::createPropertyDef(PropertyDef &propDef) error(2); } } - if (propDef.read.isNull() && propDef.member.isNull()) { - const QByteArray msg = "Property declaration " + propDef.name - + " has no READ accessor function or associated MEMBER variable. The property will be invalid."; - warning(msg.constData()); - } if (propDef.constant && !propDef.write.isNull()) { const QByteArray msg = "Property declaration " + propDef.name + " is both WRITEable and CONSTANT. CONSTANT will be ignored."; @@ -1486,6 +1522,8 @@ void Moc::parseClassInfo(BaseDef *def) next(COMMA); if (test(STRING_LITERAL)) { infoDef.value = symbol().unquotedLexem(); + } else if (test(Q_REVISION_TOKEN)) { + infoDef.value = QByteArray::number(parseRevision().toEncodedVersion<quint16>()); } else { // support Q_CLASSINFO("help", QT_TR_NOOP("blah")) next(IDENTIFIER); @@ -1563,6 +1601,16 @@ void Moc::parseDeclareMetatype() metaTypes.append(typeName); } +void Moc::parseMocInclude() +{ + next(LPAREN); + QByteArray include = lexemUntil(RPAREN); + // remove parentheses + include.remove(0, 1); + include.chop(1); + includeFiles.append(include); +} + void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access) { next(LPAREN); @@ -1751,14 +1799,34 @@ void Moc::checkProperties(ClassDef *cdef) QSet<QByteArray> definedProperties; for (int i = 0; i < cdef->propertyList.count(); ++i) { PropertyDef &p = cdef->propertyList[i]; - if (p.read.isEmpty() && p.member.isEmpty()) - continue; if (definedProperties.contains(p.name)) { QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + "."; warning(msg.constData()); } definedProperties.insert(p.name); + if (p.read.isEmpty() && p.member.isEmpty()) { + if (!cdef->qPropertyMembers.contains(p.name)) { + const int rewind = index; + if (p.location >= 0) + index = p.location; + QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member" + ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid."; + warning(msg.constData()); + index = rewind; + if (p.write.isEmpty()) { + cdef->propertyList.removeAt(i); + --i; + } + continue; + } + p.read = p.name + ".value"; + p.write = p.name + ".setValue"; + p.isQProperty = true; + p.designable = p.scriptable = p.stored = "true"; + p.user = "false"; + } + for (int j = 0; j < cdef->publicList.count(); ++j) { const FunctionDef &f = cdef->publicList.at(j); if (f.name != p.read) @@ -1971,6 +2039,7 @@ QJsonObject PropertyDef::toJson() const prop[QLatin1String("constant")] = constant; prop[QLatin1String("final")] = final; prop[QLatin1String("required")] = required; + prop[QLatin1String("isQProperty")] = isQProperty; if (revision > 0) prop[QLatin1String("revision")] = revision; diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index a3e20a061e..210b6c7c2a 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -36,6 +36,7 @@ #include <qjsondocument.h> #include <qjsonarray.h> #include <qjsonobject.h> +#include <qversionnumber.h> #include <stdio.h> #include <ctype.h> @@ -115,6 +116,7 @@ struct FunctionDef bool isConstructor = false; bool isDestructor = false; bool isAbstract = false; + bool isRawSlot = false; QJsonObject toJson() const; static void accessToJson(QJsonObject *obj, Access acs); @@ -138,6 +140,9 @@ struct PropertyDef bool constant = false; bool final = false; bool required = false; + bool isQProperty = false; + + int location = -1; // token index, used for error reporting QJsonObject toJson() const; }; @@ -186,6 +191,7 @@ struct ClassDef : BaseDef { QVector<FunctionDef> signalList, slotList, methodList, publicList; QVector<QByteArray> nonClassSignalList; QVector<PropertyDef> propertyList; + QSet<QByteArray> qPropertyMembers; int notifyableProperties = 0; int revisionedMethods = 0; int revisionedProperties = 0; @@ -245,6 +251,7 @@ public: bool parseFunction(FunctionDef *def, bool inMacro = false); bool parseMaybeFunction(const ClassDef *cdef, FunctionDef *def); + bool parseMaybeQProperty(ClassDef *def); void parseSlots(ClassDef *def, FunctionDef::Access access); void parseSignals(ClassDef *def); @@ -257,6 +264,7 @@ public: void parseInterfaces(ClassDef *def); void parseDeclareInterface(); void parseDeclareMetatype(); + void parseMocInclude(); void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access); void parsePrivateProperty(ClassDef *def); @@ -270,6 +278,7 @@ public: bool testFunctionAttribute(FunctionDef *def); bool testFunctionAttribute(Token tok, FunctionDef *def); bool testFunctionRevision(FunctionDef *def); + QTypeRevision parseRevision(); bool skipCxxAttributes(); diff --git a/src/tools/moc/token.h b/src/tools/moc/token.h index 0cc163f9e4..c11ec6a38c 100644 --- a/src/tools/moc/token.h +++ b/src/tools/moc/token.h @@ -179,6 +179,7 @@ QT_BEGIN_NAMESPACE F(Q_SCRIPTABLE_TOKEN) \ F(Q_PRIVATE_PROPERTY_TOKEN) \ F(Q_REVISION_TOKEN) \ + F(Q_MOC_INCLUDE_TOKEN) \ F(SPECIAL_TREATMENT_MARK) \ F(MOC_INCLUDE_BEGIN) \ F(MOC_INCLUDE_END) \ diff --git a/src/tools/moc/util/generate_keywords.cpp b/src/tools/moc/util/generate_keywords.cpp index 9248e9e2e7..c2cfe37fab 100644 --- a/src/tools/moc/util/generate_keywords.cpp +++ b/src/tools/moc/util/generate_keywords.cpp @@ -243,6 +243,7 @@ static const Keyword keywords[] = { { "Q_SCRIPTABLE", "Q_SCRIPTABLE_TOKEN" }, { "Q_PRIVATE_PROPERTY", "Q_PRIVATE_PROPERTY_TOKEN" }, { "Q_REVISION", "Q_REVISION_TOKEN" }, + { "Q_MOC_INCLUDE", "Q_MOC_INCLUDE_TOKEN" }, { "\n", "NEWLINE" }, { "\"", "QUOTE" }, { "\'", "SINGLEQUOTE" }, |