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