summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/moc/generator.cpp35
-rw-r--r--src/tools/moc/generator.h10
-rw-r--r--src/tools/moc/moc.cpp89
-rw-r--r--src/tools/moc/moc.h2
4 files changed, 105 insertions, 31 deletions
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index fbd6d3154e2..94c75ae6eb3 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -78,16 +78,18 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
return nullptr;
}
- Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator::Generator(Moc *moc, const ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile,
- bool requireCompleteTypes)
+ const QHash<QByteArray, QByteArray> &knownGadgets,
+ const QHash<QByteArray, QByteArray> &hashes,
+ FILE *outfile, bool requireCompleteTypes)
: parser(moc),
out(outfile),
cdef(classDef),
metaTypes(metaTypes),
knownQObjectClasses(knownQObjectClasses),
knownGadgets(knownGadgets),
+ hashes(hashes),
requireCompleteTypes(requireCompleteTypes)
{
if (cdef->superclassList.size())
@@ -228,28 +230,11 @@ void Generator::generateCode()
bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty();
- // filter out undeclared enumerators and sets
- {
- QList<EnumDef> enumList;
- for (EnumDef def : std::as_const(cdef->enumList)) {
- if (cdef->enumDeclarations.contains(def.name)) {
- enumList += def;
- }
- def.enumName = def.name;
- QByteArray alias = cdef->flagAliases.value(def.name);
- if (cdef->enumDeclarations.contains(alias)) {
- def.name = alias;
- def.flags |= cdef->enumDeclarations[alias];
- enumList += def;
- }
- }
- cdef->enumList = enumList;
- }
-
//
// Register all strings used in data section
//
strreg(cdef->qualified);
+ strreg(hashes[cdef->qualified]);
registerClassInfoStrings();
registerFunctionStrings(cdef->signalList);
registerFunctionStrings(cdef->slotList);
@@ -308,6 +293,8 @@ void Generator::generateCode()
addEnums();
fprintf(out, " };\n");
+ fprintf(out, " uint qt_metaObjectHashIndex = %d;\n", stridx(hashes[cdef->qualified]));
+
const char *uintDataParams = "";
if (isConstructible || !cdef->classInfoList.isEmpty()) {
if (isConstructible) {
@@ -340,7 +327,7 @@ void Generator::generateCode()
if (!requireCompleteness)
tagType = "qt_meta_tag_" + qualifiedClassNameIdentifier + "_t";
fprintf(out, " return QtMocHelpers::metaObjectData<%s, %s>(%s, qt_stringData,\n"
- " qt_methods, qt_properties, qt_enums%s);\n"
+ " qt_methods, qt_properties, qt_enums, qt_metaObjectHashIndex%s);\n"
"}\n",
ownType, tagType.constData(), metaObjectFlags, uintDataParams);
}
@@ -770,6 +757,10 @@ void Generator::addProperties()
addFlag("Constant");
if (p.final)
addFlag("Final");
+ if (p.virtual_)
+ addFlag("Virtual");
+ if (p.override)
+ addFlag("Override");
if (p.user != "false")
addFlag("User");
if (p.required)
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index 45df0783c2b..77be2fc6714 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -12,14 +12,15 @@ class Generator
{
Moc *parser = nullptr;
FILE *out;
- ClassDef *cdef;
+ const ClassDef *cdef;
QList<uint> meta_data;
public:
- Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator(Moc *moc, const ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr,
- bool requireCompleteTypes = false);
+ const QHash<QByteArray, QByteArray> &knownGadgets,
+ const QHash<QByteArray, QByteArray> &hashes,
+ FILE *outfile = nullptr, bool requireCompleteTypes = false);
void generateCode();
qsizetype registeredStringsCount() { return strings.size(); }
@@ -54,6 +55,7 @@ private:
QList<QByteArray> metaTypes;
QHash<QByteArray, QByteArray> knownQObjectClasses;
QHash<QByteArray, QByteArray> knownGadgets;
+ QHash<QByteArray, QByteArray> hashes;
bool requireCompleteTypes;
};
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 64af8c10fc1..7f05f34edb6 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -17,6 +17,10 @@
#include <private/qmetaobject_moc_p.h>
#include <private/qduplicatetracker_p.h>
+// This is a bootstrapped tool, so we can't rely on QCryptographicHash for the
+// faster SHA1 implementations from OpenSSL.
+#include "../../3rdparty/sha1/sha1.cpp"
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -1191,6 +1195,24 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
return required;
}
+QByteArray classDefJsonObjectHash(const QJsonObject &object)
+{
+ const QByteArray json = QJsonDocument(object).toJson(QJsonValue::JsonFormat::Compact);
+ QByteArray hash(20, 0); // SHA1 produces 160 bits of data
+
+ {
+ Sha1State state;
+ sha1InitState(&state);
+ sha1Update(&state, reinterpret_cast<const uchar *>(json.constData()), json.size());
+ sha1FinalizeState(&state);
+ sha1ToHash(&state, reinterpret_cast<uchar *>(hash.data()));
+ }
+
+ static const char revisionPrefix[] = "0$";
+ const QByteArray hashB64 = hash.toBase64(QByteArray::OmitTrailingEquals);
+ return revisionPrefix + hashB64;
+}
+
void Moc::generate(FILE *out, FILE *jsonOutput)
{
QByteArrayView fn = strippedFileName();
@@ -1247,14 +1269,40 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
"#endif\n\n");
#endif
+ // filter out undeclared enumerators and sets
+ for (ClassDef &cdef : classList) {
+ QList<EnumDef> enumList;
+ for (EnumDef def : std::as_const(cdef.enumList)) {
+ if (cdef.enumDeclarations.contains(def.name)) {
+ enumList += def;
+ }
+ def.enumName = def.name;
+ QByteArray alias = cdef.flagAliases.value(def.name);
+ if (cdef.enumDeclarations.contains(alias)) {
+ def.name = alias;
+ def.flags |= cdef.enumDeclarations[alias];
+ enumList += def;
+ }
+ }
+ cdef.enumList = enumList;
+ }
+
fprintf(out, "QT_WARNING_PUSH\n");
fprintf(out, "QT_WARNING_DISABLE_DEPRECATED\n");
fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
+ QHash<QByteArray, QJsonObject> classDefJsonObjects;
+ QHash<QByteArray, QByteArray> metaObjectHashes;
+ for (const ClassDef &def : std::as_const(classList)) {
+ const QJsonObject jsonObject = def.toJson();
+ classDefJsonObjects.insert(def.qualified, jsonObject);
+ metaObjectHashes.insert(def.qualified, classDefJsonObjectHash(jsonObject));
+ }
+
fputs("", out);
- for (ClassDef &def : classList) {
- Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
- requireCompleteTypes);
+ for (const ClassDef &def : std::as_const(classList)) {
+ Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets,
+ metaObjectHashes, out, requireCompleteTypes);
generator.generateCode();
// generator.generateCode() should have already registered all strings
@@ -1273,13 +1321,20 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
mocData["inputFile"_L1] = QLatin1StringView(fn.constData());
QJsonArray classesJsonFormatted;
+ QJsonObject hashesJsonObject;
- for (const ClassDef &cdef: std::as_const(classList))
- classesJsonFormatted.append(cdef.toJson());
+ for (const ClassDef &cdef : std::as_const(classList)) {
+ classesJsonFormatted.append(classDefJsonObjects[cdef.qualified]);
+ hashesJsonObject.insert(QString::fromLatin1(cdef.qualified),
+ QString::fromLatin1(metaObjectHashes[cdef.qualified]));
+ }
if (!classesJsonFormatted.isEmpty())
mocData["classes"_L1] = classesJsonFormatted;
+ if (!hashesJsonObject.isEmpty())
+ mocData["hashes"_L1] = hashesJsonObject;
+
QJsonDocument jsonDoc(mocData);
fputs(jsonDoc.toJson().constData(), jsonOutput);
}
@@ -1434,6 +1489,9 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
next(IDENTIFIER);
propDef.name = lexem();
continue;
+ } else if (l[0] == 'O' && l == "OVERRIDE") {
+ propDef.override = true;
+ continue;
} else if (l[0] == 'R' && l == "REQUIRED") {
propDef.required = true;
continue;
@@ -1441,6 +1499,9 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
prev();
propDef.revision = parseRevision().toEncodedVersion<int>();
continue;
+ } else if (l[0] == 'V' && l == "VIRTUAL") {
+ propDef.virtual_ = true;
+ continue;
}
QByteArray v, v2;
@@ -1545,6 +1606,24 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
propDef.write = "";
warning(msg.constData());
}
+ if (propDef.override && propDef.virtual_) {
+ const QByteArray msg = "Issue with property declaration " + propDef.name
+ + ": VIRTUAL is redundant when overriding a property. The OVERRIDE "
+ "must only be used when actually overriding an existing property; using it on a "
+ "new property is an error.";
+ error(msg.constData());
+ }
+ if (propDef.override && propDef.final) {
+ const QByteArray msg = "Issue with property declaration " + propDef.name
+ + ": OVERRIDE is redundant when property is marked FINAL";
+ error(msg.constData());
+ }
+ if (propDef.virtual_ && propDef.final) {
+ const QByteArray msg = "Issue with property declaration " + propDef.name
+ + ": The VIRTUAL cannot be combined with FINAL, as these attributes are mutually "
+ "exclusive";
+ error(msg.constData());
+ }
}
void Moc::parseProperty(ClassDef *def, Moc::PropertyMode mode)
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index aafa80d2164..a211433622a 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -130,6 +130,8 @@ struct PropertyDef
TypeTags typeTag;
bool constant = false;
bool final = false;
+ bool virtual_ = false;
+ bool override = false;
bool required = false;
int relativeIndex = -1; // property index in current metaobject
int lineNumber = 0;