source: branches/4.5.1/src/tools/moc/generator.cpp

Last change on this file was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 44.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information (qt-info@nokia.com)
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at qt-sales@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "generator.h"
43#include "outputrevision.h"
44#include "utils.h"
45#include <QtCore/qmetatype.h>
46#include <stdio.h>
47
48QT_BEGIN_NAMESPACE
49
50// if the flags change, you MUST to change it in qmetaobject.cpp too
51enum PropertyFlags {
52 Invalid = 0x00000000,
53 Readable = 0x00000001,
54 Writable = 0x00000002,
55 Resettable = 0x00000004,
56 EnumOrFlag = 0x00000008,
57 StdCppSet = 0x00000100,
58// Override = 0x00000200,
59 Designable = 0x00001000,
60 ResolveDesignable = 0x00002000,
61 Scriptable = 0x00004000,
62 ResolveScriptable = 0x00008000,
63 Stored = 0x00010000,
64 ResolveStored = 0x00020000,
65 Editable = 0x00040000,
66 ResolveEditable = 0x00080000,
67 User = 0x00100000,
68 ResolveUser = 0x00200000,
69 Notify = 0x00400000
70};
71enum MethodFlags {
72 AccessPrivate = 0x00,
73 AccessProtected = 0x01,
74 AccessPublic = 0x02,
75 MethodMethod = 0x00,
76 MethodSignal = 0x04,
77 MethodSlot = 0x08,
78 MethodConstructor = 0x0c,
79 MethodCompatibility = 0x10,
80 MethodCloned = 0x20,
81 MethodScriptable = 0x40
82};
83
84uint qvariant_nameToType(const char* name)
85{
86 if (!name)
87 return 0;
88
89 if (strcmp(name, "QVariant") == 0)
90 return 0xffffffff;
91 if (strcmp(name, "QCString") == 0)
92 return QMetaType::QByteArray;
93 if (strcmp(name, "Q_LLONG") == 0)
94 return QMetaType::LongLong;
95 if (strcmp(name, "Q_ULLONG") == 0)
96 return QMetaType::ULongLong;
97 if (strcmp(name, "QIconSet") == 0)
98 return QMetaType::QIcon;
99
100 uint tp = QMetaType::type(name);
101 return tp < QMetaType::User ? tp : 0;
102}
103
104/*
105 Returns true if the type is a QVariant types.
106*/
107bool isVariantType(const char* type)
108{
109 return qvariant_nameToType(type) != 0;
110}
111
112Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile)
113 : out(outfile), cdef(classDef), metaTypes(metaTypes)
114{
115 if (cdef->superclassList.size())
116 purestSuperClass = cdef->superclassList.first().first;
117}
118
119static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
120{
121 if (s.at(i) != '\\' || i >= s.length() - 1)
122 return 1;
123 const int startPos = i;
124 ++i;
125 char ch = s.at(i);
126 if (ch == 'x') {
127 ++i;
128 while (i < s.length() && is_hex_char(s.at(i)))
129 ++i;
130 } else if (is_octal_char(ch)) {
131 while (i < startPos + 4
132 && i < s.length()
133 && is_octal_char(s.at(i))) {
134 ++i;
135 }
136 } else { // single character escape sequence
137 i = qMin(i + 1, s.length());
138 }
139 return i - startPos;
140}
141
142int Generator::strreg(const char *s)
143{
144 int idx = 0;
145 if (!s)
146 s = "";
147 for (int i = 0; i < strings.size(); ++i) {
148 const QByteArray &str = strings.at(i);
149 if (str == s)
150 return idx;
151 idx += str.length() + 1;
152 for (int i = 0; i < str.length(); ++i) {
153 if (str.at(i) == '\\') {
154 int cnt = lengthOfEscapeSequence(str, i) - 1;
155 idx -= cnt;
156 i += cnt;
157 }
158 }
159 }
160 strings.append(s);
161 return idx;
162}
163
164void Generator::generateCode()
165{
166 bool isQt = (cdef->classname == "Qt");
167 bool isQObject = (cdef->classname == "QObject");
168 bool isConstructible = !cdef->constructorList.isEmpty();
169
170//
171// build the data array
172//
173 int i = 0;
174
175
176 // filter out undeclared enumerators and sets
177 {
178 QList<EnumDef> enumList;
179 for (i = 0; i < cdef->enumList.count(); ++i) {
180 EnumDef def = cdef->enumList.at(i);
181 if (cdef->enumDeclarations.contains(def.name)) {
182 enumList += def;
183 }
184 QByteArray alias = cdef->flagAliases.value(def.name);
185 if (cdef->enumDeclarations.contains(alias)) {
186 def.name = alias;
187 enumList += def;
188 }
189 }
190 cdef->enumList = enumList;
191 }
192
193
194 QByteArray qualifiedClassNameIdentifier = cdef->qualified;
195 qualifiedClassNameIdentifier.replace(':', '_');
196
197 int index = 12;
198 fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
199 fprintf(out, "\n // content:\n");
200 fprintf(out, " %4d, // revision\n", 2);
201 fprintf(out, " %4d, // classname\n", strreg(cdef->qualified));
202 fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
203 index += cdef->classInfoList.count() * 2;
204
205 int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
206 fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
207 index += methodCount * 5;
208 fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
209 index += cdef->propertyList.count() * 3;
210 if(cdef->notifyableProperties)
211 index += cdef->propertyList.count();
212 fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0);
213
214 int enumsIndex = index;
215 for (i = 0; i < cdef->enumList.count(); ++i)
216 index += 4 + (cdef->enumList.at(i).values.count() * 2);
217 fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
218 isConstructible ? index : 0);
219
220//
221// Build classinfo array
222//
223 generateClassInfos();
224
225//
226// Build signals array first, otherwise the signal indices would be wrong
227//
228 generateFunctions(cdef->signalList, "signal", MethodSignal);
229
230//
231// Build slots array
232//
233 generateFunctions(cdef->slotList, "slot", MethodSlot);
234
235//
236// Build method array
237//
238 generateFunctions(cdef->methodList, "method", MethodMethod);
239
240
241//
242// Build property array
243//
244 generateProperties();
245
246//
247// Build enums array
248//
249 generateEnums(enumsIndex);
250
251//
252// Build constructors array
253//
254 if (isConstructible)
255 generateFunctions(cdef->constructorList, "constructor", MethodConstructor);
256
257//
258// Terminate data array
259//
260 fprintf(out, "\n 0 // eod\n};\n\n");
261
262//
263// Build stringdata array
264//
265 fprintf(out, "static const char qt_meta_stringdata_%s[] = {\n", qualifiedClassNameIdentifier.constData());
266 fprintf(out, " \"");
267 int col = 0;
268 int len = 0;
269 for (i = 0; i < strings.size(); ++i) {
270 QByteArray s = strings.at(i);
271 len = s.length();
272 if (col && col + len >= 72) {
273 fprintf(out, "\"\n \"");
274 col = 0;
275 } else if (len && s.at(0) >= '0' && s.at(0) <= '9') {
276 fprintf(out, "\"\"");
277 len += 2;
278 }
279 int idx = 0;
280 while (idx < s.length()) {
281 if (idx > 0) {
282 col = 0;
283 fprintf(out, "\"\n \"");
284 }
285 int spanLen = qMin(70, s.length() - idx);
286 // don't cut escape sequences at the end of a line
287 int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
288 if (backSlashPos >= idx) {
289 int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
290 spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx);
291 }
292 fwrite(s.constData() + idx, 1, spanLen, out);
293 idx += spanLen;
294 col += spanLen;
295 }
296
297 fputs("\\0", out);
298 col += len + 2;
299 }
300 fprintf(out, "\"\n};\n\n");
301
302
303//
304// Generate internal qt_static_metacall() function
305//
306 if (isConstructible)
307 generateStaticMetacall(qualifiedClassNameIdentifier);
308
309//
310// Build extra array
311//
312 QList<QByteArray> extraList;
313 for (int i = 0; i < cdef->propertyList.count(); ++i) {
314 const PropertyDef &p = cdef->propertyList.at(i);
315 if (!isVariantType(p.type) && !metaTypes.contains(p.type)) {
316 int s = p.type.lastIndexOf("::");
317 if (s > 0) {
318 QByteArray scope = p.type.left(s);
319 if (scope != "Qt" && scope != cdef->classname && !extraList.contains(scope))
320 extraList += scope;
321 }
322 }
323 }
324 if (!extraList.isEmpty()) {
325 fprintf(out, "static const QMetaObject *qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData());
326 for (int i = 0; i < extraList.count(); ++i) {
327 if (i)
328 fprintf(out, ",\n ");
329 fprintf(out, " &%s::staticMetaObject", extraList.at(i).constData());
330 }
331 fprintf(out, ",0\n};\n\n");
332 }
333
334 if (isConstructible || !extraList.isEmpty()) {
335 fprintf(out, "static const QMetaObjectExtraData qt_meta_extradata2_%s = {\n ",
336 qualifiedClassNameIdentifier.constData());
337 if (extraList.isEmpty())
338 fprintf(out, "0, ");
339 else
340 fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData());
341 if (!isConstructible)
342 fprintf(out, "0");
343 else
344 fprintf(out, "%s_qt_static_metacall", qualifiedClassNameIdentifier.constData());
345 fprintf(out, " \n};\n\n");
346 }
347
348//
349// Finally create and initialize the static meta object
350//
351
352 if (isQt)
353 fprintf(out, "const QMetaObject QObject::staticQtMetaObject = {\n");
354 else
355 fprintf(out, "const QMetaObject %s::staticMetaObject = {\n", cdef->qualified.constData());
356
357 if (isQObject)
358 fprintf(out, " { 0, ");
359 else if (cdef->superclassList.size())
360 fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
361 else
362 fprintf(out, " { 0, ");
363 fprintf(out, "qt_meta_stringdata_%s,\n qt_meta_data_%s, ",
364 qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
365 if (!isConstructible && extraList.isEmpty())
366 fprintf(out, "0 }\n");
367 else
368 fprintf(out, "&qt_meta_extradata2_%s }\n", qualifiedClassNameIdentifier.constData());
369 fprintf(out, "};\n");
370
371 if (isQt || !cdef->hasQObject)
372 return;
373
374 fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return &staticMetaObject;\n}\n",
375 cdef->qualified.constData());
376//
377// Generate smart cast function
378//
379 fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
380 fprintf(out, " if (!_clname) return 0;\n");
381 fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s))\n"
382 " return static_cast<void*>(const_cast< %s*>(this));\n",
383 qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
384 for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
385 if (cdef->superclassList.at(i).second == FunctionDef::Private)
386 continue;
387 const char *cname = cdef->superclassList.at(i).first;
388 fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(const_cast< %s*>(this));\n",
389 cname, cname, cdef->classname.constData());
390 }
391 for (int i = 0; i < cdef->interfaceList.size(); ++i) {
392 const QList<ClassDef::Interface> &iface = cdef->interfaceList.at(i);
393 for (int j = 0; j < iface.size(); ++j) {
394 fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData());
395 for (int k = j; k >= 0; --k)
396 fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData());
397 fprintf(out, "const_cast< %s*>(this)%s;\n",
398 cdef->classname.constData(), QByteArray(j+1, ')').constData());
399 }
400 }
401 if (!purestSuperClass.isEmpty() && !isQObject) {
402 QByteArray superClass = purestSuperClass;
403 // workaround for VC6
404 if (superClass.contains("::")) {
405 fprintf(out, " typedef %s QMocSuperClass;\n", superClass.constData());
406 superClass = "QMocSuperClass";
407 }
408 fprintf(out, " return %s::qt_metacast(_clname);\n", superClass.constData());
409 } else {
410 fprintf(out, " return 0;\n");
411 }
412 fprintf(out, "}\n");
413
414//
415// Generate internal qt_metacall() function
416//
417 generateMetacall();
418
419//
420// Generate internal signal functions
421//
422 for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
423 generateSignal(&cdef->signalList[signalindex], signalindex);
424}
425
426
427void Generator::generateClassInfos()
428{
429 if (cdef->classInfoList.isEmpty())
430 return;
431
432 fprintf(out, "\n // classinfo: key, value\n");
433
434 for (int i = 0; i < cdef->classInfoList.size(); ++i) {
435 const ClassInfoDef &c = cdef->classInfoList.at(i);
436 fprintf(out, " %4d, %4d,\n", strreg(c.name), strreg(c.value));
437 }
438}
439
440void Generator::generateFunctions(QList<FunctionDef>& list, const char *functype, int type)
441{
442 if (list.isEmpty())
443 return;
444 fprintf(out, "\n // %ss: signature, parameters, type, tag, flags\n", functype);
445
446 for (int i = 0; i < list.count(); ++i) {
447 const FunctionDef &f = list.at(i);
448
449 QByteArray sig = f.name + '(';
450 QByteArray arguments;
451
452 for (int j = 0; j < f.arguments.count(); ++j) {
453 const ArgumentDef &a = f.arguments.at(j);
454 if (j) {
455 sig += ",";
456 arguments += ",";
457 }
458 sig += a.normalizedType;
459 arguments += a.name;
460 }
461 sig += ')';
462
463 char flags = type;
464 if (f.access == FunctionDef::Private)
465 flags |= AccessPrivate;
466 else if (f.access == FunctionDef::Public)
467 flags |= AccessPublic;
468 else if (f.access == FunctionDef::Protected)
469 flags |= AccessProtected;
470 if (f.access == FunctionDef::Private)
471 flags |= AccessPrivate;
472 else if (f.access == FunctionDef::Public)
473 flags |= AccessPublic;
474 else if (f.access == FunctionDef::Protected)
475 flags |= AccessProtected;
476 if (f.isCompat)
477 flags |= MethodCompatibility;
478 if (f.wasCloned)
479 flags |= MethodCloned;
480 if (f.isScriptable)
481 flags |= MethodScriptable;
482 fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x,\n", strreg(sig),
483 strreg(arguments), strreg(f.normalizedType), strreg(f.tag), flags);
484 }
485}
486
487void Generator::generateProperties()
488{
489 //
490 // specify get function, for compatibiliy we accept functions
491 // returning pointers, or const char * for QByteArray.
492 //
493 for (int i = 0; i < cdef->propertyList.count(); ++i) {
494 PropertyDef &p = cdef->propertyList[i];
495 if (p.read.isEmpty())
496 continue;
497 for (int j = 0; j < cdef->publicList.count(); ++j) {
498 const FunctionDef &f = cdef->publicList.at(j);
499 if (f.name != p.read)
500 continue;
501 if (!f.isConst) // get functions must be const
502 continue;
503 if (f.arguments.size()) // and must not take any arguments
504 continue;
505 PropertyDef::Specification spec = PropertyDef::ValueSpec;
506 QByteArray tmp = f.normalizedType;
507 if (p.type == "QByteArray" && tmp == "const char *")
508 tmp = "QByteArray";
509 if (tmp.left(6) == "const ")
510 tmp = tmp.mid(6);
511 if (p.type != tmp && tmp.endsWith('*')) {
512 tmp.chop(1);
513 spec = PropertyDef::PointerSpec;
514 } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
515 spec = PropertyDef::ReferenceSpec;
516 }
517 if (p.type != tmp)
518 continue;
519 p.gspec = spec;
520 break;
521 }
522 if(!p.notify.isEmpty()) {
523 int notifyId = -1;
524 for (int j = 0; j < cdef->signalList.count(); ++j) {
525 const FunctionDef &f = cdef->signalList.at(j);
526 if(f.name != p.notify) {
527 continue;
528 } else {
529 notifyId = j /* Signal indexes start from 0 */;
530 break;
531 }
532 }
533 p.notifyId = notifyId;
534 }
535 }
536
537 //
538 // Create meta data
539 //
540
541 if (cdef->propertyList.count())
542 fprintf(out, "\n // properties: name, type, flags\n");
543 for (int i = 0; i < cdef->propertyList.count(); ++i) {
544 const PropertyDef &p = cdef->propertyList.at(i);
545 uint flags = Invalid;
546 if (!isVariantType(p.type)) {
547 flags |= EnumOrFlag;
548 } else {
549 flags |= qvariant_nameToType(p.type) << 24;
550 }
551 if (!p.read.isEmpty())
552 flags |= Readable;
553 if (!p.write.isEmpty()) {
554 flags |= Writable;
555 if (p.stdCppSet())
556 flags |= StdCppSet;
557 }
558 if (!p.reset.isEmpty())
559 flags |= Resettable;
560
561// if (p.override)
562// flags |= Override;
563
564 if (p.designable.isEmpty())
565 flags |= ResolveDesignable;
566 else if (p.designable != "false")
567 flags |= Designable;
568
569 if (p.scriptable.isEmpty())
570 flags |= ResolveScriptable;
571 else if (p.scriptable != "false")
572 flags |= Scriptable;
573
574 if (p.stored.isEmpty())
575 flags |= ResolveStored;
576 else if (p.stored != "false")
577 flags |= Stored;
578
579 if (p.editable.isEmpty())
580 flags |= ResolveEditable;
581 else if (p.editable != "false")
582 flags |= Editable;
583
584 if (p.user.isEmpty())
585 flags |= ResolveUser;
586 else if (p.user != "false")
587 flags |= User;
588
589 if (p.notifyId != -1)
590 flags |= Notify;
591
592 fprintf(out, " %4d, %4d, 0x%.8x,\n",
593 strreg(p.name),
594 strreg(p.type),
595 flags);
596 }
597
598 if(cdef->notifyableProperties) {
599 fprintf(out, "\n // properties: notify_signal_id\n");
600 for (int i = 0; i < cdef->propertyList.count(); ++i) {
601 const PropertyDef &p = cdef->propertyList.at(i);
602 if(p.notifyId == -1)
603 fprintf(out, " %4d,\n",
604 0);
605 else
606 fprintf(out, " %4d,\n",
607 p.notifyId);
608 }
609 }
610}
611
612void Generator::generateEnums(int index)
613{
614 if (cdef->enumDeclarations.isEmpty())
615 return;
616
617 fprintf(out, "\n // enums: name, flags, count, data\n");
618 index += 4 * cdef->enumList.count();
619 int i;
620 for (i = 0; i < cdef->enumList.count(); ++i) {
621 const EnumDef &e = cdef->enumList.at(i);
622 fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
623 strreg(e.name),
624 cdef->enumDeclarations.value(e.name) ? 1 : 0,
625 e.values.count(),
626 index);
627 index += e.values.count() * 2;
628 }
629
630 fprintf(out, "\n // enum data: key, value\n");
631 for (i = 0; i < cdef->enumList.count(); ++i) {
632 const EnumDef &e = cdef->enumList.at(i);
633 for (int j = 0; j < e.values.count(); ++j) {
634 const QByteArray &val = e.values.at(j);
635 fprintf(out, " %4d, uint(%s::%s),\n",
636 strreg(val),
637 cdef->qualified.constData(),
638 val.constData());
639 }
640 }
641}
642
643void Generator::generateMetacall()
644{
645 bool isQObject = (cdef->classname == "QObject");
646
647 fprintf(out, "\nint %s::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
648 cdef->qualified.constData());
649
650 if (!purestSuperClass.isEmpty() && !isQObject) {
651 QByteArray superClass = purestSuperClass;
652 // workaround for VC6
653 if (superClass.contains("::")) {
654 fprintf(out, " typedef %s QMocSuperClass;\n", superClass.constData());
655 superClass = "QMocSuperClass";
656 }
657 fprintf(out, " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
658 }
659
660 fprintf(out, " if (_id < 0)\n return _id;\n");
661 fprintf(out, " ");
662
663 bool needElse = false;
664 QList<FunctionDef> methodList;
665 methodList += cdef->signalList;
666 methodList += cdef->slotList;
667 methodList += cdef->methodList;
668
669 if (methodList.size()) {
670 needElse = true;
671 fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n ");
672 fprintf(out, "switch (_id) {\n");
673 for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
674 const FunctionDef &f = methodList.at(methodindex);
675 fprintf(out, " case %d: ", methodindex);
676 if (f.normalizedType.size())
677 fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
678 if (f.inPrivateClass.size())
679 fprintf(out, "%s->", f.inPrivateClass.constData());
680 fprintf(out, "%s(", f.name.constData());
681 int offset = 1;
682 for (int j = 0; j < f.arguments.count(); ++j) {
683 const ArgumentDef &a = f.arguments.at(j);
684 if (j)
685 fprintf(out, ",");
686 fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
687 }
688 fprintf(out, ");");
689 if (f.normalizedType.size())
690 fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
691 noRef(f.normalizedType).constData());
692 fprintf(out, " break;\n");
693 }
694 fprintf(out, " default: ;\n");
695 fprintf(out, " }\n");
696 }
697 if (methodList.size())
698 fprintf(out, " _id -= %d;\n }", methodList.size());
699
700 if (cdef->propertyList.size()) {
701 bool needGet = false;
702 bool needTempVarForGet = false;
703 bool needSet = false;
704 bool needReset = false;
705 bool needDesignable = false;
706 bool needScriptable = false;
707 bool needStored = false;
708 bool needEditable = false;
709 bool needUser = false;
710 for (int i = 0; i < cdef->propertyList.size(); ++i) {
711 const PropertyDef &p = cdef->propertyList.at(i);
712 needGet |= !p.read.isEmpty();
713 if (!p.read.isEmpty())
714 needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
715 && p.gspec != PropertyDef::ReferenceSpec);
716
717 needSet |= !p.write.isEmpty();
718 needReset |= !p.reset.isEmpty();
719 needDesignable |= p.designable.endsWith(')');
720 needScriptable |= p.scriptable.endsWith(')');
721 needStored |= p.stored.endsWith(')');
722 needEditable |= p.editable.endsWith(')');
723 needUser |= p.user.endsWith(')');
724 }
725 bool needAnything = needGet
726 | needSet
727 | needReset
728 | needDesignable
729 | needScriptable
730 | needStored
731 | needEditable
732 | needUser;
733 if (!needAnything)
734 goto skip_properties;
735 fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
736
737 if (needElse)
738 fprintf(out, " else ");
739 fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n");
740 if (needGet) {
741 if (needTempVarForGet)
742 fprintf(out, " void *_v = _a[0];\n");
743 fprintf(out, " switch (_id) {\n");
744 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
745 const PropertyDef &p = cdef->propertyList.at(propindex);
746 if (p.read.isEmpty())
747 continue;
748 if (p.gspec == PropertyDef::PointerSpec)
749 fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s())); break;\n",
750 propindex, p.read.constData());
751 else if (p.gspec == PropertyDef::ReferenceSpec)
752 fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s())); break;\n",
753 propindex, p.read.constData());
754 else if (cdef->enumDeclarations.value(p.type, false))
755 fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s()); break;\n",
756 propindex, p.read.constData());
757 else
758 fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s(); break;\n",
759 propindex, p.type.constData(), p.read.constData());
760 }
761 fprintf(out, " }\n");
762 }
763
764 fprintf(out,
765 " _id -= %d;\n"
766 " }", cdef->propertyList.count());
767
768 fprintf(out, " else ");
769 fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n");
770
771 if (needSet) {
772 fprintf(out, " void *_v = _a[0];\n");
773 fprintf(out, " switch (_id) {\n");
774 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
775 const PropertyDef &p = cdef->propertyList.at(propindex);
776 if (p.write.isEmpty())
777 continue;
778 if (cdef->enumDeclarations.value(p.type, false)) {
779 fprintf(out, " case %d: %s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
780 propindex, p.write.constData());
781 } else {
782 fprintf(out, " case %d: %s(*reinterpret_cast< %s*>(_v)); break;\n",
783 propindex, p.write.constData(), p.type.constData());
784 }
785 }
786 fprintf(out, " }\n");
787 }
788
789 fprintf(out,
790 " _id -= %d;\n"
791 " }", cdef->propertyList.count());
792
793 fprintf(out, " else ");
794 fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n");
795 if (needReset) {
796 fprintf(out, " switch (_id) {\n");
797 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
798 const PropertyDef &p = cdef->propertyList.at(propindex);
799 if (!p.reset.endsWith(')'))
800 continue;
801 fprintf(out, " case %d: %s; break;\n",
802 propindex, p.reset.constData());
803 }
804 fprintf(out, " }\n");
805 }
806 fprintf(out,
807 " _id -= %d;\n"
808 " }", cdef->propertyList.count());
809
810 fprintf(out, " else ");
811 fprintf(out, "if (_c == QMetaObject::QueryPropertyDesignable) {\n");
812 if (needDesignable) {
813 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
814 fprintf(out, " switch (_id) {\n");
815 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
816 const PropertyDef &p = cdef->propertyList.at(propindex);
817 if (!p.designable.endsWith(')'))
818 continue;
819 fprintf(out, " case %d: *_b = %s; break;\n",
820 propindex, p.designable.constData());
821 }
822 fprintf(out, " }\n");
823 }
824 fprintf(out,
825 " _id -= %d;\n"
826 " }", cdef->propertyList.count());
827
828 fprintf(out, " else ");
829 fprintf(out, "if (_c == QMetaObject::QueryPropertyScriptable) {\n");
830 if (needScriptable) {
831 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
832 fprintf(out, " switch (_id) {\n");
833 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
834 const PropertyDef &p = cdef->propertyList.at(propindex);
835 if (!p.scriptable.endsWith(')'))
836 continue;
837 fprintf(out, " case %d: *_b = %s; break;\n",
838 propindex, p.scriptable.constData());
839 }
840 fprintf(out, " }\n");
841 }
842 fprintf(out,
843 " _id -= %d;\n"
844 " }", cdef->propertyList.count());
845
846 fprintf(out, " else ");
847 fprintf(out, "if (_c == QMetaObject::QueryPropertyStored) {\n");
848 if (needStored) {
849 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
850 fprintf(out, " switch (_id) {\n");
851 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
852 const PropertyDef &p = cdef->propertyList.at(propindex);
853 if (!p.stored.endsWith(')'))
854 continue;
855 fprintf(out, " case %d: *_b = %s; break;\n",
856 propindex, p.stored.constData());
857 }
858 fprintf(out, " }\n");
859 }
860 fprintf(out,
861 " _id -= %d;\n"
862 " }", cdef->propertyList.count());
863
864 fprintf(out, " else ");
865 fprintf(out, "if (_c == QMetaObject::QueryPropertyEditable) {\n");
866 if (needEditable) {
867 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
868 fprintf(out, " switch (_id) {\n");
869 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
870 const PropertyDef &p = cdef->propertyList.at(propindex);
871 if (!p.editable.endsWith(')'))
872 continue;
873 fprintf(out, " case %d: *_b = %s; break;\n",
874 propindex, p.editable.constData());
875 }
876 fprintf(out, " }\n");
877 }
878 fprintf(out,
879 " _id -= %d;\n"
880 " }", cdef->propertyList.count());
881
882
883 fprintf(out, " else ");
884 fprintf(out, "if (_c == QMetaObject::QueryPropertyUser) {\n");
885 if (needUser) {
886 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
887 fprintf(out, " switch (_id) {\n");
888 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
889 const PropertyDef &p = cdef->propertyList.at(propindex);
890 if (!p.user.endsWith(')'))
891 continue;
892 fprintf(out, " case %d: *_b = %s; break;\n",
893 propindex, p.user.constData());
894 }
895 fprintf(out, " }\n");
896 }
897 fprintf(out,
898 " _id -= %d;\n"
899 " }", cdef->propertyList.count());
900
901
902 fprintf(out, "\n#endif // QT_NO_PROPERTIES");
903 }
904 skip_properties:
905 if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size())
906 fprintf(out, "\n ");
907 fprintf(out,"return _id;\n}\n");
908}
909
910void Generator::generateStaticMetacall(const QByteArray &prefix)
911{
912 bool isQObject = (cdef->classname == "QObject");
913
914 fprintf(out, "static int %s_qt_static_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
915 prefix.constData());
916
917 fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
918 fprintf(out, " switch (_id) {\n");
919 for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
920 fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
921 cdef->classname.constData(), cdef->classname.constData());
922 const FunctionDef &f = cdef->constructorList.at(ctorindex);
923 int offset = 1;
924 for (int j = 0; j < f.arguments.count(); ++j) {
925 const ArgumentDef &a = f.arguments.at(j);
926 if (j)
927 fprintf(out, ",");
928 fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
929 }
930 fprintf(out, ");\n");
931 fprintf(out, " if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;\n");
932 }
933 fprintf(out, " }\n");
934 fprintf(out, " _id -= %d;\n", cdef->constructorList.count());
935 fprintf(out, " return _id;\n");
936 fprintf(out, " }\n");
937
938 if (!isQObject)
939 fprintf(out, " _id = %s::staticMetaObject.superClass()->static_metacall(_c, _id, _a);\n", cdef->classname.constData());
940
941 fprintf(out, " if (_id < 0)\n return _id;\n");
942
943 fprintf(out, " return _id;\n");
944 fprintf(out, "}\n\n");
945}
946
947void Generator::generateSignal(FunctionDef *def,int index)
948{
949 if (def->wasCloned || def->isAbstract)
950 return;
951 fprintf(out, "\n// SIGNAL %d\n%s %s::%s(",
952 index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
953
954 QByteArray thisPtr = "this";
955 const char *constQualifier = "";
956
957 if (def->isConst) {
958 thisPtr = "const_cast< ";
959 thisPtr += cdef->qualified;
960 thisPtr += " *>(this)";
961 constQualifier = "const";
962 }
963
964 if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) {
965 fprintf(out, ")%s\n{\n"
966 " QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n"
967 "}\n", constQualifier, thisPtr.constData(), index);
968 return;
969 }
970
971 int offset = 1;
972 for (int j = 0; j < def->arguments.count(); ++j) {
973 const ArgumentDef &a = def->arguments.at(j);
974 if (j)
975 fprintf(out, ", ");
976 fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
977 }
978 fprintf(out, ")%s\n{\n", constQualifier);
979 if (def->type.name.size() && def->normalizedType.size())
980 fprintf(out, " %s _t0;\n", noRef(def->normalizedType).constData());
981
982 fprintf(out, " void *_a[] = { ");
983 if (def->normalizedType.isEmpty()) {
984 fprintf(out, "0");
985 } else {
986 if (def->returnTypeIsVolatile)
987 fprintf(out, "const_cast<void*>(reinterpret_cast<const volatile void*>(&_t0))");
988 else
989 fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(&_t0))");
990 }
991 int i;
992 for (i = 1; i < offset; ++i)
993 if (def->arguments.at(i - 1).type.isVolatile)
994 fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t%d))", i);
995 else
996 fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
997 fprintf(out, " };\n");
998 int n = 0;
999 for (i = 0; i < def->arguments.count(); ++i)
1000 if (def->arguments.at(i).isDefault)
1001 ++n;
1002 if (n)
1003 fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, %d, _a);\n", thisPtr.constData(), index, index + n);
1004 else
1005 fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
1006 if (def->normalizedType.size())
1007 fprintf(out, " return _t0;\n");
1008 fprintf(out, "}\n");
1009}
1010
1011//
1012// Functions used when generating QMetaObject directly
1013//
1014// Much of this code is copied from the corresponding
1015// C++ code-generating functions; we can change the
1016// two generators so that more of the code is shared.
1017// The key difference from the C++ code generator is
1018// that instead of calling fprintf(), we append bytes
1019// to a buffer.
1020//
1021
1022QMetaObject *Generator::generateMetaObject(bool ignoreProperties)
1023{
1024//
1025// build the data array
1026//
1027
1028 // filter out undeclared enumerators and sets
1029 {
1030 QList<EnumDef> enumList;
1031 for (int i = 0; i < cdef->enumList.count(); ++i) {
1032 EnumDef def = cdef->enumList.at(i);
1033 if (cdef->enumDeclarations.contains(def.name)) {
1034 enumList += def;
1035 }
1036 QByteArray alias = cdef->flagAliases.value(def.name);
1037 if (cdef->enumDeclarations.contains(alias)) {
1038 def.name = alias;
1039 enumList += def;
1040 }
1041 }
1042 cdef->enumList = enumList;
1043 }
1044
1045 int index = 10;
1046 meta_data
1047 << 1 // revision
1048 << strreg(cdef->qualified) // classname
1049 << cdef->classInfoList.count() << (cdef->classInfoList.count() ? index : 0) // classinfo
1050 ;
1051 index += cdef->classInfoList.count() * 2;
1052
1053 int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
1054 meta_data << methodCount << (methodCount ? index : 0); // methods
1055 index += methodCount * 5;
1056 if (!ignoreProperties) {
1057 meta_data << cdef->propertyList.count() << (cdef->propertyList.count() ? index : 0); // properties
1058 index += cdef->propertyList.count() * 3;
1059 } else {
1060 meta_data << 0 << 0; // properties
1061 }
1062 meta_data << cdef->enumList.count() << (cdef->enumList.count() ? index : 0); // enums/sets
1063
1064//
1065// Build classinfo array
1066//
1067 _generateClassInfos();
1068
1069//
1070// Build signals array first, otherwise the signal indices would be wrong
1071//
1072 _generateFunctions(cdef->signalList, MethodSignal);
1073
1074//
1075// Build slots array
1076//
1077 _generateFunctions(cdef->slotList, MethodSlot);
1078
1079//
1080// Build method array
1081//
1082 _generateFunctions(cdef->methodList, MethodMethod);
1083
1084
1085//
1086// Build property array
1087//
1088 if (!ignoreProperties)
1089 _generateProperties();
1090
1091//
1092// Build enums array
1093//
1094 _generateEnums(index);
1095
1096//
1097// Terminate data array
1098//
1099 meta_data << 0;
1100
1101//
1102// Build stringdata array
1103//
1104 QVector<char> string_data;
1105 for (int i = 0; i < strings.size(); ++i) {
1106 const char *s = strings.at(i).constData();
1107 char c;
1108 do {
1109 c = *(s++);
1110 string_data << c;
1111 } while (c != '\0');
1112 }
1113
1114//
1115// Finally create and initialize the static meta object
1116//
1117 const int meta_object_offset = 0;
1118 const int meta_object_size = sizeof(QMetaObject);
1119 const int meta_data_offset = meta_object_offset + meta_object_size;
1120 const int meta_data_size = meta_data.count() * sizeof(uint);
1121 const int string_data_offset = meta_data_offset + meta_data_size;
1122 const int string_data_size = string_data.count();
1123 const int total_size = string_data_offset + string_data_size;
1124
1125 char *blob = new char[total_size];
1126
1127 char *string_data_output = blob + string_data_offset;
1128 const char *string_data_src = string_data.constData();
1129 for (int i = 0; i < string_data.count(); ++i)
1130 string_data_output[i] = string_data_src[i];
1131
1132 uint *meta_data_output = reinterpret_cast<uint *>(blob + meta_data_offset);
1133 const uint *meta_data_src = meta_data.constData();
1134 for (int i = 0; i < meta_data.count(); ++i)
1135 meta_data_output[i] = meta_data_src[i];
1136
1137 QMetaObject *meta_object = new (blob + meta_object_offset)QMetaObject;
1138 meta_object->d.superdata = 0;
1139 meta_object->d.stringdata = string_data_output;
1140 meta_object->d.data = meta_data_output;
1141 meta_object->d.extradata = 0;
1142 return meta_object;
1143}
1144
1145void Generator::_generateClassInfos()
1146{
1147 for (int i = 0; i < cdef->classInfoList.size(); ++i) {
1148 const ClassInfoDef &c = cdef->classInfoList.at(i);
1149 meta_data << strreg(c.name) << strreg(c.value);
1150 }
1151}
1152
1153void Generator::_generateFunctions(QList<FunctionDef> &list, int type)
1154{
1155 for (int i = 0; i < list.count(); ++i) {
1156 const FunctionDef &f = list.at(i);
1157
1158 QByteArray sig = f.name + '(';
1159 QByteArray arguments;
1160
1161 for (int j = 0; j < f.arguments.count(); ++j) {
1162 const ArgumentDef &a = f.arguments.at(j);
1163 if (j) {
1164 sig += ",";
1165 arguments += ",";
1166 }
1167 sig += a.normalizedType;
1168 arguments += a.name;
1169 }
1170 sig += ')';
1171
1172 char flags = type;
1173 if (f.access == FunctionDef::Private)
1174 flags |= AccessPrivate;
1175 else if (f.access == FunctionDef::Public)
1176 flags |= AccessPublic;
1177 else if (f.access == FunctionDef::Protected)
1178 flags |= AccessProtected;
1179 if (f.access == FunctionDef::Private)
1180 flags |= AccessPrivate;
1181 else if (f.access == FunctionDef::Public)
1182 flags |= AccessPublic;
1183 else if (f.access == FunctionDef::Protected)
1184 flags |= AccessProtected;
1185 if (f.isCompat)
1186 flags |= MethodCompatibility;
1187 if (f.wasCloned)
1188 flags |= MethodCloned;
1189 if (f.isScriptable)
1190 flags |= MethodScriptable;
1191
1192 meta_data << strreg(sig)
1193 << strreg(arguments)
1194 << strreg(f.normalizedType)
1195 << strreg(f.tag)
1196 << flags;
1197 }
1198}
1199
1200void Generator::_generateEnums(int index)
1201{
1202 index += 4 * cdef->enumList.count();
1203 int i;
1204 for (i = 0; i < cdef->enumList.count(); ++i) {
1205 const EnumDef &e = cdef->enumList.at(i);
1206 meta_data << strreg(e.name) << (cdef->enumDeclarations.value(e.name) ? 1 : 0)
1207 << e.values.count() << index;
1208 index += e.values.count() * 2;
1209 }
1210
1211 for (i = 0; i < cdef->enumList.count(); ++i) {
1212 const EnumDef &e = cdef->enumList.at(i);
1213 for (int j = 0; j < e.values.count(); ++j) {
1214 const QByteArray &val = e.values.at(j);
1215 meta_data << strreg(val) << 0; // we don't know the value itself
1216 }
1217 }
1218}
1219
1220void Generator::_generateProperties()
1221{
1222 //
1223 // specify get function, for compatibiliy we accept functions
1224 // returning pointers, or const char * for QByteArray.
1225 //
1226 for (int i = 0; i < cdef->propertyList.count(); ++i) {
1227 PropertyDef &p = cdef->propertyList[i];
1228 if (p.read.isEmpty())
1229 continue;
1230 for (int j = 0; j < cdef->publicList.count(); ++j) {
1231 const FunctionDef &f = cdef->publicList.at(j);
1232 if (f.name != p.read)
1233 continue;
1234 if (!f.isConst) // get functions must be const
1235 continue;
1236 if (f.arguments.size()) // and must not take any arguments
1237 continue;
1238 PropertyDef::Specification spec = PropertyDef::ValueSpec;
1239 QByteArray tmp = f.normalizedType;
1240 if (p.type == "QByteArray" && tmp == "const char *")
1241 tmp = "QByteArray";
1242 if (tmp.left(6) == "const ")
1243 tmp = tmp.mid(6);
1244 if (p.type != tmp && tmp.endsWith('*')) {
1245 tmp.chop(1);
1246 spec = PropertyDef::PointerSpec;
1247 } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
1248 spec = PropertyDef::ReferenceSpec;
1249 }
1250 if (p.type != tmp)
1251 continue;
1252 p.gspec = spec;
1253 break;
1254 }
1255 }
1256
1257
1258 //
1259 // Create meta data
1260 //
1261
1262 for (int i = 0; i < cdef->propertyList.count(); ++i) {
1263 const PropertyDef &p = cdef->propertyList.at(i);
1264 uint flags = Invalid;
1265 if (!isVariantType(p.type)) {
1266 flags |= EnumOrFlag;
1267 } else {
1268 flags |= qvariant_nameToType(p.type) << 24;
1269 }
1270 if (!p.read.isEmpty())
1271 flags |= Readable;
1272 if (!p.write.isEmpty()) {
1273 flags |= Writable;
1274 if (p.stdCppSet())
1275 flags |= StdCppSet;
1276 }
1277 if (!p.reset.isEmpty())
1278 flags |= Resettable;
1279
1280// if (p.override)
1281// flags |= Override;
1282
1283 if (p.designable.isEmpty())
1284 flags |= ResolveDesignable;
1285 else if (p.designable != "false")
1286 flags |= Designable;
1287
1288 if (p.scriptable.isEmpty())
1289 flags |= ResolveScriptable;
1290 else if (p.scriptable != "false")
1291 flags |= Scriptable;
1292
1293 if (p.stored.isEmpty())
1294 flags |= ResolveStored;
1295 else if (p.stored != "false")
1296 flags |= Stored;
1297
1298 if (p.editable.isEmpty())
1299 flags |= ResolveEditable;
1300 else if (p.editable != "false")
1301 flags |= Editable;
1302
1303 if (p.user.isEmpty())
1304 flags |= ResolveUser;
1305 else if (p.user != "false")
1306 flags |= User;
1307
1308 meta_data << strreg(p.name) << strreg(p.type) << flags;
1309 }
1310}
1311
1312QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.