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

Last change on this file since 1056 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 43.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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", 5);
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 // Create meta data
487 //
488
489 if (cdef->propertyList.count())
490 fprintf(out, "\n // properties: name, type, flags\n");
491 for (int i = 0; i < cdef->propertyList.count(); ++i) {
492 const PropertyDef &p = cdef->propertyList.at(i);
493 uint flags = Invalid;
494 if (!isVariantType(p.type)) {
495 flags |= EnumOrFlag;
496 } else if (!isQRealType(p.type)) {
497 flags |= qvariant_nameToType(p.type) << 24;
498 }
499 if (!p.read.isEmpty())
500 flags |= Readable;
501 if (!p.write.isEmpty()) {
502 flags |= Writable;
503 if (p.stdCppSet())
504 flags |= StdCppSet;
505 }
506 if (!p.reset.isEmpty())
507 flags |= Resettable;
508
509// if (p.override)
510// flags |= Override;
511
512 if (p.designable.isEmpty())
513 flags |= ResolveDesignable;
514 else if (p.designable != "false")
515 flags |= Designable;
516
517 if (p.scriptable.isEmpty())
518 flags |= ResolveScriptable;
519 else if (p.scriptable != "false")
520 flags |= Scriptable;
521
522 if (p.stored.isEmpty())
523 flags |= ResolveStored;
524 else if (p.stored != "false")
525 flags |= Stored;
526
527 if (p.editable.isEmpty())
528 flags |= ResolveEditable;
529 else if (p.editable != "false")
530 flags |= Editable;
531
532 if (p.user.isEmpty())
533 flags |= ResolveUser;
534 else if (p.user != "false")
535 flags |= User;
536
537 if (p.notifyId != -1)
538 flags |= Notify;
539
540 if (p.constant)
541 flags |= Constant;
542 if (p.final)
543 flags |= Final;
544
545 fprintf(out, " %4d, %4d, ",
546 strreg(p.name),
547 strreg(p.type));
548 if (!(flags >> 24) && isQRealType(p.type))
549 fprintf(out, "(QMetaType::QReal << 24) | ");
550 fprintf(out, "0x%.8x,\n", flags);
551 }
552
553 if(cdef->notifyableProperties) {
554 fprintf(out, "\n // properties: notify_signal_id\n");
555 for (int i = 0; i < cdef->propertyList.count(); ++i) {
556 const PropertyDef &p = cdef->propertyList.at(i);
557 if(p.notifyId == -1)
558 fprintf(out, " %4d,\n",
559 0);
560 else
561 fprintf(out, " %4d,\n",
562 p.notifyId);
563 }
564 }
565}
566
567void Generator::generateEnums(int index)
568{
569 if (cdef->enumDeclarations.isEmpty())
570 return;
571
572 fprintf(out, "\n // enums: name, flags, count, data\n");
573 index += 4 * cdef->enumList.count();
574 int i;
575 for (i = 0; i < cdef->enumList.count(); ++i) {
576 const EnumDef &e = cdef->enumList.at(i);
577 fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
578 strreg(e.name),
579 cdef->enumDeclarations.value(e.name) ? 1 : 0,
580 e.values.count(),
581 index);
582 index += e.values.count() * 2;
583 }
584
585 fprintf(out, "\n // enum data: key, value\n");
586 for (i = 0; i < cdef->enumList.count(); ++i) {
587 const EnumDef &e = cdef->enumList.at(i);
588 for (int j = 0; j < e.values.count(); ++j) {
589 const QByteArray &val = e.values.at(j);
590 fprintf(out, " %4d, uint(%s::%s),\n",
591 strreg(val),
592 cdef->qualified.constData(),
593 val.constData());
594 }
595 }
596}
597
598void Generator::generateMetacall()
599{
600 bool isQObject = (cdef->classname == "QObject");
601
602 fprintf(out, "\nint %s::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
603 cdef->qualified.constData());
604
605 if (!purestSuperClass.isEmpty() && !isQObject) {
606 QByteArray superClass = purestSuperClass;
607 // workaround for VC6
608 if (superClass.contains("::")) {
609 fprintf(out, " typedef %s QMocSuperClass;\n", superClass.constData());
610 superClass = "QMocSuperClass";
611 }
612 fprintf(out, " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
613 }
614
615 fprintf(out, " if (_id < 0)\n return _id;\n");
616 fprintf(out, " ");
617
618 bool needElse = false;
619 QList<FunctionDef> methodList;
620 methodList += cdef->signalList;
621 methodList += cdef->slotList;
622 methodList += cdef->methodList;
623
624 if (methodList.size()) {
625 needElse = true;
626 fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n ");
627 fprintf(out, "switch (_id) {\n");
628 for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
629 const FunctionDef &f = methodList.at(methodindex);
630 fprintf(out, " case %d: ", methodindex);
631 if (f.normalizedType.size())
632 fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
633 if (f.inPrivateClass.size())
634 fprintf(out, "%s->", f.inPrivateClass.constData());
635 fprintf(out, "%s(", f.name.constData());
636 int offset = 1;
637 for (int j = 0; j < f.arguments.count(); ++j) {
638 const ArgumentDef &a = f.arguments.at(j);
639 if (j)
640 fprintf(out, ",");
641 fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
642 }
643 fprintf(out, ");");
644 if (f.normalizedType.size())
645 fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
646 noRef(f.normalizedType).constData());
647 fprintf(out, " break;\n");
648 }
649 fprintf(out, " default: ;\n");
650 fprintf(out, " }\n");
651 }
652 if (methodList.size())
653 fprintf(out, " _id -= %d;\n }", methodList.size());
654
655 if (cdef->propertyList.size()) {
656 bool needGet = false;
657 bool needTempVarForGet = false;
658 bool needSet = false;
659 bool needReset = false;
660 bool needDesignable = false;
661 bool needScriptable = false;
662 bool needStored = false;
663 bool needEditable = false;
664 bool needUser = false;
665 for (int i = 0; i < cdef->propertyList.size(); ++i) {
666 const PropertyDef &p = cdef->propertyList.at(i);
667 needGet |= !p.read.isEmpty();
668 if (!p.read.isEmpty())
669 needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
670 && p.gspec != PropertyDef::ReferenceSpec);
671
672 needSet |= !p.write.isEmpty();
673 needReset |= !p.reset.isEmpty();
674 needDesignable |= p.designable.endsWith(')');
675 needScriptable |= p.scriptable.endsWith(')');
676 needStored |= p.stored.endsWith(')');
677 needEditable |= p.editable.endsWith(')');
678 needUser |= p.user.endsWith(')');
679 }
680 fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
681
682 if (needElse)
683 fprintf(out, " else ");
684 fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n");
685 if (needGet) {
686 if (needTempVarForGet)
687 fprintf(out, " void *_v = _a[0];\n");
688 fprintf(out, " switch (_id) {\n");
689 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
690 const PropertyDef &p = cdef->propertyList.at(propindex);
691 if (p.read.isEmpty())
692 continue;
693 QByteArray prefix;
694 if (p.inPrivateClass.size()) {
695 prefix = p.inPrivateClass;
696 prefix.append("->");
697 }
698 if (p.gspec == PropertyDef::PointerSpec)
699 fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s%s())); break;\n",
700 propindex, prefix.constData(), p.read.constData());
701 else if (p.gspec == PropertyDef::ReferenceSpec)
702 fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(&%s%s())); break;\n",
703 propindex, prefix.constData(), p.read.constData());
704 else if (cdef->enumDeclarations.value(p.type, false))
705 fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
706 propindex, prefix.constData(), p.read.constData());
707 else
708 fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
709 propindex, p.type.constData(), prefix.constData(), p.read.constData());
710 }
711 fprintf(out, " }\n");
712 }
713
714 fprintf(out,
715 " _id -= %d;\n"
716 " }", cdef->propertyList.count());
717
718 fprintf(out, " else ");
719 fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n");
720
721 if (needSet) {
722 fprintf(out, " void *_v = _a[0];\n");
723 fprintf(out, " switch (_id) {\n");
724 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
725 const PropertyDef &p = cdef->propertyList.at(propindex);
726 if (p.write.isEmpty())
727 continue;
728 QByteArray prefix;
729 if (p.inPrivateClass.size()) {
730 prefix = p.inPrivateClass;
731 prefix.append("->");
732 }
733 if (cdef->enumDeclarations.value(p.type, false)) {
734 fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
735 propindex, prefix.constData(), p.write.constData());
736 } else {
737 fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n",
738 propindex, prefix.constData(), p.write.constData(), p.type.constData());
739 }
740 }
741 fprintf(out, " }\n");
742 }
743
744 fprintf(out,
745 " _id -= %d;\n"
746 " }", cdef->propertyList.count());
747
748 fprintf(out, " else ");
749 fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n");
750 if (needReset) {
751 fprintf(out, " switch (_id) {\n");
752 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
753 const PropertyDef &p = cdef->propertyList.at(propindex);
754 if (!p.reset.endsWith(')'))
755 continue;
756 QByteArray prefix;
757 if (p.inPrivateClass.size()) {
758 prefix = p.inPrivateClass;
759 prefix.append("->");
760 }
761 fprintf(out, " case %d: %s%s; break;\n",
762 propindex, prefix.constData(), p.reset.constData());
763 }
764 fprintf(out, " }\n");
765 }
766 fprintf(out,
767 " _id -= %d;\n"
768 " }", cdef->propertyList.count());
769
770 fprintf(out, " else ");
771 fprintf(out, "if (_c == QMetaObject::QueryPropertyDesignable) {\n");
772 if (needDesignable) {
773 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
774 fprintf(out, " switch (_id) {\n");
775 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
776 const PropertyDef &p = cdef->propertyList.at(propindex);
777 if (!p.designable.endsWith(')'))
778 continue;
779 fprintf(out, " case %d: *_b = %s; break;\n",
780 propindex, p.designable.constData());
781 }
782 fprintf(out, " }\n");
783 }
784 fprintf(out,
785 " _id -= %d;\n"
786 " }", cdef->propertyList.count());
787
788 fprintf(out, " else ");
789 fprintf(out, "if (_c == QMetaObject::QueryPropertyScriptable) {\n");
790 if (needScriptable) {
791 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
792 fprintf(out, " switch (_id) {\n");
793 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
794 const PropertyDef &p = cdef->propertyList.at(propindex);
795 if (!p.scriptable.endsWith(')'))
796 continue;
797 fprintf(out, " case %d: *_b = %s; break;\n",
798 propindex, p.scriptable.constData());
799 }
800 fprintf(out, " }\n");
801 }
802 fprintf(out,
803 " _id -= %d;\n"
804 " }", cdef->propertyList.count());
805
806 fprintf(out, " else ");
807 fprintf(out, "if (_c == QMetaObject::QueryPropertyStored) {\n");
808 if (needStored) {
809 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
810 fprintf(out, " switch (_id) {\n");
811 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
812 const PropertyDef &p = cdef->propertyList.at(propindex);
813 if (!p.stored.endsWith(')'))
814 continue;
815 fprintf(out, " case %d: *_b = %s; break;\n",
816 propindex, p.stored.constData());
817 }
818 fprintf(out, " }\n");
819 }
820 fprintf(out,
821 " _id -= %d;\n"
822 " }", cdef->propertyList.count());
823
824 fprintf(out, " else ");
825 fprintf(out, "if (_c == QMetaObject::QueryPropertyEditable) {\n");
826 if (needEditable) {
827 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
828 fprintf(out, " switch (_id) {\n");
829 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
830 const PropertyDef &p = cdef->propertyList.at(propindex);
831 if (!p.editable.endsWith(')'))
832 continue;
833 fprintf(out, " case %d: *_b = %s; break;\n",
834 propindex, p.editable.constData());
835 }
836 fprintf(out, " }\n");
837 }
838 fprintf(out,
839 " _id -= %d;\n"
840 " }", cdef->propertyList.count());
841
842
843 fprintf(out, " else ");
844 fprintf(out, "if (_c == QMetaObject::QueryPropertyUser) {\n");
845 if (needUser) {
846 fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
847 fprintf(out, " switch (_id) {\n");
848 for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
849 const PropertyDef &p = cdef->propertyList.at(propindex);
850 if (!p.user.endsWith(')'))
851 continue;
852 fprintf(out, " case %d: *_b = %s; break;\n",
853 propindex, p.user.constData());
854 }
855 fprintf(out, " }\n");
856 }
857 fprintf(out,
858 " _id -= %d;\n"
859 " }", cdef->propertyList.count());
860
861
862 fprintf(out, "\n#endif // QT_NO_PROPERTIES");
863 }
864 if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size())
865 fprintf(out, "\n ");
866 fprintf(out,"return _id;\n}\n");
867}
868
869void Generator::generateStaticMetacall(const QByteArray &prefix)
870{
871 bool isQObject = (cdef->classname == "QObject");
872
873 fprintf(out, "static int %s_qt_static_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n",
874 prefix.constData());
875
876 fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
877 fprintf(out, " switch (_id) {\n");
878 for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
879 fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
880 cdef->qualified.constData(), cdef->qualified.constData());
881 const FunctionDef &f = cdef->constructorList.at(ctorindex);
882 int offset = 1;
883 for (int j = 0; j < f.arguments.count(); ++j) {
884 const ArgumentDef &a = f.arguments.at(j);
885 if (j)
886 fprintf(out, ",");
887 fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
888 }
889 fprintf(out, ");\n");
890 fprintf(out, " if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break;\n");
891 }
892 fprintf(out, " }\n");
893 fprintf(out, " _id -= %d;\n", cdef->constructorList.count());
894 fprintf(out, " return _id;\n");
895 fprintf(out, " }\n");
896
897 if (!isQObject)
898 fprintf(out, " _id = %s::staticMetaObject.superClass()->static_metacall(_c, _id, _a);\n", cdef->qualified.constData());
899
900 fprintf(out, " if (_id < 0)\n return _id;\n");
901
902 fprintf(out, " return _id;\n");
903 fprintf(out, "}\n\n");
904}
905
906void Generator::generateSignal(FunctionDef *def,int index)
907{
908 if (def->wasCloned || def->isAbstract)
909 return;
910 fprintf(out, "\n// SIGNAL %d\n%s %s::%s(",
911 index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
912
913 QByteArray thisPtr = "this";
914 const char *constQualifier = "";
915
916 if (def->isConst) {
917 thisPtr = "const_cast< ";
918 thisPtr += cdef->qualified;
919 thisPtr += " *>(this)";
920 constQualifier = "const";
921 }
922
923 if (def->arguments.isEmpty() && def->normalizedType.isEmpty()) {
924 fprintf(out, ")%s\n{\n"
925 " QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n"
926 "}\n", constQualifier, thisPtr.constData(), index);
927 return;
928 }
929
930 int offset = 1;
931 for (int j = 0; j < def->arguments.count(); ++j) {
932 const ArgumentDef &a = def->arguments.at(j);
933 if (j)
934 fprintf(out, ", ");
935 fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
936 }
937 fprintf(out, ")%s\n{\n", constQualifier);
938 if (def->type.name.size() && def->normalizedType.size())
939 fprintf(out, " %s _t0;\n", noRef(def->normalizedType).constData());
940
941 fprintf(out, " void *_a[] = { ");
942 if (def->normalizedType.isEmpty()) {
943 fprintf(out, "0");
944 } else {
945 if (def->returnTypeIsVolatile)
946 fprintf(out, "const_cast<void*>(reinterpret_cast<const volatile void*>(&_t0))");
947 else
948 fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(&_t0))");
949 }
950 int i;
951 for (i = 1; i < offset; ++i)
952 if (def->arguments.at(i - 1).type.isVolatile)
953 fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t%d))", i);
954 else
955 fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
956 fprintf(out, " };\n");
957 fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
958 if (def->normalizedType.size())
959 fprintf(out, " return _t0;\n");
960 fprintf(out, "}\n");
961}
962
963//
964// Functions used when generating QMetaObject directly
965//
966// Much of this code is copied from the corresponding
967// C++ code-generating functions; we can change the
968// two generators so that more of the code is shared.
969// The key difference from the C++ code generator is
970// that instead of calling fprintf(), we append bytes
971// to a buffer.
972//
973
974QMetaObject *Generator::generateMetaObject(bool ignoreProperties)
975{
976//
977// build the data array
978//
979
980 // filter out undeclared enumerators and sets
981 {
982 QList<EnumDef> enumList;
983 for (int i = 0; i < cdef->enumList.count(); ++i) {
984 EnumDef def = cdef->enumList.at(i);
985 if (cdef->enumDeclarations.contains(def.name)) {
986 enumList += def;
987 }
988 QByteArray alias = cdef->flagAliases.value(def.name);
989 if (cdef->enumDeclarations.contains(alias)) {
990 def.name = alias;
991 enumList += def;
992 }
993 }
994 cdef->enumList = enumList;
995 }
996
997 int index = 10;
998 meta_data
999 << 1 // revision
1000 << strreg(cdef->qualified) // classname
1001 << cdef->classInfoList.count() << (cdef->classInfoList.count() ? index : 0) // classinfo
1002 ;
1003 index += cdef->classInfoList.count() * 2;
1004
1005 int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
1006 meta_data << methodCount << (methodCount ? index : 0); // methods
1007 index += methodCount * 5;
1008 if (!ignoreProperties) {
1009 meta_data << cdef->propertyList.count() << (cdef->propertyList.count() ? index : 0); // properties
1010 index += cdef->propertyList.count() * 3;
1011 } else {
1012 meta_data << 0 << 0; // properties
1013 }
1014 meta_data << cdef->enumList.count() << (cdef->enumList.count() ? index : 0); // enums/sets
1015
1016//
1017// Build classinfo array
1018//
1019 _generateClassInfos();
1020
1021//
1022// Build signals array first, otherwise the signal indices would be wrong
1023//
1024 _generateFunctions(cdef->signalList, MethodSignal);
1025
1026//
1027// Build slots array
1028//
1029 _generateFunctions(cdef->slotList, MethodSlot);
1030
1031//
1032// Build method array
1033//
1034 _generateFunctions(cdef->methodList, MethodMethod);
1035
1036
1037//
1038// Build property array
1039//
1040 if (!ignoreProperties)
1041 _generateProperties();
1042
1043//
1044// Build enums array
1045//
1046 _generateEnums(index);
1047
1048//
1049// Terminate data array
1050//
1051 meta_data << 0;
1052
1053//
1054// Build stringdata array
1055//
1056 QVector<char> string_data;
1057 for (int i = 0; i < strings.size(); ++i) {
1058 const char *s = strings.at(i).constData();
1059 char c;
1060 do {
1061 c = *(s++);
1062 string_data << c;
1063 } while (c != '\0');
1064 }
1065
1066//
1067// Finally create and initialize the static meta object
1068//
1069 const int meta_object_offset = 0;
1070 const int meta_object_size = sizeof(QMetaObject);
1071 const int meta_data_offset = meta_object_offset + meta_object_size;
1072 const int meta_data_size = meta_data.count() * sizeof(uint);
1073 const int string_data_offset = meta_data_offset + meta_data_size;
1074 const int string_data_size = string_data.count();
1075 const int total_size = string_data_offset + string_data_size;
1076
1077 char *blob = new char[total_size];
1078
1079 char *string_data_output = blob + string_data_offset;
1080 const char *string_data_src = string_data.constData();
1081 for (int i = 0; i < string_data.count(); ++i)
1082 string_data_output[i] = string_data_src[i];
1083
1084 uint *meta_data_output = reinterpret_cast<uint *>(blob + meta_data_offset);
1085 const uint *meta_data_src = meta_data.constData();
1086 for (int i = 0; i < meta_data.count(); ++i)
1087 meta_data_output[i] = meta_data_src[i];
1088
1089 QMetaObject *meta_object = new (blob + meta_object_offset)QMetaObject;
1090 meta_object->d.superdata = 0;
1091 meta_object->d.stringdata = string_data_output;
1092 meta_object->d.data = meta_data_output;
1093 meta_object->d.extradata = 0;
1094 return meta_object;
1095}
1096
1097void Generator::_generateClassInfos()
1098{
1099 for (int i = 0; i < cdef->classInfoList.size(); ++i) {
1100 const ClassInfoDef &c = cdef->classInfoList.at(i);
1101 meta_data << strreg(c.name) << strreg(c.value);
1102 }
1103}
1104
1105void Generator::_generateFunctions(QList<FunctionDef> &list, int type)
1106{
1107 for (int i = 0; i < list.count(); ++i) {
1108 const FunctionDef &f = list.at(i);
1109
1110 QByteArray sig = f.name + '(';
1111 QByteArray arguments;
1112
1113 for (int j = 0; j < f.arguments.count(); ++j) {
1114 const ArgumentDef &a = f.arguments.at(j);
1115 if (j) {
1116 sig += ',';
1117 arguments += ',';
1118 }
1119 sig += a.normalizedType;
1120 arguments += a.name;
1121 }
1122 sig += ')';
1123
1124 char flags = type;
1125 if (f.access == FunctionDef::Private)
1126 flags |= AccessPrivate;
1127 else if (f.access == FunctionDef::Public)
1128 flags |= AccessPublic;
1129 else if (f.access == FunctionDef::Protected)
1130 flags |= AccessProtected;
1131 if (f.access == FunctionDef::Private)
1132 flags |= AccessPrivate;
1133 else if (f.access == FunctionDef::Public)
1134 flags |= AccessPublic;
1135 else if (f.access == FunctionDef::Protected)
1136 flags |= AccessProtected;
1137 if (f.isCompat)
1138 flags |= MethodCompatibility;
1139 if (f.wasCloned)
1140 flags |= MethodCloned;
1141 if (f.isScriptable)
1142 flags |= MethodScriptable;
1143
1144 meta_data << strreg(sig)
1145 << strreg(arguments)
1146 << strreg(f.normalizedType)
1147 << strreg(f.tag)
1148 << flags;
1149 }
1150}
1151
1152void Generator::_generateEnums(int index)
1153{
1154 index += 4 * cdef->enumList.count();
1155 int i;
1156 for (i = 0; i < cdef->enumList.count(); ++i) {
1157 const EnumDef &e = cdef->enumList.at(i);
1158 meta_data << strreg(e.name) << (cdef->enumDeclarations.value(e.name) ? 1 : 0)
1159 << e.values.count() << index;
1160 index += e.values.count() * 2;
1161 }
1162
1163 for (i = 0; i < cdef->enumList.count(); ++i) {
1164 const EnumDef &e = cdef->enumList.at(i);
1165 for (int j = 0; j < e.values.count(); ++j) {
1166 const QByteArray &val = e.values.at(j);
1167 meta_data << strreg(val) << 0; // we don't know the value itself
1168 }
1169 }
1170}
1171
1172void Generator::_generateProperties()
1173{
1174 //
1175 // specify get function, for compatibiliy we accept functions
1176 // returning pointers, or const char * for QByteArray.
1177 //
1178 for (int i = 0; i < cdef->propertyList.count(); ++i) {
1179 PropertyDef &p = cdef->propertyList[i];
1180 if (p.read.isEmpty())
1181 continue;
1182 for (int j = 0; j < cdef->publicList.count(); ++j) {
1183 const FunctionDef &f = cdef->publicList.at(j);
1184 if (f.name != p.read)
1185 continue;
1186 if (!f.isConst) // get functions must be const
1187 continue;
1188 if (f.arguments.size()) // and must not take any arguments
1189 continue;
1190 PropertyDef::Specification spec = PropertyDef::ValueSpec;
1191 QByteArray tmp = f.normalizedType;
1192 if (p.type == "QByteArray" && tmp == "const char *")
1193 tmp = "QByteArray";
1194 if (tmp.left(6) == "const ")
1195 tmp = tmp.mid(6);
1196 if (p.type != tmp && tmp.endsWith('*')) {
1197 tmp.chop(1);
1198 spec = PropertyDef::PointerSpec;
1199 } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
1200 spec = PropertyDef::ReferenceSpec;
1201 }
1202 if (p.type != tmp)
1203 continue;
1204 p.gspec = spec;
1205 break;
1206 }
1207 }
1208
1209
1210 //
1211 // Create meta data
1212 //
1213
1214 for (int i = 0; i < cdef->propertyList.count(); ++i) {
1215 const PropertyDef &p = cdef->propertyList.at(i);
1216 uint flags = Invalid;
1217 if (!isVariantType(p.type)) {
1218 flags |= EnumOrFlag;
1219 } else {
1220 flags |= qvariant_nameToType(p.type) << 24;
1221 }
1222 if (!p.read.isEmpty())
1223 flags |= Readable;
1224 if (!p.write.isEmpty()) {
1225 flags |= Writable;
1226 if (p.stdCppSet())
1227 flags |= StdCppSet;
1228 }
1229 if (!p.reset.isEmpty())
1230 flags |= Resettable;
1231
1232// if (p.override)
1233// flags |= Override;
1234
1235 if (p.designable.isEmpty())
1236 flags |= ResolveDesignable;
1237 else if (p.designable != "false")
1238 flags |= Designable;
1239
1240 if (p.scriptable.isEmpty())
1241 flags |= ResolveScriptable;
1242 else if (p.scriptable != "false")
1243 flags |= Scriptable;
1244
1245 if (p.stored.isEmpty())
1246 flags |= ResolveStored;
1247 else if (p.stored != "false")
1248 flags |= Stored;
1249
1250 if (p.editable.isEmpty())
1251 flags |= ResolveEditable;
1252 else if (p.editable != "false")
1253 flags |= Editable;
1254
1255 if (p.user.isEmpty())
1256 flags |= ResolveUser;
1257 else if (p.user != "false")
1258 flags |= User;
1259
1260 meta_data << strreg(p.name) << strreg(p.type) << flags;
1261 }
1262}
1263
1264QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.