1// Copyright (C) 2017-2020 Ford Motor Company
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "repcodegenerator.h"
5
6#include <QFileInfo>
7#include <QMetaType>
8#include <QCryptographicHash>
9#include <QRegularExpression>
10
11using namespace Qt;
12
13QT_BEGIN_NAMESPACE
14
15template <typename C>
16static int accumulatedSizeOfNames(const C &c)
17{
18 int result = 0;
19 for (const auto &e : c)
20 result += e.name.size();
21 return result;
22}
23
24template <typename C>
25static int accumulatedSizeOfTypes(const C &c)
26{
27 int result = 0;
28 for (const auto &e : c)
29 result += e.type.size();
30 return result;
31}
32
33static QString cap(QString name)
34{
35 if (!name.isEmpty())
36 name[0] = name[0].toUpper();
37 return name;
38}
39
40static bool isClassEnum(const ASTClass &classContext, const QString &typeName)
41{
42 for (const ASTEnum &astEnum : classContext.enums) {
43 if (astEnum.name == typeName) {
44 return true;
45 }
46 }
47
48 return false;
49}
50
51static bool hasScopedEnum(const ASTClass &classContext)
52{
53 for (const ASTEnum &astEnum : classContext.enums) {
54 if (astEnum.isScoped) {
55 return true;
56 }
57 }
58
59 return false;
60}
61
62static bool hasScopedEnum(const POD &pod)
63{
64 for (const ASTEnum &astEnum : pod.enums) {
65 if (astEnum.isScoped) {
66 return true;
67 }
68 }
69
70 return false;
71}
72
73static QString fullyQualifiedName(const ASTClass& classContext, const QString &className,
74 const QString &typeName)
75{
76 static const QRegularExpression re = QRegularExpression(QLatin1String("([^<>,\\s]+)"));
77 QString copy = typeName;
78 qsizetype offset = 0;
79 for (const QRegularExpressionMatch &match : re.globalMatch(subject: typeName)) {
80 if (isClassEnum(classContext, match.captured(nth: 1))) {
81 copy.insert(i: match.capturedStart(nth: 1) + offset, s: className + QStringLiteral("::"));
82 offset += className.size() + 2;
83 }
84 }
85 return copy;
86}
87
88// for enums we need to transform signal/slot arguments to include the class scope
89static QList<ASTFunction> transformEnumParams(const ASTClass& classContext,
90 const QList<ASTFunction> &methodList,
91 const QString &typeName) {
92 QList<ASTFunction> localList = methodList;
93 for (ASTFunction &astFunction : localList) {
94 for (ASTDeclaration &astParam : astFunction.params) {
95 for (const ASTEnum &astEnum : classContext.enums) {
96 if (astEnum.name == astParam.type) {
97 astParam.type = typeName + QStringLiteral("::") + astParam.type;
98 }
99 }
100 }
101 }
102 return localList;
103}
104
105/*
106 Returns \c true if the type is a built-in type.
107*/
108static bool isBuiltinType(const QString &type)
109 {
110 const auto metaType = QMetaType::fromName(name: type.toLatin1().constData());
111 if (!metaType.isValid())
112 return false;
113 return (metaType.id() < QMetaType::User);
114}
115
116RepCodeGenerator::RepCodeGenerator(QIODevice *outputDevice, const AST &ast)
117 : m_stream(outputDevice), m_ast(ast)
118{
119}
120
121QByteArray RepCodeGenerator::classSignature(const ASTClass &ac)
122{
123 return m_ast.typeSignatures[ac.name];
124}
125
126void RepCodeGenerator::generate(Mode mode, QString fileName)
127{
128 if (fileName.isEmpty())
129 m_stream << "#pragma once" << Qt::endl << Qt::endl;
130 else {
131 fileName = QFileInfo(fileName).fileName();
132 fileName = fileName.toUpper();
133 fileName.replace(before: QLatin1Char('.'), after: QLatin1Char('_'));
134 m_stream << "#ifndef " << fileName << Qt::endl;
135 m_stream << "#define " << fileName << Qt::endl << Qt::endl;
136 }
137
138 generateHeader(mode);
139 for (const ASTEnum &en : m_ast.enums)
140 generateEnumGadget(en, QStringLiteral("%1Enum").arg(en.name));
141 for (const POD &pod : m_ast.pods)
142 generatePOD(pod);
143
144 QSet<QString> metaTypes;
145 QSet<QString> enumTypes;
146 for (const POD &pod : m_ast.pods) {
147 metaTypes << pod.name;
148 // We register from within the code generated for classes, not PODs
149 // Thus, for enums/flags in PODs, we need the to prefix with the POD
150 // name. The enumTypes set is used to make sure we don't try to
151 // register the non-prefixed name if it is used as a member variable
152 // type.
153 for (const ASTEnum &en : pod.enums) {
154 metaTypes << QLatin1String("%1::%2").arg(pod.name, en.name);
155 enumTypes << en.name;
156 }
157 for (const ASTFlag &flag : pod.flags) {
158 metaTypes << QLatin1String("%1::%2").arg(pod.name, flag.name);
159 enumTypes << flag.name;
160 }
161 for (const PODAttribute &attribute : pod.attributes) {
162 if (!enumTypes.contains(attribute.type))
163 metaTypes << attribute.type;
164 }
165 }
166 const QString metaTypeRegistrationCode = generateMetaTypeRegistration(metaTypes);
167
168 for (const ASTClass &astClass : m_ast.classes) {
169 QSet<QString> classMetaTypes;
170 QSet<QString> pendingMetaTypes;
171 for (const ASTEnum &en : astClass.enums)
172 classMetaTypes << en.name;
173 for (const ASTProperty &property : astClass.properties) {
174 if (property.isPointer)
175 continue;
176 classMetaTypes << property.type;
177 }
178 const auto extractClassMetaTypes = [&](const ASTFunction &function) {
179 classMetaTypes << function.returnType;
180 pendingMetaTypes << function.returnType;
181 for (const ASTDeclaration &decl : function.params) {
182 classMetaTypes << decl.type;
183
184 // Collect types packaged by Qt containers, to register their metatypes if needed
185 QRegularExpression re(
186 QStringLiteral("(QList|QMap|QHash)<\\s*([\\w]+)\\s*(,\\s*([\\w]+))?\\s*>"));
187 QRegularExpressionMatch m = re.match(decl.type);
188 if (m.hasMatch()) {
189 if (auto captured = m.captured(2);
190 !captured.isNull() && !metaTypes.contains(captured)) {
191 classMetaTypes << captured;
192 }
193 if (auto captured = m.captured(4);
194 !captured.isNull() && !metaTypes.contains(captured)) {
195 classMetaTypes << captured;
196 }
197 }
198 }
199 };
200 for (const ASTFunction &function : astClass.signalsList)
201 extractClassMetaTypes(function);
202 for (const ASTFunction &function : astClass.slotsList)
203 extractClassMetaTypes(function);
204
205 const QString classMetaTypeRegistrationCode = metaTypeRegistrationCode
206 + generateMetaTypeRegistration(classMetaTypes);
207 const QString replicaMetaTypeRegistrationCode = classMetaTypeRegistrationCode
208 + generateMetaTypeRegistrationForPending(pendingMetaTypes);
209
210 if (mode == MERGED) {
211 generateClass(REPLICA, astClass, replicaMetaTypeRegistrationCode);
212 generateClass(SOURCE, astClass, classMetaTypeRegistrationCode);
213 generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
214 generateSourceAPI(astClass);
215 } else {
216 generateClass(mode, astClass, mode == REPLICA ? replicaMetaTypeRegistrationCode
217 : classMetaTypeRegistrationCode);
218 if (mode == SOURCE) {
219 generateClass(SIMPLE_SOURCE, astClass, classMetaTypeRegistrationCode);
220 generateSourceAPI(astClass);
221 }
222 }
223 }
224
225 m_stream << Qt::endl;
226 if (!fileName.isEmpty())
227 m_stream << "#endif // " << fileName << Qt::endl;
228}
229
230void RepCodeGenerator::generateHeader(Mode mode)
231{
232 m_stream <<
233 "// This is an autogenerated file.\n"
234 "// Do not edit this file, any changes made will be lost the next time it is generated.\n"
235 "\n"
236 "#include <QtCore/qobject.h>\n"
237 "#include <QtCore/qdatastream.h>\n"
238 "#include <QtCore/qvariant.h>\n"
239 "#include <QtCore/qmap.h>\n"
240 "#include <QtCore/qmetatype.h>\n";
241 bool hasModel = false;
242 for (auto c : m_ast.classes)
243 {
244 if (c.modelMetadata.size() > 0)
245 {
246 hasModel = true;
247 break;
248 }
249 }
250 if (hasModel)
251 m_stream << "#include <QtCore/qabstractitemmodel.h>\n";
252 m_stream << "\n"
253 "#include <QtRemoteObjects/qremoteobjectnode.h>\n";
254
255 if (mode == MERGED) {
256 m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
257 m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
258 m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
259 if (hasModel)
260 m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
261 } else if (mode == REPLICA) {
262 m_stream << "#include <QtRemoteObjects/qremoteobjectpendingcall.h>\n";
263 m_stream << "#include <QtRemoteObjects/qremoteobjectreplica.h>\n";
264 if (hasModel)
265 m_stream << "#include <QtRemoteObjects/qremoteobjectabstractitemmodelreplica.h>\n";
266 } else
267 m_stream << "#include <QtRemoteObjects/qremoteobjectsource.h>\n";
268 m_stream << "\n";
269
270 m_stream << m_ast.preprocessorDirectives.join(QLatin1Char('\n'));
271 m_stream << "\n";
272
273 m_stream << "using namespace Qt::Literals::StringLiterals;";
274 m_stream << "\n";
275}
276
277static QString formatTemplateStringArgTypeNameCapitalizedName(int numberOfTypeOccurrences,
278 int numberOfNameOccurrences,
279 QString templateString,
280 const POD &pod)
281{
282 QString out;
283 const int LengthOfPlaceholderText = 2;
284 Q_ASSERT(templateString.count(QRegularExpression(QStringLiteral("%\\d")))
285 == numberOfNameOccurrences + numberOfTypeOccurrences);
286 const auto expectedOutSize
287 = numberOfNameOccurrences * accumulatedSizeOfNames(pod.attributes)
288 + numberOfTypeOccurrences * accumulatedSizeOfTypes(pod.attributes)
289 + pod.attributes.size() * (templateString.size()
290 - (numberOfNameOccurrences + numberOfTypeOccurrences)
291 * LengthOfPlaceholderText);
292 out.reserve(asize: expectedOutSize);
293 for (const PODAttribute &a : pod.attributes)
294 out += templateString.arg(a.type, a.name, cap(a.name));
295 return out;
296}
297
298QString RepCodeGenerator::formatQPropertyDeclarations(const POD &pod)
299{
300 QString prop = QStringLiteral(" Q_PROPERTY(%1 %2 READ %2 WRITE set%3)\n");
301 return formatTemplateStringArgTypeNameCapitalizedName(1, 3, prop, pod);
302}
303
304QString RepCodeGenerator::formatConstructors(const POD &pod)
305{
306 QString initializerString = QStringLiteral(": ");
307 QString defaultInitializerString = initializerString;
308 QString argString;
309 for (const PODAttribute &a : pod.attributes) {
310 initializerString += QString::fromLatin1("m_%1(%1), ").arg(a.name);
311 defaultInitializerString += QString::fromLatin1("m_%1(), ").arg(a.name);
312 argString += QString::fromLatin1("%1 %2, ").arg(a.type, a.name);
313 }
314 argString.chop(n: 2);
315 initializerString.chop(n: 2);
316 defaultInitializerString.chop(n: 2);
317
318 return QString::fromLatin1(ba: " %1() %2 {}\n"
319 " explicit %1(%3) %4 {}\n")
320 .arg(pod.name, defaultInitializerString, argString, initializerString);
321}
322
323QString RepCodeGenerator::formatPropertyGettersAndSetters(const POD &pod)
324{
325 QString templateString
326 = QString::fromLatin1(ba: " %1 %2() const { return m_%2; }\n"
327 " void set%3(%1 %2) { if (%2 != m_%2) { m_%2 = %2; } }\n");
328 return formatTemplateStringArgTypeNameCapitalizedName(2, 8, qMove(templateString), pod);
329}
330
331QString RepCodeGenerator::formatDataMembers(const POD &pod)
332{
333 QString out;
334 const QString prefix = QStringLiteral(" ");
335 const QString infix = QStringLiteral(" m_");
336 const QString suffix = QStringLiteral(";\n");
337 const auto expectedOutSize
338 = accumulatedSizeOfNames(pod.attributes)
339 + accumulatedSizeOfTypes(pod.attributes)
340 + pod.attributes.size() * (prefix.size() + infix.size() + suffix.size());
341 out.reserve(asize: expectedOutSize);
342 for (const PODAttribute &a : pod.attributes) {
343 out += prefix;
344 out += a.type;
345 out += infix;
346 out += a.name;
347 out += suffix;
348 }
349 Q_ASSERT(out.size() == expectedOutSize);
350 return out;
351}
352
353QString RepCodeGenerator::formatDebugOperator(const POD &pod)
354{
355 QString props;
356 int count = 0;
357 for (const PODAttribute &attribute : pod.attributes) {
358 if (count++ > 0)
359 props.append(QLatin1String(" << \", \""));
360 props.append(QLatin1String(" << \"%1: \" << obj.%1()").arg(attribute.name));
361 }
362
363 return QLatin1String("inline QDebug operator<<(QDebug dbg, const %1 &obj) {\n" \
364 " dbg.nospace() << \"%1(\" %2 << \")\";\n" \
365 " return dbg.maybeSpace();\n}\n\n").arg(pod.name, props);
366}
367
368QString RepCodeGenerator::formatMarshallingOperators(const POD &pod)
369{
370 return QLatin1String("inline QDataStream &operator<<(QDataStream &ds, const ") + pod.name
371 + QLatin1String(" &obj) {\n"
372 " QtRemoteObjects::copyStoredProperties(&obj, ds);\n"
373 " return ds;\n"
374 "}\n"
375 "\n"
376 "inline QDataStream &operator>>(QDataStream &ds, ") + pod.name
377 + QLatin1String(" &obj) {\n"
378 " QtRemoteObjects::copyStoredProperties(ds, &obj);\n"
379 " return ds;\n"
380 "}\n")
381 ;
382}
383
384QString RepCodeGenerator::typeForMode(const ASTProperty &property, RepCodeGenerator::Mode mode)
385{
386 if (!property.isPointer)
387 return property.type;
388
389 if (property.type.startsWith(QStringLiteral("QAbstractItemModel")))
390 return mode == REPLICA ? property.type + QStringLiteral("Replica*")
391 : property.type + QStringLiteral("*");
392
393 switch (mode) {
394 case REPLICA: return property.type + QStringLiteral("Replica*");
395 case SIMPLE_SOURCE:
396 Q_FALLTHROUGH();
397 case SOURCE: return property.type + QStringLiteral("Source*");
398 default: qCritical(msg: "Invalid mode");
399 }
400
401 return QStringLiteral("InvalidPropertyName");
402}
403
404void RepCodeGenerator::generateSimpleSetter(const ASTProperty &property, bool generateOverride)
405{
406 if (!generateOverride)
407 m_stream << " virtual ";
408 else
409 m_stream << " ";
410 m_stream << "void set" << cap(property.name) << "(" << typeForMode(property, SIMPLE_SOURCE)
411 << " " << property.name << ")";
412 if (generateOverride)
413 m_stream << " override";
414 m_stream << Qt::endl;
415 m_stream << " {" << Qt::endl;
416 m_stream << " if (" << property.name << " != m_" << property.name << ") {" << Qt::endl;
417 m_stream << " m_" << property.name << " = " << property.name << ";" << Qt::endl;
418 m_stream << " Q_EMIT " << property.name << "Changed(m_" << property.name << ");"
419 << Qt::endl;
420 m_stream << " }" << Qt::endl;
421 m_stream << " }" << Qt::endl;
422}
423
424void RepCodeGenerator::generatePOD(const POD &pod)
425{
426 QStringList equalityCheck;
427 for (const PODAttribute &attr : pod.attributes)
428 equalityCheck << QStringLiteral("left.%1() == right.%1()").arg(attr.name);
429 m_stream << "class " << pod.name << "\n"
430 "{\n"
431 " Q_GADGET\n"
432 << "\n"
433 << formatQPropertyDeclarations(pod);
434 if (hasScopedEnum(pod)) // See https://bugreports.qt.io/browse/QTBUG-73360
435 m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
436 m_stream << "public:\n";
437 generateDeclarationsForEnums(pod.enums);
438 for (auto &flag : pod.flags) {
439 m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
440 m_stream << " Q_FLAG(" << flag.name << ")\n";
441 }
442 m_stream << formatConstructors(pod)
443 << formatPropertyGettersAndSetters(pod)
444 << "private:\n"
445 << formatDataMembers(pod)
446 << "};\n"
447 << "\n"
448 << "inline bool operator==(const " << pod.name << " &left, const " << pod.name <<
449 " &right) Q_DECL_NOTHROW {\n"
450 << " return " << equalityCheck.join(QStringLiteral(" && ")) << ";\n"
451 << "}\n"
452 << "inline bool operator!=(const " << pod.name << " &left, const " << pod.name <<
453 " &right) Q_DECL_NOTHROW {\n"
454 << " return !(left == right);\n"
455 << "}\n"
456 << "\n"
457 << formatDebugOperator(pod)
458 << formatMarshallingOperators(pod);
459 for (auto &flag : pod.flags)
460 m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << pod.name << "::" << flag.name << ")\n";
461 m_stream << "\n";
462}
463
464QString getEnumType(const ASTEnum &en)
465{
466 if (!en.type.isEmpty())
467 return en.type;
468 if (en.isSigned) {
469 if (en.max < 0x7F)
470 return QStringLiteral("qint8");
471 if (en.max < 0x7FFF)
472 return QStringLiteral("qint16");
473 return QStringLiteral("qint32");
474 } else {
475 if (en.max < 0xFF)
476 return QStringLiteral("quint8");
477 if (en.max < 0xFFFF)
478 return QStringLiteral("quint16");
479 return QStringLiteral("quint32");
480 }
481}
482
483void RepCodeGenerator::generateDeclarationsForEnums(const QList<ASTEnum> &enums,
484 bool generateQENUM)
485{
486 if (!generateQENUM) {
487 m_stream << " // You need to add this enum as well as Q_ENUM to your" << Qt::endl;
488 m_stream << " // QObject class in order to use .rep enums over QtRO for" << Qt::endl;
489 m_stream << " // non-repc generated QObjects." << Qt::endl;
490 }
491
492 for (const ASTEnum &en : enums) {
493 m_stream << " enum " << (en.isScoped ? "class " : "") << en.name
494 << (en.type.isEmpty() ? "" : " : ") << en.type << " {\n";
495 for (const ASTEnumParam &p : en.params)
496 m_stream << " " << p.name << " = " << p.value << ",\n";
497
498 m_stream << " };\n";
499
500 if (generateQENUM)
501 m_stream << " Q_ENUM(" << en.name << ")\n";
502 }
503}
504
505void RepCodeGenerator::generateEnumGadget(const ASTEnum &en, const QString &className)
506{
507 m_stream << "class " << className << "\n"
508 "{\n"
509 " Q_GADGET\n";
510 if (en.isScoped)
511 m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
512 m_stream << " " << className << "();\n"
513 "\n"
514 "public:\n";
515
516 auto enums = QList<ASTEnum>() << en;
517 generateDeclarationsForEnums(enums);
518 if (en.flagIndex >= 0) {
519 auto flag = m_ast.flags.at(en.flagIndex);
520 m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
521 m_stream << " Q_FLAG(" << flag.name << ")\n";
522 m_stream << "};\n\n";
523 m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name << ")\n\n";
524 } else {
525 m_stream << "};\n\n";
526 }
527}
528
529QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &metaTypes)
530{
531 QString out;
532 const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<");
533 const QString lineEnding = QStringLiteral(">();\n");
534 for (const QString &metaType : metaTypes) {
535 if (isBuiltinType(type: metaType))
536 continue;
537
538 out += qRegisterMetaType;
539 out += metaType;
540 out += lineEnding;
541 }
542 return out;
543}
544
545QString RepCodeGenerator::generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes)
546{
547 QString out;
548 if (!metaTypes.isEmpty())
549 out += QLatin1String(" qRegisterMetaType<QRemoteObjectPendingCall>();\n");
550 const QString qRegisterMetaType =
551 QStringLiteral(" qRegisterMetaType<QRemoteObjectPendingReply<%1>>();\n");
552 const QString qRegisterConverterConditional =
553 QStringLiteral(" if (!QMetaType::hasRegisteredConverterFunction<"
554 "QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>())\n");
555 const QString qRegisterConverter =
556 QStringLiteral(" QMetaType::registerConverter<QRemoteObjectPendingReply<%1>"
557 ", QRemoteObjectPendingCall>();\n");
558 for (const QString &metaType : metaTypes) {
559 out += qRegisterMetaType.arg(a: metaType);
560 out += qRegisterConverterConditional.arg(a: metaType);
561 out += qRegisterConverter.arg(a: metaType);
562 }
563 return out;
564}
565
566void RepCodeGenerator::generateClass(Mode mode, const ASTClass &astClass,
567 const QString &metaTypeRegistrationCode)
568{
569 const QString className = (astClass.name + (mode == REPLICA ?
570 QStringLiteral("Replica") : mode == SOURCE ?
571 QStringLiteral("Source") : QStringLiteral("SimpleSource")));
572 if (mode == REPLICA)
573 m_stream << "class " << className << " : public QRemoteObjectReplica" << Qt::endl;
574 else if (mode == SIMPLE_SOURCE)
575 m_stream << "class " << className << " : public " << astClass.name << "Source"
576 << Qt::endl;
577 else
578 m_stream << "class " << className << " : public QObject" << Qt::endl;
579
580 m_stream << "{\n";
581 m_stream << " Q_OBJECT\n";
582 if (hasScopedEnum(astClass)) // See https://bugreports.qt.io/browse/QTBUG-73360
583 m_stream << " Q_CLASSINFO(\"RegisterEnumClassesUnscoped\", \"false\")\n";
584 if (mode != SIMPLE_SOURCE) {
585 m_stream << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_TYPE, \"" << astClass.name
586 << "\")" << Qt::endl;
587 m_stream << " Q_CLASSINFO(QCLASSINFO_REMOTEOBJECT_SIGNATURE, \""
588 << QLatin1String(classSignature(astClass)) << "\")" << Qt::endl;
589 for (int i = 0; i < astClass.modelMetadata.size(); i++) {
590 const auto model = astClass.modelMetadata.at(i);
591 const auto modelName = astClass.properties.at(model.propertyIndex).name;
592 if (!model.roles.isEmpty()) {
593 QStringList list;
594 for (auto role : model.roles)
595 list << role.name;
596 m_stream << QString::fromLatin1(ba: " Q_CLASSINFO(\"%1_ROLES\", \"%2\")")
597 .arg(modelName.toUpper(), list.join(sep: QChar::fromLatin1(c: '|')))
598 << Qt::endl;
599 }
600 }
601
602
603 //First output properties
604 for (const ASTProperty &property : astClass.properties) {
605 m_stream << " Q_PROPERTY(" << typeForMode(property, mode) << " " << property.name
606 << " READ " << property.name;
607 if (property.modifier == ASTProperty::Constant) {
608 if (mode == REPLICA) // We still need to notify when we get the initial value
609 m_stream << " NOTIFY " << property.name << "Changed";
610 else
611 m_stream << " CONSTANT";
612 } else if (property.modifier == ASTProperty::ReadOnly)
613 m_stream << " NOTIFY " << property.name << "Changed";
614 else if (property.modifier == ASTProperty::ReadWrite)
615 m_stream << " WRITE set" << cap(property.name) << " NOTIFY " << property.name
616 << "Changed";
617 else if (property.modifier == ASTProperty::ReadPush ||
618 property.modifier == ASTProperty::SourceOnlySetter) {
619 if (mode == REPLICA) // The setter slot isn't known to the PROP
620 m_stream << " NOTIFY " << property.name << "Changed";
621 else // The Source can use the setter, since non-asynchronous
622 m_stream << " WRITE set" << cap(property.name) << " NOTIFY "
623 << property.name << "Changed";
624 }
625 m_stream << ")" << Qt::endl;
626 }
627
628 if (!astClass.enums.isEmpty()) {
629 m_stream << "" << Qt::endl;
630 m_stream << "public:" << Qt::endl;
631 generateDeclarationsForEnums(astClass.enums);
632 for (const auto &flag : astClass.flags) {
633 m_stream << " Q_DECLARE_FLAGS(" << flag.name << ", " << flag._enum << ")\n";
634 m_stream << " Q_FLAG(" << flag.name << ")\n";
635 }
636 }
637 }
638
639 m_stream << "" << Qt::endl;
640 m_stream << "public:" << Qt::endl;
641
642 if (mode == REPLICA) {
643 m_stream << " " << className << "() : QRemoteObjectReplica() { initialize(); }"
644 << Qt::endl;
645 m_stream << " static void registerMetatypes()" << Qt::endl;
646 m_stream << " {" << Qt::endl;
647 m_stream << " static bool initialized = false;" << Qt::endl;
648 m_stream << " if (initialized)" << Qt::endl;
649 m_stream << " return;" << Qt::endl;
650 m_stream << " initialized = true;" << Qt::endl;
651
652 if (!metaTypeRegistrationCode.isEmpty())
653 m_stream << metaTypeRegistrationCode << Qt::endl;
654
655 m_stream << " }" << Qt::endl;
656
657 if (astClass.hasPointerObjects())
658 {
659 m_stream << " void setNode(QRemoteObjectNode *node) override" << Qt::endl;
660 m_stream << " {" << Qt::endl;
661 m_stream << " QRemoteObjectReplica::setNode(node);" << Qt::endl;
662 for (int index = 0; index < astClass.properties.size(); ++index) {
663 const ASTProperty &property = astClass.properties.at(index);
664 if (!property.isPointer)
665 continue;
666 const QString acquireName = astClass.name + QLatin1String("::") + property.name;
667 if (astClass.subClassPropertyIndices.contains(index))
668 m_stream << QString::fromLatin1(ba: " setChild(%1, QVariant::fromValue("
669 "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
670 ".arg(u\"%3\"_s))));")
671 .arg(QString::number(index), property.type, acquireName)
672 << Qt::endl;
673 else
674 m_stream << QString::fromLatin1(ba: " setChild(%1, QVariant::fromValue("
675 "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
676 ".arg(u\"%2\"_s))));")
677 .arg(args: QString::number(index), args: acquireName) << Qt::endl;
678 m_stream << " Q_EMIT " << property.name << "Changed(" << property.name
679 << "()" << ");" << Qt::endl;
680
681 }
682 m_stream << " }" << Qt::endl;
683 }
684 m_stream << "" << Qt::endl;
685 m_stream << "private:" << Qt::endl;
686 m_stream << " " << className
687 << "(QRemoteObjectNode *node, const QString &name = QString())" << Qt::endl;
688 m_stream << " : QRemoteObjectReplica(ConstructWithNode)" << Qt::endl;
689 m_stream << " {" << Qt::endl;
690 m_stream << " initializeNode(node, name);" << Qt::endl;
691 for (int index = 0; index < astClass.properties.size(); ++index) {
692 const ASTProperty &property = astClass.properties.at(index);
693 if (!property.isPointer)
694 continue;
695 const QString acquireName = astClass.name + QLatin1String("::") + property.name;
696 if (astClass.subClassPropertyIndices.contains(index))
697 m_stream << QString::fromLatin1(ba: " setChild(%1, QVariant::fromValue("
698 "node->acquire<%2Replica>(QRemoteObjectStringLiterals::CLASS()"
699 ".arg(u\"%3\"_s))));")
700 .arg(QString::number(index), property.type, acquireName) << Qt::endl;
701 else
702 m_stream << QString::fromLatin1(ba: " setChild(%1, QVariant::fromValue("
703 "node->acquireModel(QRemoteObjectStringLiterals::MODEL()"
704 ".arg(u\"%2\"_s))));")
705 .arg(args: QString::number(index), args: acquireName) << Qt::endl;
706 }
707 m_stream << " }" << Qt::endl;
708
709 m_stream << "" << Qt::endl;
710
711 m_stream << " void initialize() override" << Qt::endl;
712 m_stream << " {" << Qt::endl;
713 m_stream << " " << className << "::registerMetatypes();" << Qt::endl;
714 m_stream << " QVariantList properties;" << Qt::endl;
715 m_stream << " properties.reserve(" << astClass.properties.size() << ");"
716 << Qt::endl;
717 for (const ASTProperty &property : astClass.properties) {
718 if (property.isPointer)
719 m_stream << " properties << QVariant::fromValue(("
720 << typeForMode(property, mode) << ")" << property.defaultValue
721 << ");" << Qt::endl;
722 else
723 m_stream << " properties << QVariant::fromValue("
724 << typeForMode(property, mode) << "(" << property.defaultValue
725 << "));" << Qt::endl;
726 }
727 int nPersisted = 0;
728 if (astClass.hasPersisted) {
729 m_stream << " QVariantList stored = retrieveProperties(QStringLiteral(\""
730 << astClass.name << "\"), \"" << classSignature(astClass) << "\");"
731 << Qt::endl;
732 m_stream << " if (!stored.isEmpty()) {" << Qt::endl;
733 for (int i = 0; i < astClass.properties.size(); i++) {
734 if (astClass.properties.at(i).persisted) {
735 m_stream << " properties[" << i << "] = stored.at(" << nPersisted
736 << ");" << Qt::endl;
737 nPersisted++;
738 }
739 }
740 m_stream << " }" << Qt::endl;
741 }
742 m_stream << " setProperties(std::move(properties));" << Qt::endl;
743 m_stream << " }" << Qt::endl;
744 } else if (mode == SOURCE) {
745 m_stream << " explicit " << className
746 << "(QObject *parent = nullptr) : QObject(parent)" << Qt::endl;
747 m_stream << " {" << Qt::endl;
748 if (!metaTypeRegistrationCode.isEmpty())
749 m_stream << metaTypeRegistrationCode << Qt::endl;
750 m_stream << " }" << Qt::endl;
751 } else {
752 QList<int> constIndices;
753 for (int index = 0; index < astClass.properties.size(); ++index) {
754 const ASTProperty &property = astClass.properties.at(index);
755 if (property.modifier == ASTProperty::Constant)
756 constIndices.append(t: index);
757 }
758 if (constIndices.isEmpty()) {
759 m_stream << " explicit " << className << "(QObject *parent = nullptr) : "
760 << astClass.name << "Source(parent)" << Qt::endl;
761 } else {
762 QStringList parameters;
763 for (int index : constIndices) {
764 const ASTProperty &property = astClass.properties.at(index);
765 parameters.append(QString::fromLatin1("%1 %2 = %3")
766 .arg(typeForMode(property, SOURCE), property.name,
767 property.defaultValue));
768 }
769 parameters.append(QStringLiteral("QObject *parent = nullptr"));
770 m_stream << " explicit " << className << "("
771 << parameters.join(QStringLiteral(", ")) << ") : " << astClass.name
772 << "Source(parent)" << Qt::endl;
773 }
774 for (const ASTProperty &property : astClass.properties) {
775 if (property.modifier == ASTProperty::Constant)
776 m_stream << " , m_" << property.name << "(" << property.name << ")"
777 << Qt::endl;
778 else
779 m_stream << " , m_" << property.name << "(" << property.defaultValue << ")"
780 << Qt::endl;
781 }
782 m_stream << " {" << Qt::endl;
783 m_stream << " }" << Qt::endl;
784 }
785
786 m_stream << "" << Qt::endl;
787 m_stream << "public:" << Qt::endl;
788
789 if (mode == REPLICA && astClass.hasPersisted) {
790 m_stream << " ~" << className << "() override {" << Qt::endl;
791 m_stream << " QVariantList persisted;" << Qt::endl;
792 for (int i = 0; i < astClass.properties.size(); i++) {
793 if (astClass.properties.at(i).persisted) {
794 m_stream << " persisted << propAsVariant(" << i << ");" << Qt::endl;
795 }
796 }
797 m_stream << " persistProperties(QStringLiteral(\"" << astClass.name << "\"), \""
798 << classSignature(astClass) << "\", persisted);" << Qt::endl;
799 m_stream << " }" << Qt::endl;
800 } else {
801 m_stream << " ~" << className << "() override = default;" << Qt::endl;
802 }
803 m_stream << "" << Qt::endl;
804
805 //Next output getter/setter
806 if (mode == REPLICA) {
807 int i = 0;
808 for (const ASTProperty &property : astClass.properties) {
809 auto type = typeForMode(property, mode);
810 if (type == QLatin1String("QVariant")) {
811 m_stream << " " << type << " " << property.name << "() const" << Qt::endl;
812 m_stream << " {" << Qt::endl;
813 m_stream << " return propAsVariant(" << i << ");" << Qt::endl;
814 m_stream << " }" << Qt::endl;
815 } else {
816 m_stream << " " << type << " " << property.name << "() const" << Qt::endl;
817 m_stream << " {" << Qt::endl;
818 m_stream << " const QVariant variant = propAsVariant(" << i << ");"
819 << Qt::endl;
820 m_stream << " if (!variant.canConvert<" << type << ">()) {" << Qt::endl;
821 m_stream << " qWarning() << \"QtRO cannot convert the property "
822 << property.name << " to type " << type << "\";" << Qt::endl;
823 m_stream << " }" << Qt::endl;
824 m_stream << " return variant.value<" << type << " >();" << Qt::endl;
825 m_stream << " }" << Qt::endl;
826 }
827 i++;
828 if (property.modifier == ASTProperty::ReadWrite) {
829 m_stream << "" << Qt::endl;
830 m_stream << " void set" << cap(property.name) << "(" << property.type << " "
831 << property.name << ")" << Qt::endl;
832 m_stream << " {" << Qt::endl;
833 m_stream << " static int __repc_index = " << className
834 << "::staticMetaObject.indexOfProperty(\"" << property.name << "\");"
835 << Qt::endl;
836 m_stream << " QVariantList __repc_args;" << Qt::endl;
837 m_stream << " __repc_args << QVariant::fromValue(" << property.name << ");"
838 << Qt::endl;
839 m_stream << " send(QMetaObject::WriteProperty, __repc_index, __repc_args);"
840 << Qt::endl;
841 m_stream << " }" << Qt::endl;
842 }
843 m_stream << "" << Qt::endl;
844 }
845 } else if (mode == SOURCE) {
846 for (const ASTProperty &property : astClass.properties)
847 m_stream << " virtual " << typeForMode(property, mode) << " " << property.name
848 << "() const = 0;" << Qt::endl;
849 for (const ASTProperty &property : astClass.properties) {
850 if (property.modifier == ASTProperty::ReadWrite ||
851 property.modifier == ASTProperty::ReadPush ||
852 property.modifier == ASTProperty::SourceOnlySetter)
853 m_stream << " virtual void set" << cap(property.name) << "("
854 << typeForMode(property, mode) << " " << property.name << ") = 0;"
855 << Qt::endl;
856 }
857 } else {
858 for (const ASTProperty &property : astClass.properties)
859 m_stream << " " << typeForMode(property, mode) << " " << property.name
860 << "() const override { return m_"
861 << property.name << "; }" << Qt::endl;
862 for (const ASTProperty &property : astClass.properties) {
863 if (property.modifier == ASTProperty::ReadWrite ||
864 property.modifier == ASTProperty::ReadPush ||
865 property.modifier == ASTProperty::SourceOnlySetter) {
866 generateSimpleSetter(property);
867 }
868 }
869 }
870
871 if (mode != SIMPLE_SOURCE) {
872 //Next output property signals
873 if (!astClass.properties.isEmpty() || !astClass.signalsList.isEmpty()) {
874 m_stream << "" << Qt::endl;
875 m_stream << "Q_SIGNALS:" << Qt::endl;
876 for (const ASTProperty &property : astClass.properties) {
877 if (property.modifier != ASTProperty::Constant)
878 m_stream
879 << " void " << property.name << "Changed("
880 << fullyQualifiedName(astClass, className, typeForMode(property, mode))
881 << " " << property.name << ");" << Qt::endl;
882 }
883
884 const auto signalsList = transformEnumParams(astClass, astClass.signalsList,
885 className);
886 for (const ASTFunction &signal : signalsList)
887 m_stream << " void " << signal.name << "(" << signal.paramsAsString() << ");"
888 << Qt::endl;
889
890 // CONSTANT source properties still need an onChanged signal on the Replica side to
891 // update (once) when the value is initialized. Put these last, so they don't mess
892 // up the signal index order
893 for (const ASTProperty &property : astClass.properties) {
894 if (mode == REPLICA && property.modifier == ASTProperty::Constant)
895 m_stream
896 << " void " << property.name << "Changed("
897 << fullyQualifiedName(astClass, className, typeForMode(property, mode))
898 << " " << property.name << ");" << Qt::endl;
899 }
900 }
901 bool hasWriteSlots = false;
902 for (const ASTProperty &property : astClass.properties) {
903 if (property.modifier == ASTProperty::ReadPush) {
904 hasWriteSlots = true;
905 break;
906 }
907 }
908 if (hasWriteSlots || !astClass.slotsList.isEmpty()) {
909 m_stream << "" << Qt::endl;
910 m_stream << "public Q_SLOTS:" << Qt::endl;
911 for (const ASTProperty &property : astClass.properties) {
912 if (property.modifier == ASTProperty::ReadPush) {
913 const auto type = fullyQualifiedName(astClass, className, property.type);
914 if (mode != REPLICA) {
915 m_stream << " virtual void push" << cap(property.name) << "(" << type
916 << " " << property.name << ")" << Qt::endl;
917 m_stream << " {" << Qt::endl;
918 m_stream << " set" << cap(property.name) << "(" << property.name
919 << ");" << Qt::endl;
920 m_stream << " }" << Qt::endl;
921 } else {
922 m_stream << " void push" << cap(property.name) << "(" << type << " "
923 << property.name << ")" << Qt::endl;
924 m_stream << " {" << Qt::endl;
925 m_stream << " static int __repc_index = " << className
926 << "::staticMetaObject.indexOfSlot(\"push" << cap(property.name)
927 << "(" << type << ")\");" << Qt::endl;
928 m_stream << " QVariantList __repc_args;" << Qt::endl;
929 m_stream << " __repc_args << QVariant::fromValue(" << property.name
930 << ");" << Qt::endl;
931 m_stream << " send(QMetaObject::InvokeMetaMethod, __repc_index,"
932 << " __repc_args);" << Qt::endl;
933 m_stream << " }" << Qt::endl;
934 }
935 }
936 }
937 const auto slotsList = transformEnumParams(astClass, astClass.slotsList, className);
938 for (const ASTFunction &slot : slotsList) {
939 const auto returnType = fullyQualifiedName(astClass, className, slot.returnType);
940 if (mode != REPLICA) {
941 m_stream << " virtual " << returnType << " " << slot.name << "("
942 << slot.paramsAsString() << ") = 0;" << Qt::endl;
943 } else {
944 // TODO: Discuss whether it is a good idea to special-case for void here,
945 const bool isVoid = slot.returnType == QStringLiteral("void");
946
947 if (isVoid)
948 m_stream << " void " << slot.name << "(" << slot.paramsAsString()
949 << ")" << Qt::endl;
950 else
951 m_stream << " QRemoteObjectPendingReply<" << returnType << "> "
952 << slot.name << "(" << slot.paramsAsString()<< ")" << Qt::endl;
953 m_stream << " {" << Qt::endl;
954 m_stream << " static int __repc_index = " << className
955 << "::staticMetaObject.indexOfSlot(\"" << slot.name << "("
956 << slot.paramsAsString(ASTFunction::Normalized) << ")\");"
957 << Qt::endl;
958 m_stream << " QVariantList __repc_args;" << Qt::endl;
959 const auto &paramNames = slot.paramNames();
960 if (!paramNames.isEmpty()) {
961 m_stream << " __repc_args" << Qt::endl;
962 for (const QString &name : paramNames)
963 m_stream << " << " << "QVariant::fromValue(" << name << ")"
964 << Qt::endl;
965 m_stream << " ;" << Qt::endl;
966 }
967 if (isVoid)
968 m_stream << " send(QMetaObject::InvokeMetaMethod, __repc_index,"
969 << " __repc_args);" << Qt::endl;
970 else
971 m_stream << " return QRemoteObjectPendingReply<" << returnType
972 << ">(sendWithReply(QMetaObject::InvokeMetaMethod, __repc_index,"
973 << " __repc_args));" << Qt::endl;
974 m_stream << " }" << Qt::endl;
975 }
976 }
977 }
978 } else {
979 if (!astClass.properties.isEmpty()) {
980 bool addProtected = true;
981 for (const ASTProperty &property : astClass.properties) {
982 if (property.modifier == ASTProperty::ReadOnly) {
983 if (addProtected) {
984 m_stream << "" << Qt::endl;
985 m_stream << "protected:" << Qt::endl;
986 addProtected = false;
987 }
988 generateSimpleSetter(property, false);
989 }
990 }
991 }
992 }
993
994 m_stream << "" << Qt::endl;
995 m_stream << "private:" << Qt::endl;
996
997 //Next output data members
998 if (mode == SIMPLE_SOURCE) {
999 for (const ASTProperty &property : astClass.properties)
1000 m_stream << " " << typeForMode(property, SOURCE) << " " << "m_" << property.name
1001 << ";" << Qt::endl;
1002 }
1003
1004 if (mode != SIMPLE_SOURCE)
1005 m_stream << " friend class QT_PREPEND_NAMESPACE(QRemoteObjectNode);" << Qt::endl;
1006
1007 m_stream << "};\n\n";
1008 if (mode != SIMPLE_SOURCE) {
1009 for (const ASTFlag &flag : astClass.flags)
1010 m_stream << "Q_DECLARE_OPERATORS_FOR_FLAGS(" << className << "::" << flag.name
1011 << ")\n\n";
1012 }
1013}
1014
1015void RepCodeGenerator::generateSourceAPI(const ASTClass &astClass)
1016{
1017 const QString className = astClass.name + QStringLiteral("SourceAPI");
1018 m_stream << QStringLiteral("template <class ObjectType>") << Qt::endl;
1019 m_stream << QString::fromLatin1(ba: "struct %1 : public SourceApiMap").arg(a: className) << Qt::endl;
1020 m_stream << QStringLiteral("{") << Qt::endl;
1021 if (!astClass.enums.isEmpty()) {
1022 // Include enum definition in SourceAPI
1023 generateDeclarationsForEnums(astClass.enums, false);
1024 }
1025 for (const auto &flag : astClass.flags)
1026 m_stream << QLatin1String(" typedef QFlags<typename ObjectType::%1> %2;")
1027 .arg(flag._enum, flag.name) << Qt::endl;
1028 m_stream << QString::fromLatin1(ba: " %1(ObjectType *object, const QString &name = "
1029 "QLatin1String(\"%2\"))").arg(className, astClass.name)
1030 << Qt::endl;
1031 m_stream << QStringLiteral(" : SourceApiMap(), m_name(name)") << Qt::endl;
1032 m_stream << QStringLiteral(" {") << Qt::endl;
1033 if (!astClass.hasPointerObjects())
1034 m_stream << QStringLiteral(" Q_UNUSED(object)") << Qt::endl;
1035
1036 const auto enumCount = astClass.enums.size();
1037 const auto totalCount = enumCount + astClass.flags.size();
1038 for (int i : astClass.subClassPropertyIndices) {
1039 const ASTProperty &child = astClass.properties.at(i);
1040 m_stream << QString::fromLatin1(" using %1_type_t = typename std::remove_pointer<"
1041 "decltype(object->%1())>::type;")
1042 .arg(child.name) << Qt::endl;
1043 }
1044 m_stream << QString::fromLatin1(ba: " m_enums[0] = %1;").arg(totalCount) << Qt::endl;
1045 for (qsizetype i = 0; i < enumCount; ++i) {
1046 const auto enumerator = astClass.enums.at(i);
1047 m_stream << QString::fromLatin1(ba: " m_enums[%1] = ObjectType::staticMetaObject."
1048 "indexOfEnumerator(\"%2\");")
1049 .arg(a: i+1).arg(enumerator.name) << Qt::endl;
1050 }
1051 for (qsizetype i = enumCount; i < totalCount; ++i) {
1052 const auto flag = astClass.flags.at(i - enumCount);
1053 m_stream << QString::fromLatin1(ba: " m_enums[%1] = ObjectType::staticMetaObject."
1054 "indexOfEnumerator(\"%2\");")
1055 .arg(a: i+1).arg(flag.name) << Qt::endl;
1056 }
1057 const auto propCount = astClass.properties.size();
1058 m_stream << QString::fromLatin1(ba: " m_properties[0] = %1;").arg(propCount) << Qt::endl;
1059 QList<ASTProperty> onChangeProperties;
1060 QList<qsizetype> propertyChangeIndex;
1061 for (qsizetype i = 0; i < propCount; ++i) {
1062 const ASTProperty &prop = astClass.properties.at(i);
1063 const QString propTypeName =
1064 fullyQualifiedName(astClass, QStringLiteral("typename ObjectType"),
1065 typeForMode(prop, SOURCE));
1066 m_stream << QString::fromLatin1(ba: " m_properties[%1] = "
1067 "QtPrivate::qtro_property_index<ObjectType>("
1068 "&ObjectType::%2, static_cast<%3 (QObject::*)()>(nullptr)"
1069 ",\"%2\");")
1070 .arg(QString::number(i+1), prop.name, propTypeName)
1071 << Qt::endl;
1072 if (prop.modifier == prop.ReadWrite) //Make sure we have a setter function
1073 m_stream << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>("
1074 "&ObjectType::set%1, static_cast<void (QObject::*)(%2)>"
1075 "(nullptr));")
1076 .arg(cap(prop.name), propTypeName) << Qt::endl;
1077 if (prop.modifier != prop.Constant) { //Make sure we have an onChange signal
1078 m_stream << QStringLiteral(" QtPrivate::qtro_method_test<ObjectType>("
1079 "&ObjectType::%1Changed, static_cast<void (QObject::*)()>("
1080 "nullptr));")
1081 .arg(prop.name) << Qt::endl;
1082 onChangeProperties << prop;
1083 propertyChangeIndex << i + 1; //m_properties[0] is the count, so index is one higher
1084 }
1085 }
1086 const auto signalCount = astClass.signalsList.size();
1087 const auto changedCount = onChangeProperties.size();
1088 m_stream << QString::fromLatin1(ba: " m_signals[0] = %1;")
1089 .arg(signalCount+onChangeProperties.size()) << Qt::endl;
1090 for (qsizetype i = 0; i < changedCount; ++i)
1091 m_stream
1092 << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index"
1093 "<ObjectType>(&ObjectType::%2Changed, static_cast<void"
1094 "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
1095 "&m_signalArgTypes[%4]);")
1096 .arg(QString::number(i+1), onChangeProperties.at(i).name,
1097 fullyQualifiedName(astClass,
1098 QStringLiteral("typename ObjectType"),
1099 typeForMode(onChangeProperties.at(i),
1100 SOURCE)),
1101 QString::number(i))
1102 << Qt::endl;
1103
1104 QList<ASTFunction> signalsList = transformEnumParams(astClass, astClass.signalsList,
1105 QStringLiteral("typename ObjectType"));
1106 for (qsizetype i = 0; i < signalCount; ++i) {
1107 const ASTFunction &sig = signalsList.at(i);
1108 m_stream << QString::fromLatin1(" m_signals[%1] = QtPrivate::qtro_signal_index"
1109 "<ObjectType>(&ObjectType::%2, static_cast<void "
1110 "(QObject::*)(%3)>(nullptr),m_signalArgCount+%4,"
1111 "&m_signalArgTypes[%4]);")
1112 .arg(QString::number(changedCount+i+1), sig.name,
1113 sig.paramsAsString(ASTFunction::Normalized),
1114 QString::number(changedCount+i))
1115 << Qt::endl;
1116 }
1117 const auto slotCount = astClass.slotsList.size();
1118 QList<ASTProperty> pushProps;
1119 for (const ASTProperty &property : astClass.properties) {
1120 if (property.modifier == ASTProperty::ReadPush)
1121 pushProps << property;
1122 }
1123 const auto pushCount = pushProps.size();
1124 const auto methodCount = slotCount + pushCount;
1125 m_stream << QString::fromLatin1(ba: " m_methods[0] = %1;").arg(methodCount) << Qt::endl;
1126 const QString objType = QStringLiteral("typename ObjectType::");
1127 for (qsizetype i = 0; i < pushCount; ++i) {
1128 const ASTProperty &prop = pushProps.at(i);
1129 const QString propTypeName = fullyQualifiedName(astClass,
1130 QStringLiteral("typename ObjectType"),
1131 prop.type);
1132 m_stream <<
1133 QString::fromLatin1(ba: " m_methods[%1] = QtPrivate::qtro_method_index"
1134 "<ObjectType>(&ObjectType::push%2, static_cast<void "
1135 "(QObject::*)(%3)>(nullptr),\"push%2(%4)\","
1136 "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
1137 .arg(QString::number(i+1), cap(prop.name), propTypeName,
1138 // we don't want "typename ObjectType::" in the signature
1139 QString(propTypeName).remove(s: objType),
1140 QString::number(i))
1141 << Qt::endl;
1142 }
1143
1144 QList<ASTFunction> slotsList = transformEnumParams(astClass, astClass.slotsList,
1145 QStringLiteral("typename ObjectType"));
1146 for (qsizetype i = 0; i < slotCount; ++i) {
1147 const ASTFunction &slot = slotsList.at(i);
1148 const QString params = slot.paramsAsString(ASTFunction::Normalized);
1149 m_stream << QString::fromLatin1(ba: " m_methods[%1] = QtPrivate::qtro_method_index"
1150 "<ObjectType>(&ObjectType::%2, static_cast<void "
1151 "(QObject::*)(%3)>(nullptr),\"%2(%4)\","
1152 "m_methodArgCount+%5,&m_methodArgTypes[%5]);")
1153 .arg(QString::number(i+pushCount+1), slot.name, params,
1154 // we don't want "typename ObjectType::" in the signature
1155 QString(params).remove(s: objType),
1156 QString::number(i+pushCount))
1157 << Qt::endl;
1158 }
1159 for (const auto &model : astClass.modelMetadata) {
1160 const ASTProperty &property = astClass.properties.at(model.propertyIndex);
1161 m_stream << QString::fromLatin1(" m_models << ModelInfo({object->%1(),")
1162 .arg(property.name) << Qt::endl;
1163 m_stream << QString::fromLatin1(" QStringLiteral(\"%1\"),")
1164 .arg(property.name) << Qt::endl;
1165 QStringList list;
1166 if (!model.roles.isEmpty()) {
1167 for (auto role : model.roles)
1168 list << role.name;
1169 }
1170 m_stream <<
1171 QString::fromLatin1(" QByteArrayLiteral(\"%1\")});")
1172 .arg(list.join(QChar::fromLatin1('|'))) << Qt::endl;
1173 }
1174 for (int i : astClass.subClassPropertyIndices) {
1175 const ASTProperty &child = astClass.properties.at(i);
1176 m_stream <<
1177 QString::fromLatin1(" m_subclasses << new %2SourceAPI<%1_type_t>(object->%1(),"
1178 " QStringLiteral(\"%1\"));")
1179 .arg(child.name, child.type) << Qt::endl;
1180 }
1181 m_stream << QStringLiteral(" }") << Qt::endl;
1182 m_stream << QStringLiteral("") << Qt::endl;
1183 m_stream << QString::fromLatin1(ba: " QString name() const override { return m_name; }")
1184 << Qt::endl;
1185 m_stream << QString::fromLatin1(ba: " QString typeName() const override { "
1186 "return QStringLiteral(\"%1\"); }")
1187 .arg(astClass.name) << Qt::endl;
1188 m_stream << QStringLiteral(" int enumCount() const override { return m_enums[0]; }")
1189 << Qt::endl;
1190 m_stream <<
1191 QStringLiteral(" int propertyCount() const override { return m_properties[0]; }")
1192 << Qt::endl;
1193 m_stream << QStringLiteral(" int signalCount() const override { return m_signals[0]; }")
1194 << Qt::endl;
1195 m_stream << QStringLiteral(" int methodCount() const override { return m_methods[0]; }")
1196 << Qt::endl;
1197 m_stream << QStringLiteral(" int sourceEnumIndex(int index) const override") << Qt::endl;
1198 m_stream << QStringLiteral(" {") << Qt::endl;
1199 m_stream << QStringLiteral(" if (index < 0 || index >= m_enums[0]"
1200 " || index + 1 >= int(std::size(m_enums)))")
1201 << Qt::endl;
1202 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1203 m_stream << QStringLiteral(" return m_enums[index+1];") << Qt::endl;
1204 m_stream << QStringLiteral(" }") << Qt::endl;
1205 m_stream << QStringLiteral(" int sourcePropertyIndex(int index) const override")
1206 << Qt::endl;
1207 m_stream << QStringLiteral(" {") << Qt::endl;
1208 m_stream << QStringLiteral(" if (index < 0 || index >= m_properties[0]"
1209 " || index + 1 >= int(std::size(m_properties)))")
1210 << Qt::endl;
1211 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1212 m_stream << QStringLiteral(" return m_properties[index+1];") << Qt::endl;
1213 m_stream << QStringLiteral(" }") << Qt::endl;
1214 m_stream << QStringLiteral(" int sourceSignalIndex(int index) const override") << Qt::endl;
1215 m_stream << QStringLiteral(" {") << Qt::endl;
1216 m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0]"
1217 " || index + 1 >= int(std::size(m_signals)))")
1218 << Qt::endl;
1219 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1220 m_stream << QStringLiteral(" return m_signals[index+1];") << Qt::endl;
1221 m_stream << QStringLiteral(" }") << Qt::endl;
1222 m_stream << QStringLiteral(" int sourceMethodIndex(int index) const override") << Qt::endl;
1223 m_stream << QStringLiteral(" {") << Qt::endl;
1224 m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0]"
1225 " || index + 1 >= int(std::size(m_methods)))")
1226 << Qt::endl;
1227 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1228 m_stream << QStringLiteral(" return m_methods[index+1];") << Qt::endl;
1229 m_stream << QStringLiteral(" }") << Qt::endl;
1230 if (signalCount+changedCount > 0) {
1231 m_stream << QStringLiteral(" int signalParameterCount(int index) const override")
1232 << Qt::endl;
1233 m_stream << QStringLiteral(" {") << Qt::endl;
1234 m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0])") << Qt::endl;
1235 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1236 m_stream << QStringLiteral(" return m_signalArgCount[index];") << Qt::endl;
1237 m_stream << QStringLiteral(" }") << Qt::endl;
1238 m_stream << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) "
1239 "const override") << Qt::endl;
1240 m_stream << QStringLiteral(" {") << Qt::endl;
1241 m_stream << QStringLiteral(" if (sigIndex < 0 || sigIndex >= m_signals[0] || "
1242 "paramIndex < 0 || paramIndex >= m_signalArgCount[sigIndex])")
1243 << Qt::endl;
1244 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1245 m_stream << QStringLiteral(" return m_signalArgTypes[sigIndex][paramIndex];")
1246 << Qt::endl;
1247 m_stream << QStringLiteral(" }") << Qt::endl;
1248 } else {
1249 m_stream << QStringLiteral(" int signalParameterCount(int index) const override "
1250 "{ Q_UNUSED(index) return -1; }") << Qt::endl;
1251 m_stream << QStringLiteral(" int signalParameterType(int sigIndex, int paramIndex) "
1252 "const override") << Qt::endl;
1253 m_stream << QStringLiteral(" { Q_UNUSED(sigIndex) Q_UNUSED(paramIndex) return -1; }")
1254 << Qt::endl;
1255 }
1256 if (methodCount > 0) {
1257 m_stream << QStringLiteral(" int methodParameterCount(int index) const override")
1258 << Qt::endl;
1259 m_stream << QStringLiteral(" {") << Qt::endl;
1260 m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0])") << Qt::endl;
1261 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1262 m_stream << QStringLiteral(" return m_methodArgCount[index];") << Qt::endl;
1263 m_stream << QStringLiteral(" }") << Qt::endl;
1264 m_stream << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) "
1265 "const override") << Qt::endl;
1266 m_stream << QStringLiteral(" {") << Qt::endl;
1267 m_stream <<
1268 QStringLiteral(" if (methodIndex < 0 || methodIndex >= m_methods[0] || "
1269 "paramIndex < 0 || paramIndex >= m_methodArgCount[methodIndex])")
1270 << Qt::endl;
1271 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1272 m_stream << QStringLiteral(" return m_methodArgTypes[methodIndex][paramIndex];")
1273 << Qt::endl;
1274 m_stream << QStringLiteral(" }") << Qt::endl;
1275 } else {
1276 m_stream << QStringLiteral(" int methodParameterCount(int index) const override { "
1277 "Q_UNUSED(index) return -1; }") << Qt::endl;
1278 m_stream << QStringLiteral(" int methodParameterType(int methodIndex, int paramIndex) "
1279 "const override") << Qt::endl;
1280 m_stream <<
1281 QStringLiteral(" { Q_UNUSED(methodIndex) Q_UNUSED(paramIndex) return -1; }")
1282 << Qt::endl;
1283 }
1284 //propertyIndexFromSignal method
1285 m_stream << QStringLiteral(" int propertyIndexFromSignal(int index) const override")
1286 << Qt::endl;
1287 m_stream << QStringLiteral(" {") << Qt::endl;
1288 if (!propertyChangeIndex.isEmpty()) {
1289 m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
1290 for (int i = 0; i < propertyChangeIndex.size(); ++i)
1291 m_stream << QString::fromLatin1(ba: " case %1: return m_properties[%2];")
1292 .arg(a: i).arg(a: propertyChangeIndex.at(i)) << Qt::endl;
1293 m_stream << QStringLiteral(" }") << Qt::endl;
1294 } else
1295 m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
1296 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1297 m_stream << QStringLiteral(" }") << Qt::endl;
1298 //propertyRawIndexFromSignal method
1299 m_stream << QStringLiteral(" int propertyRawIndexFromSignal(int index) const override")
1300 << Qt::endl;
1301 m_stream << QStringLiteral(" {") << Qt::endl;
1302 if (!propertyChangeIndex.isEmpty()) {
1303 m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
1304 for (int i = 0; i < propertyChangeIndex.size(); ++i)
1305 m_stream << QString::fromLatin1(ba: " case %1: return %2;").arg(a: i)
1306 .arg(a: propertyChangeIndex.at(i)-1) << Qt::endl;
1307 m_stream << QStringLiteral(" }") << Qt::endl;
1308 } else
1309 m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
1310 m_stream << QStringLiteral(" return -1;") << Qt::endl;
1311 m_stream << QStringLiteral(" }") << Qt::endl;
1312
1313 //signalSignature method
1314 m_stream << QStringLiteral(" const QByteArray signalSignature(int index) const override")
1315 << Qt::endl;
1316 m_stream << QStringLiteral(" {") << Qt::endl;
1317 if (signalCount+changedCount > 0) {
1318 m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
1319 for (int i = 0; i < changedCount; ++i) {
1320 const ASTProperty &prop = onChangeProperties.at(i);
1321 if (isClassEnum(astClass, prop.type))
1322 m_stream <<
1323 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"%2"
1324 "Changed($1)\").replace(\"$1\", "
1325 "QtPrivate::qtro_enum_signature<ObjectType>(\"%3\"));")
1326 .arg(QString::number(i), prop.name, prop.type)
1327 << Qt::endl;
1328 else
1329 m_stream <<
1330 QString::fromLatin1(" case %1: return QByteArrayLiteral(\"%2"
1331 "Changed(%3)\");")
1332 .arg(QString::number(i), prop.name,
1333 typeForMode(prop, SOURCE))
1334 << Qt::endl;
1335 }
1336 for (int i = 0; i < signalCount; ++i)
1337 {
1338 const ASTFunction &sig = astClass.signalsList.at(i);
1339 auto paramsAsString = sig.paramsAsString(ASTFunction::Normalized);
1340 const auto paramsAsList = paramsAsString.split(QLatin1String(","));
1341 int enumCount = 0;
1342 QString enumString;
1343 for (int j = 0; j < paramsAsList.size(); j++) {
1344 auto const p = paramsAsList.at(j);
1345 if (isClassEnum(astClass, p)) {
1346 paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
1347 QStringLiteral("$%1").arg(a: enumCount));
1348 enumString.append(QString::fromLatin1(ba: ".replace(\"$%1\", QtPrivate::"
1349 "qtro_enum_signature<ObjectType>"
1350 "(\"%2\"))")
1351 .arg(a: enumCount++)
1352 .arg(paramsAsList.at(j)));
1353 }
1354 }
1355 m_stream <<
1356 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"%2(%3)\")%4;")
1357 .arg(QString::number(i+changedCount), sig.name,
1358 paramsAsString, enumString) << Qt::endl;
1359 }
1360 m_stream << QStringLiteral(" }") << Qt::endl;
1361 } else
1362 m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
1363 m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
1364 m_stream << QStringLiteral(" }") << Qt::endl;
1365
1366 //signalParameterNames method
1367 m_stream <<
1368 QStringLiteral(" QByteArrayList signalParameterNames(int index) const override")
1369 << Qt::endl;
1370 m_stream << QStringLiteral(" {") << Qt::endl;
1371 m_stream << QStringLiteral(" if (index < 0 || index >= m_signals[0]"
1372 " || index + 1 >= int(std::size(m_signals)))")
1373 << Qt::endl;
1374 m_stream << QStringLiteral(" return QByteArrayList();") << Qt::endl;
1375 m_stream << QStringLiteral(" return ObjectType::staticMetaObject.method(m_signals["
1376 "index + 1]).parameterNames();") << Qt::endl;
1377 m_stream << QStringLiteral(" }") << Qt::endl;
1378
1379 //methodSignature method
1380 m_stream << QStringLiteral(" const QByteArray methodSignature(int index) const override")
1381 << Qt::endl;
1382 m_stream << QStringLiteral(" {") << Qt::endl;
1383 if (methodCount > 0) {
1384 m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
1385 for (int i = 0; i < pushCount; ++i)
1386 {
1387 const ASTProperty &prop = pushProps.at(i);
1388 if (isClassEnum(astClass, prop.type))
1389 m_stream << QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"push"
1390 "%2($1)\").replace(\"$1\", QtPrivate::"
1391 "qtro_enum_signature<ObjectType>(\"%3\"));")
1392 .arg(QString::number(i), prop.name, prop.type)
1393 << Qt::endl;
1394 else
1395 m_stream <<
1396 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"push"
1397 "%2(%3)\");")
1398 .arg(QString::number(i), cap(prop.name), prop.type)
1399 << Qt::endl;
1400 }
1401 for (int i = 0; i < slotCount; ++i)
1402 {
1403 const ASTFunction &slot = astClass.slotsList.at(i);
1404 auto paramsAsString = slot.paramsAsString(ASTFunction::Normalized);
1405 const auto paramsAsList = paramsAsString.split(QLatin1String(","));
1406 int enumCount = 0;
1407 QString enumString;
1408 for (int j = 0; j < paramsAsList.size(); j++) {
1409 auto const p = paramsAsList.at(j);
1410 if (isClassEnum(astClass, p)) {
1411 paramsAsString.replace(paramsAsString.indexOf(p), p.size(),
1412 QStringLiteral("$%1").arg(a: enumCount));
1413 enumString.append(QString::fromLatin1(ba: ".replace(\"$%1\", QtPrivate::"
1414 "qtro_enum_signature<ObjectType>"
1415 "(\"%2\"))")
1416 .arg(a: enumCount++)
1417 .arg(paramsAsList.at(j)));
1418 }
1419 }
1420 m_stream << QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"%2(%3)"
1421 "\")%4;")
1422 .arg(QString::number(i+pushCount), slot.name,
1423 paramsAsString, enumString) << Qt::endl;
1424 }
1425 m_stream << QStringLiteral(" }") << Qt::endl;
1426 } else
1427 m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
1428 m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
1429 m_stream << QStringLiteral(" }") << Qt::endl;
1430
1431 //methodType method
1432 m_stream << QStringLiteral(" QMetaMethod::MethodType methodType(int) const override")
1433 << Qt::endl;
1434 m_stream << QStringLiteral(" {") << Qt::endl;
1435 m_stream << QStringLiteral(" return QMetaMethod::Slot;") << Qt::endl;
1436 m_stream << QStringLiteral(" }") << Qt::endl;
1437
1438 //methodParameterNames method
1439 m_stream <<
1440 QStringLiteral(" QByteArrayList methodParameterNames(int index) const override")
1441 << Qt::endl;
1442 m_stream << QStringLiteral(" {") << Qt::endl;
1443 m_stream << QStringLiteral(" if (index < 0 || index >= m_methods[0]"
1444 " || index + 1 >= int(std::size(m_methods)))")
1445 << Qt::endl;
1446 m_stream << QStringLiteral(" return QByteArrayList();") << Qt::endl;
1447 m_stream << QStringLiteral(" return ObjectType::staticMetaObject.method(m_methods["
1448 "index + 1]).parameterNames();") << Qt::endl;
1449 m_stream << QStringLiteral(" }") << Qt::endl;
1450
1451 //typeName method
1452 m_stream << QStringLiteral(" const QByteArray typeName(int index) const override")
1453 << Qt::endl;
1454 m_stream << QStringLiteral(" {") << Qt::endl;
1455 if (methodCount > 0) {
1456 m_stream << QStringLiteral(" switch (index) {") << Qt::endl;
1457 for (int i = 0; i < pushCount; ++i)
1458 {
1459 m_stream <<
1460 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"void\");")
1461 .arg(a: QString::number(i)) << Qt::endl;
1462 }
1463 for (int i = 0; i < slotCount; ++i)
1464 {
1465 const ASTFunction &slot = astClass.slotsList.at(i);
1466 if (isClassEnum(astClass, slot.returnType))
1467 m_stream <<
1468 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"$1\")"
1469 ".replace(\"$1\", QtPrivate::qtro_enum_signature"
1470 "<ObjectType>(\"%2\"));")
1471 .arg(QString::number(i+pushCount), slot.returnType)
1472 << Qt::endl;
1473 else
1474 m_stream <<
1475 QString::fromLatin1(ba: " case %1: return QByteArrayLiteral(\"%2\");")
1476 .arg(QString::number(i+pushCount), slot.returnType) << Qt::endl;
1477 }
1478 m_stream << QStringLiteral(" }") << Qt::endl;
1479 } else
1480 m_stream << QStringLiteral(" Q_UNUSED(index)") << Qt::endl;
1481 m_stream << QStringLiteral(" return QByteArrayLiteral(\"\");") << Qt::endl;
1482 m_stream << QStringLiteral(" }") << Qt::endl;
1483
1484 //objectSignature method
1485 m_stream <<
1486 QStringLiteral(" QByteArray objectSignature() const override { return QByteArray{\"")
1487 << QLatin1String(classSignature(astClass))
1488 << QStringLiteral("\"}; }") << Qt::endl;
1489
1490 m_stream << QStringLiteral("") << Qt::endl;
1491 m_stream << QString::fromLatin1(ba: " int m_enums[%1];").arg(totalCount + 1) << Qt::endl;
1492 m_stream << QString::fromLatin1(ba: " int m_properties[%1];").arg(propCount+1) << Qt::endl;
1493 m_stream << QString::fromLatin1(ba: " int m_signals[%1];").arg(signalCount+changedCount+1)
1494 << Qt::endl;
1495 m_stream << QString::fromLatin1(ba: " int m_methods[%1];").arg(methodCount+1) << Qt::endl;
1496 m_stream << QString::fromLatin1(ba: " const QString m_name;") << Qt::endl;
1497 if (signalCount+changedCount > 0) {
1498 m_stream << QString::fromLatin1(ba: " int m_signalArgCount[%1];")
1499 .arg(signalCount+changedCount) << Qt::endl;
1500 m_stream << QString::fromLatin1(ba: " const int* m_signalArgTypes[%1];")
1501 .arg(signalCount+changedCount) << Qt::endl;
1502 }
1503 if (methodCount > 0) {
1504 m_stream << QString::fromLatin1(ba: " int m_methodArgCount[%1];").arg(methodCount)
1505 << Qt::endl;
1506 m_stream << QString::fromLatin1(ba: " const int* m_methodArgTypes[%1];").arg(methodCount)
1507 << Qt::endl;
1508 }
1509 m_stream << QStringLiteral("};") << Qt::endl;
1510 m_stream << "" << Qt::endl;
1511}
1512
1513QT_END_NAMESPACE
1514

source code of qtremoteobjects/tools/repc/repcodegenerator.cpp