📄 moc.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the tools applications of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "moc.h"#include "generator.h"#include "qdatetime.h"#include "utils.h"#include "outputrevision.h"// for normalizeTypeInternal#include <private/qmetaobject_p.h>// only moc needs this functionstatic QByteArray normalizeType(const char *s, bool fixScope = false){ int len = qstrlen(s); char stackbuf[64]; char *buf = (len >= 64 ? new char[len + 1] : stackbuf); char *d = buf; char last = 0; while(*s && is_space(*s)) s++; while (*s) { while (*s && !is_space(*s)) last = *d++ = *s++; while (*s && is_space(*s)) s++; if (*s && is_ident_char(*s) && is_ident_char(last)) last = *d++ = ' '; } *d = '\0'; QByteArray result; if (strncmp("void", buf, d - buf) != 0) result = normalizeTypeInternal(buf, d, fixScope); if (buf != stackbuf) delete [] buf; return result;}bool Moc::parseClassHead(ClassDef *def){ // figure out whether this is a class declaration, or only a // forward or variable declaration. int i = 0; Token token; do { token = lookup(i++); if (token == COLON || token == LBRACE) break; if (token == SEMIC || token == RANGLE) return false; } while (token); if (!test(IDENTIFIER)) // typedef struct { ... } return false; QByteArray name = lexem(); // support "class IDENT name" and "class IDENT(IDENT) name" if (test(LPAREN)) { until(RPAREN); if (!test(IDENTIFIER)) return false; name = lexem(); } else if (test(IDENTIFIER)) { name = lexem(); } def->qualified += name; while (test(SCOPE)) { def->qualified += lexem(); if (test(IDENTIFIER)) { name = lexem(); def->qualified += name; } } def->classname = name; if (test(COLON)) { do { test(VIRTUAL); FunctionDef::Access access = FunctionDef::Public; if (test(PRIVATE)) access = FunctionDef::Private; else if (test(PROTECTED)) access = FunctionDef::Protected; else test(PUBLIC); test(VIRTUAL); const QByteArray type = parseType().name; // ignore the 'class Foo : BAR(Baz)' case if (test(LPAREN)) { until(RPAREN); } else { def->superclassList += qMakePair(type, access); } } while (test(COMMA)); } if (!test(LBRACE)) return false; def->begin = index - 1; bool foundRBrace = until(RBRACE); def->end = index; index = def->begin + 1; return foundRBrace;}Type Moc::parseType(){ Type type; bool hasSignedOrUnsigned = false; bool isVoid = false; type.firstToken = lookup(); for (;;) { switch (next()) { case SIGNED: case UNSIGNED: hasSignedOrUnsigned = true; // fall through case CONST: case VOLATILE: type.name += lexem(); type.name += ' '; if (lookup(0) == VOLATILE) type.isVolatile = true; continue; case Q_MOC_COMPAT_TOKEN: case Q_QT3_SUPPORT_TOKEN: case Q_INVOKABLE_TOKEN: case Q_SCRIPTABLE_TOKEN: case Q_SIGNALS_TOKEN: case Q_SLOTS_TOKEN: type.name += lexem(); return type; default: prev(); break; } break; } test(ENUM) || test(CLASS) || test(STRUCT); for(;;) { switch (next()) { case IDENTIFIER: // void mySlot(unsigned myArg) if (hasSignedOrUnsigned) { prev(); break; } case CHAR: case SHORT: case INT: case LONG: type.name += lexem(); // preserve '[unsigned] long long', 'short int', 'long int', 'long double' if (test(LONG) || test(INT) || test(DOUBLE)) { type.name += ' '; prev(); continue; } break; case FLOAT: case DOUBLE: case VOID: case BOOL: type.name += lexem(); isVoid |= (lookup(0) == VOID); break; default: prev(); ; } if (test(LANGLE)) { QByteArray templ = lexemUntil(RANGLE); for (int i = 0; i < templ.size(); ++i) { type.name += templ.at(i); if (templ.at(i) == '>' && i < templ.size()-1 && templ.at(i+1) == '>') type.name += ' '; } } if (test(SCOPE)) { type.name += lexem(); type.isScoped = true; } else { break; } } while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED) || test(STAR) || test(AND)) { type.name += ' '; type.name += lexem(); if (lookup(0) == AND) type.referenceType = Type::Reference; else if (lookup(0) == STAR) type.referenceType = Type::Pointer; } // transform stupid things like 'const void' or 'void const' into 'void' if (isVoid && type.referenceType == Type::NoReference) { type.name = "void"; } return type;}bool Moc::parseEnum(EnumDef *def){ bool isTypdefEnum = false; // typedef enum { ... } Foo; if (test(IDENTIFIER)) { def->name = lexem(); } else { if (lookup(-1) != TYPEDEF) return false; // anonymous enum isTypdefEnum = true; } if (!test(LBRACE)) return false; do { if (lookup() == RBRACE) // accept trailing comma break; next(IDENTIFIER); def->values += lexem(); } while (test(EQ) ? until(COMMA) : test(COMMA)); next(RBRACE); if (isTypdefEnum) { if (!test(IDENTIFIER)) return false; def->name = lexem(); } return true;}void Moc::parseFunctionArguments(FunctionDef *def){ Q_UNUSED(def); while (hasNext()) { ArgumentDef arg; arg.type = parseType(); if (arg.type.name == "void") break; if (test(IDENTIFIER)) arg.name = lexem(); while (test(LBRACK)) { arg.rightType += lexemUntil(RBRACK); } if (test(CONST) || test(VOLATILE)) { arg.rightType += ' '; arg.rightType += lexem(); } arg.normalizedType = normalizeType(arg.type.name + ' ' + arg.rightType); arg.typeNameForCast = normalizeType(noRef(arg.type.name) + "(*)" + arg.rightType); if (test(EQ)) arg.isDefault = true; def->arguments += arg; if (!until(COMMA)) break; }}bool Moc::testFunctionAttribute(FunctionDef *def){ if (index < symbols.size() && testFunctionAttribute(symbols.at(index).token, def)) { ++index; return true; } return false;}bool Moc::testFunctionAttribute(Token tok, FunctionDef *def){ switch (tok) { case Q_MOC_COMPAT_TOKEN: case Q_QT3_SUPPORT_TOKEN: def->isCompat = true; return true; case Q_INVOKABLE_TOKEN: def->isInvokable = true; return true; case Q_SCRIPTABLE_TOKEN: def->isInvokable = def->isScriptable = true; return true; default: break; } return false;}// returns false if the function should be ignoredbool Moc::parseFunction(FunctionDef *def, bool inMacro){ def->isVirtual = false; while (test(INLINE) || test(STATIC) || test(VIRTUAL) || testFunctionAttribute(def)) { if (lookup() == VIRTUAL) def->isVirtual = true; } bool templateFunction = (lookup() == TEMPLATE); def->type = parseType(); if (def->type.name.isEmpty()) { if (templateFunction) error("Template function as signal or slot"); else error(); } bool scopedFunctionName = false; if (test(LPAREN)) { def->name = def->type.name; scopedFunctionName = def->type.isScoped; def->type = Type("int"); } else { Type tempType = parseType();; while (!tempType.name.isEmpty() && lookup() != LPAREN) { if (testFunctionAttribute(def->type.firstToken, def)) ; // fine else if (def->type.firstToken == Q_SIGNALS_TOKEN) error(); else if (def->type.firstToken == Q_SLOTS_TOKEN) error(); else { if (!def->tag.isEmpty()) def->tag += ' '; def->tag += def->type.name; } def->type = tempType; tempType = parseType(); } next(LPAREN, "Not a signal or slot declaration"); def->name = tempType.name; scopedFunctionName = tempType.isScoped; } // we don't support references as return types, it's too dangerous if (def->type.referenceType == Type::Reference) def->type = Type("void"); def->normalizedType = normalizeType(def->type.name); if (!test(RPAREN)) { parseFunctionArguments(def); next(RPAREN); } // support optional macros with compiler specific options while (test(IDENTIFIER)) ; def->isConst = test(CONST); while (test(IDENTIFIER)) ; if (inMacro) { next(RPAREN); } else { if (test(SEMIC)) ; else if ((def->inlineCode = test(LBRACE))) until(RBRACE); else if (test(EQ) || test(THROW)) until(SEMIC); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -