1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
3// Copyright (C) 2018 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
5
6#include "generator.h"
7#include "cbordevice.h"
8#include "outputrevision.h"
9#include "utils.h"
10#include <QtCore/qmetatype.h>
11#include <QtCore/qjsondocument.h>
12#include <QtCore/qjsonobject.h>
13#include <QtCore/qjsonvalue.h>
14#include <QtCore/qjsonarray.h>
15#include <QtCore/qplugin.h>
16#include <QtCore/qstringview.h>
17
18#include <math.h>
19#include <stdio.h>
20
21#include <private/qmetaobject_p.h> //for the flags.
22#include <private/qplugin_p.h> //for the flags.
23
24QT_BEGIN_NAMESPACE
25
26uint nameToBuiltinType(const QByteArray &name)
27{
28 if (name.isEmpty())
29 return 0;
30
31 uint tp = qMetaTypeTypeInternal(name.constData());
32 return tp < uint(QMetaType::User) ? tp : uint(QMetaType::UnknownType);
33}
34
35/*
36 Returns \c true if the type is a built-in type.
37*/
38bool isBuiltinType(const QByteArray &type)
39 {
40 int id = qMetaTypeTypeInternal(type.constData());
41 if (id == QMetaType::UnknownType)
42 return false;
43 return (id < QMetaType::User);
44}
45
46static const char *metaTypeEnumValueString(int type)
47 {
48#define RETURN_METATYPENAME_STRING(MetaTypeName, MetaTypeId, RealType) \
49 case QMetaType::MetaTypeName: return #MetaTypeName;
50
51 switch (type) {
52QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
53 }
54#undef RETURN_METATYPENAME_STRING
55 return nullptr;
56 }
57
58 Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
59 const QHash<QByteArray, QByteArray> &knownQObjectClasses,
60 const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile,
61 bool requireCompleteTypes)
62 : out(outfile),
63 cdef(classDef),
64 metaTypes(metaTypes),
65 knownQObjectClasses(knownQObjectClasses),
66 knownGadgets(knownGadgets),
67 requireCompleteTypes(requireCompleteTypes)
68 {
69 if (cdef->superclassList.size())
70 purestSuperClass = cdef->superclassList.constFirst().first;
71}
72
73static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i)
74{
75 if (s.at(i) != '\\' || i >= s.size() - 1)
76 return 1;
77 const qsizetype startPos = i;
78 ++i;
79 char ch = s.at(i);
80 if (ch == 'x') {
81 ++i;
82 while (i < s.size() && is_hex_char(s: s.at(i)))
83 ++i;
84 } else if (is_octal_char(s: ch)) {
85 while (i < startPos + 4
86 && i < s.size()
87 && is_octal_char(s: s.at(i))) {
88 ++i;
89 }
90 } else { // single character escape sequence
91 i = qMin(a: i + 1, b: s.size());
92 }
93 return i - startPos;
94}
95
96static inline uint lengthOfEscapedString(const QByteArray &str)
97{
98 int extra = 0;
99 for (int j = 0; j < str.size(); ++j) {
100 if (str.at(i: j) == '\\') {
101 int cnt = lengthOfEscapeSequence(s: str, i: j) - 1;
102 extra += cnt;
103 j += cnt;
104 }
105 }
106 return str.size() - extra;
107}
108
109// Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
110// opening and closing quotes are NOT included (it's up to the caller).
111static void printStringWithIndentation(FILE *out, const QByteArray &s)
112{
113 static constexpr int ColumnWidth = 72;
114 const qsizetype len = s.size();
115 qsizetype idx = 0;
116
117 do {
118 qsizetype spanLen = qMin(a: ColumnWidth - 2, b: len - idx);
119 // don't cut escape sequences at the end of a line
120 const qsizetype backSlashPos = s.lastIndexOf(c: '\\', from: idx + spanLen - 1);
121 if (backSlashPos >= idx) {
122 const qsizetype escapeLen = lengthOfEscapeSequence(s, i: backSlashPos);
123 spanLen = qBound(min: spanLen, val: backSlashPos + escapeLen - idx, max: len - idx);
124 }
125 fprintf(stream: out, format: "\n \"%.*s\"", int(spanLen), s.constData() + idx);
126 idx += spanLen;
127 } while (idx < len);
128}
129
130void Generator::strreg(const QByteArray &s)
131{
132 if (!strings.contains(t: s))
133 strings.append(t: s);
134}
135
136int Generator::stridx(const QByteArray &s)
137{
138 int i = strings.indexOf(t: s);
139 Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
140 return i;
141}
142
143// Returns the sum of all parameters (including return type) for the given
144// \a list of methods. This is needed for calculating the size of the methods'
145// parameter type/name meta-data.
146static int aggregateParameterCount(const QList<FunctionDef> &list)
147{
148 int sum = 0;
149 for (const FunctionDef &def : list)
150 sum += int(def.arguments.size()) + 1; // +1 for return type
151 return sum;
152}
153
154bool Generator::registerableMetaType(const QByteArray &propertyType)
155{
156 if (metaTypes.contains(t: propertyType))
157 return true;
158
159 if (propertyType.endsWith(c: '*')) {
160 QByteArray objectPointerType = propertyType;
161 // The objects container stores class names, such as 'QState', 'QLabel' etc,
162 // not 'QState*', 'QLabel*'. The propertyType does contain the '*', so we need
163 // to chop it to find the class type in the known QObjects list.
164 objectPointerType.chop(n: 1);
165 if (knownQObjectClasses.contains(key: objectPointerType))
166 return true;
167 }
168
169 static const QList<QByteArray> smartPointers = QList<QByteArray>()
170#define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
171 QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
172#undef STREAM_SMART_POINTER
173 ;
174
175 for (const QByteArray &smartPointer : smartPointers) {
176 QByteArray ba = smartPointer + "<";
177 if (propertyType.startsWith(bv: ba) && !propertyType.endsWith(bv: "&"))
178 return knownQObjectClasses.contains(key: propertyType.mid(index: smartPointer.size() + 1, len: propertyType.size() - smartPointer.size() - 1 - 1));
179 }
180
181 static const QList<QByteArray> oneArgTemplates = QList<QByteArray>()
182#define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
183 QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
184#undef STREAM_1ARG_TEMPLATE
185 ;
186 for (const QByteArray &oneArgTemplateType : oneArgTemplates) {
187 QByteArray ba = oneArgTemplateType + "<";
188 if (propertyType.startsWith(bv: ba) && propertyType.endsWith(bv: ">")) {
189 const qsizetype argumentSize = propertyType.size() - oneArgTemplateType.size() - 1
190 // The closing '>'
191 - 1
192 // templates inside templates have an extra whitespace char to strip.
193 - (propertyType.at(i: propertyType.size() - 2) == ' ' ? 1 : 0 );
194 const QByteArray templateArg = propertyType.mid(index: oneArgTemplateType.size() + 1, len: argumentSize);
195 return isBuiltinType(type: templateArg) || registerableMetaType(propertyType: templateArg);
196 }
197 }
198 return false;
199}
200
201/* returns \c true if name and qualifiedName refers to the same name.
202 * If qualified name is "A::B::C", it returns \c true for "C", "B::C" or "A::B::C" */
203static bool qualifiedNameEquals(const QByteArray &qualifiedName, const QByteArray &name)
204{
205 if (qualifiedName == name)
206 return true;
207 const qsizetype index = qualifiedName.indexOf(bv: "::");
208 if (index == -1)
209 return false;
210 return qualifiedNameEquals(qualifiedName: qualifiedName.mid(index: index+2), name);
211}
212
213static QByteArray generateQualifiedClassNameIdentifier(const QByteArray &identifier)
214{
215 QByteArray qualifiedClassNameIdentifier = identifier;
216
217 // Remove ':'s in the name, but be sure not to create any illegal
218 // identifiers in the process. (Don't replace with '_', because
219 // that will create problems with things like NS_::_class.)
220 qualifiedClassNameIdentifier.replace(before: "::", after: "SCOPE");
221
222 // Also, avoid any leading/trailing underscores (we'll concatenate
223 // the generated name with other prefixes/suffixes, and these latter
224 // may already include an underscore, leading to two underscores)
225 qualifiedClassNameIdentifier = "CLASS" + qualifiedClassNameIdentifier + "ENDCLASS";
226 return qualifiedClassNameIdentifier;
227}
228
229void Generator::generateCode()
230{
231 bool isQObject = (cdef->classname == "QObject");
232 bool isConstructible = !cdef->constructorList.isEmpty();
233
234 // filter out undeclared enumerators and sets
235 {
236 QList<EnumDef> enumList;
237 for (EnumDef def : std::as_const(t&: cdef->enumList)) {
238 if (cdef->enumDeclarations.contains(key: def.name)) {
239 enumList += def;
240 }
241 def.enumName = def.name;
242 QByteArray alias = cdef->flagAliases.value(key: def.name);
243 if (cdef->enumDeclarations.contains(key: alias)) {
244 def.name = alias;
245 enumList += def;
246 }
247 }
248 cdef->enumList = enumList;
249 }
250
251//
252// Register all strings used in data section
253//
254 strreg(s: cdef->qualified);
255 registerClassInfoStrings();
256 registerFunctionStrings(list: cdef->signalList);
257 registerFunctionStrings(list: cdef->slotList);
258 registerFunctionStrings(list: cdef->methodList);
259 registerFunctionStrings(list: cdef->constructorList);
260 registerByteArrayVector(list: cdef->nonClassSignalList);
261 registerPropertyStrings();
262 registerEnumStrings();
263
264 const bool hasStaticMetaCall =
265 (cdef->hasQObject || !cdef->methodList.isEmpty()
266 || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty());
267
268 const QByteArray qualifiedClassNameIdentifier = generateQualifiedClassNameIdentifier(identifier: cdef->qualified);
269
270 // ensure the qt_meta_stringdata_XXXX_t type is local
271 fprintf(stream: out, format: "namespace {\n");
272
273//
274// Build the strings using QtMocHelpers::StringData
275//
276
277 fprintf(stream: out, format: "\n#ifdef QT_MOC_HAS_STRINGDATA\n"
278 "struct qt_meta_stringdata_%s_t {};\n"
279 "static constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
280 qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
281 {
282 char comma = 0;
283 for (const QByteArray &str : strings) {
284 if (comma)
285 fputc(c: comma, stream: out);
286 printStringWithIndentation(out, s: str);
287 comma = ',';
288 }
289 }
290 fprintf(stream: out, format: "\n);\n"
291 "#else // !QT_MOC_HAS_STRING_DATA\n");
292
293#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
294 fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n");
295#else
296//
297// Build stringdata struct
298//
299
300 fprintf(stream: out, format: "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
301 fprintf(stream: out, format: " uint offsetsAndSizes[%d];\n", int(strings.size() * 2));
302 for (int i = 0; i < strings.size(); ++i) {
303 int thisLength = lengthOfEscapedString(str: strings.at(i)) + 1;
304 fprintf(stream: out, format: " char stringdata%d[%d];\n", i, thisLength);
305 }
306 fprintf(stream: out, format: "};\n");
307
308 // Macro that simplifies the string data listing. The offset is calculated
309 // from the top of the stringdata object (i.e., past the uints).
310 fprintf(stream: out, format: "#define QT_MOC_LITERAL(ofs, len) \\\n"
311 " uint(sizeof(qt_meta_stringdata_%s_t::offsetsAndSizes) + ofs), len \n",
312 qualifiedClassNameIdentifier.constData());
313
314 fprintf(stream: out, format: "Q_CONSTINIT static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
315 qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
316 fprintf(stream: out, format: " {");
317 {
318 int idx = 0;
319 for (int i = 0; i < strings.size(); ++i) {
320 const QByteArray &str = strings.at(i);
321 const QByteArray comment = str.size() > 32 ? str.left(len: 29) + "..." : str;
322 const char *comma = (i != strings.size() - 1 ? "," : " ");
323 int len = lengthOfEscapedString(str);
324 fprintf(stream: out, format: "\n QT_MOC_LITERAL(%d, %d)%s // \"%s\"", idx, len, comma,
325 comment.constData());
326
327 idx += len + 1;
328 }
329 fprintf(stream: out, format: "\n }");
330 }
331
332//
333// Build stringdata arrays
334//
335 for (const QByteArray &s : std::as_const(t&: strings)) {
336 fputc(c: ',', stream: out);
337 printStringWithIndentation(out, s);
338 }
339
340// Terminate stringdata struct
341 fprintf(stream: out, format: "\n};\n");
342 fprintf(stream: out, format: "#undef QT_MOC_LITERAL\n");
343#endif // Qt 6.9
344
345 fprintf(stream: out, format: "#endif // !QT_MOC_HAS_STRING_DATA\n");
346 fprintf(stream: out, format: "} // unnamed namespace\n\n");
347
348//
349// build the data array
350//
351
352 int index = MetaObjectPrivateFieldCount;
353 fprintf(stream: out, format: "Q_CONSTINIT static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
354 fprintf(stream: out, format: "\n // content:\n");
355 fprintf(stream: out, format: " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
356 fprintf(stream: out, format: " %4d, // classname\n", stridx(s: cdef->qualified));
357 fprintf(stream: out, format: " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0));
358 index += cdef->classInfoList.size() * 2;
359
360 const qsizetype methodCount = cdef->signalList.size() + cdef->slotList.size() + cdef->methodList.size();
361 fprintf(stream: out, format: " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0);
362 index += methodCount * QMetaObjectPrivate::IntsPerMethod;
363 if (cdef->revisionedMethods)
364 index += methodCount;
365 int paramsIndex = index;
366 int totalParameterCount = aggregateParameterCount(list: cdef->signalList)
367 + aggregateParameterCount(list: cdef->slotList)
368 + aggregateParameterCount(list: cdef->methodList)
369 + aggregateParameterCount(list: cdef->constructorList);
370 index += totalParameterCount * 2 // types and parameter names
371 - methodCount // return "parameters" don't have names
372 - cdef->constructorList.size(); // "this" parameters don't have names
373
374 fprintf(stream: out, format: " %4d, %4d, // properties\n", int(cdef->propertyList.size()), int(cdef->propertyList.size() ? index : 0));
375 index += cdef->propertyList.size() * QMetaObjectPrivate::IntsPerProperty;
376 fprintf(stream: out, format: " %4d, %4d, // enums/sets\n", int(cdef->enumList.size()), cdef->enumList.size() ? index : 0);
377
378 int enumsIndex = index;
379 for (const EnumDef &def : std::as_const(t&: cdef->enumList))
380 index += QMetaObjectPrivate::IntsPerEnum + (def.values.size() * 2);
381
382 fprintf(stream: out, format: " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.size()) : 0,
383 isConstructible ? index : 0);
384
385 int flags = 0;
386 if (cdef->hasQGadget || cdef->hasQNamespace) {
387 // Ideally, all the classes could have that flag. But this broke classes generated
388 // by qdbusxml2cpp which generate code that require that we call qt_metacall for properties
389 flags |= PropertyAccessInStaticMetaCall;
390 }
391 fprintf(stream: out, format: " %4d, // flags\n", flags);
392 fprintf(stream: out, format: " %4d, // signalCount\n", int(cdef->signalList.size()));
393
394
395//
396// Build classinfo array
397//
398 generateClassInfos();
399
400 // all property metatypes + all enum metatypes + 1 for the type of the current class itself
401 int initialMetaTypeOffset = cdef->propertyList.size() + cdef->enumList.size() + 1;
402
403//
404// Build signals array first, otherwise the signal indices would be wrong
405//
406 generateFunctions(list: cdef->signalList, functype: "signal", type: MethodSignal, paramsIndex, initialMetatypeOffset&: initialMetaTypeOffset);
407
408//
409// Build slots array
410//
411 generateFunctions(list: cdef->slotList, functype: "slot", type: MethodSlot, paramsIndex, initialMetatypeOffset&: initialMetaTypeOffset);
412
413//
414// Build method array
415//
416 generateFunctions(list: cdef->methodList, functype: "method", type: MethodMethod, paramsIndex, initialMetatypeOffset&: initialMetaTypeOffset);
417
418//
419// Build method version arrays
420//
421 if (cdef->revisionedMethods) {
422 generateFunctionRevisions(list: cdef->signalList, functype: "signal");
423 generateFunctionRevisions(list: cdef->slotList, functype: "slot");
424 generateFunctionRevisions(list: cdef->methodList, functype: "method");
425 }
426
427//
428// Build method parameters array
429//
430 generateFunctionParameters(list: cdef->signalList, functype: "signal");
431 generateFunctionParameters(list: cdef->slotList, functype: "slot");
432 generateFunctionParameters(list: cdef->methodList, functype: "method");
433 if (isConstructible)
434 generateFunctionParameters(list: cdef->constructorList, functype: "constructor");
435
436//
437// Build property array
438//
439 generateProperties();
440
441//
442// Build enums array
443//
444 generateEnums(index: enumsIndex);
445
446//
447// Build constructors array
448//
449 if (isConstructible)
450 generateFunctions(list: cdef->constructorList, functype: "constructor", type: MethodConstructor, paramsIndex, initialMetatypeOffset&: initialMetaTypeOffset);
451
452//
453// Terminate data array
454//
455 fprintf(stream: out, format: "\n 0 // eod\n};\n\n");
456
457//
458// Build extra array
459//
460 QList<QByteArray> extraList;
461 QMultiHash<QByteArray, QByteArray> knownExtraMetaObject(knownGadgets);
462 knownExtraMetaObject.unite(other: knownQObjectClasses);
463
464 for (const PropertyDef &p : std::as_const(t&: cdef->propertyList)) {
465 if (isBuiltinType(type: p.type))
466 continue;
467
468 if (p.type.contains(c: '*') || p.type.contains(c: '<') || p.type.contains(c: '>'))
469 continue;
470
471 const qsizetype s = p.type.lastIndexOf(bv: "::");
472 if (s <= 0)
473 continue;
474
475 QByteArray unqualifiedScope = p.type.left(len: s);
476
477 // The scope may be a namespace for example, so it's only safe to include scopes that are known QObjects (QTBUG-2151)
478 QMultiHash<QByteArray, QByteArray>::ConstIterator scopeIt;
479
480 QByteArray thisScope = cdef->qualified;
481 do {
482 const qsizetype s = thisScope.lastIndexOf(bv: "::");
483 thisScope = thisScope.left(len: s);
484 QByteArray currentScope = thisScope.isEmpty() ? unqualifiedScope : thisScope + "::" + unqualifiedScope;
485 scopeIt = knownExtraMetaObject.constFind(key: currentScope);
486 } while (!thisScope.isEmpty() && scopeIt == knownExtraMetaObject.constEnd());
487
488 if (scopeIt == knownExtraMetaObject.constEnd())
489 continue;
490
491 const QByteArray &scope = *scopeIt;
492
493 if (scope == "Qt")
494 continue;
495 if (qualifiedNameEquals(qualifiedName: cdef->qualified, name: scope))
496 continue;
497
498 if (!extraList.contains(t: scope))
499 extraList += scope;
500 }
501
502 // QTBUG-20639 - Accept non-local enums for QML signal/slot parameters.
503 // Look for any scoped enum declarations, and add those to the list
504 // of extra/related metaobjects for this object.
505 for (auto it = cdef->enumDeclarations.keyBegin(),
506 end = cdef->enumDeclarations.keyEnd(); it != end; ++it) {
507 const QByteArray &enumKey = *it;
508 const qsizetype s = enumKey.lastIndexOf(bv: "::");
509 if (s > 0) {
510 QByteArray scope = enumKey.left(len: s);
511 if (scope != "Qt" && !qualifiedNameEquals(qualifiedName: cdef->qualified, name: scope) && !extraList.contains(t: scope))
512 extraList += scope;
513 }
514 }
515
516//
517// Generate meta object link to parent meta objects
518//
519
520 if (!extraList.isEmpty()) {
521 fprintf(stream: out, format: "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n",
522 qualifiedClassNameIdentifier.constData());
523 for (const QByteArray &ba : std::as_const(t&: extraList))
524 fprintf(stream: out, format: " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", ba.constData());
525
526 fprintf(stream: out, format: " nullptr\n};\n\n");
527 }
528
529//
530// Finally create and initialize the static meta object
531//
532 fprintf(stream: out, format: "Q_CONSTINIT const QMetaObject %s::staticMetaObject = { {\n",
533 cdef->qualified.constData());
534
535 if (isQObject)
536 fprintf(stream: out, format: " nullptr,\n");
537 else if (cdef->superclassList.size() && !cdef->hasQGadget && !cdef->hasQNamespace) // for qobject, we know the super class must have a static metaobject
538 fprintf(stream: out, format: " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData());
539 else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it
540 fprintf(stream: out, format: " QtPrivate::MetaObjectForType<%s>::value,\n", purestSuperClass.constData());
541 else
542 fprintf(stream: out, format: " nullptr,\n");
543 fprintf(stream: out, format: " qt_meta_stringdata_%s.offsetsAndSizes,\n"
544 " qt_meta_data_%s,\n", qualifiedClassNameIdentifier.constData(),
545 qualifiedClassNameIdentifier.constData());
546 if (hasStaticMetaCall)
547 fprintf(stream: out, format: " qt_static_metacall,\n");
548 else
549 fprintf(stream: out, format: " nullptr,\n");
550
551 if (extraList.isEmpty())
552 fprintf(stream: out, format: " nullptr,\n");
553 else
554 fprintf(stream: out, format: " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData());
555
556 const char *comma = "";
557 const bool requireCompleteness = requireCompleteTypes || cdef->requireCompleteMethodTypes;
558 auto stringForType = [requireCompleteness](const QByteArray &type, bool forceComplete) -> QByteArray {
559 const char *forceCompleteType = forceComplete ? ", std::true_type>" : ", std::false_type>";
560 if (requireCompleteness)
561 return type;
562 return "QtPrivate::TypeAndForceComplete<" % type % forceCompleteType;
563 };
564 if (!requireCompleteness) {
565 fprintf(stream: out, format: " qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t", qualifiedClassNameIdentifier.constData());
566 comma = ",";
567 } else {
568 fprintf(stream: out, format: " qt_metaTypeArray<");
569 }
570 // metatypes for properties
571 for (const PropertyDef &p : std::as_const(t&: cdef->propertyList)) {
572 fprintf(stream: out, format: "%s\n // property '%s'\n %s",
573 comma, p.name.constData(), stringForType(p.type, true).constData());
574 comma = ",";
575 }
576
577 // metatypes for enums
578 for (const EnumDef &e : std::as_const(t&: cdef->enumList)) {
579 fprintf(stream: out, format: "%s\n // enum '%s'\n %s",
580 comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData());
581 comma = ",";
582 }
583
584 // type name for the Q_OJBECT/GADGET itself, void for namespaces
585 auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void";
586 fprintf(stream: out, format: "%s\n // Q_OBJECT / Q_GADGET\n %s",
587 comma, stringForType(ownType, true).constData());
588 comma = ",";
589
590 // metatypes for all exposed methods
591 // because we definitely printed something above, this section doesn't need comma control
592 for (const QList<FunctionDef> &methodContainer :
593 { cdef->signalList, cdef->slotList, cdef->methodList }) {
594 for (const FunctionDef &fdef : methodContainer) {
595 fprintf(stream: out, format: ",\n // method '%s'\n %s",
596 fdef.name.constData(), stringForType(fdef.type.name, false).constData());
597 for (const auto &argument: fdef.arguments)
598 fprintf(stream: out, format: ",\n %s", stringForType(argument.type.name, false).constData());
599 }
600 }
601
602 // but constructors have no return types, so this needs comma control again
603 for (const FunctionDef &fdef : std::as_const(t&: cdef->constructorList)) {
604 if (fdef.arguments.isEmpty())
605 continue;
606
607 fprintf(stream: out, format: "%s\n // constructor '%s'", comma, fdef.name.constData());
608 comma = "";
609 for (const auto &argument: fdef.arguments) {
610 fprintf(stream: out, format: "%s\n %s", comma,
611 stringForType(argument.type.name, false).constData());
612 comma = ",";
613 }
614 }
615 fprintf(stream: out, format: "\n >,\n");
616
617 fprintf(stream: out, format: " nullptr\n} };\n\n");
618
619//
620// Generate internal qt_static_metacall() function
621//
622 if (hasStaticMetaCall)
623 generateStaticMetacall();
624
625 if (!cdef->hasQObject)
626 return;
627
628 fprintf(stream: out, format: "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;\n}\n",
629 cdef->qualified.constData());
630
631
632//
633// Generate smart cast function
634//
635 fprintf(stream: out, format: "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
636 fprintf(stream: out, format: " if (!_clname) return nullptr;\n");
637 fprintf(stream: out, format: " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
638 " return static_cast<void*>(this);\n",
639 qualifiedClassNameIdentifier.constData());
640
641 // for all superclasses but the first one
642 if (cdef->superclassList.size() > 1) {
643 auto it = cdef->superclassList.cbegin() + 1;
644 const auto end = cdef->superclassList.cend();
645 for (; it != end; ++it) {
646 const auto &[className, access] = *it;
647 if (access == FunctionDef::Private)
648 continue;
649 const char *cname = className.constData();
650 fprintf(stream: out, format: " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
651 cname, cname);
652 }
653 }
654
655 for (const QList<ClassDef::Interface> &iface : std::as_const(t&: cdef->interfaceList)) {
656 for (qsizetype j = 0; j < iface.size(); ++j) {
657 fprintf(stream: out, format: " if (!strcmp(_clname, %s))\n return ", iface.at(i: j).interfaceId.constData());
658 for (qsizetype k = j; k >= 0; --k)
659 fprintf(stream: out, format: "static_cast< %s*>(", iface.at(i: k).className.constData());
660 fprintf(stream: out, format: "this%s;\n", QByteArray(j + 1, ')').constData());
661 }
662 }
663 if (!purestSuperClass.isEmpty() && !isQObject) {
664 QByteArray superClass = purestSuperClass;
665 fprintf(stream: out, format: " return %s::qt_metacast(_clname);\n", superClass.constData());
666 } else {
667 fprintf(stream: out, format: " return nullptr;\n");
668 }
669 fprintf(stream: out, format: "}\n");
670
671//
672// Generate internal qt_metacall() function
673//
674 generateMetacall();
675
676//
677// Generate internal signal functions
678//
679 for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
680 generateSignal(def: &cdef->signalList[signalindex], index: signalindex);
681
682//
683// Generate plugin meta data
684//
685 generatePluginMetaData();
686
687//
688// Generate function to make sure the non-class signals exist in the parent classes
689//
690 if (!cdef->nonClassSignalList.isEmpty()) {
691 fprintf(stream: out, format: "// If you get a compile error in this function it can be because either\n");
692 fprintf(stream: out, format: "// a) You are using a NOTIFY signal that does not exist. Fix it.\n");
693 fprintf(stream: out, format: "// b) You are using a NOTIFY signal that does exist (in a parent class) but has a non-empty parameter list. This is a moc limitation.\n");
694 fprintf(stream: out, format: "[[maybe_unused]] static void checkNotifySignalValidity_%s(%s *t) {\n", qualifiedClassNameIdentifier.constData(), cdef->qualified.constData());
695 for (const QByteArray &nonClassSignal : std::as_const(t&: cdef->nonClassSignalList))
696 fprintf(stream: out, format: " t->%s();\n", nonClassSignal.constData());
697 fprintf(stream: out, format: "}\n");
698 }
699}
700
701
702void Generator::registerClassInfoStrings()
703{
704 for (const ClassInfoDef &c : std::as_const(t&: cdef->classInfoList)) {
705 strreg(s: c.name);
706 strreg(s: c.value);
707 }
708}
709
710void Generator::generateClassInfos()
711{
712 if (cdef->classInfoList.isEmpty())
713 return;
714
715 fprintf(stream: out, format: "\n // classinfo: key, value\n");
716
717 for (const ClassInfoDef &c : std::as_const(t&: cdef->classInfoList))
718 fprintf(stream: out, format: " %4d, %4d,\n", stridx(s: c.name), stridx(s: c.value));
719}
720
721void Generator::registerFunctionStrings(const QList<FunctionDef> &list)
722{
723 for (const FunctionDef &f : list) {
724 strreg(s: f.name);
725 if (!isBuiltinType(type: f.normalizedType))
726 strreg(s: f.normalizedType);
727 strreg(s: f.tag);
728
729 for (const ArgumentDef &a : f.arguments) {
730 if (!isBuiltinType(type: a.normalizedType))
731 strreg(s: a.normalizedType);
732 strreg(s: a.name);
733 }
734 }
735}
736
737void Generator::registerByteArrayVector(const QList<QByteArray> &list)
738{
739 for (const QByteArray &ba : list)
740 strreg(s: ba);
741}
742
743void Generator::generateFunctions(const QList<FunctionDef> &list, const char *functype, int type,
744 int &paramsIndex, int &initialMetatypeOffset)
745{
746 if (list.isEmpty())
747 return;
748 fprintf(stream: out, format: "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype);
749
750 for (const FunctionDef &f : list) {
751 QByteArray comment;
752 uint flags = type;
753 if (f.access == FunctionDef::Private) {
754 flags |= AccessPrivate;
755 comment.append(s: "Private");
756 } else if (f.access == FunctionDef::Public) {
757 flags |= AccessPublic;
758 comment.append(s: "Public");
759 } else if (f.access == FunctionDef::Protected) {
760 flags |= AccessProtected;
761 comment.append(s: "Protected");
762 }
763 if (f.isCompat) {
764 flags |= MethodCompatibility;
765 comment.append(s: " | MethodCompatibility");
766 }
767 if (f.wasCloned) {
768 flags |= MethodCloned;
769 comment.append(s: " | MethodCloned");
770 }
771 if (f.isScriptable) {
772 flags |= MethodScriptable;
773 comment.append(s: " | isScriptable");
774 }
775 if (f.revision > 0) {
776 flags |= MethodRevisioned;
777 comment.append(s: " | MethodRevisioned");
778 }
779
780 if (f.isConst) {
781 flags |= MethodIsConst;
782 comment.append(s: " | MethodIsConst ");
783 }
784
785 int argc = f.arguments.size();
786 fprintf(stream: out, format: " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n",
787 stridx(s: f.name), argc, paramsIndex, stridx(s: f.tag), flags, initialMetatypeOffset, comment.constData());
788
789 paramsIndex += 1 + argc * 2;
790 // constructors don't have a return type
791 initialMetatypeOffset += (f.isConstructor ? 0 : 1) + argc;
792 }
793}
794
795void Generator::generateFunctionRevisions(const QList<FunctionDef> &list, const char *functype)
796{
797 if (list.size())
798 fprintf(stream: out, format: "\n // %ss: revision\n", functype);
799 for (const FunctionDef &f : list)
800 fprintf(stream: out, format: " %4d,\n", f.revision);
801}
802
803void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const char *functype)
804{
805 if (list.isEmpty())
806 return;
807 fprintf(stream: out, format: "\n // %ss: parameters\n", functype);
808 for (const FunctionDef &f : list) {
809 fprintf(stream: out, format: " ");
810
811 // Types
812 int argsCount = f.arguments.size();
813 for (int j = -1; j < argsCount; ++j) {
814 if (j > -1)
815 fputc(c: ' ', stream: out);
816 const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(i: j).normalizedType;
817 generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor);
818 fputc(c: ',', stream: out);
819 }
820
821 // Parameter names
822 for (const ArgumentDef &arg : f.arguments)
823 fprintf(stream: out, format: " %4d,", stridx(s: arg.name));
824
825 fprintf(stream: out, format: "\n");
826 }
827}
828
829void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName)
830{
831 Q_UNUSED(allowEmptyName);
832 if (isBuiltinType(type: typeName)) {
833 int type;
834 const char *valueString;
835 if (typeName == "qreal") {
836 type = QMetaType::UnknownType;
837 valueString = "QReal";
838 } else {
839 type = nameToBuiltinType(name: typeName);
840 valueString = metaTypeEnumValueString(type);
841 }
842 if (valueString) {
843 fprintf(stream: out, format: "QMetaType::%s", valueString);
844 } else {
845 Q_ASSERT(type != QMetaType::UnknownType);
846 fprintf(stream: out, format: "%4d", type);
847 }
848 } else {
849 Q_ASSERT(!typeName.isEmpty() || allowEmptyName);
850 fprintf(stream: out, format: "0x%.8x | %d", IsUnresolvedType, stridx(s: typeName));
851 }
852}
853
854void Generator::registerPropertyStrings()
855{
856 for (const PropertyDef &p : std::as_const(t&: cdef->propertyList)) {
857 strreg(s: p.name);
858 if (!isBuiltinType(type: p.type))
859 strreg(s: p.type);
860 }
861}
862
863void Generator::generateProperties()
864{
865 //
866 // Create meta data
867 //
868
869 if (cdef->propertyList.size())
870 fprintf(stream: out, format: "\n // properties: name, type, flags\n");
871 for (const PropertyDef &p : std::as_const(t&: cdef->propertyList)) {
872 uint flags = Invalid;
873 if (!isBuiltinType(type: p.type))
874 flags |= EnumOrFlag;
875 if (!p.member.isEmpty() && !p.constant)
876 flags |= Writable;
877 if (!p.read.isEmpty() || !p.member.isEmpty())
878 flags |= Readable;
879 if (!p.write.isEmpty()) {
880 flags |= Writable;
881 if (p.stdCppSet())
882 flags |= StdCppSet;
883 }
884
885 if (!p.reset.isEmpty())
886 flags |= Resettable;
887
888 if (p.designable != "false")
889 flags |= Designable;
890
891 if (p.scriptable != "false")
892 flags |= Scriptable;
893
894 if (p.stored != "false")
895 flags |= Stored;
896
897 if (p.user != "false")
898 flags |= User;
899
900 if (p.constant)
901 flags |= Constant;
902 if (p.final)
903 flags |= Final;
904 if (p.required)
905 flags |= Required;
906
907 if (!p.bind.isEmpty())
908 flags |= Bindable;
909
910 fprintf(stream: out, format: " %4d, ", stridx(s: p.name));
911 generateTypeInfo(typeName: p.type);
912 int notifyId = p.notifyId;
913 if (p.notifyId < -1) {
914 // signal is in parent class
915 const int indexInStrings = strings.indexOf(t: p.notify);
916 notifyId = indexInStrings | IsUnresolvedSignal;
917 }
918 fprintf(stream: out, format: ", 0x%.8x, uint(%d), %d,\n", flags, notifyId, p.revision);
919 }
920}
921
922void Generator::registerEnumStrings()
923{
924 for (const EnumDef &e : std::as_const(t&: cdef->enumList)) {
925 strreg(s: e.name);
926 if (!e.enumName.isNull())
927 strreg(s: e.enumName);
928 for (const QByteArray &val : e.values)
929 strreg(s: val);
930 }
931}
932
933void Generator::generateEnums(int index)
934{
935 if (cdef->enumDeclarations.isEmpty())
936 return;
937
938 fprintf(stream: out, format: "\n // enums: name, alias, flags, count, data\n");
939 index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size();
940 int i;
941 for (i = 0; i < cdef->enumList.size(); ++i) {
942 const EnumDef &e = cdef->enumList.at(i);
943 int flags = 0;
944 if (cdef->enumDeclarations.value(key: e.name))
945 flags |= EnumIsFlag;
946 if (e.isEnumClass)
947 flags |= EnumIsScoped;
948 fprintf(stream: out, format: " %4d, %4d, 0x%.1x, %4d, %4d,\n",
949 stridx(s: e.name),
950 e.enumName.isNull() ? stridx(s: e.name) : stridx(s: e.enumName),
951 flags,
952 int(e.values.size()),
953 index);
954 index += e.values.size() * 2;
955 }
956
957 fprintf(stream: out, format: "\n // enum data: key, value\n");
958 for (const EnumDef &e : std::as_const(t&: cdef->enumList)) {
959 for (const QByteArray &val : e.values) {
960 QByteArray code = cdef->qualified.constData();
961 if (e.isEnumClass)
962 code += "::" + (e.enumName.isNull() ? e.name : e.enumName);
963 code += "::" + val;
964 fprintf(stream: out, format: " %4d, uint(%s),\n",
965 stridx(s: val), code.constData());
966 }
967 }
968}
969
970void Generator::generateMetacall()
971{
972 bool isQObject = (cdef->classname == "QObject");
973
974 fprintf(stream: out, format: "\nint %s::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
975 cdef->qualified.constData());
976
977 if (!purestSuperClass.isEmpty() && !isQObject) {
978 QByteArray superClass = purestSuperClass;
979 fprintf(stream: out, format: " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
980 }
981
982
983 bool needElse = false;
984 QList<FunctionDef> methodList;
985 methodList += cdef->signalList;
986 methodList += cdef->slotList;
987 methodList += cdef->methodList;
988
989 // If there are no methods or properties, we will return _id anyway, so
990 // don't emit this comparison -- it is unnecessary, and it makes coverity
991 // unhappy.
992 if (methodList.size() || cdef->propertyList.size()) {
993 fprintf(stream: out, format: " if (_id < 0)\n return _id;\n");
994 }
995
996 fprintf(stream: out, format: " ");
997
998 if (methodList.size()) {
999 needElse = true;
1000 fprintf(stream: out, format: "if (_c == QMetaObject::InvokeMetaMethod) {\n");
1001 fprintf(stream: out, format: " if (_id < %d)\n", int(methodList.size()));
1002 fprintf(stream: out, format: " qt_static_metacall(this, _c, _id, _a);\n");
1003 fprintf(stream: out, format: " _id -= %d;\n }", int(methodList.size()));
1004
1005 fprintf(stream: out, format: " else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {\n");
1006 fprintf(stream: out, format: " if (_id < %d)\n", int(methodList.size()));
1007
1008 if (methodsWithAutomaticTypesHelper(methodList).isEmpty())
1009 fprintf(stream: out, format: " *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType();\n");
1010 else
1011 fprintf(stream: out, format: " qt_static_metacall(this, _c, _id, _a);\n");
1012 fprintf(stream: out, format: " _id -= %d;\n }", int(methodList.size()));
1013
1014 }
1015
1016 if (cdef->propertyList.size()) {
1017 if (needElse)
1018 fprintf(stream: out, format: "else ");
1019 fprintf(stream: out,
1020 format: "if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n"
1021 " || _c == QMetaObject::ResetProperty || _c == QMetaObject::BindableProperty\n"
1022 " || _c == QMetaObject::RegisterPropertyMetaType) {\n"
1023 " qt_static_metacall(this, _c, _id, _a);\n"
1024 " _id -= %d;\n }", int(cdef->propertyList.size()));
1025 }
1026 if (methodList.size() || cdef->propertyList.size())
1027 fprintf(stream: out, format: "\n ");
1028 fprintf(stream: out,format: "return _id;\n}\n");
1029}
1030
1031
1032// ### Qt 7 (6.x?): remove
1033QMultiMap<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
1034{
1035 QMultiMap<QByteArray, int> automaticPropertyMetaTypes;
1036 for (int i = 0; i < cdef->propertyList.size(); ++i) {
1037 const QByteArray propertyType = cdef->propertyList.at(i).type;
1038 if (registerableMetaType(propertyType) && !isBuiltinType(type: propertyType))
1039 automaticPropertyMetaTypes.insert(key: propertyType, value: i);
1040 }
1041 return automaticPropertyMetaTypes;
1042}
1043
1044QMap<int, QMultiMap<QByteArray, int>>
1045Generator::methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList)
1046{
1047 QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypes;
1048 for (int i = 0; i < methodList.size(); ++i) {
1049 const FunctionDef &f = methodList.at(i);
1050 for (int j = 0; j < f.arguments.size(); ++j) {
1051 const QByteArray argType = f.arguments.at(i: j).normalizedType;
1052 if (registerableMetaType(propertyType: argType) && !isBuiltinType(type: argType))
1053 methodsWithAutomaticTypes[i].insert(key: argType, value: j);
1054 }
1055 }
1056 return methodsWithAutomaticTypes;
1057}
1058
1059void Generator::generateStaticMetacall()
1060{
1061 fprintf(stream: out, format: "void %s::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)\n{\n",
1062 cdef->qualified.constData());
1063
1064 bool needElse = false;
1065 bool isUsed_a = false;
1066
1067 const auto generateCtorArguments = [&](int ctorindex) {
1068 const FunctionDef &f = cdef->constructorList.at(i: ctorindex);
1069 Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed
1070 int offset = 1;
1071
1072 const auto begin = f.arguments.cbegin();
1073 const auto end = f.arguments.cend();
1074 for (auto it = begin; it != end; ++it) {
1075 const ArgumentDef &a = *it;
1076 if (it != begin)
1077 fprintf(stream: out, format: ",");
1078 fprintf(stream: out, format: "(*reinterpret_cast<%s>(_a[%d]))",
1079 a.typeNameForCast.constData(), offset++);
1080 }
1081 };
1082
1083 if (!cdef->constructorList.isEmpty()) {
1084 fprintf(stream: out, format: " if (_c == QMetaObject::CreateInstance) {\n");
1085 fprintf(stream: out, format: " switch (_id) {\n");
1086 const int ctorend = cdef->constructorList.size();
1087 for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
1088 fprintf(stream: out, format: " case %d: { %s *_r = new %s(", ctorindex,
1089 cdef->classname.constData(), cdef->classname.constData());
1090 generateCtorArguments(ctorindex);
1091 fprintf(stream: out, format: ");\n");
1092 fprintf(stream: out, format: " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n",
1093 (cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject");
1094 }
1095 fprintf(stream: out, format: " default: break;\n");
1096 fprintf(stream: out, format: " }\n");
1097 fprintf(stream: out, format: " } else if (_c == QMetaObject::ConstructInPlace) {\n");
1098 fprintf(stream: out, format: " switch (_id) {\n");
1099 for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
1100 fprintf(stream: out, format: " case %d: { new (_a[0]) %s(",
1101 ctorindex, cdef->classname.constData());
1102 generateCtorArguments(ctorindex);
1103 fprintf(stream: out, format: "); } break;\n");
1104 }
1105 fprintf(stream: out, format: " default: break;\n");
1106 fprintf(stream: out, format: " }\n");
1107 fprintf(stream: out, format: " }");
1108 needElse = true;
1109 isUsed_a = true;
1110 }
1111
1112 QList<FunctionDef> methodList;
1113 methodList += cdef->signalList;
1114 methodList += cdef->slotList;
1115 methodList += cdef->methodList;
1116
1117 if (!methodList.isEmpty()) {
1118 if (needElse)
1119 fprintf(stream: out, format: " else ");
1120 else
1121 fprintf(stream: out, format: " ");
1122 fprintf(stream: out, format: "if (_c == QMetaObject::InvokeMetaMethod) {\n");
1123 if (cdef->hasQObject) {
1124#ifndef QT_NO_DEBUG
1125 fprintf(stream: out, format: " Q_ASSERT(staticMetaObject.cast(_o));\n");
1126#endif
1127 fprintf(stream: out, format: " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData());
1128 } else {
1129 fprintf(stream: out, format: " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
1130 }
1131 fprintf(stream: out, format: " (void)_t;\n");
1132 fprintf(stream: out, format: " switch (_id) {\n");
1133 for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
1134 const FunctionDef &f = methodList.at(i: methodindex);
1135 Q_ASSERT(!f.normalizedType.isEmpty());
1136 fprintf(stream: out, format: " case %d: ", methodindex);
1137 if (f.normalizedType != "void")
1138 fprintf(stream: out, format: "{ %s _r = ", noRef(type: f.normalizedType).constData());
1139 fprintf(stream: out, format: "_t->");
1140 if (f.inPrivateClass.size())
1141 fprintf(stream: out, format: "%s->", f.inPrivateClass.constData());
1142 fprintf(stream: out, format: "%s(", f.name.constData());
1143 int offset = 1;
1144
1145 if (f.isRawSlot) {
1146 fprintf(stream: out, format: "QMethodRawArguments{ _a }");
1147 } else {
1148 const auto begin = f.arguments.cbegin();
1149 const auto end = f.arguments.cend();
1150 for (auto it = begin; it != end; ++it) {
1151 const ArgumentDef &a = *it;
1152 if (it != begin)
1153 fprintf(stream: out, format: ",");
1154 fprintf(stream: out, format: "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
1155 isUsed_a = true;
1156 }
1157 if (f.isPrivateSignal) {
1158 if (!f.arguments.isEmpty())
1159 fprintf(stream: out, format: ", ");
1160 fprintf(stream: out, format: "%s", "QPrivateSignal()");
1161 }
1162 }
1163 fprintf(stream: out, format: ");");
1164 if (f.normalizedType != "void") {
1165 fprintf(stream: out, format: "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = std::move(_r); } ",
1166 noRef(type: f.normalizedType).constData());
1167 isUsed_a = true;
1168 }
1169 fprintf(stream: out, format: " break;\n");
1170 }
1171 fprintf(stream: out, format: " default: ;\n");
1172 fprintf(stream: out, format: " }\n");
1173 fprintf(stream: out, format: " }");
1174 needElse = true;
1175
1176 QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypes = methodsWithAutomaticTypesHelper(methodList);
1177
1178 if (!methodsWithAutomaticTypes.isEmpty()) {
1179 fprintf(stream: out, format: " else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {\n");
1180 fprintf(stream: out, format: " switch (_id) {\n");
1181 fprintf(stream: out, format: " default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;\n");
1182 QMap<int, QMultiMap<QByteArray, int> >::const_iterator it = methodsWithAutomaticTypes.constBegin();
1183 const QMap<int, QMultiMap<QByteArray, int> >::const_iterator end = methodsWithAutomaticTypes.constEnd();
1184 for ( ; it != end; ++it) {
1185 fprintf(stream: out, format: " case %d:\n", it.key());
1186 fprintf(stream: out, format: " switch (*reinterpret_cast<int*>(_a[1])) {\n");
1187 fprintf(stream: out, format: " default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;\n");
1188 auto jt = it->begin();
1189 const auto jend = it->end();
1190 while (jt != jend) {
1191 fprintf(stream: out, format: " case %d:\n", jt.value());
1192 const QByteArray &lastKey = jt.key();
1193 ++jt;
1194 if (jt == jend || jt.key() != lastKey)
1195 fprintf(stream: out, format: " *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType::fromType< %s >(); break;\n", lastKey.constData());
1196 }
1197 fprintf(stream: out, format: " }\n");
1198 fprintf(stream: out, format: " break;\n");
1199 }
1200 fprintf(stream: out, format: " }\n");
1201 fprintf(stream: out, format: " }");
1202 isUsed_a = true;
1203 }
1204
1205 }
1206 if (!cdef->signalList.isEmpty()) {
1207 Q_ASSERT(needElse); // if there is signal, there was method.
1208 fprintf(stream: out, format: " else if (_c == QMetaObject::IndexOfMethod) {\n");
1209 fprintf(stream: out, format: " int *result = reinterpret_cast<int *>(_a[0]);\n");
1210 bool anythingUsed = false;
1211 for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
1212 const FunctionDef &f = cdef->signalList.at(i: methodindex);
1213 if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic)
1214 continue;
1215 anythingUsed = true;
1216 fprintf(stream: out, format: " {\n");
1217 fprintf(stream: out, format: " using _t = %s (%s::*)(",f.type.rawName.constData() , cdef->classname.constData());
1218
1219 const auto begin = f.arguments.cbegin();
1220 const auto end = f.arguments.cend();
1221 for (auto it = begin; it != end; ++it) {
1222 const ArgumentDef &a = *it;
1223 if (it != begin)
1224 fprintf(stream: out, format: ", ");
1225 fprintf(stream: out, format: "%s", QByteArray(a.type.name + ' ' + a.rightType).constData());
1226 }
1227 if (f.isPrivateSignal) {
1228 if (!f.arguments.isEmpty())
1229 fprintf(stream: out, format: ", ");
1230 fprintf(stream: out, format: "%s", "QPrivateSignal");
1231 }
1232 if (f.isConst)
1233 fprintf(stream: out, format: ") const;\n");
1234 else
1235 fprintf(stream: out, format: ");\n");
1236 fprintf(stream: out, format: " if (_t _q_method = &%s::%s; *reinterpret_cast<_t *>(_a[1]) == _q_method) {\n",
1237 cdef->classname.constData(), f.name.constData());
1238 fprintf(stream: out, format: " *result = %d;\n", methodindex);
1239 fprintf(stream: out, format: " return;\n");
1240 fprintf(stream: out, format: " }\n }\n");
1241 }
1242 if (!anythingUsed)
1243 fprintf(stream: out, format: " (void)result;\n");
1244 fprintf(stream: out, format: " }");
1245 needElse = true;
1246 }
1247
1248 const QMultiMap<QByteArray, int> automaticPropertyMetaTypes = automaticPropertyMetaTypesHelper();
1249
1250 if (!automaticPropertyMetaTypes.isEmpty()) {
1251 if (needElse)
1252 fprintf(stream: out, format: " else ");
1253 else
1254 fprintf(stream: out, format: " ");
1255 fprintf(stream: out, format: "if (_c == QMetaObject::RegisterPropertyMetaType) {\n");
1256 fprintf(stream: out, format: " switch (_id) {\n");
1257 fprintf(stream: out, format: " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n");
1258 auto it = automaticPropertyMetaTypes.begin();
1259 const auto end = automaticPropertyMetaTypes.end();
1260 while (it != end) {
1261 fprintf(stream: out, format: " case %d:\n", it.value());
1262 const QByteArray &lastKey = it.key();
1263 ++it;
1264 if (it == end || it.key() != lastKey)
1265 fprintf(stream: out, format: " *reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< %s >(); break;\n", lastKey.constData());
1266 }
1267 fprintf(stream: out, format: " }\n");
1268 fprintf(stream: out, format: " } ");
1269 isUsed_a = true;
1270 needElse = true;
1271 }
1272
1273 if (!cdef->propertyList.empty()) {
1274 bool needGet = false;
1275 bool needTempVarForGet = false;
1276 bool needSet = false;
1277 bool needReset = false;
1278 bool hasBindableProperties = false;
1279 for (const PropertyDef &p : std::as_const(t&: cdef->propertyList)) {
1280 needGet |= !p.read.isEmpty() || !p.member.isEmpty();
1281 if (!p.read.isEmpty() || !p.member.isEmpty())
1282 needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
1283 && p.gspec != PropertyDef::ReferenceSpec);
1284
1285 needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant);
1286 needReset |= !p.reset.isEmpty();
1287 hasBindableProperties |= !p.bind.isEmpty();
1288 }
1289 if (needElse)
1290 fprintf(stream: out, format: " else ");
1291 fprintf(stream: out, format: "if (_c == QMetaObject::ReadProperty) {\n");
1292
1293 auto setupMemberAccess = [this]() {
1294 if (cdef->hasQObject) {
1295#ifndef QT_NO_DEBUG
1296 fprintf(stream: out, format: " Q_ASSERT(staticMetaObject.cast(_o));\n");
1297#endif
1298 fprintf(stream: out, format: " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData());
1299 } else {
1300 fprintf(stream: out, format: " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
1301 }
1302 fprintf(stream: out, format: " (void)_t;\n");
1303 };
1304
1305 if (needGet) {
1306 setupMemberAccess();
1307 if (needTempVarForGet)
1308 fprintf(stream: out, format: " void *_v = _a[0];\n");
1309 fprintf(stream: out, format: " switch (_id) {\n");
1310 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
1311 const PropertyDef &p = cdef->propertyList.at(i: propindex);
1312 if (p.read.isEmpty() && p.member.isEmpty())
1313 continue;
1314 QByteArray prefix = "_t->";
1315 if (p.inPrivateClass.size()) {
1316 prefix += p.inPrivateClass + "->";
1317 }
1318
1319 if (p.gspec == PropertyDef::PointerSpec)
1320 fprintf(stream: out, format: " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s%s())); break;\n",
1321 propindex, prefix.constData(), p.read.constData());
1322 else if (p.gspec == PropertyDef::ReferenceSpec)
1323 fprintf(stream: out, format: " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s%s())); break;\n",
1324 propindex, prefix.constData(), p.read.constData());
1325 else if (cdef->enumDeclarations.value(key: p.type, defaultValue: false))
1326 fprintf(stream: out, format: " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
1327 propindex, prefix.constData(), p.read.constData());
1328 else if (p.read == "default")
1329 fprintf(stream: out, format: " case %d: *reinterpret_cast< %s*>(_v) = %s%s().value(); break;\n",
1330 propindex, p.type.constData(), prefix.constData(), p.bind.constData());
1331 else if (!p.read.isEmpty())
1332 fprintf(stream: out, format: " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
1333 propindex, p.type.constData(), prefix.constData(), p.read.constData());
1334 else
1335 fprintf(stream: out, format: " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
1336 propindex, p.type.constData(), prefix.constData(), p.member.constData());
1337 }
1338 fprintf(stream: out, format: " default: break;\n");
1339 fprintf(stream: out, format: " }\n");
1340 }
1341
1342 fprintf(stream: out, format: " }");
1343
1344 fprintf(stream: out, format: " else ");
1345 fprintf(stream: out, format: "if (_c == QMetaObject::WriteProperty) {\n");
1346
1347 if (needSet) {
1348 setupMemberAccess();
1349 fprintf(stream: out, format: " void *_v = _a[0];\n");
1350 fprintf(stream: out, format: " switch (_id) {\n");
1351 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
1352 const PropertyDef &p = cdef->propertyList.at(i: propindex);
1353 if (p.constant)
1354 continue;
1355 if (p.write.isEmpty() && p.member.isEmpty())
1356 continue;
1357 QByteArray prefix = "_t->";
1358 if (p.inPrivateClass.size()) {
1359 prefix += p.inPrivateClass + "->";
1360 }
1361 if (cdef->enumDeclarations.value(key: p.type, defaultValue: false)) {
1362 fprintf(stream: out, format: " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
1363 propindex, prefix.constData(), p.write.constData());
1364 } else if (p.write == "default") {
1365 fprintf(stream: out, format: " case %d: {\n", propindex);
1366 fprintf(stream: out, format: " %s%s().setValue(*reinterpret_cast< %s*>(_v));\n",
1367 prefix.constData(), p.bind.constData(), p.type.constData());
1368 fprintf(stream: out, format: " break;\n");
1369 fprintf(stream: out, format: " }\n");
1370 } else if (!p.write.isEmpty()) {
1371 fprintf(stream: out, format: " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n",
1372 propindex, prefix.constData(), p.write.constData(), p.type.constData());
1373 } else {
1374 fprintf(stream: out, format: " case %d:\n", propindex);
1375 fprintf(stream: out, format: " if (%s%s != *reinterpret_cast< %s*>(_v)) {\n",
1376 prefix.constData(), p.member.constData(), p.type.constData());
1377 fprintf(stream: out, format: " %s%s = *reinterpret_cast< %s*>(_v);\n",
1378 prefix.constData(), p.member.constData(), p.type.constData());
1379 if (!p.notify.isEmpty() && p.notifyId > -1) {
1380 const FunctionDef &f = cdef->signalList.at(i: p.notifyId);
1381 if (f.arguments.size() == 0)
1382 fprintf(stream: out, format: " Q_EMIT _t->%s();\n", p.notify.constData());
1383 else if (f.arguments.size() == 1 && f.arguments.at(i: 0).normalizedType == p.type)
1384 fprintf(stream: out, format: " Q_EMIT _t->%s(%s%s);\n",
1385 p.notify.constData(), prefix.constData(), p.member.constData());
1386 } else if (!p.notify.isEmpty() && p.notifyId < -1) {
1387 fprintf(stream: out, format: " Q_EMIT _t->%s();\n", p.notify.constData());
1388 }
1389 fprintf(stream: out, format: " }\n");
1390 fprintf(stream: out, format: " break;\n");
1391 }
1392 }
1393 fprintf(stream: out, format: " default: break;\n");
1394 fprintf(stream: out, format: " }\n");
1395 }
1396
1397 fprintf(stream: out, format: " }");
1398
1399 fprintf(stream: out, format: " else ");
1400 fprintf(stream: out, format: "if (_c == QMetaObject::ResetProperty) {\n");
1401 if (needReset) {
1402 setupMemberAccess();
1403 fprintf(stream: out, format: " switch (_id) {\n");
1404 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
1405 const PropertyDef &p = cdef->propertyList.at(i: propindex);
1406 if (p.reset.isEmpty())
1407 continue;
1408 QByteArray prefix = "_t->";
1409 if (p.inPrivateClass.size()) {
1410 prefix += p.inPrivateClass + "->";
1411 }
1412 fprintf(stream: out, format: " case %d: %s%s(); break;\n",
1413 propindex, prefix.constData(), p.reset.constData());
1414 }
1415 fprintf(stream: out, format: " default: break;\n");
1416 fprintf(stream: out, format: " }\n");
1417 }
1418 fprintf(stream: out, format: " }");
1419
1420 fprintf(stream: out, format: " else ");
1421 fprintf(stream: out, format: "if (_c == QMetaObject::BindableProperty) {\n");
1422 if (hasBindableProperties) {
1423 setupMemberAccess();
1424 fprintf(stream: out, format: " switch (_id) {\n");
1425 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
1426 const PropertyDef &p = cdef->propertyList.at(i: propindex);
1427 if (p.bind.isEmpty())
1428 continue;
1429 QByteArray prefix = "_t->";
1430 if (p.inPrivateClass.size()) {
1431 prefix += p.inPrivateClass + "->";
1432 }
1433 fprintf(stream: out,
1434 format: " case %d: *static_cast<QUntypedBindable *>(_a[0]) = %s%s(); "
1435 "break;\n",
1436 propindex, prefix.constData(), p.bind.constData());
1437 }
1438 fprintf(stream: out, format: " default: break;\n");
1439 fprintf(stream: out, format: " }\n");
1440 }
1441 fprintf(stream: out, format: " }");
1442 needElse = true;
1443 }
1444
1445 if (needElse)
1446 fprintf(stream: out, format: "\n");
1447
1448 if (methodList.isEmpty()) {
1449 fprintf(stream: out, format: " (void)_o;\n");
1450 if (cdef->constructorList.isEmpty() && automaticPropertyMetaTypes.isEmpty() && methodsWithAutomaticTypesHelper(methodList).isEmpty()) {
1451 fprintf(stream: out, format: " (void)_id;\n");
1452 fprintf(stream: out, format: " (void)_c;\n");
1453 }
1454 }
1455 if (!isUsed_a)
1456 fprintf(stream: out, format: " (void)_a;\n");
1457
1458 fprintf(stream: out, format: "}\n");
1459}
1460
1461void Generator::generateSignal(FunctionDef *def,int index)
1462{
1463 if (def->wasCloned || def->isAbstract)
1464 return;
1465 fprintf(stream: out, format: "\n// SIGNAL %d\n%s %s::%s(",
1466 index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
1467
1468 QByteArray thisPtr = "this";
1469 const char *constQualifier = "";
1470
1471 if (def->isConst) {
1472 thisPtr = "const_cast< " + cdef->qualified + " *>(this)";
1473 constQualifier = "const";
1474 }
1475
1476 Q_ASSERT(!def->normalizedType.isEmpty());
1477 if (def->arguments.isEmpty() && def->normalizedType == "void" && !def->isPrivateSignal) {
1478 fprintf(stream: out, format: ")%s\n{\n"
1479 " QMetaObject::activate(%s, &staticMetaObject, %d, nullptr);\n"
1480 "}\n", constQualifier, thisPtr.constData(), index);
1481 return;
1482 }
1483
1484 int offset = 1;
1485 const auto begin = def->arguments.cbegin();
1486 const auto end = def->arguments.cend();
1487 for (auto it = begin; it != end; ++it) {
1488 const ArgumentDef &a = *it;
1489 if (it != begin)
1490 fputs(s: ", ", stream: out);
1491 if (a.type.name.size())
1492 fputs(s: a.type.name.constData(), stream: out);
1493 fprintf(stream: out, format: " _t%d", offset++);
1494 if (a.rightType.size())
1495 fputs(s: a.rightType.constData(), stream: out);
1496 }
1497 if (def->isPrivateSignal) {
1498 if (!def->arguments.isEmpty())
1499 fprintf(stream: out, format: ", ");
1500 fprintf(stream: out, format: "QPrivateSignal _t%d", offset++);
1501 }
1502
1503 fprintf(stream: out, format: ")%s\n{\n", constQualifier);
1504 if (def->type.name.size() && def->normalizedType != "void") {
1505 QByteArray returnType = noRef(type: def->normalizedType);
1506 fprintf(stream: out, format: " %s _t0{};\n", returnType.constData());
1507 }
1508
1509 fprintf(stream: out, format: " void *_a[] = { ");
1510 if (def->normalizedType == "void") {
1511 fprintf(stream: out, format: "nullptr");
1512 } else {
1513 if (def->returnTypeIsVolatile)
1514 fprintf(stream: out, format: "const_cast<void*>(reinterpret_cast<const volatile void*>(std::addressof(_t0)))");
1515 else
1516 fprintf(stream: out, format: "const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t0)))");
1517 }
1518 int i;
1519 for (i = 1; i < offset; ++i)
1520 if (i <= def->arguments.size() && def->arguments.at(i: i - 1).type.isVolatile)
1521 fprintf(stream: out, format: ", const_cast<void*>(reinterpret_cast<const volatile void*>(std::addressof(_t%d)))", i);
1522 else
1523 fprintf(stream: out, format: ", const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t%d)))", i);
1524 fprintf(stream: out, format: " };\n");
1525 fprintf(stream: out, format: " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
1526 if (def->normalizedType != "void")
1527 fprintf(stream: out, format: " return _t0;\n");
1528 fprintf(stream: out, format: "}\n");
1529}
1530
1531static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
1532static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
1533{
1534 auto it = o.constBegin();
1535 auto end = o.constEnd();
1536 CborEncoder map;
1537 cbor_encoder_create_map(parentEncoder: parent, mapEncoder: &map, length: o.size());
1538
1539 for ( ; it != end; ++it) {
1540 QByteArray key = it.key().toUtf8();
1541 cbor_encode_text_string(encoder: &map, string: key.constData(), length: key.size());
1542 jsonValueToCbor(parent: &map, v: it.value());
1543 }
1544 return cbor_encoder_close_container(parentEncoder: parent, containerEncoder: &map);
1545}
1546
1547static CborError jsonArrayToCbor(CborEncoder *parent, const QJsonArray &a)
1548{
1549 CborEncoder array;
1550 cbor_encoder_create_array(parentEncoder: parent, arrayEncoder: &array, length: a.size());
1551 for (const QJsonValue v : a)
1552 jsonValueToCbor(parent: &array, v);
1553 return cbor_encoder_close_container(parentEncoder: parent, containerEncoder: &array);
1554}
1555
1556static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v)
1557{
1558 switch (v.type()) {
1559 case QJsonValue::Null:
1560 case QJsonValue::Undefined:
1561 return cbor_encode_null(encoder: parent);
1562 case QJsonValue::Bool:
1563 return cbor_encode_boolean(encoder: parent, value: v.toBool());
1564 case QJsonValue::Array:
1565 return jsonArrayToCbor(parent, a: v.toArray());
1566 case QJsonValue::Object:
1567 return jsonObjectToCbor(parent, o: v.toObject());
1568 case QJsonValue::String: {
1569 QByteArray s = v.toString().toUtf8();
1570 return cbor_encode_text_string(encoder: parent, string: s.constData(), length: s.size());
1571 }
1572 case QJsonValue::Double: {
1573 double d = v.toDouble();
1574 if (d == floor(x: d) && fabs(x: d) <= (Q_INT64_C(1) << std::numeric_limits<double>::digits))
1575 return cbor_encode_int(encoder: parent, value: qint64(d));
1576 return cbor_encode_double(encoder: parent, value: d);
1577 }
1578 }
1579 Q_UNREACHABLE_RETURN(CborUnknownError);
1580}
1581
1582void Generator::generatePluginMetaData()
1583{
1584 if (cdef->pluginData.iid.isEmpty())
1585 return;
1586
1587 auto outputCborData = [this]() {
1588 CborDevice dev(out);
1589 CborEncoder enc;
1590 cbor_encoder_init_writer(encoder: &enc, writer: CborDevice::callback, &dev);
1591
1592 CborEncoder map;
1593 cbor_encoder_create_map(parentEncoder: &enc, mapEncoder: &map, length: CborIndefiniteLength);
1594
1595 dev.nextItem(comment: "\"IID\"");
1596 cbor_encode_int(encoder: &map, value: int(QtPluginMetaDataKeys::IID));
1597 cbor_encode_text_string(encoder: &map, string: cdef->pluginData.iid.constData(), length: cdef->pluginData.iid.size());
1598
1599 dev.nextItem(comment: "\"className\"");
1600 cbor_encode_int(encoder: &map, value: int(QtPluginMetaDataKeys::ClassName));
1601 cbor_encode_text_string(encoder: &map, string: cdef->classname.constData(), length: cdef->classname.size());
1602
1603 QJsonObject o = cdef->pluginData.metaData.object();
1604 if (!o.isEmpty()) {
1605 dev.nextItem(comment: "\"MetaData\"");
1606 cbor_encode_int(encoder: &map, value: int(QtPluginMetaDataKeys::MetaData));
1607 jsonObjectToCbor(parent: &map, o);
1608 }
1609
1610 if (!cdef->pluginData.uri.isEmpty()) {
1611 dev.nextItem(comment: "\"URI\"");
1612 cbor_encode_int(encoder: &map, value: int(QtPluginMetaDataKeys::URI));
1613 cbor_encode_text_string(encoder: &map, string: cdef->pluginData.uri.constData(), length: cdef->pluginData.uri.size());
1614 }
1615
1616 // Add -M args from the command line:
1617 for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) {
1618 const QJsonArray &a = it.value();
1619 QByteArray key = it.key().toUtf8();
1620 dev.nextItem(comment: QByteArray("command-line \"" + key + "\"").constData());
1621 cbor_encode_text_string(encoder: &map, string: key.constData(), length: key.size());
1622 jsonArrayToCbor(parent: &map, a);
1623 }
1624
1625 // Close the CBOR map manually
1626 dev.nextItem();
1627 cbor_encoder_close_container(parentEncoder: &enc, containerEncoder: &map);
1628 };
1629
1630 // 'Use' all namespaces.
1631 qsizetype pos = cdef->qualified.indexOf(bv: "::");
1632 for ( ; pos != -1 ; pos = cdef->qualified.indexOf(bv: "::", from: pos + 2) )
1633 fprintf(stream: out, format: "using namespace %s;\n", cdef->qualified.left(len: pos).constData());
1634
1635 fputs(s: "\n#ifdef QT_MOC_EXPORT_PLUGIN_V2", stream: out);
1636
1637 // Qt 6.3+ output
1638 fprintf(stream: out, format: "\nstatic constexpr unsigned char qt_pluginMetaDataV2_%s[] = {",
1639 cdef->classname.constData());
1640 outputCborData();
1641 fprintf(stream: out, format: "\n};\nQT_MOC_EXPORT_PLUGIN_V2(%s, %s, qt_pluginMetaDataV2_%s)\n",
1642 cdef->qualified.constData(), cdef->classname.constData(), cdef->classname.constData());
1643
1644 // compatibility with Qt 6.0-6.2
1645 fprintf(stream: out, format: "#else\nQT_PLUGIN_METADATA_SECTION\n"
1646 "Q_CONSTINIT static constexpr unsigned char qt_pluginMetaData_%s[] = {\n"
1647 " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n"
1648 " // metadata version, Qt version, architectural requirements\n"
1649 " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),",
1650 cdef->classname.constData());
1651 outputCborData();
1652 fprintf(stream: out, format: "\n};\nQT_MOC_EXPORT_PLUGIN(%s, %s)\n"
1653 "#endif // QT_MOC_EXPORT_PLUGIN_V2\n",
1654 cdef->qualified.constData(), cdef->classname.constData());
1655
1656 fputs(s: "\n", stream: out);
1657}
1658
1659QT_WARNING_DISABLE_GCC("-Wunused-function")
1660QT_WARNING_DISABLE_CLANG("-Wunused-function")
1661QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
1662QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
1663
1664#define CBOR_ENCODER_WRITER_CONTROL 1
1665#define CBOR_ENCODER_WRITE_FUNCTION CborDevice::callback
1666
1667QT_END_NAMESPACE
1668
1669#include "cborencoder.c"
1670

source code of qtbase/src/tools/moc/generator.cpp