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 | |
11 | using namespace Qt; |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | template <typename C> |
16 | static 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 | |
24 | template <typename C> |
25 | static 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 | |
33 | static QString cap(QString name) |
34 | { |
35 | if (!name.isEmpty()) |
36 | name[0] = name[0].toUpper(); |
37 | return name; |
38 | } |
39 | |
40 | static 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 | |
51 | static 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 | |
62 | static 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 | |
73 | static 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 |
89 | static QList<ASTFunction> (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 | */ |
108 | static 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 | |
116 | RepCodeGenerator::RepCodeGenerator(QIODevice *outputDevice, const AST &ast) |
117 | : m_stream(outputDevice), m_ast(ast) |
118 | { |
119 | } |
120 | |
121 | QByteArray RepCodeGenerator::classSignature(const ASTClass &ac) |
122 | { |
123 | return m_ast.typeSignatures[ac.name]; |
124 | } |
125 | |
126 | void 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 | |
230 | void RepCodeGenerator::(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 | |
277 | static 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 | |
298 | QString 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 | |
304 | QString 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 | |
323 | QString 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 | |
331 | QString 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 | |
353 | QString 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 | |
368 | QString 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 | |
384 | QString 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 | |
404 | void 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 | |
424 | void 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 | |
464 | QString 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 | |
483 | void 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 | |
505 | void 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 | |
529 | QString 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 | |
545 | QString 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 | |
566 | void 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 ¶mNames = 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 | |
1015 | void 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 | |
1513 | QT_END_NAMESPACE |
1514 | |