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