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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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