blob: 8673a0e841bf1a08b043789f5f6d1f5719bde798 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtRemoteObjects module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "repcodegenerator.h"
#include "repparser.h"
#include <QFileInfo>
#include <QMetaType>
#include <QTextStream>
#include <QCryptographicHash>
#include <QRegExp>
QT_BEGIN_NAMESPACE
template <typename C>
static int accumulatedSizeOfNames(const C &c)
{
int result = 0;
for (const auto &e : c)
result += e.name.size();
return result;
}
template <typename C>
static int accumulatedSizeOfTypes(const C &c)
{
int result = 0;
for (const auto &e : c)
result += e.type.size();
return result;
}
static QString cap(QString name)
{
if (!name.isEmpty())
name[0] = name[0].toUpper();
return name;
}
static bool isClassEnum(const ASTClass &classContext, const QString &typeName)
{
for (const ASTEnum &astEnum : classContext.enums) {
if (astEnum.name == typeName) {
return true;
}
}
return false;
}
static QString fullyQualifiedTypeName(const ASTClass& classContext, const QString &className, const QString &typeName)
{
if (isClassEnum(classContext, typeName)) {
// type was defined in this class' context, prefix typeName with class name
return className + QStringLiteral("::") + typeName;
}
return typeName;
}
// for enums we need to transform signal/slot arguments to include the class scope
static QVector<ASTFunction> transformEnumParams(const ASTClass& classContext, const QVector<ASTFunction> &methodList, const QString &typeName) {
QVector<ASTFunction> localList = methodList;
for (ASTFunction &astFunction : localList) {
for (ASTDeclaration &astParam : astFunction.params) {
for (const ASTEnum &astEnum : classContext.enums) {
if (astEnum.name == astParam.type) {
astParam.type = typeName + QStringLiteral("::") + astParam.type;
}
}
}
}
return localList;
}
/*
Returns \c true if the type is a built-in type.
*/
static bool isBuiltinType(const QString &type)
{
int id = QMetaType::type(type.toLatin1().constData());
if (id == QMetaType::UnknownType)
return false;
return (id < QMetaType::User);
}
RepCodeGenerator::RepCodeGenerator(QIODevice *outputDevice)
: m_outputDevice(outputDevice)
{
Q_ASSERT(m_outputDevice);
}
static QByteArray enumSignature(const ASTEnum &e)
{
QByteArray ret;
ret += e.name.toLatin1();
for (const ASTEnumParam &param : e.params)
ret += param.name.toLatin1() + QByteArray::number(param.value);
return ret;
}
static QByteArray typeData(const QString &type, const QHash<QString, QByteArray> &specialTypes)
{
QHash<QString, QByteArray>::const_iterator it = specialTypes.find(type);
if (it != specialTypes.end())
return it.value();
int pos = type.lastIndexOf(QLatin1String("::"));
if (pos > 0)
return typeData(type.mid(pos + 2), specialTypes);
return type.toLatin1();
}
static QByteArray functionsData(const QVector<ASTFunction> &functions, const QHash<QString, QByteArray> &specialTypes)
{
QByteArray ret;
for (const ASTFunction &func : functions) {
ret += func.name.toLatin1();
for (const ASTDeclaration &param : func.params) {
ret += param.name.toLatin1();
ret += typeData(param.type, specialTypes);
ret += QByteArray(reinterpret_cast<const char *>(&param.variableType), sizeof(param.variableType));
}
ret += typeData(func.returnType, specialTypes);
}
return ret;
}
QByteArray RepCodeGenerator::classSignature(const ASTClass &ac)
{
QCryptographicHash checksum(QCryptographicHash::Sha1);
QHash<QString, QByteArray> localTypes = m_globalEnumsPODs;
for (const ASTEnum &e : ac.enums) // add local enums
localTypes[e.name] = enumSignature(e);
checksum.addData(ac.name.toLatin1());
// Checksum properties
for (const ASTProperty &p : ac.properties) {
checksum.addData(p.name.toLatin1());
checksum.addData(typeData(p.type, localTypes));
checksum.addData(reinterpret_cast<const char *>(&p.modifier), sizeof(p.modifier));
}
// Checksum signals
checksum.addData(functionsData(ac.signalsList, localTypes));
// Checksum slots
checksum.addData(functionsData(ac.slotsList, localTypes));
return checksum.result().toHex();
}
void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
{
QTextStream stream(m_outputDevice);
if (fileName.isEmpty())
stream << "#pragma once" << endl << endl;
else {
fileName = QFileInfo(fileName).fileName();
fileName = fileName.toUpper();
fileName.replace(QLatin1Char('.'), QLatin1Char('_'));
stream << "#ifndef " << fileName << endl;
stream << "#define " << fileName << endl << endl;
}
generateHeader(mode, stream, ast);
for (const ASTEnum &en : ast.enums)
generateENUM(stream, en);
for (const POD &pod : ast.pods)
generatePOD(stream, pod);
QSet<QString> metaTypes;
for (const POD &pod : ast.pods) {
metaTypes << pod.name;
for (const PODAttribute &attribute : pod.attributes)
metaTypes << attribute.type;
}
const QString metaTypeRegistrationCode = generateMetaTypeRegistration(metaTypes)
+ generateMetaTypeRegistrationForEnums(ast.enumUses);
for (const ASTClass &astClass : ast.classes) {
QSet<QString> classMetaTypes;
QSet<QString> pendingMetaTypes;
for (const ASTProperty &property : astClass.properties) {
if (property.isPointer)
continue;
classMetaTypes << property.type;
}
const auto extractClassMetaTypes = [&](const ASTFunction &function) {
classMetaTypes << function.returnType;
pendingMetaTypes << function.returnType;
for (const ASTDeclaration &decl : function.params) {
classMetaTypes << decl.type;
}
};
for (const ASTFunction &function : astClass.signalsList)
extractClassMetaTypes(function);
for (const ASTFunction &function : astClass.slotsList)
extractClassMetaTypes(function);
const QString classMetaTypeRegistrationCode = metaTypeRegistrationCode
+ generateMetaTypeRegistration(classMetaTypes);
const QString replicaMetaTypeRegistrationCode = classMetaTypeRegistrationCode
+ generateMetaTypeRegistrationForPending(pendingMetaTypes);
if (mode == MERGED) {
generateClass(REPLICA, stream, astClass, replicaMetaTypeRegistrationCode);
generateClass(SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateClass(SIMPLE_SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateSourceAPI(stream, astClass);
} else {
generateClass(mode, stream, astClass, mode == REPLICA ? replicaMetaTypeRegistrationCode : classMetaTypeRegistrationCode);
if (mode == SOURCE) {
generateClass(SIMPLE_SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateSourceAPI(stream, astClass);
}
}
}
generateStreamOperatorsForEnums(stream, ast.enumUses);
stream << endl;
if (!fileName.isEmpty())
stream << "#endif // " << fileName << endl;
}
void RepCodeGenerator::generateHeader(Mode mode, QTextStream &out, const AST &ast)
{
out << "// This is an autogenerated file.\n"
"// Do not edit this file, any changes made will be lost the next time it is generated.\n"
"\n"
"#include <QtCore/qobject.h>\n"
"#include <QtCore/qdatastream.h>\n"
"#include <QtCore/qvariant.h>\n"
"#include <QtCore/qmetatype.h>\n";
bool hasModel = false;
for (auto c : ast.classes)
{
if (c.modelMetadata.count() > 0)
{
hasModel = true;
break;
}
}
if (hasModel)
out << "#include <QtCore/qabstractitemmodel.h>\n";
out << "\n"
"#include <QtRemoteObjects/qremoteobjectnode.h>\n";
if (mode == MERGED) {
out << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
out << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
out << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
if (hasModel)
out << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
} else if (mode == REPLICA) {
out << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
out << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
if (hasModel)
out << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
} else
out << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
out << "\n";
out << ast.preprocessorDirectives.join(QLatin1Char('\n'));
out << "\n";
}
static QString formatTemplateStringArgTypeNameCapitalizedName(int numberOfTypeOccurrences, int numberOfNameOccurrences,
QString templateString, const POD &pod)
{
QString out;
const int LengthOfPlaceholderText = 2;
Q_ASSERT(templateString.count(QRegExp(QStringLiteral("%\\d"))) == numberOfNameOccurrences + numberOfTypeOccurrences);
const int expectedOutSize
= numberOfNameOccurrences * accumulatedSizeOfNames(pod.attributes)
+ numberOfTypeOccurrences * accumulatedSizeOfTypes(pod.attributes)
+ pod.attributes.size() * (templateString.size() - (numberOfNameOccurrences + numberOfTypeOccurrences) * LengthOfPlaceholderText);
out.reserve(expectedOutSize);
for (const PODAttribute &a : pod.attributes)
out += templateString.arg(a.type, a.name, cap(a.name));
return out;
}
QString RepCodeGenerator::formatQPropertyDeclarations(const POD &pod)
{
return formatTemplateStringArgTypeNameCapitalizedName(1, 3, QStringLiteral(" Q_PROPERTY(%1 %2 READ %2 WRITE set%3)\n"), pod);
}
QString RepCodeGenerator::formatConstructors(const POD &pod)
{
QString initializerString = QStringLiteral(": ");
QString defaultInitializerString = initializerString;
QString argString;
for (const PODAttribute &a : pod.attributes) {
initializerString += QString::fromLatin1("m_%1(%1), ").arg(a.name);
defaultInitializerString += QString::fromLatin1("m_%1(), ").arg(a.name);
argString += QString::fromLatin1("%1 %2, ").arg(a.type, a.name);
}
argString.chop(2);
initializerString.chop(2);
defaultInitializerString.chop(2);
return QString::fromLatin1(" %1() %2 {}\n"
" explicit %1(%3) %4 {}\n")
.arg(pod.name, defaultInitializerString, argString, initializerString);
}
QString RepCodeGenerator::formatPropertyGettersAndSetters(const POD &pod)
{
// MSVC doesn't like adjacent string literal concatenation within QStringLiteral, so keep it in one line:
QString templateString
= QStringLiteral(" %1 %2() const { return m_%2; }\n void set%3(%1 %2) { if (%2 != m_%2) { m_%2 = %2; } }\n");
return formatTemplateStringArgTypeNameCapitalizedName(2, 8, qMove(templateString), pod);
}
QString RepCodeGenerator::formatDataMembers(const POD &pod)
{
QString out;
const QString prefix = QStringLiteral(" ");
const QString infix = QStringLiteral(" m_");
const QString suffix = QStringLiteral(";\n");
const int expectedOutSize
= accumulatedSizeOfNames(pod.attributes)
+ accumulatedSizeOfTypes(pod.attributes)
+ pod.attributes.size() * (prefix.size() + infix.size() + suffix.size());
out.reserve(expectedOutSize);
for (const PODAttribute &a : pod.attributes) {
out += prefix;
out += a.type;
out += infix;
out += a.name;
out += suffix;
}
Q_ASSERT(out.size() == expectedOutSize);
return out;
}
QString RepCodeGenerator::formatMarshallingOperators(const POD &pod)
{
return QLatin1String("inline QDataStream &operator<<(QDataStream &ds, const ") + pod.name + QLatin1String(" &obj) {\n"
" QtRemoteObjects::copyStoredProperties(&obj, ds);\n"
" return ds;\n"
"}\n"
"\n"
"inline QDataStream &operator>>(QDataStream &ds, ") + pod.name + QLatin1String(" &obj) {\n"
" QtRemoteObjects::copyStoredProperties(ds, &obj);\n"
" return ds;\n"
"}\n")
;
}
QString RepCodeGenerator::typeForMode(const ASTProperty &property, RepCodeGenerator::Mode mode)
{
if (!property.isPointer)
return property.type;
if (property.type.startsWith(QStringLiteral("QAbstractItemModel")))
return mode == REPLICA ? property.type + QStringLiteral("Replica*") : property.type + QStringLiteral("*");
switch (mode) {
case REPLICA: return property.type + QStringLiteral("Replica*");
case SIMPLE_SOURCE:
Q_FALLTHROUGH();
case SOURCE: return property.type + QStringLiteral("Source*");
default: qCritical("Invalid mode");
}
return QStringLiteral("InvalidPropertyName");
}
void RepCodeGenerator::generateSimpleSetter(QTextStream &out, const ASTProperty &property, bool generateOverride)
{
if (!generateOverride)
out << " virtual ";
else
out << " ";
out << "void set" << cap(property.name) << "(" << typeForMode(property, SIMPLE_SOURCE) << " " << property.name << ")";
if (generateOverride)
out << " override";
out << endl;
out << " {" << endl;
out << " if (" << property.name << " != m_" << property.name << ") {" << endl;
out << " m_" << property.name << " = " << property.name << ";" << endl;
out << " Q_EMIT " << property.name << "Changed(m_" << property.name << ");" << endl;
out << " }" << endl;
out << " }" << endl;
}
void RepCodeGenerator::generatePOD(QTextStream &out, const POD &pod)
{
QByteArray podData = pod.name.toLatin1();
QStringList equalityCheck;
for (const PODAttribute &attr : pod.attributes) {
equalityCheck << QStringLiteral("left.%1() == right.%1()").arg(attr.name);
podData += attr.name.toLatin1() + typeData(attr.type, m_globalEnumsPODs);
}
m_globalEnumsPODs[pod.name] = podData;
out << "class " << pod.name << "\n"
"{\n"
" Q_GADGET\n"
<< "\n"
<< formatQPropertyDeclarations(pod)
<< "public:\n"
<< formatConstructors(pod)
<< formatPropertyGettersAndSetters(pod)
<< "private:\n"
<< formatDataMembers(pod)
<< "};\n"
<< "\n"
<< "inline bool operator==(const " << pod.name << " &left, const " << pod.name << " &right) Q_DECL_NOTHROW {\n"
<< " return " << equalityCheck.join(QStringLiteral(" && ")) << ";\n"
<< "}\n"
<< "inline bool operator!=(const " << pod.name << " &left, const " << pod.name << " &right) Q_DECL_NOTHROW {\n"
<< " return !(left == right);\n"
<< "}\n"
<< "\n"
<< formatMarshallingOperators(pod)
<< "\n"
"\n"
;
}
QString getEnumType(const ASTEnum &en)
{
if (en.isSigned) {
if (en.max < 0x7F)
return QStringLiteral("qint8");
if (en.max < 0x7FFF)
return QStringLiteral("qint16");
return QStringLiteral("qint32");
} else {
if (en.max < 0xFF)
return QStringLiteral("quint8");
if (en.max < 0xFFFF)
return QStringLiteral("quint16");
return QStringLiteral("quint32");
}
}
void RepCodeGenerator::generateDeclarationsForEnums(QTextStream &out, const QVector<ASTEnum> &enums, bool generateQENUM)
{
if (!generateQENUM) {
out << " // You need to add this enum as well as Q_ENUM to your" << endl;
out << " // QObject class in order to use .rep enums over QtRO for" << endl;
out << " // non-repc generated QObjects." << endl;
}
for (const ASTEnum &en : enums) {
m_globalEnumsPODs[en.name] = enumSignature(en);
out << " enum " << en.name << " {" << endl;
for (const ASTEnumParam &p : en.params)
out << " " << p.name << " = " << p.value << "," << endl;
out << " };" << endl;
if (generateQENUM)
out << " Q_ENUM(" << en.name << ")" << endl;
}
}
void RepCodeGenerator::generateENUMs(QTextStream &out, const QVector<ASTEnum> &enums, const QString &className)
{
out << "class " << className << "\n"
"{\n"
" Q_GADGET\n"
" " << className << "();\n"
"\n"
"public:\n";
generateDeclarationsForEnums(out, enums);
generateConversionFunctionsForEnums(out, enums);
out << "};\n\n";
generateStreamOperatorsForEnums(out, enums, className);
}
void RepCodeGenerator::generateConversionFunctionsForEnums(QTextStream &out, const QVector<ASTEnum> &enums)
{
for (const ASTEnum &en : enums)
{
const QString type = getEnumType(en);
out << " static inline " << en.name << " to" << en.name << "(" << type << " i, bool *ok = nullptr)\n"
" {\n"
" if (ok)\n"
" *ok = true;\n"
" switch (i) {\n";
for (const ASTEnumParam &p : en.params)
out << " case " << p.value << ": return " << p.name << ";\n";
out << " default:\n"
" if (ok)\n"
" *ok = false;\n"
" return " << en.params.at(0).name << ";\n"
" }\n"
" }\n";
}
}
void RepCodeGenerator::generateStreamOperatorsForEnums(QTextStream &out, const QVector<ASTEnum> &enums, const QString &className)
{
for (const ASTEnum &en : enums)
{
const QString type = getEnumType(en);
out << "inline QDataStream &operator<<(QDataStream &ds, const " << className << "::" << en.name << " &obj)\n"
"{\n"
" " << type << " val = obj;\n"
" ds << val;\n"
" return ds;\n"
"}\n\n"
"inline QDataStream &operator>>(QDataStream &ds, " << className << "::" << en.name << " &obj) {\n"
" bool ok;\n"
" " << type << " val;\n"
" ds >> val;\n"
" obj = " << className << "::to" << en.name << "(val, &ok);\n"
" if (!ok)\n qWarning() << \"QtRO received an invalid enum value for type" << en.name << ", value =\" << val;\n"
" return ds;\n"
"}\n\n";
}
}
void RepCodeGenerator::generateENUM(QTextStream &out, const ASTEnum &en)
{
generateENUMs(out, (QVector<ASTEnum>() << en), QStringLiteral("%1Enum").arg(en.name));
}
QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &metaTypes)
{
QString out;
const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<");
const QString qRegisterMetaTypeStreamOperators = QStringLiteral(" qRegisterMetaTypeStreamOperators<");
const QString lineEnding = QStringLiteral(">();\n");
for (const QString &metaType : metaTypes) {
if (isBuiltinType(metaType))
continue;
out += qRegisterMetaType;
out += metaType;
out += lineEnding;
out += qRegisterMetaTypeStreamOperators;
out += metaType;
out += lineEnding;
}
return out;
}
QString RepCodeGenerator::generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes)
{
QString out;
if (!metaTypes.isEmpty())
out += QLatin1String(" qRegisterMetaType<QRemoteObjectPendingCall>();\n");
const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<QRemoteObjectPendingReply<%1>>();\n");
const QString qRegisterConverterConditional = QStringLiteral(" if (!QMetaType::hasRegisteredConverterFunction<QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>())\n");
const QString qRegisterConverter = QStringLiteral(" QMetaType::registerConverter<QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>();\n");
for (const QString &metaType : metaTypes) {
out += qRegisterMetaType.arg(metaType);
out += qRegisterConverterConditional.arg(metaType);
out += qRegisterConverter.arg(metaType);
}
return out;
}
QString RepCodeGenerator::generateMetaTypeRegistrationForEnums(const QVector<QString> &enumUses)
{
QString out;
for (const QString &enumName : enumUses) {
out += QLatin1String(" qRegisterMetaTypeStreamOperators<") + enumName + QLatin1String(">(\"") + enumName + QLatin1String("\");\n");
}
return out;
}
void RepCodeGenerator::generateStreamOperatorsForEnums(QTextStream &out, const QVector<QString> &enumUses)
{
out << "QT_BEGIN_NAMESPACE" << endl;
for (const QString &enumName : enumUses) {
out << "inline QDataStream &operator<<(QDataStream &out, " << enumName << " value)" << endl;
out << "{" << endl;
out << " out << static_cast<qint32>(value);" << endl;
out << " return out;" << endl;
out << "}" << endl;
out << endl;
out << "inline QDataStream &operator>>(QDataStream &in, " << enumName << " &value)" << endl;
out << "{" << endl;
out << " qint32 intValue = 0;" << endl;
out << " in >> intValue;" << endl;
out << " value = static_cast<" << enumName << ">(intValue);" << endl;
out << " return in;" << endl;
out << "}" << endl;
out << endl;
}
out << "QT_END_NAMESPACE" << endl << endl;
}
void RepCodeGenerator::generateClass(Mode mode, QTextStream &out, const ASTClass &astClass, const QString &metaTypeRegistrationCode)
{
const QString className = (astClass.name + (mode == REPLICA ? QStringLiteral("Replica") : mode == SOURCE ? QStringLiteral("Source") : QStringLiteral("SimpleSource")));
if (mode == REPLICA)
out << "class " << className << " : public QRemoteObjectReplica" << endl;
else if (mode == SIMPLE_SOURCE)
out << "class " << className << " : public " << astClass.name << "Source" << endl;
else
out << "class " << className << " : public QObject" << endl;
out << "{" << endl;
out << " Q_OBJECT" << endl;
if (mode != SIMPLE_SOURCE) {
out << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"" << astClass.name << "\")" << endl;
out << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, \"" << QLatin1String(classSignature(astClass)) << "\")" << endl;
for (int i = 0; i < astClass.modelMetadata.count(); i++) {
const auto model = astClass.modelMetadata.at(i);
const auto modelName = astClass.properties.at(model.propertyIndex).name;
if (!model.roles.isEmpty()) {
QStringList list;
for (auto role : model.roles)
list << role.name;
out << QString::fromLatin1(" Q_CLASSINFO(\"%1_ROLES\", \"%2\")").arg(modelName.toUpper(), list.join(QChar::fromLatin1('|'))) << endl;
}
}
//First output properties
for (const ASTProperty &property : astClass.properties) {
out << " Q_PROPERTY(" << typeForMode(property, mode) << " " << property.name << " READ " << property.name;
if (property.modifier == ASTProperty::Constant) {
if (mode == REPLICA) // We still need to notify when we get the initial value
out << " NOTIFY " << property.name << "Changed";
else
out << " CONSTANT";
} else if (property.modifier == ASTProperty::ReadOnly)
out << " NOTIFY " << property.name << "Changed";
else if (property.modifier == ASTProperty::ReadWrite)
out << " WRITE set" << cap(property.name) << " NOTIFY " << property.name << "Changed";
else if (property.modifier == ASTProperty::ReadPush || property.modifier == ASTProperty::SourceOnlySetter) {
if (mode == REPLICA) // The setter slot isn't known to the PROP
out << " NOTIFY " << property.name << "Changed";
else // The Source can use the setter, since non-asynchronous
out << " WRITE set" << cap(property.name) << " NOTIFY " << property.name << "Changed";
}
out << ")" << endl;
}
if (!astClass.enums.isEmpty()) {
out << "" << endl;
out << "public:" << endl;
generateDeclarationsForEnums(out, astClass.enums);
}
}
out << "" << endl;
out << "public:" << endl;
if (mode == REPLICA) {
out << " " << className << "() : QRemoteObjectReplica() { initialize(); }" << endl;
out << " static void registerMetatypes()" << endl;
out << " {" << endl;
out << " static bool initialized = false;" << endl;
out << " if (initialized)" << endl;
out << " return;" << endl;
out << " initialized = true;" << endl;
if (!metaTypeRegistrationCode.isEmpty())
out << metaTypeRegistrationCode << endl;
out << " }" << endl;
if (astClass.hasPointerObjects())
{
out << " void setNode(QRemoteObjectNode *node) override" << endl;
out << " {" << endl;
out << " QRemoteObjectReplica::setNode(node);" << endl;
for (int index = 0; index < astClass.properties.count(); ++index) {
const ASTProperty &property = astClass.properties.at(index);
if (!property.isPointer)
continue;
if (astClass.subClassPropertyIndices.contains(index))
out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS().arg(\"%3\"))));")
.arg(QString::number(index), property.type, property.name) << endl;
else
out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquireModel(QRemoteObjectStringLiterals::MODEL().arg(\"%2\"))));")
.arg(QString::number(index), property.name) << endl;
out << " Q_EMIT " << property.name << "Changed(" << property.name << "()" << ");" << endl;
}
out << " }" << endl;
}
out << "" << endl;
out << "private:" << endl;
out << " " << className << "(QRemoteObjectNode *node, const QString &name = QString())" << endl;
out << " : QRemoteObjectReplica(ConstructWithNode)" << endl;
out << " {" << endl;
out << " initializeNode(node, name);" << endl;
for (int index = 0; index < astClass.properties.count(); ++index) {
const ASTProperty &property = astClass.properties.at(index);
if (!property.isPointer)
continue;
if (astClass.subClassPropertyIndices.contains(index))
out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS().arg(\"%3\"))));")
.arg(QString::number(index), property.type, property.name) << endl;
else
out << QString::fromLatin1(" setChild(%1, QVariant::fromValue(node->acquireModel(QRemoteObjectStringLiterals::MODEL().arg(\"%2\"))));")
.arg(QString::number(index), property.name) << endl;
}
out << " }" << endl;
out << "" << endl;
out << " void initialize() override" << endl;
out << " {" << endl;
out << " " << className << "::registerMetatypes();" << endl;
out << " QVariantList properties;" << endl;
out << " properties.reserve(" << astClass.properties.size() << ");" << endl;
for (const ASTProperty &property : astClass.properties) {
if (property.isPointer)
out << " properties << QVariant::fromValue((" << typeForMode(property, mode) << ")" << property.defaultValue << ");" << endl;
else
out << " properties << QVariant::fromValue(" << typeForMode(property, mode) << "(" << property.defaultValue << "));" << endl;
}
int nPersisted = 0;
if (astClass.hasPersisted) {
out << " QVariantList stored = retrieveProperties(\"" << astClass.name << "\", \"" << classSignature(astClass) << "\");" << endl;
out << " if (!stored.isEmpty()) {" << endl;
for (int i = 0; i < astClass.properties.size(); i++) {
if (astClass.properties.at(i).persisted) {
out << " properties[" << i << "] = stored.at(" << nPersisted << ");" << endl;
nPersisted++;
}
}
out << " }" << endl;
}
out << " setProperties(properties);" << endl;
out << " }" << endl;
} else if (mode == SOURCE) {
out << " explicit " << className << "(QObject *parent = nullptr) : QObject(parent)" << endl;
out << " {" << endl;
if (!metaTypeRegistrationCode.isEmpty())
out << metaTypeRegistrationCode << endl;
out << " }" << endl;
} else {
QVector<int> constIndices;
for (int index = 0; index < astClass.properties.count(); ++index) {
const ASTProperty &property = astClass.properties.at(index);
if (property.modifier == ASTProperty::Constant)
constIndices.append(index);
}
if (constIndices.isEmpty()) {
out << " explicit " << className << "(QObject *parent = nullptr) : " << astClass.name << "Source(parent)" << endl;
} else {
QStringList parameters;
for (int index : constIndices) {
const ASTProperty &property = astClass.properties.at(index);
parameters.append(QString::fromLatin1("%1 %2 = %3").arg(typeForMode(property, SOURCE), property.name, property.defaultValue));
}
parameters.append(QStringLiteral("QObject *parent = nullptr"));
out << " explicit " << className << "(" << parameters.join(QStringLiteral(", ")) << ") : " << astClass.name << "Source(parent)" << endl;
}
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::Constant)
out << " , m_" << property.name << "(" << property.name << ")" << endl;
else
out << " , m_" << property.name << "(" << property.defaultValue << ")" << endl;
}
out << " {" << endl;
out << " }" << endl;
}
out << "" << endl;
out << "public:" << endl;
if (mode == REPLICA && astClass.hasPersisted) {
out << " ~" << className << "() override {" << endl;
out << " QVariantList persisted;" << endl;
for (int i = 0; i < astClass.properties.size(); i++) {
if (astClass.properties.at(i).persisted) {
out << " persisted << propAsVariant(" << i << ");" << endl;
}
}
out << " persistProperties(\"" << astClass.name << "\", \"" << classSignature(astClass) << "\", persisted);" << endl;
out << " }" << endl;
} else {
out << " ~" << className << "() override = default;" << endl;
}
out << "" << endl;
if (mode != SIMPLE_SOURCE)
generateConversionFunctionsForEnums(out, astClass.enums);
//Next output getter/setter
if (mode == REPLICA) {
int i = 0;
for (const ASTProperty &property : astClass.properties) {
auto type = typeForMode(property, mode);
if (type == QLatin1String("QVariant")) {
out << " " << type << " " << property.name << "() const" << endl;
out << " {" << endl;
out << " return propAsVariant(" << i << ");" << endl;
out << " }" << endl;
} else {
out << " " << type << " " << property.name << "() const" << endl;
out << " {" << endl;
out << " const QVariant variant = propAsVariant(" << i << ");" << endl;
out << " if (!variant.canConvert<" << type << ">()) {" << endl;
out << " qWarning() << \"QtRO cannot convert the property " << property.name << " to type " << type << "\";" << endl;
out << " }" << endl;
out << " return variant.value<" << type << " >();" << endl;
out << " }" << endl;
}
i++;
if (property.modifier == ASTProperty::ReadWrite) {
out << "" << endl;
out << " void set" << cap(property.name) << "(" << property.type << " " << property.name << ")" << endl;
out << " {" << endl;
out << " static int __repc_index = " << className << "::staticMetaObject.indexOfProperty(\"" << property.name << "\");" << endl;
out << " QVariantList __repc_args;" << endl;
out << " __repc_args << QVariant::fromValue(" << property.name << ");" << endl;
out << " send(QMetaObject::WriteProperty, __repc_index, __repc_args);" << endl;
out << " }" << endl;
}
out << "" << endl;
}
} else if (mode == SOURCE) {
for (const ASTProperty &property : astClass.properties)
out << " virtual " << typeForMode(property, mode) << " " << property.name << "() const = 0;" << endl;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadWrite ||
property.modifier == ASTProperty::ReadPush ||
property.modifier == ASTProperty::SourceOnlySetter)
out << " virtual void set" << cap(property.name) << "(" << typeForMode(property, mode) << " " << property.name << ") = 0;" << endl;
}
} else {
for (const ASTProperty &property : astClass.properties)
out << " " << typeForMode(property, mode) << " " << property.name << "() const override { return m_"
<< property.name << "; }" << endl;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadWrite ||
property.modifier == ASTProperty::ReadPush ||
property.modifier == ASTProperty::SourceOnlySetter) {
generateSimpleSetter(out, property);
}
}
}
if (mode != SIMPLE_SOURCE) {
//Next output property signals
if (!astClass.properties.isEmpty() || !astClass.signalsList.isEmpty()) {
out << "" << endl;
out << "Q_SIGNALS:" << endl;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier != ASTProperty::Constant)
out << " void " << property.name << "Changed(" << fullyQualifiedTypeName(astClass, className, typeForMode(property, mode)) << " " << property.name << ");" << endl;
}
const QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, className);
for (const ASTFunction &signal : signalsList)
out << " void " << signal.name << "(" << signal.paramsAsString() << ");" << endl;
// CONSTANT source properties still need an onChanged signal on the Replica side to
// update (once) when the value is initialized. Put these last, so they don't mess
// up the signal index order
for (const ASTProperty &property : astClass.properties) {
if (mode == REPLICA && property.modifier == ASTProperty::Constant)
out << " void " << property.name << "Changed(" << fullyQualifiedTypeName(astClass, className, typeForMode(property, mode)) << " " << property.name << ");" << endl;
}
}
bool hasWriteSlots = false;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadPush) {
hasWriteSlots = true;
break;
}
}
if (hasWriteSlots || !astClass.slotsList.isEmpty()) {
out << "" << endl;
out << "public Q_SLOTS:" << endl;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadPush) {
const auto type = fullyQualifiedTypeName(astClass, className, property.type);
if (mode != REPLICA) {
out << " virtual void push" << cap(property.name) << "(" << type << " " << property.name << ")" << endl;
out << " {" << endl;
out << " set" << cap(property.name) << "(" << property.name << ");" << endl;
out << " }" << endl;
} else {
out << " void push" << cap(property.name) << "(" << type << " " << property.name << ")" << endl;
out << " {" << endl;
out << " static int __repc_index = " << className << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name) << "(" << type << ")\");" << endl;
out << " QVariantList __repc_args;" << endl;
out << " __repc_args << QVariant::fromValue(" << property.name << ");" << endl;
out << " send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);" << endl;
out << " }" << endl;
}
}
}
const QVector<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList, className);
for (const ASTFunction &slot : slotsList) {
const auto returnType = fullyQualifiedTypeName(astClass, className, slot.returnType);
if (mode != REPLICA) {
out << " virtual " << returnType << " " << slot.name << "(" << slot.paramsAsString() << ") = 0;" << endl;
} else {
// TODO: Discuss whether it is a good idea to special-case for void here,
const bool isVoid = slot.returnType == QStringLiteral("void");
if (isVoid)
out << " void " << slot.name << "(" << slot.paramsAsString() << ")" << endl;
else
out << " QRemoteObjectPendingReply<" << returnType << "> " << slot.name << "(" << slot.paramsAsString()<< ")" << endl;
out << " {" << endl;
out << " static int __repc_index = " << className << "::staticMetaObject.indexOfSlot(\"" << slot.name << "(" << slot.paramsAsString(ASTFunction::Normalized) << ")\");" << endl;
out << " QVariantList __repc_args;" << endl;
const auto &paramNames = slot.paramNames();
if (!paramNames.isEmpty()) {
out << " __repc_args" << endl;
for (const QString &name : paramNames)
out << " << " << "QVariant::fromValue(" << name << ")" << endl;
out << " ;" << endl;
}
if (isVoid)
out << " send(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args);" << endl;
else
out << " return QRemoteObjectPendingReply<" << returnType << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index, __repc_args));" << endl;
out << " }" << endl;
}
}
}
} else {
if (!astClass.properties.isEmpty()) {
bool addProtected = true;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadOnly) {
if (addProtected) {
out << "" << endl;
out << "protected:" << endl;
addProtected = false;
}
generateSimpleSetter(out, property, false);
}
}
}
}
out << "" << endl;
out << "private:" << endl;
//Next output data members
if (mode == SIMPLE_SOURCE) {
for (const ASTProperty &property : astClass.properties)
out << " " << typeForMode(property, SOURCE) << " " << "m_" << property.name << ";" << endl;
}
if (mode != SIMPLE_SOURCE)
out << " friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);" << endl;
out << "};" << endl;
out << "" << endl;
if (mode != SIMPLE_SOURCE)
generateStreamOperatorsForEnums(out, astClass.enums, className);
out << "" << endl;
}
void RepCodeGenerator::generateSourceAPI(QTextStream &out, const ASTClass &astClass)
{
const QString className = astClass.name + QStringLiteral("SourceAPI");
out << QStringLiteral("template <class ObjectType>") << endl;
out << QString::fromLatin1("struct %1 : public SourceApiMap").arg(className) << endl;
out << QStringLiteral("{") << endl;
if (!astClass.enums.isEmpty()) {
// Include enum definition in SourceAPI
generateDeclarationsForEnums(out, astClass.enums, false);
}
out << QString::fromLatin1(" %1(ObjectType *object, const QString &name = QLatin1String(\"%2\"))").arg(className, astClass.name) << endl;
out << QStringLiteral(" : SourceApiMap(), m_name(name)") << endl;
out << QStringLiteral(" {") << endl;
if (!astClass.hasPointerObjects())
out << QStringLiteral(" Q_UNUSED(object);") << endl;
const int enumCount = astClass.enums.count();
for (int i : astClass.subClassPropertyIndices) {
const ASTProperty &child = astClass.properties.at(i);
out << QString::fromLatin1(" using %1_type_t = typename std::remove_pointer<decltype(object->%1())>::type;")
.arg(child.name) << endl;
}
out << QString::fromLatin1(" m_enums[0] = %1;").arg(enumCount) << endl;
for (int i = 0; i < enumCount; ++i) {
const auto enumerator = astClass.enums.at(i);
out << QString::fromLatin1(" m_enums[%1] = ObjectType::staticMetaObject.indexOfEnumerator(\"%2\");")
.arg(i+1).arg(enumerator.name) << endl;
}
const int propCount = astClass.properties.count();
out << QString::fromLatin1(" m_properties[0] = %1;").arg(propCount) << endl;
QList<ASTProperty> onChangeProperties;
QList<int> propertyChangeIndex;
for (int i = 0; i < propCount; ++i) {
const ASTProperty &prop = astClass.properties.at(i);
const QString propTypeName = fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), typeForMode(prop, SOURCE));
out << QString::fromLatin1(" m_properties[%1] = QtPrivate::qtro_property_index<ObjectType>(&ObjectType::%2, "
"static_cast<%3 (QObject::*)()>(0),\"%2\");")
.arg(QString::number(i+1), prop.name, propTypeName) << endl;
if (prop.modifier == prop.ReadWrite) //Make sure we have a setter function
out << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>(&ObjectType::set%1, static_cast<void (QObject::*)(%2)>(0));")
.arg(cap(prop.name), propTypeName) << endl;
if (prop.modifier != prop.Constant) { //Make sure we have an onChange signal
out << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>(&ObjectType::%1Changed, static_cast<void (QObject::*)()>(0));")
.arg(prop.name) << endl;
onChangeProperties << prop;
propertyChangeIndex << i + 1; //m_properties[0] is the count, so index is one higher
}
}
const int signalCount = astClass.signalsList.count();
const int changedCount = onChangeProperties.size();
out << QString::fromLatin1(" m_signals[0] = %1;").arg(signalCount+onChangeProperties.size()) << endl;
for (int i = 0; i < changedCount; ++i)
out << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::%2Changed, "
"static_cast<void (QObject::*)(%3)>(0),m_signalArgCount+%4,&m_signalArgTypes[%4]);")
.arg(QString::number(i+1), onChangeProperties.at(i).name,
fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), typeForMode(onChangeProperties.at(i), SOURCE)),
QString::number(i)) << endl;
QVector<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList, QStringLiteral("typename ObjectType"));
for (int i = 0; i < signalCount; ++i) {
const ASTFunction &sig = signalsList.at(i);
out << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index<ObjectType>(&ObjectType::%2, "
"static_cast<void (QObject::*)(%3)>(0),m_signalArgCount+%4,&m_signalArgTypes[%4]);")
.arg(QString::number(changedCount+i+1), sig.name, sig.paramsAsString(ASTFunction::Normalized), QString::number(changedCount+i)) << endl;
}
const int slotCount = astClass.slotsList.count();
QVector<ASTProperty> pushProps;
for (const ASTProperty &property : astClass.properties) {
if (property.modifier == ASTProperty::ReadPush)
pushProps << property;
}
const int pushCount = pushProps.count();
const int methodCount = slotCount + pushCount;
out << QString::fromLatin1(" m_methods[0] = %1;").arg(methodCount) << endl;
for (int i = 0; i < pushCount; ++i) {
const ASTProperty &prop = pushProps.at(i);
const QString propTypeName = fullyQualifiedTypeName(astClass, QStringLiteral("typename ObjectType"), prop.type);
out << QString::fromLatin1(" m_methods[%1] = QtPrivate::qtro_method_index<ObjectType>(&ObjectType::push%2, "
"static_cast<void (QObject::*)(%3)>(0),\"push%2(%4)\",m_methodArgCount+%5,&m_methodArgTypes[%5]);")
.arg(QString::number(i+1), cap(prop.name), propTypeName,
QString(propTypeName).remove(QStringLiteral("typename ObjectType::")), // we don't want this in the string signature
QString::number(i)) << endl;
}
QVector<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList, QStringLiteral("typename ObjectType"));
for (int i = 0; i < slotCount; ++i) {
const ASTFunction &slot = slotsList.at(i);
const QString params = slot.paramsAsString(ASTFunction::Normalized);
out << QString::fromLatin1(" m_methods[%1] = QtPrivate::qtro_method_index<ObjectType>(&ObjectType::%2, "
"static_cast<void (QObject::*)(%3)>(0),\"%2(%4)\",m_methodArgCount+%5,&m_methodArgTypes[%5]);")
.arg(QString::number(i+pushCount+1), slot.name, params,
QString(params).remove(QStringLiteral("typename ObjectType::")), // we don't want this in the string signature
QString::number(i+pushCount)) << endl;
}
for (const auto &model : astClass.modelMetadata) {
const ASTProperty &property = astClass.properties.at(model.propertyIndex);
out << QString::fromLatin1(" m_models << ModelInfo({object->%1(),").arg(property.name) << endl;
out << QString::fromLatin1(" QStringLiteral(\"%1\"),").arg(property.name) << endl;
QStringList list;
if (!model.roles.isEmpty()) {
for (auto role : model.roles)
list << role.name;
}
out << QString::fromLatin1(" QByteArrayLiteral(\"%1\")});").arg(list.join(QChar::fromLatin1('|'))) << endl;
}
for (int i : astClass.subClassPropertyIndices) {
const ASTProperty &child = astClass.properties.at(i);
out << QString::fromLatin1(" m_subclasses << new %2SourceAPI<%1_type_t>(object->%1(), QStringLiteral(\"%1\"));")
.arg(child.name, child.type) << endl;
}
out << QStringLiteral(" }") << endl;
out << QStringLiteral("") << endl;
out << QString::fromLatin1(" QString name() const override { return m_name; }") << endl;
out << QString::fromLatin1(" QString typeName() const override { return QStringLiteral(\"%1\"); }").arg(astClass.name) << endl;
out << QStringLiteral(" int enumCount() const override { return m_enums[0]; }") << endl;
out << QStringLiteral(" int propertyCount() const override { return m_properties[0]; }") << endl;
out << QStringLiteral(" int signalCount() const override { return m_signals[0]; }") << endl;
out << QStringLiteral(" int methodCount() const override { return m_methods[0]; }") << endl;
out << QStringLiteral(" int sourceEnumIndex(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_enums[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_enums[index+1];") << endl;
out << QStringLiteral(" }") << endl;
out << QStringLiteral(" int sourcePropertyIndex(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_properties[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_properties[index+1];") << endl;
out << QStringLiteral(" }") << endl;
out << QStringLiteral(" int sourceSignalIndex(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_signals[index+1];") << endl;
out << QStringLiteral(" }") << endl;
out << QStringLiteral(" int sourceMethodIndex(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_methods[index+1];") << endl;
out << QStringLiteral(" }") << endl;
if (signalCount+changedCount > 0) {
out << QStringLiteral(" int signalParameterCount(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_signalArgCount[index];") << endl;
out << QStringLiteral(" }") << endl;
out << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (sigIndex < 0 || sigIndex >= m_signals[0] || paramIndex < 0 || paramIndex >= m_signalArgCount[sigIndex])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_signalArgTypes[sigIndex][paramIndex];") << endl;
out << QStringLiteral(" }") << endl;
} else {
out << QStringLiteral(" int signalParameterCount(int index) const override { Q_UNUSED(index); return -1; }") << endl;
out << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) const override") << endl;
out << QStringLiteral(" { Q_UNUSED(sigIndex); Q_UNUSED(paramIndex); return -1; }") << endl;
}
if (methodCount > 0) {
out << QStringLiteral(" int methodParameterCount(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_methodArgCount[index];") << endl;
out << QStringLiteral(" }") << endl;
out << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (methodIndex < 0 || methodIndex >= m_methods[0] || paramIndex < 0 || paramIndex >= m_methodArgCount[methodIndex])") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" return m_methodArgTypes[methodIndex][paramIndex];") << endl;
out << QStringLiteral(" }") << endl;
} else {
out << QStringLiteral(" int methodParameterCount(int index) const override { Q_UNUSED(index); return -1; }") << endl;
out << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) const override") << endl;
out << QStringLiteral(" { Q_UNUSED(methodIndex); Q_UNUSED(paramIndex); return -1; }") << endl;
}
//propertyIndexFromSignal method
out << QStringLiteral(" int propertyIndexFromSignal(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
if (!propertyChangeIndex.isEmpty()) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < propertyChangeIndex.size(); ++i)
out << QString::fromLatin1(" case %1: return m_properties[%2];").arg(i).arg(propertyChangeIndex.at(i)) << endl;
out << QStringLiteral(" }") << endl;
} else
out << QStringLiteral(" Q_UNUSED(index);") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" }") << endl;
//propertyRawIndexFromSignal method
out << QStringLiteral(" int propertyRawIndexFromSignal(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
if (!propertyChangeIndex.isEmpty()) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < propertyChangeIndex.size(); ++i)
out << QString::fromLatin1(" case %1: return %2;").arg(i).arg(propertyChangeIndex.at(i)-1) << endl;
out << QStringLiteral(" }") << endl;
} else
out << QStringLiteral(" Q_UNUSED(index);") << endl;
out << QStringLiteral(" return -1;") << endl;
out << QStringLiteral(" }") << endl;
//signalSignature method
out << QStringLiteral(" const QByteArray signalSignature(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
if (signalCount+changedCount > 0) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < changedCount; ++i) {
const ASTProperty &prop = onChangeProperties.at(i);
if (isClassEnum(astClass, prop.type))
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2Changed($1)\").replace(\"$1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%3\"));")
.arg(QString::number(i), prop.name, prop.type) << endl;
else
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2Changed(%3)\");")
.arg(QString::number(i), prop.name, typeForMode(prop, SOURCE)) << endl;
}
for (int i = 0; i < signalCount; ++i)
{
const ASTFunction &sig = astClass.signalsList.at(i);
auto paramsAsString = sig.paramsAsString(ASTFunction::Normalized);
const auto paramsAsList = paramsAsString.split(QLatin1String(","));
int enumCount = 0;
QString enumString;
for (int j = 0; j < paramsAsList.count(); j++) {
auto const p = paramsAsList.at(j);
if (isClassEnum(astClass, p)) {
paramsAsString.replace(paramsAsString.indexOf(p), p.size(), QStringLiteral("$%1").arg(enumCount));
enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%2\"))").arg(enumCount++).arg(paramsAsList.at(j)));
}
}
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2(%3)\")%4;")
.arg(QString::number(i+changedCount), sig.name, paramsAsString, enumString) << endl;
}
out << QStringLiteral(" }") << endl;
} else
out << QStringLiteral(" Q_UNUSED(index);") << endl;
out << QStringLiteral(" return QByteArrayLiteral(\"\");") << endl;
out << QStringLiteral(" }") << endl;
//signalParameterNames method
out << QStringLiteral(" QList<QByteArray> signalParameterNames(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << endl;
out << QStringLiteral(" return QList<QByteArray>();") << endl;
out << QStringLiteral(" return ObjectType::staticMetaObject.method(m_signals[index + 1]).parameterNames();") << endl;
out << QStringLiteral(" }") << endl;
//methodSignature method
out << QStringLiteral(" const QByteArray methodSignature(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
if (methodCount > 0) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < pushCount; ++i)
{
const ASTProperty &prop = pushProps.at(i);
if (isClassEnum(astClass, prop.type))
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"push%2($1)\").replace(\"$1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%3\"));")
.arg(QString::number(i), prop.name, prop.type) << endl;
else
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"push%2(%3)\");")
.arg(QString::number(i), cap(prop.name), prop.type) << endl;
}
for (int i = 0; i < slotCount; ++i)
{
const ASTFunction &slot = astClass.slotsList.at(i);
auto paramsAsString = slot.paramsAsString(ASTFunction::Normalized);
const auto paramsAsList = paramsAsString.split(QLatin1String(","));
int enumCount = 0;
QString enumString;
for (int j = 0; j < paramsAsList.count(); j++) {
auto const p = paramsAsList.at(j);
if (isClassEnum(astClass, p)) {
paramsAsString.replace(paramsAsString.indexOf(p), p.size(), QStringLiteral("$%1").arg(enumCount));
enumString.append(QString::fromLatin1(".replace(\"$%1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%2\"))").arg(enumCount++).arg(paramsAsList.at(j)));
}
}
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2(%3)\")%4;")
.arg(QString::number(i+pushCount), slot.name, paramsAsString, enumString) << endl;
}
out << QStringLiteral(" }") << endl;
} else
out << QStringLiteral(" Q_UNUSED(index);") << endl;
out << QStringLiteral(" return QByteArrayLiteral(\"\");") << endl;
out << QStringLiteral(" }") << endl;
//methodType method
out << QStringLiteral(" QMetaMethod::MethodType methodType(int) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" return QMetaMethod::Slot;") << endl;
out << QStringLiteral(" }") << endl;
//methodParameterNames method
out << QStringLiteral(" QList<QByteArray> methodParameterNames(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
out << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << endl;
out << QStringLiteral(" return QList<QByteArray>();") << endl;
out << QStringLiteral(" return ObjectType::staticMetaObject.method(m_methods[index + 1]).parameterNames();") << endl;
out << QStringLiteral(" }") << endl;
//typeName method
out << QStringLiteral(" const QByteArray typeName(int index) const override") << endl;
out << QStringLiteral(" {") << endl;
if (methodCount > 0) {
out << QStringLiteral(" switch (index) {") << endl;
for (int i = 0; i < pushCount; ++i)
{
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"void\");")
.arg(QString::number(i)) << endl;
}
for (int i = 0; i < slotCount; ++i)
{
const ASTFunction &slot = astClass.slotsList.at(i);
if (isClassEnum(astClass, slot.returnType))
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"$1\").replace(\"$1\", QtPrivate::qtro_enum_signature<ObjectType>(\"%2\"));")
.arg(QString::number(i+pushCount), slot.returnType) << endl;
else
out << QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2\");")
.arg(QString::number(i+pushCount), slot.returnType) << endl;
}
out << QStringLiteral(" }") << endl;
} else
out << QStringLiteral(" Q_UNUSED(index);") << endl;
out << QStringLiteral(" return QByteArrayLiteral(\"\");") << endl;
out << QStringLiteral(" }") << endl;
//objectSignature method
out << QStringLiteral(" QByteArray objectSignature() const override { return QByteArray{\"")
<< QLatin1String(classSignature(astClass))
<< QStringLiteral("\"}; }") << endl;
out << QStringLiteral("") << endl;
out << QString::fromLatin1(" int m_enums[%1];").arg(enumCount + 1) << endl;
out << QString::fromLatin1(" int m_properties[%1];").arg(propCount+1) << endl;
out << QString::fromLatin1(" int m_signals[%1];").arg(signalCount+changedCount+1) << endl;
out << QString::fromLatin1(" int m_methods[%1];").arg(methodCount+1) << endl;
out << QString::fromLatin1(" const QString m_name;") << endl;
if (signalCount+changedCount > 0) {
out << QString::fromLatin1(" int m_signalArgCount[%1];").arg(signalCount+changedCount) << endl;
out << QString::fromLatin1(" const int* m_signalArgTypes[%1];").arg(signalCount+changedCount) << endl;
}
if (methodCount > 0) {
out << QString::fromLatin1(" int m_methodArgCount[%1];").arg(methodCount) << endl;
out << QString::fromLatin1(" const int* m_methodArgTypes[%1];").arg(methodCount) << endl;
}
out << QStringLiteral("};") << endl;
out << "" << endl;
}
QT_END_NAMESPACE