Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / tools / moc / moc.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the tools applications of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "moc.h"
43 #include "generator.h"
44 #include "qdatetime.h"
45 #include "utils.h"
46 #include "outputrevision.h"
47
48 // for normalizeTypeInternal
49 #include <private/qmetaobject_p.h>
50
51 QT_BEGIN_NAMESPACE
52
53 // only moc needs this function
54 static QByteArray normalizeType(const char *s, bool fixScope = false)
55 {
56     int len = qstrlen(s);
57     char stackbuf[64];
58     char *buf = (len >= 64 ? new char[len + 1] : stackbuf);
59     char *d = buf;
60     char last = 0;
61     while(*s && is_space(*s))
62         s++;
63     while (*s) {
64         while (*s && !is_space(*s))
65             last = *d++ = *s++;
66         while (*s && is_space(*s))
67             s++;
68         if (*s && ((is_ident_char(*s) && is_ident_char(last))
69                    || ((*s == ':') && (last == '<')))) {
70             last = *d++ = ' ';
71         }
72     }
73     *d = '\0';
74     QByteArray result;
75     if (strncmp("void", buf, d - buf) != 0)
76         result = normalizeTypeInternal(buf, d, fixScope);
77     if (buf != stackbuf)
78         delete [] buf;
79     return result;
80 }
81
82 bool Moc::parseClassHead(ClassDef *def)
83 {
84     // figure out whether this is a class declaration, or only a
85     // forward or variable declaration.
86     int i = 0;
87     Token token;
88     do {
89         token = lookup(i++);
90         if (token == COLON || token == LBRACE)
91             break;
92         if (token == SEMIC || token == RANGLE)
93             return false;
94     } while (token);
95
96     if (!test(IDENTIFIER)) // typedef struct { ... }
97         return false;
98     QByteArray name = lexem();
99
100     // support "class IDENT name" and "class IDENT(IDENT) name"
101     if (test(LPAREN)) {
102         until(RPAREN);
103         if (!test(IDENTIFIER))
104             return false;
105         name = lexem();
106     } else  if (test(IDENTIFIER)) {
107         name = lexem();
108     }
109
110     def->qualified += name;
111     while (test(SCOPE)) {
112         def->qualified += lexem();
113         if (test(IDENTIFIER)) {
114             name = lexem();
115             def->qualified += name;
116         }
117     }
118     def->classname = name;
119     if (test(COLON)) {
120         do {
121             test(VIRTUAL);
122             FunctionDef::Access access = FunctionDef::Public;
123             if (test(PRIVATE))
124                 access = FunctionDef::Private;
125             else if (test(PROTECTED))
126                 access = FunctionDef::Protected;
127             else
128                 test(PUBLIC);
129             test(VIRTUAL);
130             const QByteArray type = parseType().name;
131             // ignore the 'class Foo : BAR(Baz)' case
132             if (test(LPAREN)) {
133                 until(RPAREN);
134             } else {
135                 def->superclassList += qMakePair(type, access);
136             }
137         } while (test(COMMA));
138     }
139     if (!test(LBRACE))
140         return false;
141     def->begin = index - 1;
142     bool foundRBrace = until(RBRACE);
143     def->end = index;
144     index = def->begin + 1;
145     return foundRBrace;
146 }
147
148 Type Moc::parseType()
149 {
150     Type type;
151     bool hasSignedOrUnsigned = false;
152     bool isVoid = false;
153     type.firstToken = lookup();
154     for (;;) {
155         switch (next()) {
156             case SIGNED:
157             case UNSIGNED:
158                 hasSignedOrUnsigned = true;
159                 // fall through
160             case CONST:
161             case VOLATILE:
162                 type.name += lexem();
163                 type.name += ' ';
164                 if (lookup(0) == VOLATILE)
165                     type.isVolatile = true;
166                 continue;
167             case Q_MOC_COMPAT_TOKEN:
168             case Q_QT3_SUPPORT_TOKEN:
169             case Q_INVOKABLE_TOKEN:
170             case Q_SCRIPTABLE_TOKEN:
171             case Q_SIGNALS_TOKEN:
172             case Q_SLOTS_TOKEN:
173             case Q_SIGNAL_TOKEN:
174             case Q_SLOT_TOKEN:
175                 type.name += lexem();
176                 return type;
177             default:
178                 prev();
179                 break;
180         }
181         break;
182     }
183     test(ENUM) || test(CLASS) || test(STRUCT);
184     for(;;) {
185         switch (next()) {
186         case IDENTIFIER:
187             // void mySlot(unsigned myArg)
188             if (hasSignedOrUnsigned) {
189                 prev();
190                 break;
191             }
192         case CHAR:
193         case SHORT:
194         case INT:
195         case LONG:
196             type.name += lexem();
197             // preserve '[unsigned] long long', 'short int', 'long int', 'long double'
198             if (test(LONG) || test(INT) || test(DOUBLE)) {
199                 type.name += ' ';
200                 prev();
201                 continue;
202             }
203             break;
204         case FLOAT:
205         case DOUBLE:
206         case VOID:
207         case BOOL:
208             type.name += lexem();
209             isVoid |= (lookup(0) == VOID);
210             break;
211         default:
212             prev();
213             ;
214         }
215         if (test(LANGLE)) {
216             QByteArray templ = lexemUntil(RANGLE);
217             for (int i = 0; i < templ.size(); ++i) {
218                 type.name += templ.at(i);
219                 if ((templ.at(i) == '<' && i+1 < templ.size() && templ.at(i+1) == ':')
220                     || (templ.at(i) == '>' && i+1 < templ.size() && templ.at(i+1) == '>')) {
221                     type.name += ' ';
222                 }
223             }
224         }
225         if (test(SCOPE)) {
226             type.name += lexem();
227             type.isScoped = true;
228         } else {
229             break;
230         }
231     }
232     while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
233            || test(STAR) || test(AND) || test(ANDAND)) {
234         type.name += ' ';
235         type.name += lexem();
236         if (lookup(0) == AND)
237             type.referenceType = Type::Reference;
238         else if (lookup(0) == ANDAND)
239             type.referenceType = Type::RValueReference;
240         else if (lookup(0) == STAR)
241             type.referenceType = Type::Pointer;
242     }
243     // transform stupid things like 'const void' or 'void const' into 'void'
244     if (isVoid && type.referenceType == Type::NoReference) {
245         type.name = "void";
246     }
247     return type;
248 }
249
250 bool Moc::parseEnum(EnumDef *def)
251 {
252     bool isTypdefEnum = false; // typedef enum { ... } Foo;
253
254     if (test(IDENTIFIER)) {
255         def->name = lexem();
256     } else {
257         if (lookup(-1) != TYPEDEF)
258             return false; // anonymous enum
259         isTypdefEnum = true;
260     }
261     if (!test(LBRACE))
262         return false;
263     do {
264         if (lookup() == RBRACE) // accept trailing comma
265             break;
266         next(IDENTIFIER);
267         def->values += lexem();
268     } while (test(EQ) ? until(COMMA) : test(COMMA));
269     next(RBRACE);
270     if (isTypdefEnum) {
271         if (!test(IDENTIFIER))
272             return false;
273         def->name = lexem();
274     }
275     return true;
276 }
277
278 void Moc::parseFunctionArguments(FunctionDef *def)
279 {
280     Q_UNUSED(def);
281     while (hasNext()) {
282         ArgumentDef  arg;
283         arg.type = parseType();
284         if (arg.type.name == "void")
285             break;
286         if (test(IDENTIFIER))
287             arg.name = lexem();
288         while (test(LBRACK)) {
289             arg.rightType += lexemUntil(RBRACK);
290         }
291         if (test(CONST) || test(VOLATILE)) {
292             arg.rightType += ' ';
293             arg.rightType += lexem();
294         }
295         arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
296         arg.typeNameForCast = normalizeType(QByteArray(noRef(arg.type.name) + "(*)" + arg.rightType));
297         if (test(EQ))
298             arg.isDefault = true;
299         def->arguments += arg;
300         if (!until(COMMA))
301             break;
302     }
303 }
304
305 bool Moc::testFunctionAttribute(FunctionDef *def)
306 {
307     if (index < symbols.size() && testFunctionAttribute(symbols.at(index).token, def)) {
308         ++index;
309         return true;
310     }
311     return false;
312 }
313
314 bool Moc::testFunctionAttribute(Token tok, FunctionDef *def)
315 {
316     switch (tok) {
317         case Q_MOC_COMPAT_TOKEN:
318         case Q_QT3_SUPPORT_TOKEN:
319             def->isCompat = true;
320             return true;
321         case Q_INVOKABLE_TOKEN:
322             def->isInvokable = true;
323             return true;
324         case Q_SIGNAL_TOKEN:
325             def->isSignal = true;
326             return true;
327         case Q_SLOT_TOKEN:
328             def->isSlot = true;
329             return true;
330         case Q_SCRIPTABLE_TOKEN:
331             def->isInvokable = def->isScriptable = true;
332             return true;
333         default: break;
334     }
335     return false;
336 }
337
338 bool Moc::testFunctionRevision(FunctionDef *def)
339 {
340     if (test(Q_REVISION_TOKEN)) {
341         next(LPAREN);
342         QByteArray revision = lexemUntil(RPAREN);
343         revision.remove(0, 1);
344         revision.chop(1);
345         bool ok = false;
346         def->revision = revision.toInt(&ok);
347         if (!ok || def->revision < 0)
348             error("Invalid revision");
349         return true;
350     }
351
352     return false;
353 }
354
355 // returns false if the function should be ignored
356 bool Moc::parseFunction(FunctionDef *def, bool inMacro)
357 {
358     def->isVirtual = false;
359     def->isStatic = false;
360     //skip modifiers and attributes
361     while (test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
362         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
363         || testFunctionAttribute(def) || testFunctionRevision(def)) {}
364     bool templateFunction = (lookup() == TEMPLATE);
365     def->type = parseType();
366     if (def->type.name.isEmpty()) {
367         if (templateFunction)
368             error("Template function as signal or slot");
369         else
370             error();
371     }
372     bool scopedFunctionName = false;
373     if (test(LPAREN)) {
374         def->name = def->type.name;
375         scopedFunctionName = def->type.isScoped;
376         def->type = Type("int");
377     } else {
378         Type tempType = parseType();;
379         while (!tempType.name.isEmpty() && lookup() != LPAREN) {
380             if (testFunctionAttribute(def->type.firstToken, def))
381                 ; // fine
382             else if (def->type.firstToken == Q_SIGNALS_TOKEN)
383                 error();
384             else if (def->type.firstToken == Q_SLOTS_TOKEN)
385                 error();
386             else {
387                 if (!def->tag.isEmpty())
388                     def->tag += ' ';
389                 def->tag += def->type.name;
390             }
391             def->type = tempType;
392             tempType = parseType();
393         }
394         next(LPAREN, "Not a signal or slot declaration");
395         def->name = tempType.name;
396         scopedFunctionName = tempType.isScoped;
397     }
398
399     // we don't support references as return types, it's too dangerous
400     if (def->type.referenceType == Type::Reference)
401         def->type = Type("void");
402
403     def->normalizedType = normalizeType(def->type.name);
404
405     if (!test(RPAREN)) {
406         parseFunctionArguments(def);
407         next(RPAREN);
408     }
409
410     // support optional macros with compiler specific options
411     while (test(IDENTIFIER))
412         ;
413
414     def->isConst = test(CONST);
415
416     while (test(IDENTIFIER))
417         ;
418
419     if (inMacro) {
420         next(RPAREN);
421         prev();
422     } else {
423         if (test(THROW)) {
424             next(LPAREN);
425             until(RPAREN);
426         }
427         if (test(SEMIC))
428             ;
429         else if ((def->inlineCode = test(LBRACE)))
430             until(RBRACE);
431         else if ((def->isAbstract = test(EQ)))
432             until(SEMIC);
433         else
434             error();
435     }
436
437     if (scopedFunctionName) {
438         QByteArray msg("Function declaration ");
439         msg += def->name;
440         msg += " contains extra qualification. Ignoring as signal or slot.";
441         warning(msg.constData());
442         return false;
443     }
444     return true;
445 }
446
447 // like parseFunction, but never aborts with an error
448 bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
449 {
450     def->isVirtual = false;
451     def->isStatic = false;
452     //skip modifiers and attributes
453     while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true)) ||
454         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
455         || testFunctionAttribute(def) || testFunctionRevision(def)) {}
456     bool tilde = test(TILDE);
457     def->type = parseType();
458     if (def->type.name.isEmpty())
459         return false;
460     bool scopedFunctionName = false;
461     if (test(LPAREN)) {
462         def->name = def->type.name;
463         scopedFunctionName = def->type.isScoped;
464         if (def->name == cdef->classname) {
465             def->isDestructor = tilde;
466             def->isConstructor = !tilde;
467             def->type = Type();
468         } else {
469             def->type = Type("int");
470         }
471     } else {
472         Type tempType = parseType();;
473         while (!tempType.name.isEmpty() && lookup() != LPAREN) {
474             if (testFunctionAttribute(def->type.firstToken, def))
475                 ; // fine
476             else if (def->type.name == "Q_SIGNAL")
477                 def->isSignal = true;
478             else if (def->type.name == "Q_SLOT")
479                 def->isSlot = true;
480             else {
481                 if (!def->tag.isEmpty())
482                     def->tag += ' ';
483                 def->tag += def->type.name;
484             }
485             def->type = tempType;
486             tempType = parseType();
487         }
488         if (!test(LPAREN))
489             return false;
490         def->name = tempType.name;
491         scopedFunctionName = tempType.isScoped;
492     }
493
494     // we don't support references as return types, it's too dangerous
495     if (def->type.referenceType == Type::Reference)
496         def->type = Type("void");
497
498     def->normalizedType = normalizeType(def->type.name);
499
500     if (!test(RPAREN)) {
501         parseFunctionArguments(def);
502         if (!test(RPAREN))
503             return false;
504     }
505     def->isConst = test(CONST);
506     if (scopedFunctionName
507         && (def->isSignal || def->isSlot || def->isInvokable)) {
508         QByteArray msg("parsemaybe: Function declaration ");
509         msg += def->name;
510         msg += " contains extra qualification. Ignoring as signal or slot.";
511         warning(msg.constData());
512         return false;
513     }
514     return true;
515 }
516
517
518 void Moc::parse()
519 {
520     QList<NamespaceDef> namespaceList;
521     bool templateClass = false;
522     while (hasNext()) {
523         Token t = next();
524         switch (t) {
525             case NAMESPACE: {
526                 int rewind = index;
527                 if (test(IDENTIFIER)) {
528                     if (test(EQ)) {
529                         // namespace Foo = Bar::Baz;
530                         until(SEMIC);
531                     } else if (!test(SEMIC)) {
532                         NamespaceDef def;
533                         def.name = lexem();
534                         next(LBRACE);
535                         def.begin = index - 1;
536                         until(RBRACE);
537                         def.end = index;
538                         index = def.begin + 1;
539                         namespaceList += def;
540                         index = rewind;
541                     }
542                 }
543                 break;
544             }
545             case SEMIC:
546             case RBRACE:
547                 templateClass = false;
548                 break;
549             case TEMPLATE:
550                 templateClass = true;
551                 break;
552             case MOC_INCLUDE_BEGIN:
553                 currentFilenames.push(symbol().unquotedLexem());
554                 break;
555             case MOC_INCLUDE_END:
556                 currentFilenames.pop();
557                 break;
558             case Q_DECLARE_INTERFACE_TOKEN:
559                 parseDeclareInterface();
560                 break;
561             case Q_DECLARE_METATYPE_TOKEN:
562                 parseDeclareMetatype();
563                 break;
564             case USING:
565                 if (test(NAMESPACE)) {
566                     while (test(SCOPE) || test(IDENTIFIER))
567                         ;
568                     next(SEMIC);
569                 }
570                 break;
571             case CLASS:
572             case STRUCT: {
573                 if (currentFilenames.size() <= 1)
574                     break;
575
576                 ClassDef def;
577                 if (!parseClassHead(&def))
578                     continue;
579
580                 while (inClass(&def) && hasNext()) {
581                     if (next() == Q_OBJECT_TOKEN) {
582                         def.hasQObject = true;
583                         break;
584                     }
585                 }
586
587                 if (!def.hasQObject)
588                     continue;
589
590                 for (int i = namespaceList.size() - 1; i >= 0; --i)
591                     if (inNamespace(&namespaceList.at(i)))
592                         def.qualified.prepend(namespaceList.at(i).name + "::");
593
594                 knownQObjectClasses.insert(def.classname);
595                 knownQObjectClasses.insert(def.qualified);
596
597                 continue; }
598             default: break;
599         }
600         if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
601             continue;
602         ClassDef def;
603         if (parseClassHead(&def)) {
604             FunctionDef::Access access = FunctionDef::Private;
605             for (int i = namespaceList.size() - 1; i >= 0; --i)
606                 if (inNamespace(&namespaceList.at(i)))
607                     def.qualified.prepend(namespaceList.at(i).name + "::");
608             while (inClass(&def) && hasNext()) {
609                 switch ((t = next())) {
610                 case PRIVATE:
611                     access = FunctionDef::Private;
612                     if (test(Q_SIGNALS_TOKEN))
613                         error("Signals cannot have access specifier");
614                     break;
615                 case PROTECTED:
616                     access = FunctionDef::Protected;
617                     if (test(Q_SIGNALS_TOKEN))
618                         error("Signals cannot have access specifier");
619                     break;
620                 case PUBLIC:
621                     access = FunctionDef::Public;
622                     if (test(Q_SIGNALS_TOKEN))
623                         error("Signals cannot have access specifier");
624                     break;
625                 case CLASS: {
626                     ClassDef nestedDef;
627                     if (parseClassHead(&nestedDef)) {
628                         while (inClass(&nestedDef) && inClass(&def)) {
629                             t = next();
630                             if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
631                                 error("Meta object features not supported for nested classes");
632                         }
633                     }
634                 } break;
635                 case Q_SIGNALS_TOKEN:
636                     parseSignals(&def);
637                     break;
638                 case Q_SLOTS_TOKEN:
639                     switch (lookup(-1)) {
640                     case PUBLIC:
641                     case PROTECTED:
642                     case PRIVATE:
643                         parseSlots(&def, access);
644                         break;
645                     default:
646                         error("Missing access specifier for slots");
647                     }
648                     break;
649                 case Q_OBJECT_TOKEN:
650                     def.hasQObject = true;
651                     if (templateClass)
652                         error("Template classes not supported by Q_OBJECT");
653                     if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
654                         error("Class contains Q_OBJECT macro but does not inherit from QObject");
655                     break;
656                 case Q_GADGET_TOKEN:
657                     def.hasQGadget = true;
658                     if (templateClass)
659                         error("Template classes not supported by Q_GADGET");
660                     break;
661                 case Q_PROPERTY_TOKEN:
662                     parseProperty(&def);
663                     break;
664                 case Q_ENUMS_TOKEN:
665                     parseEnumOrFlag(&def, false);
666                     break;
667                 case Q_FLAGS_TOKEN:
668                     parseEnumOrFlag(&def, true);
669                     break;
670                 case Q_DECLARE_FLAGS_TOKEN:
671                     parseFlag(&def);
672                     break;
673                 case Q_CLASSINFO_TOKEN:
674                     parseClassInfo(&def);
675                     break;
676                 case Q_INTERFACES_TOKEN:
677                     parseInterfaces(&def);
678                     break;
679                 case Q_PRIVATE_SLOT_TOKEN:
680                     parseSlotInPrivate(&def, access);
681                     break;
682                 case Q_PRIVATE_PROPERTY_TOKEN:
683                     parsePrivateProperty(&def);
684                     break;
685                 case ENUM: {
686                     EnumDef enumDef;
687                     if (parseEnum(&enumDef))
688                         def.enumList += enumDef;
689                 } break;
690                 case SEMIC:
691                 case COLON:
692                     break;
693                 default:
694                     FunctionDef funcDef;
695                     funcDef.access = access;
696                     int rewind = index--;
697                     if (parseMaybeFunction(&def, &funcDef)) {
698                         if (funcDef.isConstructor) {
699                             if ((access == FunctionDef::Public) && funcDef.isInvokable) {
700                                 def.constructorList += funcDef;
701                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
702                                     funcDef.wasCloned = true;
703                                     funcDef.arguments.removeLast();
704                                     def.constructorList += funcDef;
705                                 }
706                             }
707                         } else if (funcDef.isDestructor) {
708                             // don't care about destructors
709                         } else {
710                             if (access == FunctionDef::Public)
711                                 def.publicList += funcDef;
712                             if (funcDef.isSlot) {
713                                 def.slotList += funcDef;
714                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
715                                     funcDef.wasCloned = true;
716                                     funcDef.arguments.removeLast();
717                                     def.slotList += funcDef;
718                                 }
719                                 if (funcDef.revision > 0)
720                                     ++def.revisionedMethods;
721                             } else if (funcDef.isSignal) {
722                                 def.signalList += funcDef;
723                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
724                                     funcDef.wasCloned = true;
725                                     funcDef.arguments.removeLast();
726                                     def.signalList += funcDef;
727                                 }
728                                 if (funcDef.revision > 0)
729                                     ++def.revisionedMethods;
730                             } else if (funcDef.isInvokable) {
731                                 def.methodList += funcDef;
732                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
733                                     funcDef.wasCloned = true;
734                                     funcDef.arguments.removeLast();
735                                     def.methodList += funcDef;
736                                 }
737                                 if (funcDef.revision > 0)
738                                     ++def.revisionedMethods;
739                             }
740                         }
741                     } else {
742                         index = rewind;
743                     }
744                 }
745             }
746
747             next(RBRACE);
748
749             if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
750                 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
751                 continue; // no meta object code required
752
753
754             if (!def.hasQObject && !def.hasQGadget)
755                 error("Class declarations lacks Q_OBJECT macro.");
756
757             checkSuperClasses(&def);
758             checkProperties(&def);
759
760             classList += def;
761             knownQObjectClasses.insert(def.classname);
762             knownQObjectClasses.insert(def.qualified);
763         }
764     }
765 }
766
767 void Moc::generate(FILE *out)
768 {
769
770     QDateTime dt = QDateTime::currentDateTime();
771     QByteArray dstr = dt.toString().toLatin1();
772     QByteArray fn = filename;
773     int i = filename.length()-1;
774     while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
775         --i;                                // skip path
776     if (i >= 0)
777         fn = filename.mid(i);
778     fprintf(out, "/****************************************************************************\n"
779             "** Meta object code from reading C++ file '%s'\n**\n" , (const char*)fn);
780     fprintf(out, "** Created: %s\n"
781             "**      by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , dstr.data(), mocOutputRevision, QT_VERSION_STR);
782     fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
783             "*****************************************************************************/\n\n");
784
785
786     if (!noInclude) {
787         if (includePath.size() && !includePath.endsWith('/'))
788             includePath += '/';
789         for (int i = 0; i < includeFiles.size(); ++i) {
790             QByteArray inc = includeFiles.at(i);
791             if (inc[0] != '<' && inc[0] != '"') {
792                 if (includePath.size() && includePath != "./")
793                     inc.prepend(includePath);
794                 inc = '\"' + inc + '\"';
795             }
796             fprintf(out, "#include %s\n", inc.constData());
797         }
798     }
799     if (classList.size() && classList.first().classname == "Qt")
800         fprintf(out, "#include <QtCore/qobject.h>\n");
801
802     if (mustIncludeQMetaTypeH)
803         fprintf(out, "#include <QtCore/qmetatype.h>\n");
804
805     fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
806             "#error \"The header file '%s' doesn't include <QObject>.\"\n", (const char *)fn);
807     fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
808     fprintf(out, "#error \"This file was generated using the moc from %s."
809             " It\"\n#error \"cannot be used with the include files from"
810             " this version of Qt.\"\n#error \"(The moc has changed too"
811             " much.)\"\n", QT_VERSION_STR);
812     fprintf(out, "#endif\n\n");
813
814     fprintf(out, "QT_BEGIN_MOC_NAMESPACE\n");
815
816     for (i = 0; i < classList.size(); ++i) {
817         Generator generator(&classList[i], metaTypes, out);
818         generator.generateCode();
819     }
820
821     fprintf(out, "QT_END_MOC_NAMESPACE\n");
822 }
823
824
825 QList<QMetaObject*> Moc::generate(bool ignoreProperties)
826 {
827     QList<QMetaObject*> result;
828     for (int i = 0; i < classList.size(); ++i) {
829         Generator generator(&classList[i], metaTypes);
830         result << generator.generateMetaObject(ignoreProperties);
831     }
832     return result;
833 }
834
835 void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
836 {
837     int defaultRevision = -1;
838     if (test(Q_REVISION_TOKEN)) {
839         next(LPAREN);
840         QByteArray revision = lexemUntil(RPAREN);
841         revision.remove(0, 1);
842         revision.chop(1);
843         bool ok = false;
844         defaultRevision = revision.toInt(&ok);
845         if (!ok || defaultRevision < 0)
846             error("Invalid revision");
847     }
848
849     next(COLON);
850     while (inClass(def) && hasNext()) {
851         switch (next()) {
852         case PUBLIC:
853         case PROTECTED:
854         case PRIVATE:
855         case Q_SIGNALS_TOKEN:
856         case Q_SLOTS_TOKEN:
857             prev();
858             return;
859         case SEMIC:
860             continue;
861         case FRIEND:
862             until(SEMIC);
863             continue;
864         case USING:
865             error("'using' directive not supported in 'slots' section");
866         default:
867             prev();
868         }
869
870         FunctionDef funcDef;
871         funcDef.access = access;
872         if (!parseFunction(&funcDef))
873             continue;
874         if (funcDef.revision > 0) {
875             ++def->revisionedMethods;
876         } else if (defaultRevision != -1) {
877             funcDef.revision = defaultRevision;
878             ++def->revisionedMethods;
879         }
880         def->slotList += funcDef;
881         while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
882             funcDef.wasCloned = true;
883             funcDef.arguments.removeLast();
884             def->slotList += funcDef;
885         }
886     }
887 }
888
889 void Moc::parseSignals(ClassDef *def)
890 {
891     int defaultRevision = -1;
892     if (test(Q_REVISION_TOKEN)) {
893         next(LPAREN);
894         QByteArray revision = lexemUntil(RPAREN);
895         revision.remove(0, 1);
896         revision.chop(1);
897         bool ok = false;
898         defaultRevision = revision.toInt(&ok);
899         if (!ok || defaultRevision < 0)
900             error("Invalid revision");
901     }
902
903     next(COLON);
904     while (inClass(def) && hasNext()) {
905         switch (next()) {
906         case PUBLIC:
907         case PROTECTED:
908         case PRIVATE:
909         case Q_SIGNALS_TOKEN:
910         case Q_SLOTS_TOKEN:
911             prev();
912             return;
913         case SEMIC:
914             continue;
915         case FRIEND:
916             until(SEMIC);
917             continue;
918         case USING:
919             error("'using' directive not supported in 'signals' section");
920         default:
921             prev();
922         }
923         FunctionDef funcDef;
924         funcDef.access = FunctionDef::Protected;
925         parseFunction(&funcDef);
926         if (funcDef.isVirtual)
927             warning("Signals cannot be declared virtual");
928         if (funcDef.inlineCode)
929             error("Not a signal declaration");
930         if (funcDef.revision > 0) {
931             ++def->revisionedMethods;
932         } else if (defaultRevision != -1) {
933             funcDef.revision = defaultRevision;
934             ++def->revisionedMethods;
935         }
936         def->signalList += funcDef;
937         while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
938             funcDef.wasCloned = true;
939             funcDef.arguments.removeLast();
940             def->signalList += funcDef;
941         }
942     }
943 }
944
945 void Moc::createPropertyDef(PropertyDef &propDef)
946 {
947     QByteArray type = parseType().name;
948     if (type.isEmpty())
949         error();
950     propDef.designable = propDef.scriptable = propDef.stored = "true";
951     propDef.user = "false";
952     /*
953       The Q_PROPERTY construct cannot contain any commas, since
954       commas separate macro arguments. We therefore expect users
955       to type "QMap" instead of "QMap<QString, QVariant>". For
956       coherence, we also expect the same for
957       QValueList<QVariant>, the other template class supported by
958       QVariant.
959     */
960     type = normalizeType(type);
961     if (type == "QMap")
962         type = "QMap<QString,QVariant>";
963     else if (type == "QValueList")
964         type = "QValueList<QVariant>";
965     else if (type == "LongLong")
966         type = "qlonglong";
967     else if (type == "ULongLong")
968         type = "qulonglong";
969     else if (type == "qreal")
970         mustIncludeQMetaTypeH = true;
971
972     propDef.type = type;
973
974     next();
975     propDef.name = lexem();
976     while (test(IDENTIFIER)) {
977         QByteArray l = lexem();
978         if (l[0] == 'C' && l == "CONSTANT") {
979             propDef.constant = true;
980             continue;
981         } else if(l[0] == 'F' && l == "FINAL") {
982             propDef.final = true;
983             continue;
984         }
985
986         QByteArray v, v2;
987         if (test(LPAREN)) {
988             v = lexemUntil(RPAREN);
989         } else if (test(INTEGER_LITERAL)) {
990             v = lexem();
991             if (l != "REVISION")
992                 error(1);
993         } else {
994             next(IDENTIFIER);
995             v = lexem();
996             if (test(LPAREN))
997                 v2 = lexemUntil(RPAREN);
998             else if (v != "true" && v != "false")
999                 v2 = "()";
1000         }
1001         switch (l[0]) {
1002         case 'R':
1003             if (l == "READ")
1004                 propDef.read = v;
1005             else if (l == "RESET")
1006                 propDef.reset = v + v2;
1007             else if (l == "REVISION") {
1008                 bool ok = false;
1009                 propDef.revision = v.toInt(&ok);
1010                 if (!ok || propDef.revision < 0)
1011                     error(1);
1012             } else
1013                 error(2);
1014             break;
1015         case 'S':
1016             if (l == "SCRIPTABLE")
1017                 propDef.scriptable = v + v2;
1018             else if (l == "STORED")
1019                 propDef.stored = v + v2;
1020             else
1021                 error(2);
1022             break;
1023         case 'W': if (l != "WRITE") error(2);
1024             propDef.write = v;
1025             break;
1026         case 'D': if (l != "DESIGNABLE") error(2);
1027             propDef.designable = v + v2;
1028             break;
1029         case 'E': if (l != "EDITABLE") error(2);
1030             propDef.editable = v + v2;
1031             break;
1032         case 'N': if (l != "NOTIFY") error(2);
1033             propDef.notify = v;
1034             break;
1035         case 'U': if (l != "USER") error(2);
1036             propDef.user = v + v2;
1037             break;
1038         default:
1039             error(2);
1040         }
1041     }
1042     if (propDef.read.isNull()) {
1043         QByteArray msg;
1044         msg += "Property declaration ";
1045         msg += propDef.name;
1046         msg += " has no READ accessor function. The property will be invalid.";
1047         warning(msg.constData());
1048     }
1049     if (propDef.constant && !propDef.write.isNull()) {
1050         QByteArray msg;
1051         msg += "Property declaration ";
1052         msg += propDef.name;
1053         msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
1054         propDef.constant = false;
1055         warning(msg.constData());
1056     }
1057     if (propDef.constant && !propDef.notify.isNull()) {
1058         QByteArray msg;
1059         msg += "Property declaration ";
1060         msg += propDef.name;
1061         msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
1062         propDef.constant = false;
1063         warning(msg.constData());
1064     }
1065 }
1066
1067 void Moc::parseProperty(ClassDef *def)
1068 {
1069     next(LPAREN);
1070     PropertyDef propDef;
1071     createPropertyDef(propDef);
1072     next(RPAREN);
1073
1074
1075     if(!propDef.notify.isEmpty())
1076         def->notifyableProperties++;
1077     if (propDef.revision > 0)
1078         ++def->revisionedProperties;
1079     def->propertyList += propDef;
1080 }
1081
1082 void Moc::parsePrivateProperty(ClassDef *def)
1083 {
1084     next(LPAREN);
1085     PropertyDef propDef;
1086     next(IDENTIFIER);
1087     propDef.inPrivateClass = lexem();
1088     while (test(SCOPE)) {
1089         propDef.inPrivateClass += lexem();
1090         next(IDENTIFIER);
1091         propDef.inPrivateClass += lexem();
1092     }
1093     // also allow void functions
1094     if (test(LPAREN)) {
1095         next(RPAREN);
1096         propDef.inPrivateClass += "()";
1097     }
1098
1099     next(COMMA);
1100
1101     createPropertyDef(propDef);
1102
1103     if(!propDef.notify.isEmpty())
1104         def->notifyableProperties++;
1105     if (propDef.revision > 0)
1106         ++def->revisionedProperties;
1107
1108     def->propertyList += propDef;
1109 }
1110
1111 void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
1112 {
1113     next(LPAREN);
1114     QByteArray identifier;
1115     while (test(IDENTIFIER)) {
1116         identifier = lexem();
1117         while (test(SCOPE) && test(IDENTIFIER)) {
1118             identifier += "::";
1119             identifier += lexem();
1120         }
1121         def->enumDeclarations[identifier] = isFlag;
1122     }
1123     next(RPAREN);
1124 }
1125
1126 void Moc::parseFlag(ClassDef *def)
1127 {
1128     next(LPAREN);
1129     QByteArray flagName, enumName;
1130     while (test(IDENTIFIER)) {
1131         flagName = lexem();
1132         while (test(SCOPE) && test(IDENTIFIER)) {
1133             flagName += "::";
1134             flagName += lexem();
1135         }
1136     }
1137     next(COMMA);
1138     while (test(IDENTIFIER)) {
1139         enumName = lexem();
1140         while (test(SCOPE) && test(IDENTIFIER)) {
1141             enumName += "::";
1142             enumName += lexem();
1143         }
1144     }
1145
1146     def->flagAliases.insert(enumName, flagName);
1147     next(RPAREN);
1148 }
1149
1150 void Moc::parseClassInfo(ClassDef *def)
1151 {
1152     next(LPAREN);
1153     ClassInfoDef infoDef;
1154     next(STRING_LITERAL);
1155     infoDef.name = symbol().unquotedLexem();
1156     next(COMMA);
1157     if (test(STRING_LITERAL)) {
1158         infoDef.value = symbol().unquotedLexem();
1159     } else {
1160         // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
1161         next(IDENTIFIER);
1162         next(LPAREN);
1163         next(STRING_LITERAL);
1164         infoDef.value = symbol().unquotedLexem();
1165         next(RPAREN);
1166     }
1167     next(RPAREN);
1168     def->classInfoList += infoDef;
1169 }
1170
1171 void Moc::parseInterfaces(ClassDef *def)
1172 {
1173     next(LPAREN);
1174     while (test(IDENTIFIER)) {
1175         QList<ClassDef::Interface> iface;
1176         iface += ClassDef::Interface(lexem());
1177         while (test(SCOPE)) {
1178             iface.last().className += lexem();
1179             next(IDENTIFIER);
1180             iface.last().className += lexem();
1181         }
1182         while (test(COLON)) {
1183             next(IDENTIFIER);
1184             iface += ClassDef::Interface(lexem());
1185             while (test(SCOPE)) {
1186                 iface.last().className += lexem();
1187                 next(IDENTIFIER);
1188                 iface.last().className += lexem();
1189             }
1190         }
1191         // resolve from classnames to interface ids
1192         for (int i = 0; i < iface.count(); ++i) {
1193             const QByteArray iid = interface2IdMap.value(iface.at(i).className);
1194             if (iid.isEmpty())
1195                 error("Undefined interface");
1196
1197             iface[i].interfaceId = iid;
1198         }
1199         def->interfaceList += iface;
1200     }
1201     next(RPAREN);
1202 }
1203
1204 void Moc::parseDeclareInterface()
1205 {
1206     next(LPAREN);
1207     QByteArray interface;
1208     next(IDENTIFIER);
1209     interface += lexem();
1210     while (test(SCOPE)) {
1211         interface += lexem();
1212         next(IDENTIFIER);
1213         interface += lexem();
1214     }
1215     next(COMMA);
1216     QByteArray iid;
1217     if (test(STRING_LITERAL)) {
1218         iid = lexem();
1219     } else {
1220         next(IDENTIFIER);
1221         iid = lexem();
1222     }
1223     interface2IdMap.insert(interface, iid);
1224     next(RPAREN);
1225 }
1226
1227 void Moc::parseDeclareMetatype()
1228 {
1229     next(LPAREN);
1230     QByteArray typeName = lexemUntil(RPAREN);
1231     typeName.remove(0, 1);
1232     typeName.chop(1);
1233     metaTypes.append(typeName);
1234 }
1235
1236 void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
1237 {
1238     next(LPAREN);
1239     FunctionDef funcDef;
1240     next(IDENTIFIER);
1241     funcDef.inPrivateClass = lexem();
1242     // also allow void functions
1243     if (test(LPAREN)) {
1244         next(RPAREN);
1245         funcDef.inPrivateClass += "()";
1246     }
1247     next(COMMA);
1248     funcDef.access = access;
1249     parseFunction(&funcDef, true);
1250     def->slotList += funcDef;
1251     while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
1252         funcDef.wasCloned = true;
1253         funcDef.arguments.removeLast();
1254         def->slotList += funcDef;
1255     }
1256     if (funcDef.revision > 0)
1257         ++def->revisionedMethods;
1258
1259 }
1260
1261 QByteArray Moc::lexemUntil(Token target)
1262 {
1263     int from = index;
1264     until(target);
1265     QByteArray s;
1266     while (from <= index) {
1267         QByteArray n = symbols.at(from++-1).lexem();
1268         if (s.size() && n.size()
1269             && is_ident_char(s.at(s.size()-1))
1270             && is_ident_char(n.at(0)))
1271             s += ' ';
1272         s += n;
1273     }
1274     return s;
1275 }
1276
1277 bool Moc::until(Token target) {
1278     int braceCount = 0;
1279     int brackCount = 0;
1280     int parenCount = 0;
1281     int angleCount = 0;
1282     if (index) {
1283         switch(symbols.at(index-1).token) {
1284         case LBRACE: ++braceCount; break;
1285         case LBRACK: ++brackCount; break;
1286         case LPAREN: ++parenCount; break;
1287         case LANGLE: ++angleCount; break;
1288         default: break;
1289         }
1290     }
1291
1292     //when searching commas within the default argument, we should take care of template depth (anglecount)
1293     // unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or
1294     // the beginning of a template type. so we just use heuristics.
1295     int possible = -1;
1296
1297     while (index < symbols.size()) {
1298         Token t = symbols.at(index++).token;
1299         switch (t) {
1300         case LBRACE: ++braceCount; break;
1301         case RBRACE: --braceCount; break;
1302         case LBRACK: ++brackCount; break;
1303         case RBRACK: --brackCount; break;
1304         case LPAREN: ++parenCount; break;
1305         case RPAREN: --parenCount; break;
1306         case LANGLE: ++angleCount; break;
1307         case RANGLE: --angleCount; break;
1308         case GTGT: angleCount -= 2; t = RANGLE; break;
1309         default: break;
1310         }
1311         if (t == target
1312             && braceCount <= 0
1313             && brackCount <= 0
1314             && parenCount <= 0
1315             && (target != RANGLE || angleCount <= 0)) {
1316             if (target != COMMA || angleCount <= 0)
1317                 return true;
1318             possible = index;
1319         }
1320
1321         if (target == COMMA && t == EQ && possible != -1) {
1322             index = possible;
1323             return true;
1324         }
1325
1326         if (braceCount < 0 || brackCount < 0 || parenCount < 0
1327             || (target == RANGLE && angleCount < 0)) {
1328             --index;
1329             break;
1330         }
1331     }
1332
1333     if(target == COMMA && angleCount != 0 && possible != -1) {
1334         index = possible;
1335         return true;
1336     }
1337
1338     return false;
1339 }
1340
1341 void Moc::checkSuperClasses(ClassDef *def)
1342 {
1343     const QByteArray firstSuperclass = def->superclassList.value(0).first;
1344
1345     if (!knownQObjectClasses.contains(firstSuperclass)) {
1346         // enable once we /require/ include paths
1347 #if 0
1348         QByteArray msg;
1349         msg += "Class ";
1350         msg += def->className;
1351         msg += " contains the Q_OBJECT macro and inherits from ";
1352         msg += def->superclassList.value(0);
1353         msg += " but that is not a known QObject subclass. You may get compilation errors.";
1354         warning(msg.constData());
1355 #endif
1356         return;
1357     }
1358     for (int i = 1; i < def->superclassList.count(); ++i) {
1359         const QByteArray superClass = def->superclassList.at(i).first;
1360         if (knownQObjectClasses.contains(superClass)) {
1361             QByteArray msg;
1362             msg += "Class ";
1363             msg += def->classname;
1364             msg += " inherits from two QObject subclasses ";
1365             msg += firstSuperclass;
1366             msg += " and ";
1367             msg += superClass;
1368             msg += ". This is not supported!";
1369             warning(msg.constData());
1370         }
1371
1372         if (interface2IdMap.contains(superClass)) {
1373             bool registeredInterface = false;
1374             for (int i = 0; i < def->interfaceList.count(); ++i)
1375                 if (def->interfaceList.at(i).first().className == superClass) {
1376                     registeredInterface = true;
1377                     break;
1378                 }
1379
1380             if (!registeredInterface) {
1381                 QByteArray msg;
1382                 msg += "Class ";
1383                 msg += def->classname;
1384                 msg += " implements the interface ";
1385                 msg += superClass;
1386                 msg += " but does not list it in Q_INTERFACES. qobject_cast to ";
1387                 msg += superClass;
1388                 msg += " will not work!";
1389                 warning(msg.constData());
1390             }
1391         }
1392     }
1393 }
1394
1395 void Moc::checkProperties(ClassDef *cdef)
1396 {
1397     //
1398     // specify get function, for compatibiliy we accept functions
1399     // returning pointers, or const char * for QByteArray.
1400     //
1401     for (int i = 0; i < cdef->propertyList.count(); ++i) {
1402         PropertyDef &p = cdef->propertyList[i];
1403         if (p.read.isEmpty())
1404             continue;
1405         for (int j = 0; j < cdef->publicList.count(); ++j) {
1406             const FunctionDef &f = cdef->publicList.at(j);
1407             if (f.name != p.read)
1408                 continue;
1409             if (!f.isConst) // get  functions must be const
1410                 continue;
1411             if (f.arguments.size()) // and must not take any arguments
1412                 continue;
1413             PropertyDef::Specification spec = PropertyDef::ValueSpec;
1414             QByteArray tmp = f.normalizedType;
1415             if (p.type == "QByteArray" && tmp == "const char *")
1416                 tmp = "QByteArray";
1417             if (tmp.left(6) == "const ")
1418                 tmp = tmp.mid(6);
1419             if (p.type != tmp && tmp.endsWith('*')) {
1420                 tmp.chop(1);
1421                 spec = PropertyDef::PointerSpec;
1422             } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
1423                 spec = PropertyDef::ReferenceSpec;
1424             }
1425             if (p.type != tmp)
1426                 continue;
1427             p.gspec = spec;
1428             break;
1429         }
1430         if(!p.notify.isEmpty()) {
1431             int notifyId = -1;
1432             for (int j = 0; j < cdef->signalList.count(); ++j) {
1433                 const FunctionDef &f = cdef->signalList.at(j);
1434                 if(f.name != p.notify) {
1435                     continue;
1436                 } else {
1437                     notifyId = j /* Signal indexes start from 0 */;
1438                     break;
1439                 }
1440             }
1441             p.notifyId = notifyId;
1442             if (notifyId == -1) {
1443                 QByteArray msg = "NOTIFY signal '" + p.notify + "' of property '" + p.name
1444                         + "' does not exist in class " + cdef->classname + ".";
1445                 error(msg.constData());
1446             }
1447         }
1448     }
1449 }
1450
1451
1452
1453 QT_END_NAMESPACE