source: trunk/src/tools/moc/generator.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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