src/tools/moc/moc.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    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 < templ.size()-1 && templ.at(i+1) == ':')
       
   220                     || (templ.at(i) == '>' && i < templ.size()-1 && 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)) {
       
   234         type.name += ' ';
       
   235         type.name += lexem();
       
   236         if (lookup(0) == AND)
       
   237             type.referenceType = Type::Reference;
       
   238         else if (lookup(0) == STAR)
       
   239             type.referenceType = Type::Pointer;
       
   240     }
       
   241     // transform stupid things like 'const void' or 'void const' into 'void'
       
   242     if (isVoid && type.referenceType == Type::NoReference) {
       
   243         type.name = "void";
       
   244     }
       
   245     return type;
       
   246 }
       
   247 
       
   248 bool Moc::parseEnum(EnumDef *def)
       
   249 {
       
   250     bool isTypdefEnum = false; // typedef enum { ... } Foo;
       
   251 
       
   252     if (test(IDENTIFIER)) {
       
   253         def->name = lexem();
       
   254     } else {
       
   255         if (lookup(-1) != TYPEDEF)
       
   256             return false; // anonymous enum
       
   257         isTypdefEnum = true;
       
   258     }
       
   259     if (!test(LBRACE))
       
   260         return false;
       
   261     do {
       
   262         if (lookup() == RBRACE) // accept trailing comma
       
   263             break;
       
   264         next(IDENTIFIER);
       
   265         def->values += lexem();
       
   266     } while (test(EQ) ? until(COMMA) : test(COMMA));
       
   267     next(RBRACE);
       
   268     if (isTypdefEnum) {
       
   269         if (!test(IDENTIFIER))
       
   270             return false;
       
   271         def->name = lexem();
       
   272     }
       
   273     return true;
       
   274 }
       
   275 
       
   276 void Moc::parseFunctionArguments(FunctionDef *def)
       
   277 {
       
   278     Q_UNUSED(def);
       
   279     while (hasNext()) {
       
   280         ArgumentDef  arg;
       
   281         arg.type = parseType();
       
   282         if (arg.type.name == "void")
       
   283             break;
       
   284         if (test(IDENTIFIER))
       
   285             arg.name = lexem();
       
   286         while (test(LBRACK)) {
       
   287             arg.rightType += lexemUntil(RBRACK);
       
   288         }
       
   289         if (test(CONST) || test(VOLATILE)) {
       
   290             arg.rightType += ' ';
       
   291             arg.rightType += lexem();
       
   292         }
       
   293         arg.normalizedType = normalizeType(arg.type.name + ' ' + arg.rightType);
       
   294         arg.typeNameForCast = normalizeType(noRef(arg.type.name) + "(*)" + arg.rightType);
       
   295         if (test(EQ))
       
   296             arg.isDefault = true;
       
   297         def->arguments += arg;
       
   298         if (!until(COMMA))
       
   299             break;
       
   300     }
       
   301 }
       
   302 
       
   303 bool Moc::testFunctionAttribute(FunctionDef *def)
       
   304 {
       
   305     if (index < symbols.size() && testFunctionAttribute(symbols.at(index).token, def)) {
       
   306         ++index;
       
   307         return true;
       
   308     }
       
   309     return false;
       
   310 }
       
   311 
       
   312 bool Moc::testFunctionAttribute(Token tok, FunctionDef *def)
       
   313 {
       
   314     switch (tok) {
       
   315         case Q_MOC_COMPAT_TOKEN:
       
   316         case Q_QT3_SUPPORT_TOKEN:
       
   317             def->isCompat = true;
       
   318             return true;
       
   319         case Q_INVOKABLE_TOKEN:
       
   320             def->isInvokable = true;
       
   321             return true;
       
   322         case Q_SIGNAL_TOKEN:
       
   323             def->isSignal = true;
       
   324             return true;
       
   325         case Q_SLOT_TOKEN:
       
   326             def->isSlot = true;
       
   327             return true;
       
   328         case Q_SCRIPTABLE_TOKEN:
       
   329             def->isInvokable = def->isScriptable = true;
       
   330             return true;
       
   331         default: break;
       
   332     }
       
   333     return false;
       
   334 }
       
   335 
       
   336 // returns false if the function should be ignored
       
   337 bool Moc::parseFunction(FunctionDef *def, bool inMacro)
       
   338 {
       
   339     def->isVirtual = false;
       
   340     //skip modifiers and attributes
       
   341     while (test(INLINE) || test(STATIC) ||
       
   342         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
       
   343         || testFunctionAttribute(def)) {}
       
   344     bool templateFunction = (lookup() == TEMPLATE);
       
   345     def->type = parseType();
       
   346     if (def->type.name.isEmpty()) {
       
   347         if (templateFunction)
       
   348             error("Template function as signal or slot");
       
   349         else
       
   350             error();
       
   351     }
       
   352     bool scopedFunctionName = false;
       
   353     if (test(LPAREN)) {
       
   354         def->name = def->type.name;
       
   355         scopedFunctionName = def->type.isScoped;
       
   356         def->type = Type("int");
       
   357     } else {
       
   358         Type tempType = parseType();;
       
   359         while (!tempType.name.isEmpty() && lookup() != LPAREN) {
       
   360             if (testFunctionAttribute(def->type.firstToken, def))
       
   361                 ; // fine
       
   362             else if (def->type.firstToken == Q_SIGNALS_TOKEN)
       
   363                 error();
       
   364             else if (def->type.firstToken == Q_SLOTS_TOKEN)
       
   365                 error();
       
   366             else {
       
   367                 if (!def->tag.isEmpty())
       
   368                     def->tag += ' ';
       
   369                 def->tag += def->type.name;
       
   370             }
       
   371             def->type = tempType;
       
   372             tempType = parseType();
       
   373         }
       
   374         next(LPAREN, "Not a signal or slot declaration");
       
   375         def->name = tempType.name;
       
   376         scopedFunctionName = tempType.isScoped;
       
   377     }
       
   378 
       
   379     // we don't support references as return types, it's too dangerous
       
   380     if (def->type.referenceType == Type::Reference)
       
   381         def->type = Type("void");
       
   382 
       
   383     def->normalizedType = normalizeType(def->type.name);
       
   384 
       
   385     if (!test(RPAREN)) {
       
   386         parseFunctionArguments(def);
       
   387         next(RPAREN);
       
   388     }
       
   389 
       
   390     // support optional macros with compiler specific options
       
   391     while (test(IDENTIFIER))
       
   392         ;
       
   393 
       
   394     def->isConst = test(CONST);
       
   395 
       
   396     while (test(IDENTIFIER))
       
   397         ;
       
   398 
       
   399     if (inMacro) {
       
   400         next(RPAREN);
       
   401         prev();
       
   402     } else {
       
   403         if (test(THROW)) {
       
   404             next(LPAREN);
       
   405             until(RPAREN);
       
   406         }
       
   407         if (test(SEMIC))
       
   408             ;
       
   409         else if ((def->inlineCode = test(LBRACE)))
       
   410             until(RBRACE);
       
   411         else if ((def->isAbstract = test(EQ)))
       
   412             until(SEMIC);
       
   413         else
       
   414             error();
       
   415     }
       
   416 
       
   417     if (scopedFunctionName) {
       
   418         QByteArray msg("Function declaration ");
       
   419         msg += def->name;
       
   420         msg += " contains extra qualification. Ignoring as signal or slot.";
       
   421         warning(msg.constData());
       
   422         return false;
       
   423     }
       
   424     return true;
       
   425 }
       
   426 
       
   427 // like parseFunction, but never aborts with an error
       
   428 bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
       
   429 {
       
   430     def->isVirtual = false;
       
   431     //skip modifiers and attributes
       
   432     while (test(EXPLICIT) || test(INLINE) || test(STATIC) ||
       
   433         (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
       
   434         || testFunctionAttribute(def)) {}
       
   435     bool tilde = test(TILDE);
       
   436     def->type = parseType();
       
   437     if (def->type.name.isEmpty())
       
   438         return false;
       
   439     bool scopedFunctionName = false;
       
   440     if (test(LPAREN)) {
       
   441         def->name = def->type.name;
       
   442         scopedFunctionName = def->type.isScoped;
       
   443         if (def->name == cdef->classname) {
       
   444             def->isDestructor = tilde;
       
   445             def->isConstructor = !tilde;
       
   446             def->type = Type();
       
   447         } else {
       
   448             def->type = Type("int");
       
   449         }
       
   450     } else {
       
   451         Type tempType = parseType();;
       
   452         while (!tempType.name.isEmpty() && lookup() != LPAREN) {
       
   453             if (testFunctionAttribute(def->type.firstToken, def))
       
   454                 ; // fine
       
   455             else if (def->type.name == "Q_SIGNAL")
       
   456                 def->isSignal = true;
       
   457             else if (def->type.name == "Q_SLOT")
       
   458                 def->isSlot = true;
       
   459             else {
       
   460                 if (!def->tag.isEmpty())
       
   461                     def->tag += ' ';
       
   462                 def->tag += def->type.name;
       
   463             }
       
   464             def->type = tempType;
       
   465             tempType = parseType();
       
   466         }
       
   467         if (!test(LPAREN))
       
   468             return false;
       
   469         def->name = tempType.name;
       
   470         scopedFunctionName = tempType.isScoped;
       
   471     }
       
   472 
       
   473     // we don't support references as return types, it's too dangerous
       
   474     if (def->type.referenceType == Type::Reference)
       
   475         def->type = Type("void");
       
   476 
       
   477     def->normalizedType = normalizeType(def->type.name);
       
   478 
       
   479     if (!test(RPAREN)) {
       
   480         parseFunctionArguments(def);
       
   481         if (!test(RPAREN))
       
   482             return false;
       
   483     }
       
   484     def->isConst = test(CONST);
       
   485     if (scopedFunctionName
       
   486         && (def->isSignal || def->isSlot || def->isInvokable)) {
       
   487         QByteArray msg("parsemaybe: Function declaration ");
       
   488         msg += def->name;
       
   489         msg += " contains extra qualification. Ignoring as signal or slot.";
       
   490         warning(msg.constData());
       
   491         return false;
       
   492     }
       
   493     return true;
       
   494 }
       
   495 
       
   496 
       
   497 void Moc::parse()
       
   498 {
       
   499     QList<NamespaceDef> namespaceList;
       
   500     bool templateClass = false;
       
   501     while (hasNext()) {
       
   502         Token t = next();
       
   503         switch (t) {
       
   504             case NAMESPACE: {
       
   505                 int rewind = index;
       
   506                 if (test(IDENTIFIER)) {
       
   507                     if (test(EQ)) {
       
   508                         // namespace Foo = Bar::Baz;
       
   509                         until(SEMIC);
       
   510                     } else if (!test(SEMIC)) {
       
   511                         NamespaceDef def;
       
   512                         def.name = lexem();
       
   513                         next(LBRACE);
       
   514                         def.begin = index - 1;
       
   515                         until(RBRACE);
       
   516                         def.end = index;
       
   517                         index = def.begin + 1;
       
   518                         namespaceList += def;
       
   519                         index = rewind;
       
   520                     }
       
   521                 }
       
   522                 break;
       
   523             }
       
   524             case SEMIC:
       
   525             case RBRACE:
       
   526                 templateClass = false;
       
   527                 break;
       
   528             case TEMPLATE:
       
   529                 templateClass = true;
       
   530                 break;
       
   531             case MOC_INCLUDE_BEGIN:
       
   532                 currentFilenames.push(symbol().unquotedLexem());
       
   533                 break;
       
   534             case MOC_INCLUDE_END:
       
   535                 currentFilenames.pop();
       
   536                 break;
       
   537             case Q_DECLARE_INTERFACE_TOKEN:
       
   538                 parseDeclareInterface();
       
   539                 break;
       
   540             case Q_DECLARE_METATYPE_TOKEN:
       
   541                 parseDeclareMetatype();
       
   542                 break;
       
   543             case USING:
       
   544                 if (test(NAMESPACE)) {
       
   545                     while (test(SCOPE) || test(IDENTIFIER))
       
   546                         ;
       
   547                     next(SEMIC);
       
   548                 }
       
   549                 break;
       
   550             case CLASS:
       
   551             case STRUCT: {
       
   552                 if (currentFilenames.size() <= 1)
       
   553                     break;
       
   554 
       
   555                 ClassDef def;
       
   556                 if (!parseClassHead(&def))
       
   557                     continue;
       
   558 
       
   559                 while (inClass(&def) && hasNext()) {
       
   560                     if (next() == Q_OBJECT_TOKEN) {
       
   561                         def.hasQObject = true;
       
   562                         break;
       
   563                     }
       
   564                 }
       
   565 
       
   566                 if (!def.hasQObject)
       
   567                     continue;
       
   568 
       
   569                 for (int i = namespaceList.size() - 1; i >= 0; --i)
       
   570                     if (inNamespace(&namespaceList.at(i)))
       
   571                         def.qualified.prepend(namespaceList.at(i).name + "::");
       
   572 
       
   573                 knownQObjectClasses.insert(def.classname);
       
   574                 knownQObjectClasses.insert(def.qualified);
       
   575 
       
   576                 continue; }
       
   577             default: break;
       
   578         }
       
   579         if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
       
   580             continue;
       
   581         ClassDef def;
       
   582         if (parseClassHead(&def)) {
       
   583             FunctionDef::Access access = FunctionDef::Private;
       
   584             for (int i = namespaceList.size() - 1; i >= 0; --i)
       
   585                 if (inNamespace(&namespaceList.at(i)))
       
   586                     def.qualified.prepend(namespaceList.at(i).name + "::");
       
   587             while (inClass(&def) && hasNext()) {
       
   588                 switch ((t = next())) {
       
   589                 case PRIVATE:
       
   590                     access = FunctionDef::Private;
       
   591                     if (test(Q_SIGNALS_TOKEN))
       
   592                         error("Signals cannot have access specifier");
       
   593                     break;
       
   594                 case PROTECTED:
       
   595                     access = FunctionDef::Protected;
       
   596                     if (test(Q_SIGNALS_TOKEN))
       
   597                         error("Signals cannot have access specifier");
       
   598                     break;
       
   599                 case PUBLIC:
       
   600                     access = FunctionDef::Public;
       
   601                     if (test(Q_SIGNALS_TOKEN))
       
   602                         error("Signals cannot have access specifier");
       
   603                     break;
       
   604                 case CLASS: {
       
   605                     ClassDef nestedDef;
       
   606                     if (parseClassHead(&nestedDef)) {
       
   607                         while (inClass(&nestedDef) && inClass(&def)) {
       
   608                             t = next();
       
   609                             if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
       
   610                                 error("Meta object features not supported for nested classes");
       
   611                         }
       
   612                     }
       
   613                 } break;
       
   614                 case Q_SIGNALS_TOKEN:
       
   615                     parseSignals(&def);
       
   616                     break;
       
   617                 case Q_SLOTS_TOKEN:
       
   618                     switch (lookup(-1)) {
       
   619                     case PUBLIC:
       
   620                     case PROTECTED:
       
   621                     case PRIVATE:
       
   622                         parseSlots(&def, access);
       
   623                         break;
       
   624                     default:
       
   625                         error("Missing access specifier for slots");
       
   626                     }
       
   627                     break;
       
   628                 case Q_OBJECT_TOKEN:
       
   629                     def.hasQObject = true;
       
   630                     if (templateClass)
       
   631                         error("Template classes not supported by Q_OBJECT");
       
   632                     if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
       
   633                         error("Class contains Q_OBJECT macro but does not inherit from QObject");
       
   634                     break;
       
   635                 case Q_GADGET_TOKEN:
       
   636                     def.hasQGadget = true;
       
   637                     if (templateClass)
       
   638                         error("Template classes not supported by Q_GADGET");
       
   639                     break;
       
   640                 case Q_PROPERTY_TOKEN:
       
   641                     parseProperty(&def);
       
   642                     break;
       
   643                 case Q_ENUMS_TOKEN:
       
   644                     parseEnumOrFlag(&def, false);
       
   645                     break;
       
   646                 case Q_FLAGS_TOKEN:
       
   647                     parseEnumOrFlag(&def, true);
       
   648                     break;
       
   649                 case Q_DECLARE_FLAGS_TOKEN:
       
   650                     parseFlag(&def);
       
   651                     break;
       
   652                 case Q_CLASSINFO_TOKEN:
       
   653                     parseClassInfo(&def);
       
   654                     break;
       
   655                 case Q_INTERFACES_TOKEN:
       
   656                     parseInterfaces(&def);
       
   657                     break;
       
   658                 case Q_PRIVATE_SLOT_TOKEN:
       
   659                     parseSlotInPrivate(&def, access);
       
   660                     break;
       
   661                 case ENUM: {
       
   662                     EnumDef enumDef;
       
   663                     if (parseEnum(&enumDef))
       
   664                         def.enumList += enumDef;
       
   665                 } break;
       
   666                 default:
       
   667                     FunctionDef funcDef;
       
   668                     funcDef.access = access;
       
   669                     int rewind = index;
       
   670                     if (parseMaybeFunction(&def, &funcDef)) {
       
   671                         if (funcDef.isConstructor) {
       
   672                             if ((access == FunctionDef::Public) && funcDef.isInvokable) {
       
   673                                 def.constructorList += funcDef;
       
   674                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   675                                     funcDef.wasCloned = true;
       
   676                                     funcDef.arguments.removeLast();
       
   677                                     def.constructorList += funcDef;
       
   678                                 }
       
   679                             }
       
   680                         } else if (funcDef.isDestructor) {
       
   681                             // don't care about destructors
       
   682                         } else {
       
   683                             if (access == FunctionDef::Public)
       
   684                                 def.publicList += funcDef;
       
   685                             if (funcDef.isSlot) {
       
   686                                 def.slotList += funcDef;
       
   687                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   688                                     funcDef.wasCloned = true;
       
   689                                     funcDef.arguments.removeLast();
       
   690                                     def.slotList += funcDef;
       
   691                                 }
       
   692                             } else if (funcDef.isSignal) {
       
   693                                 def.signalList += funcDef;
       
   694                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   695                                     funcDef.wasCloned = true;
       
   696                                     funcDef.arguments.removeLast();
       
   697                                     def.signalList += funcDef;
       
   698                                 }
       
   699                             } else if (funcDef.isInvokable) {
       
   700                                 def.methodList += funcDef;
       
   701                                 while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   702                                     funcDef.wasCloned = true;
       
   703                                     funcDef.arguments.removeLast();
       
   704                                     def.methodList += funcDef;
       
   705                                 }
       
   706                             }
       
   707                         }
       
   708                     } else {
       
   709                         index = rewind;
       
   710                     }
       
   711                 }
       
   712             }
       
   713 
       
   714             next(RBRACE);
       
   715 
       
   716             if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
       
   717                 && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
       
   718                 continue; // no meta object code required
       
   719 
       
   720 
       
   721             if (!def.hasQObject && !def.hasQGadget)
       
   722                 error("Class declarations lacks Q_OBJECT macro.");
       
   723 
       
   724             checkSuperClasses(&def);
       
   725 
       
   726             classList += def;
       
   727             knownQObjectClasses.insert(def.classname);
       
   728             knownQObjectClasses.insert(def.qualified);
       
   729         }
       
   730     }
       
   731 }
       
   732 
       
   733 void Moc::generate(FILE *out)
       
   734 {
       
   735 
       
   736     QDateTime dt = QDateTime::currentDateTime();
       
   737     QByteArray dstr = dt.toString().toLatin1();
       
   738     QByteArray fn = filename;
       
   739     int i = filename.length()-1;
       
   740     while (i>0 && filename[i-1] != '/' && filename[i-1] != '\\')
       
   741         --i;                                // skip path
       
   742     if (i >= 0)
       
   743         fn = filename.mid(i);
       
   744     fprintf(out, "/****************************************************************************\n"
       
   745             "** Meta object code from reading C++ file '%s'\n**\n" , (const char*)fn);
       
   746     fprintf(out, "** Created: %s\n"
       
   747             "**      by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , dstr.data(), mocOutputRevision, QT_VERSION_STR);
       
   748     fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
       
   749             "*****************************************************************************/\n\n");
       
   750 
       
   751 
       
   752     if (!noInclude) {
       
   753         if (includePath.size() && !includePath.endsWith('/'))
       
   754             includePath += '/';
       
   755         for (int i = 0; i < includeFiles.size(); ++i) {
       
   756             QByteArray inc = includeFiles.at(i);
       
   757             if (inc[0] != '<' && inc[0] != '"') {
       
   758                 if (includePath.size() && includePath != "./")
       
   759                     inc.prepend(includePath);
       
   760                 inc = '\"' + inc + '\"';
       
   761             }
       
   762             fprintf(out, "#include %s\n", inc.constData());
       
   763         }
       
   764     }
       
   765     if (classList.size() && classList.first().classname == "Qt")
       
   766         fprintf(out, "#include <QtCore/qobject.h>\n");
       
   767 
       
   768     if (mustIncludeQMetaTypeH)
       
   769         fprintf(out, "#include <QtCore/qmetatype.h>\n");
       
   770 
       
   771     fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
       
   772             "#error \"The header file '%s' doesn't include <QObject>.\"\n", (const char *)fn);
       
   773     fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
       
   774     fprintf(out, "#error \"This file was generated using the moc from %s."
       
   775             " It\"\n#error \"cannot be used with the include files from"
       
   776             " this version of Qt.\"\n#error \"(The moc has changed too"
       
   777             " much.)\"\n", QT_VERSION_STR);
       
   778     fprintf(out, "#endif\n\n");
       
   779 
       
   780     fprintf(out, "QT_BEGIN_MOC_NAMESPACE\n");
       
   781 
       
   782     for (i = 0; i < classList.size(); ++i) {
       
   783         Generator generator(&classList[i], metaTypes, out);
       
   784         generator.generateCode();
       
   785     }
       
   786 
       
   787     fprintf(out, "QT_END_MOC_NAMESPACE\n");
       
   788 }
       
   789 
       
   790 
       
   791 QList<QMetaObject*> Moc::generate(bool ignoreProperties)
       
   792 {
       
   793     QList<QMetaObject*> result;
       
   794     for (int i = 0; i < classList.size(); ++i) {
       
   795         Generator generator(&classList[i], metaTypes);
       
   796         result << generator.generateMetaObject(ignoreProperties);
       
   797     }
       
   798     return result;
       
   799 }
       
   800 
       
   801 void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
       
   802 {
       
   803     next(COLON);
       
   804     while (inClass(def) && hasNext()) {
       
   805         switch (next()) {
       
   806         case PUBLIC:
       
   807         case PROTECTED:
       
   808         case PRIVATE:
       
   809         case Q_SIGNALS_TOKEN:
       
   810         case Q_SLOTS_TOKEN:
       
   811             prev();
       
   812             return;
       
   813         case SEMIC:
       
   814             continue;
       
   815         case FRIEND:
       
   816             until(SEMIC);
       
   817             continue;
       
   818         case USING:
       
   819             error("'using' directive not supported in 'slots' section");
       
   820         default:
       
   821             prev();
       
   822         }
       
   823 
       
   824         FunctionDef funcDef;
       
   825         funcDef.access = access;
       
   826         if (!parseFunction(&funcDef))
       
   827             continue;
       
   828         def->slotList += funcDef;
       
   829         while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   830             funcDef.wasCloned = true;
       
   831             funcDef.arguments.removeLast();
       
   832             def->slotList += funcDef;
       
   833         }
       
   834     }
       
   835 }
       
   836 
       
   837 void Moc::parseSignals(ClassDef *def)
       
   838 {
       
   839     next(COLON);
       
   840     while (inClass(def) && hasNext()) {
       
   841         switch (next()) {
       
   842         case PUBLIC:
       
   843         case PROTECTED:
       
   844         case PRIVATE:
       
   845         case Q_SIGNALS_TOKEN:
       
   846         case Q_SLOTS_TOKEN:
       
   847             prev();
       
   848             return;
       
   849         case SEMIC:
       
   850             continue;
       
   851         case FRIEND:
       
   852             until(SEMIC);
       
   853             continue;
       
   854         case USING:
       
   855             error("'using' directive not supported in 'signals' section");
       
   856         default:
       
   857             prev();
       
   858         }
       
   859         FunctionDef funcDef;
       
   860         funcDef.access = FunctionDef::Protected;
       
   861         parseFunction(&funcDef);
       
   862         if (funcDef.isVirtual)
       
   863             warning("Signals cannot be declared virtual");
       
   864         if (funcDef.inlineCode)
       
   865             error("Not a signal declaration");
       
   866         def->signalList += funcDef;
       
   867         while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
   868             funcDef.wasCloned = true;
       
   869             funcDef.arguments.removeLast();
       
   870             def->signalList += funcDef;
       
   871         }
       
   872     }
       
   873 }
       
   874 
       
   875 
       
   876 void Moc::parseProperty(ClassDef *def)
       
   877 {
       
   878     next(LPAREN);
       
   879     PropertyDef propDef;
       
   880     QByteArray type = parseType().name;
       
   881     if (type.isEmpty())
       
   882         error();
       
   883     propDef.designable = propDef.scriptable = propDef.stored = "true";
       
   884     propDef.user = "false";
       
   885     /*
       
   886       The Q_PROPERTY construct cannot contain any commas, since
       
   887       commas separate macro arguments. We therefore expect users
       
   888       to type "QMap" instead of "QMap<QString, QVariant>". For
       
   889       coherence, we also expect the same for
       
   890       QValueList<QVariant>, the other template class supported by
       
   891       QVariant.
       
   892     */
       
   893     type = normalizeType(type);
       
   894     if (type == "QMap")
       
   895         type = "QMap<QString,QVariant>";
       
   896     else if (type == "QValueList")
       
   897         type = "QValueList<QVariant>";
       
   898     else if (type == "LongLong")
       
   899         type = "qlonglong";
       
   900     else if (type == "ULongLong")
       
   901         type = "qulonglong";
       
   902     else if (type == "qreal")
       
   903         mustIncludeQMetaTypeH = true;
       
   904 
       
   905     propDef.type = type;
       
   906 
       
   907     next();
       
   908     propDef.name = lexem();
       
   909     while (test(IDENTIFIER)) {
       
   910         QByteArray l = lexem();
       
   911 
       
   912         if (l[0] == 'C' && l == "CONSTANT") {
       
   913             propDef.constant = true;
       
   914             continue;
       
   915         } else if(l[0] == 'F' && l == "FINAL") {
       
   916             propDef.final = true;
       
   917             continue;
       
   918         }
       
   919 
       
   920         QByteArray v, v2;
       
   921         if (test(LPAREN)) {
       
   922             v = lexemUntil(RPAREN);
       
   923         } else {
       
   924             next(IDENTIFIER);
       
   925             v = lexem();
       
   926             if (test(LPAREN))
       
   927                 v2 = lexemUntil(RPAREN);
       
   928             else if (v != "true" && v != "false")
       
   929                 v2 = "()";
       
   930         }
       
   931         switch (l[0]) {
       
   932         case 'R':
       
   933             if (l == "READ")
       
   934                 propDef.read = v;
       
   935             else if (l == "RESET")
       
   936                 propDef.reset = v + v2;
       
   937             else
       
   938                 error(2);
       
   939             break;
       
   940         case 'S':
       
   941             if (l == "SCRIPTABLE")
       
   942                 propDef.scriptable = v + v2;
       
   943             else if (l == "STORED")
       
   944                 propDef.stored = v + v2;
       
   945             else
       
   946                 error(2);
       
   947             break;
       
   948         case 'W': if (l != "WRITE") error(2);
       
   949             propDef.write = v;
       
   950             break;
       
   951         case 'D': if (l != "DESIGNABLE") error(2);
       
   952             propDef.designable = v + v2;
       
   953             break;
       
   954         case 'E': if (l != "EDITABLE") error(2);
       
   955             propDef.editable = v + v2;
       
   956             break;
       
   957         case 'N': if (l != "NOTIFY") error(2);
       
   958             propDef.notify = v;
       
   959             break;
       
   960         case 'U': if (l != "USER") error(2);
       
   961             propDef.user = v + v2;
       
   962             break;
       
   963         default:
       
   964             error(2);
       
   965         }
       
   966     }
       
   967     next(RPAREN);
       
   968     if (propDef.read.isNull()) {
       
   969         QByteArray msg;
       
   970         msg += "Property declaration ";
       
   971         msg += propDef.name;
       
   972         msg += " has no READ accessor function. The property will be invalid.";
       
   973         warning(msg.constData());
       
   974     }
       
   975     if (propDef.constant && !propDef.write.isNull()) {
       
   976         QByteArray msg;
       
   977         msg += "Property declaration ";
       
   978         msg += propDef.name;
       
   979         msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
       
   980         propDef.constant = false;
       
   981         warning(msg.constData());
       
   982     }
       
   983     if (propDef.constant && !propDef.notify.isNull()) {
       
   984         QByteArray msg;
       
   985         msg += "Property declaration ";
       
   986         msg += propDef.name;
       
   987         msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
       
   988         propDef.constant = false;
       
   989         warning(msg.constData());
       
   990     }
       
   991 
       
   992     if(!propDef.notify.isEmpty())
       
   993         def->notifyableProperties++;
       
   994 
       
   995     def->propertyList += propDef;
       
   996 }
       
   997 
       
   998 void Moc::parseEnumOrFlag(ClassDef *def, bool isFlag)
       
   999 {
       
  1000     next(LPAREN);
       
  1001     QByteArray identifier;
       
  1002     while (test(IDENTIFIER)) {
       
  1003         identifier = lexem();
       
  1004         while (test(SCOPE) && test(IDENTIFIER)) {
       
  1005             identifier += "::";
       
  1006             identifier += lexem();
       
  1007         }
       
  1008         def->enumDeclarations[identifier] = isFlag;
       
  1009     }
       
  1010     next(RPAREN);
       
  1011 }
       
  1012 
       
  1013 void Moc::parseFlag(ClassDef *def)
       
  1014 {
       
  1015     next(LPAREN);
       
  1016     QByteArray flagName, enumName;
       
  1017     while (test(IDENTIFIER)) {
       
  1018         flagName = lexem();
       
  1019         while (test(SCOPE) && test(IDENTIFIER)) {
       
  1020             flagName += "::";
       
  1021             flagName += lexem();
       
  1022         }
       
  1023     }
       
  1024     next(COMMA);
       
  1025     while (test(IDENTIFIER)) {
       
  1026         enumName = lexem();
       
  1027         while (test(SCOPE) && test(IDENTIFIER)) {
       
  1028             enumName += "::";
       
  1029             enumName += lexem();
       
  1030         }
       
  1031     }
       
  1032 
       
  1033     def->flagAliases.insert(enumName, flagName);
       
  1034     next(RPAREN);
       
  1035 }
       
  1036 
       
  1037 void Moc::parseClassInfo(ClassDef *def)
       
  1038 {
       
  1039     next(LPAREN);
       
  1040     ClassInfoDef infoDef;
       
  1041     next(STRING_LITERAL);
       
  1042     infoDef.name = symbol().unquotedLexem();
       
  1043     next(COMMA);
       
  1044     if (test(STRING_LITERAL)) {
       
  1045         infoDef.value = symbol().unquotedLexem();
       
  1046     } else {
       
  1047         // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
       
  1048         next(IDENTIFIER);
       
  1049         next(LPAREN);
       
  1050         next(STRING_LITERAL);
       
  1051         infoDef.value = symbol().unquotedLexem();
       
  1052         next(RPAREN);
       
  1053     }
       
  1054     next(RPAREN);
       
  1055     def->classInfoList += infoDef;
       
  1056 }
       
  1057 
       
  1058 void Moc::parseInterfaces(ClassDef *def)
       
  1059 {
       
  1060     next(LPAREN);
       
  1061     while (test(IDENTIFIER)) {
       
  1062         QList<ClassDef::Interface> iface;
       
  1063         iface += ClassDef::Interface(lexem());
       
  1064         while (test(SCOPE)) {
       
  1065             iface.last().className += lexem();
       
  1066             next(IDENTIFIER);
       
  1067             iface.last().className += lexem();
       
  1068         }
       
  1069         while (test(COLON)) {
       
  1070             next(IDENTIFIER);
       
  1071             iface += ClassDef::Interface(lexem());
       
  1072             while (test(SCOPE)) {
       
  1073                 iface.last().className += lexem();
       
  1074                 next(IDENTIFIER);
       
  1075                 iface.last().className += lexem();
       
  1076             }
       
  1077         }
       
  1078         // resolve from classnames to interface ids
       
  1079         for (int i = 0; i < iface.count(); ++i) {
       
  1080             const QByteArray iid = interface2IdMap.value(iface.at(i).className);
       
  1081             if (iid.isEmpty())
       
  1082                 error("Undefined interface");
       
  1083 
       
  1084             iface[i].interfaceId = iid;
       
  1085         }
       
  1086         def->interfaceList += iface;
       
  1087     }
       
  1088     next(RPAREN);
       
  1089 }
       
  1090 
       
  1091 void Moc::parseDeclareInterface()
       
  1092 {
       
  1093     next(LPAREN);
       
  1094     QByteArray interface;
       
  1095     next(IDENTIFIER);
       
  1096     interface += lexem();
       
  1097     while (test(SCOPE)) {
       
  1098         interface += lexem();
       
  1099         next(IDENTIFIER);
       
  1100         interface += lexem();
       
  1101     }
       
  1102     next(COMMA);
       
  1103     QByteArray iid;
       
  1104     if (test(STRING_LITERAL)) {
       
  1105         iid = lexem();
       
  1106     } else {
       
  1107         next(IDENTIFIER);
       
  1108         iid = lexem();
       
  1109     }
       
  1110     interface2IdMap.insert(interface, iid);
       
  1111     next(RPAREN);
       
  1112 }
       
  1113 
       
  1114 void Moc::parseDeclareMetatype()
       
  1115 {
       
  1116     next(LPAREN);
       
  1117     QByteArray typeName = lexemUntil(RPAREN);
       
  1118     typeName.remove(0, 1);
       
  1119     typeName.chop(1);
       
  1120     metaTypes.append(typeName);
       
  1121 }
       
  1122 
       
  1123 void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
       
  1124 {
       
  1125     next(LPAREN);
       
  1126     FunctionDef funcDef;
       
  1127     next(IDENTIFIER);
       
  1128     funcDef.inPrivateClass = lexem();
       
  1129     // also allow void functions
       
  1130     if (test(LPAREN)) {
       
  1131         next(RPAREN);
       
  1132         funcDef.inPrivateClass += "()";
       
  1133     }
       
  1134     next(COMMA);
       
  1135     funcDef.access = access;
       
  1136     parseFunction(&funcDef, true);
       
  1137     def->slotList += funcDef;
       
  1138     while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {
       
  1139         funcDef.wasCloned = true;
       
  1140         funcDef.arguments.removeLast();
       
  1141         def->slotList += funcDef;
       
  1142     }
       
  1143 }
       
  1144 
       
  1145 QByteArray Moc::lexemUntil(Token target)
       
  1146 {
       
  1147     int from = index;
       
  1148     until(target);
       
  1149     QByteArray s;
       
  1150     while (from <= index) {
       
  1151         QByteArray n = symbols.at(from++-1).lexem();
       
  1152         if (s.size() && n.size()
       
  1153             && is_ident_char(s.at(s.size()-1))
       
  1154             && is_ident_char(n.at(0)))
       
  1155             s += ' ';
       
  1156         s += n;
       
  1157     }
       
  1158     return s;
       
  1159 }
       
  1160 
       
  1161 bool Moc::until(Token target) {
       
  1162     int braceCount = 0;
       
  1163     int brackCount = 0;
       
  1164     int parenCount = 0;
       
  1165     int angleCount = 0;
       
  1166     if (index) {
       
  1167         switch(symbols.at(index-1).token) {
       
  1168         case LBRACE: ++braceCount; break;
       
  1169         case LBRACK: ++brackCount; break;
       
  1170         case LPAREN: ++parenCount; break;
       
  1171         case LANGLE: ++angleCount; break;
       
  1172         default: break;
       
  1173         }
       
  1174     }
       
  1175     while (index < symbols.size()) {
       
  1176         Token t = symbols.at(index++).token;
       
  1177         switch (t) {
       
  1178         case LBRACE: ++braceCount; break;
       
  1179         case RBRACE: --braceCount; break;
       
  1180         case LBRACK: ++brackCount; break;
       
  1181         case RBRACK: --brackCount; break;
       
  1182         case LPAREN: ++parenCount; break;
       
  1183         case RPAREN: --parenCount; break;
       
  1184         case LANGLE: ++angleCount; break;
       
  1185         case RANGLE: --angleCount; break;
       
  1186         case GTGT: angleCount -= 2; t = RANGLE; break;
       
  1187         default: break;
       
  1188         }
       
  1189         if (t == target
       
  1190             && braceCount <= 0
       
  1191             && brackCount <= 0
       
  1192             && parenCount <= 0
       
  1193             && (target != RANGLE || angleCount <= 0))
       
  1194             return true;
       
  1195 
       
  1196         if (braceCount < 0 || brackCount < 0 || parenCount < 0
       
  1197             || (target == RANGLE && angleCount < 0)) {
       
  1198             --index;
       
  1199             break;
       
  1200         }
       
  1201     }
       
  1202     return false;
       
  1203 }
       
  1204 
       
  1205 void Moc::checkSuperClasses(ClassDef *def)
       
  1206 {
       
  1207     const QByteArray firstSuperclass = def->superclassList.value(0).first;
       
  1208 
       
  1209     if (!knownQObjectClasses.contains(firstSuperclass)) {
       
  1210         // enable once we /require/ include paths
       
  1211 #if 0
       
  1212         QByteArray msg;
       
  1213         msg += "Class ";
       
  1214         msg += def->className;
       
  1215         msg += " contains the Q_OBJECT macro and inherits from ";
       
  1216         msg += def->superclassList.value(0);
       
  1217         msg += " but that is not a known QObject subclass. You may get compilation errors.";
       
  1218         warning(msg.constData());
       
  1219 #endif
       
  1220         return;
       
  1221     }
       
  1222     for (int i = 1; i < def->superclassList.count(); ++i) {
       
  1223         const QByteArray superClass = def->superclassList.at(i).first;
       
  1224         if (knownQObjectClasses.contains(superClass)) {
       
  1225             QByteArray msg;
       
  1226             msg += "Class ";
       
  1227             msg += def->classname;
       
  1228             msg += " inherits from two QObject subclasses ";
       
  1229             msg += firstSuperclass;
       
  1230             msg += " and ";
       
  1231             msg += superClass;
       
  1232             msg += ". This is not supported!";
       
  1233             warning(msg.constData());
       
  1234         }
       
  1235 
       
  1236         if (interface2IdMap.contains(superClass)) {
       
  1237             bool registeredInterface = false;
       
  1238             for (int i = 0; i < def->interfaceList.count(); ++i)
       
  1239                 if (def->interfaceList.at(i).first().className == superClass) {
       
  1240                     registeredInterface = true;
       
  1241                     break;
       
  1242                 }
       
  1243 
       
  1244             if (!registeredInterface) {
       
  1245                 QByteArray msg;
       
  1246                 msg += "Class ";
       
  1247                 msg += def->classname;
       
  1248                 msg += " implements the interface ";
       
  1249                 msg += superClass;
       
  1250                 msg += " but does not list it in Q_INTERFACES. qobject_cast to ";
       
  1251                 msg += superClass;
       
  1252                 msg += " will not work!";
       
  1253                 warning(msg.constData());
       
  1254             }
       
  1255         }
       
  1256     }
       
  1257 }
       
  1258 
       
  1259 
       
  1260 QT_END_NAMESPACE