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

source code of qtscxml/tools/qscxmlc/generator.cpp