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