// like parseFunction, but never aborts with an error bool Moc::parseMaybeFunction(FunctionDef *def) { def->type = parseType(); if (def->type.name.isEmpty()) return false; 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 (def->type.name == "QT_MOC_COMPAT" || def->type.name == "QT3_SUPPORT") def->isCompat = true; else if (def->type.name == "Q_INVOKABLE") def->isInvokable = true; else if (def->type.name == "Q_SCRIPTABLE") def->isInvokable = def->isScriptable = true; else if (def->type.name == "Q_SIGNAL") def->isSignal = true; else if (def->type.name == "Q_SLOT") def->isSlot = true; else { if (!def->tag.isEmpty()) def->tag += ' '; def->tag += def->type.name; } def->type = tempType; tempType = parseType(); } if (!test(LPAREN)) return false; 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); if (!test(RPAREN)) return false; } def->isConst = test(CONST); if (scopedFunctionName && (def->isSignal || def->isSlot || def->isInvokable)) { QByteArray msg("parsemaybe: Function declaration "); msg += def->name; msg += " contains extra qualification. Ignoring as signal or slot."; warning(msg.constData()); return false; } return true; }
void CppTree2Uml::parseFunctionDeclaration(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl) { bool isFriend = false; //:unused: bool isVirtual = false; bool isStatic = false; //:unused: bool isInline = false; bool isPure = decl->initializer() != 0; bool isConstructor = false; if (funSpec){ //:unused: QList<AST*> l = funSpec->nodeList(); //:unused: for (int i = 0; i < l.size(); ++i) { //:unused: QString text = l.at(i)->text(); //:unused: if (text == QLatin1String("virtual")) isVirtual = true; //:unused: else if (text == QLatin1String("inline")) isInline = true; //:unused: } } if (storageSpec){ QList<AST*> l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; } } DeclaratorAST* d = decl->declarator(); QString id = d->declaratorId()->unqualifiedName()->text(); UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == NULL) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); // if a class has no return type, it could de a constructor or // a destructor if (d && returnType.isEmpty() && id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, isPure, isFriend, isConstructor, m_comment); m_comment = QString(); }
// like parseFunction, but never aborts with an error bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) { def->isVirtual = false; //skip modifiers and attributes while (test(EXPLICIT) || test(INLINE) || test(STATIC) || (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual || testFunctionAttribute(def)) {} bool tilde = test(TILDE); def->type = parseType(); if (def->type.name.isEmpty()) return false; bool scopedFunctionName = false; if (test(LPAREN)) { def->name = def->type.name; scopedFunctionName = def->type.isScoped; if (def->name == cdef->classname) { def->isDestructor = tilde; def->isConstructor = !tilde; def->type = Type(); } else { 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.name == "Q_SIGNAL") def->isSignal = true; else if (def->type.name == "Q_SLOT") def->isSlot = true; else { if (!def->tag.isEmpty()) def->tag += ' '; def->tag += def->type.name; } def->type = tempType; tempType = parseType(); } if (!test(LPAREN)) return false; 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); if (!test(RPAREN)) return false; } def->isConst = test(CONST); if (scopedFunctionName && (def->isSignal || def->isSlot || def->isInvokable)) { QByteArray msg("parsemaybe: Function declaration "); msg += def->name; msg += " contains extra qualification. Ignoring as signal or slot."; warning(msg.constData()); return false; } return true; }
// returns false if the function should be ignored bool Moc::parseFunction(FunctionDef *def, bool inMacro) { def->isVirtual = false; //skip modifiers and attributes while (test(INLINE) || test(STATIC) || (test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual || testFunctionAttribute(def)) {} 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); prev(); } else { if (test(THROW)) { next(LPAREN); until(RPAREN); } if (test(SEMIC)) ; else if ((def->inlineCode = test(LBRACE))) until(RBRACE); else if ((def->isAbstract = test(EQ))) until(SEMIC); else error(); } if (scopedFunctionName) { QByteArray msg("Function declaration "); msg += def->name; msg += " contains extra qualification. Ignoring as signal or slot."; warning(msg.constData()); return false; } return true; }
void CppTree2Uml::parseFunctionDefinition(FunctionDefinitionAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); GroupAST* funSpec = ast->functionSpecifier(); GroupAST* storageSpec = ast->storageSpecifier(); if (!ast->initDeclarator()) return; DeclaratorAST* d = ast->initDeclarator()->declarator(); if (!d->declaratorId()) return; bool isFriend = false; //:unused: bool isVirtual = false; bool isStatic = false; //:unused: bool isInline = false; bool isConstructor = false; if (funSpec){ //:unused: QList<AST*> l = funSpec->nodeList(); //:unused: for (int i = 0; i < l.size(); ++i) { //:unused: QString text = l.at(i)->text(); //:unused: if (text == "virtual") isVirtual = true; //:unused: else if (text == "inline") isInline = true; //:unused: } } if (storageSpec){ QList<AST*> l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; } } QString id = d->declaratorId()->unqualifiedName()->text().trimmed(); if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("method ") + id); } uDebug() << id; UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == NULL) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); // if a class has no return type, it could be a constructor or // a destructor if (d && returnType.isEmpty() && id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, false /*isAbstract*/, isFriend, isConstructor, m_comment); m_comment = QString(); /* For reference, Kdevelop does some more: method->setFileName(m_fileName); if (m_inSignals) method->setSignal(true); if (m_inSlots) method->setSlot(true); */ }