diff options
Diffstat (limited to 'src/qdoc/cppcodeparser.cpp')
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 1543 |
1 files changed, 79 insertions, 1464 deletions
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 29e1c0fe6..c81a385a3 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -46,12 +46,10 @@ QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ static bool inMacroCommand_ = false; -static bool parsingHeaderFile_ = false; QStringList CppCodeParser::exampleFiles; QStringList CppCodeParser::exampleDirs; QSet<QString> CppCodeParser::excludeDirs; QSet<QString> CppCodeParser::excludeFiles; -CppCodeParser* CppCodeParser::cppParser_ = 0; /*! The constructor initializes some regular expressions @@ -61,7 +59,6 @@ CppCodeParser::CppCodeParser() : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::") { reset(); - cppParser_ = this; } /*! @@ -88,6 +85,7 @@ void CppCodeParser::initializeParser(const Config &config) nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace); nodeTypeMap.insert(COMMAND_CLASS, Node::Class); nodeTypeMap.insert(COMMAND_ENUM, Node::Enum); + nodeTypeMap.insert(COMMAND_TYPEALIAS, Node::Typedef); nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef); nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property); nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable); @@ -140,7 +138,7 @@ QString CppCodeParser::language() */ QStringList CppCodeParser::headerFileNameFilter() { - return QStringList() << "*.ch" << "*.h" << "*.h++" << "*.hh" << "*.hpp" << "*.hxx"; + return QStringList(); } /*! @@ -149,121 +147,9 @@ QStringList CppCodeParser::headerFileNameFilter() */ QStringList CppCodeParser::sourceFileNameFilter() { - return QStringList() << "*.c++" << "*.cc" << "*.cpp" << "*.cxx" << "*.mm"; + return QStringList(); } -/*! - Parse the C++ header file identified by \a filePath and add - the parsed contents to the database. The \a location is used - for reporting errors. - */ -void CppCodeParser::parseHeaderFile(const Location& location, const QString& filePath) -{ - QFile in(filePath); - currentFile_ = filePath; - if (!in.open(QIODevice::ReadOnly)) { - location.error(tr("Cannot open C++ header file '%1'").arg(filePath)); - currentFile_.clear(); - return; - } - - reset(); - Location fileLocation(filePath); - Tokenizer fileTokenizer(fileLocation, in); - tokenizer = &fileTokenizer; - readToken(); - parsingHeaderFile_ = true; - matchDeclList(qdb_->primaryTreeRoot()); - parsingHeaderFile_ = false; - if (!fileTokenizer.version().isEmpty()) - qdb_->setVersion(fileTokenizer.version()); - in.close(); - - if (fileLocation.fileName() == "qiterator.h") - parseQiteratorDotH(location, filePath); - currentFile_.clear(); -} - -/*! - Get ready to parse the C++ cpp file identified by \a filePath - and add its parsed contents to the database. \a location is - used for reporting errors. - - Call matchDocsAndStuff() to do all the parsing and tree building. - */ -void CppCodeParser::parseSourceFile(const Location& location, const QString& filePath) -{ - QFile in(filePath); - currentFile_ = filePath; - if (!in.open(QIODevice::ReadOnly)) { - location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno))); - currentFile_.clear(); - return; - } - - reset(); - Location fileLocation(filePath); - Tokenizer fileTokenizer(fileLocation, in); - tokenizer = &fileTokenizer; - readToken(); - - /* - The set of open namespaces is cleared before parsing - each source file. The word "source" here means cpp file. - */ - qdb_->clearOpenNamespaces(); - - matchDocsAndStuff(); - in.close(); - currentFile_.clear(); -} - -/*! - This is called after all the C++ header files have been - parsed. The most important thing it does is resolve C++ - class inheritance links in the tree. It also initializes - a bunch of other collections. - */ -void CppCodeParser::doneParsingHeaderFiles() -{ - QMapIterator<QString, QString> i(sequentialIteratorClasses); - while (i.hasNext()) { - i.next(); - instantiateIteratorMacro(i.key(), i.value(), sequentialIteratorDefinition); - } - i = mutableSequentialIteratorClasses; - while (i.hasNext()) { - i.next(); - instantiateIteratorMacro(i.key(), i.value(), mutableSequentialIteratorDefinition); - } - i = associativeIteratorClasses; - while (i.hasNext()) { - i.next(); - instantiateIteratorMacro(i.key(), i.value(), associativeIteratorDefinition); - } - i = mutableAssociativeIteratorClasses; - while (i.hasNext()) { - i.next(); - instantiateIteratorMacro(i.key(), i.value(), mutableAssociativeIteratorDefinition); - } - sequentialIteratorDefinition.clear(); - mutableSequentialIteratorDefinition.clear(); - associativeIteratorDefinition.clear(); - mutableAssociativeIteratorDefinition.clear(); - sequentialIteratorClasses.clear(); - mutableSequentialIteratorClasses.clear(); - associativeIteratorClasses.clear(); - mutableAssociativeIteratorClasses.clear(); -} - -/*! - This is called after all the source files (i.e., not the - header files) have been parsed. Currently nothing to do. - */ -void CppCodeParser::doneParsingSourceFiles() -{ - // contents moved to QdocDatabase::resolveIssues() -} static QSet<QString> topicCommands_; /*! @@ -286,6 +172,7 @@ const QSet<QString>& CppCodeParser::topicCommands() << COMMAND_NAMESPACE << COMMAND_PAGE << COMMAND_PROPERTY + << COMMAND_TYPEALIAS << COMMAND_TYPEDEF << COMMAND_VARIABLE << COMMAND_QMLTYPE @@ -321,86 +208,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, { ExtraFuncData extra; if (command == COMMAND_FN) { - QStringList parentPath; - FunctionNode *func = 0; - FunctionNode *clone = 0; - - if (!makeFunctionNode(arg.first, &parentPath, &clone, extra) && - !makeFunctionNode("void " + arg.first, &parentPath, &clone, extra)) { - doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN)); - } - else { - func = qdb_->findFunctionNode(parentPath, clone); - if (func == 0) { - if (parentPath.isEmpty() && !lastPath_.isEmpty()) - func = qdb_->findFunctionNode(lastPath_, clone); - } - - /* - If the node was not found, then search for it in the - open C++ namespaces. We don't expect this search to - be necessary often. Nor do we expect it to succeed - very often. - */ - if (func == 0) - func = qdb_->findNodeInOpenNamespace(parentPath, clone); - - if (func == 0) { - doc.location().warning(tr("Cannot find '%1' in '\\%2' %3") - .arg(clone->name() + "(...)") - .arg(COMMAND_FN) - .arg(arg.first), - tr("I cannot find any function of that name with the " - "specified signature. Make sure that the signature " - "is identical to the declaration, including 'const' " - "qualifiers.")); - } - else - lastPath_ = parentPath; - if (func) { - func->borrowParameterNames(clone); - func->setParentPath(clone->parentPath()); - } - delete clone; - } - return func; - } - else if (command == COMMAND_MACRO) { - QStringList parentPath; - FunctionNode *func = 0; - - extra.root = qdb_->primaryTreeRoot(); - extra.isMacro = true; - if (makeFunctionNode(arg.first, &parentPath, &func, extra)) { - if (!parentPath.isEmpty()) { - doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_MACRO)); - delete func; - func = 0; - } - else { - func->setMetaness(FunctionNode::MacroWithParams); - QVector<Parameter> params = func->parameters(); - for (int i = 0; i < params.size(); ++i) { - Parameter ¶m = params[i]; - if (param.name().isEmpty() && !param.dataType().isEmpty() - && param.dataType() != "...") - param = Parameter("", "", param.dataType()); - } - func->setParameters(params); - } - return func; - } - else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg.first)) { - func = new FunctionNode(qdb_->primaryTreeRoot(), arg.first); - func->setAccess(Node::Public); - func->setLocation(doc.startLocation()); - func->setMetaness(FunctionNode::MacroWithoutParams); - } - else { - doc.location().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_MACRO)); - - } - return func; + Q_UNREACHABLE(); } else if (nodeTypeMap.contains(command)) { /* @@ -420,8 +228,10 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, if (node == 0) node = qdb_->findNodeByNameAndType(path, type); if (node == 0) { - doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file") - .arg(arg.first).arg(command)); + if (isWorthWarningAbout(doc)) { + doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file") + .arg(arg.first).arg(command)); + } lastPath_ = path; } @@ -560,50 +370,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_JSMETHOD) || (command == COMMAND_JSATTACHEDSIGNAL) || (command == COMMAND_JSATTACHEDMETHOD)) { - QString module; - QString name; - QString type; - if (splitQmlMethodArg(arg.first, type, module, name)) { - Aggregate* aggregate = qdb_->findQmlType(module, name); - if (!aggregate) - aggregate = qdb_->findQmlBasicType(module, name); - if (aggregate) { - bool attached = false; - Node::NodeType nodeType = Node::QmlMethod; - if ((command == COMMAND_QMLSIGNAL) || - (command == COMMAND_JSSIGNAL)) - nodeType = Node::QmlSignal; - else if ((command == COMMAND_QMLATTACHEDSIGNAL) || - (command == COMMAND_JSATTACHEDSIGNAL)) { - nodeType = Node::QmlSignal; - attached = true; - } - else if ((command == COMMAND_QMLMETHOD) || - (command == COMMAND_JSMETHOD)) { - // do nothing - } - else if ((command == COMMAND_QMLATTACHEDMETHOD) || - (command == COMMAND_JSATTACHEDMETHOD)) - attached = true; - else - return 0; // never get here. - FunctionNode* fn = makeFunctionNode(doc, - arg.first, - aggregate, - nodeType, - attached, - command); - if (fn) { - fn->setLocation(doc.startLocation()); - if ((command == COMMAND_JSSIGNAL) || - (command == COMMAND_JSMETHOD) || - (command == COMMAND_JSATTACHEDSIGNAL) || - (command == COMMAND_JSATTACHEDMETHOD)) - fn->setGenus(Node::JS); - } - return fn; - } - } + Q_UNREACHABLE(); } return 0; } @@ -623,7 +390,8 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, bool CppCodeParser::splitQmlPropertyGroupArg(const QString& arg, QString& module, QString& qmlTypeName, - QString& name) + QString& name, + const Location& location) { QStringList colonSplit = arg.split("::"); if (colonSplit.size() == 3) { @@ -633,7 +401,7 @@ bool CppCodeParser::splitQmlPropertyGroupArg(const QString& arg, return true; } QString msg = "Unrecognizable QML module/component qualifier for " + arg; - location().warning(tr(msg.toLatin1().data())); + location.warning(tr(msg.toLatin1().data())); return false; } @@ -660,7 +428,8 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, QString& type, QString& module, QString& qmlTypeName, - QString& name) + QString& name, + const Location &location) { QStringList blankSplit = arg.split(QLatin1Char(' ')); if (blankSplit.size() > 1) { @@ -679,66 +448,16 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, return true; } QString msg = "Unrecognizable QML module/component qualifier for " + arg; - location().warning(tr(msg.toLatin1().data())); + location.warning(tr(msg.toLatin1().data())); } else { QString msg = "Missing property type for " + arg; - location().warning(tr(msg.toLatin1().data())); + location.warning(tr(msg.toLatin1().data())); } return false; } /*! - A QML signal or method argument has the form... - - <type> <QML-type>::<name>(<param>, <param>, ...) - <type> <QML-module>::<QML-type>::<name>(<param>, <param>, ...) - - This function splits the \a{arg}ument into one of those - two forms, sets \a type, \a module, and \a qmlTypeName, - and returns true. If the argument doesn't match either - form, an error message is emitted and false is returned. - - \note The two QML types \e{Component} and \e{QtObject} never - have a module qualifier. - */ -bool CppCodeParser::splitQmlMethodArg(const QString& arg, - QString& type, - QString& module, - QString& qmlTypeName) -{ - QString name; - int leftParen = arg.indexOf(QChar('(')); - if (leftParen > 0) - name = arg.left(leftParen); - else - name = arg; - int firstBlank = name.indexOf(QChar(' ')); - if (firstBlank > 0) { - type = name.left(firstBlank); - name = name.right(name.length() - firstBlank - 1); - } - else - type.clear(); - - QStringList colonSplit(name.split("::")); - if (colonSplit.size() > 1) { - if (colonSplit.size() > 2) { - module = colonSplit[0]; - qmlTypeName = colonSplit[1]; - } - else { - module.clear(); - qmlTypeName = colonSplit[0]; - } - return true; - } - QString msg = "Unrecognizable QML module/component qualifier for " + arg; - location().warning(tr(msg.toLatin1().data())); - return false; -} - -/*! Process the topic \a command group found in the \a doc with arguments \a args. Currently, this function is called only for \e{qmlproperty} @@ -775,7 +494,7 @@ void CppCodeParser::processQmlProperties(const Doc& doc, else qmlPropertyGroupTopic.topic = COMMAND_QMLPROPERTYGROUP; arg = qmlPropertyGroupTopic.args; - if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property)) { + if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property, doc.location())) { int i = property.indexOf('.'); if (i != -1) { property = property.left(i); @@ -795,7 +514,7 @@ void CppCodeParser::processQmlProperties(const Doc& doc, if (!qmlPropertyGroupTopic.isEmpty()) { arg = qmlPropertyGroupTopic.args; - if (splitQmlPropertyGroupArg(arg, module, qmlTypeName, property)) { + if (splitQmlPropertyGroupArg(arg, module, qmlTypeName, property, doc.location())) { qmlType = qdb_->findQmlType(module, qmlTypeName); if (qmlType) { qpgn = new QmlPropertyGroupNode(qmlType, property); @@ -817,7 +536,7 @@ void CppCodeParser::processQmlProperties(const Doc& doc, (topic == COMMAND_JSPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY)) { bool attached = ((topic == COMMAND_QMLATTACHEDPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY)); - if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property)) { + if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property, doc.location())) { Aggregate* aggregate = qdb_->findQmlType(module, qmlTypeName); if (!aggregate) aggregate = qdb_->findQmlBasicType(module, qmlTypeName); @@ -909,11 +628,13 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, FunctionNode *func = (FunctionNode *) node; const FunctionNode *from = func->reimplementedFrom(); if (from == 0) { - doc.location().warning(tr("Cannot find base function for '\\%1' in %2()") - .arg(COMMAND_REIMP).arg(node->name()), - tr("The function either doesn't exist in any " - "base class with the same signature or it " - "exists but isn't virtual.")); + if (isWorthWarningAbout(doc)) { + doc.location().warning(tr("Cannot find base function for '\\%1' in %2()") + .arg(COMMAND_REIMP).arg(node->name()), + tr("The function either doesn't exist in any " + "base class with the same signature or it " + "exists but isn't virtual.")); + } } /* Ideally, we would enable this check to warn whenever @@ -921,8 +642,9 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, internal if the function is a reimplementation of another function in a base class. */ - else if (from->access() == Node::Private - || from->parent()->access() == Node::Private) { + else if ((from->access() == Node::Private + || from->parent()->access() == Node::Private) + && isWorthWarningAbout(doc)) { doc.location().warning(tr("'\\%1' in %2() should be '\\internal' " "because its base function is private " "or internal").arg(COMMAND_REIMP).arg(node->name())); @@ -1179,15 +901,6 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType) return matches; } -/* - This function is no longer used. - */ -bool CppCodeParser::matchTemplateHeader() -{ - readToken(); - return matchTemplateAngles(); -} - bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) { /* @@ -1212,11 +925,24 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) */ while (match(Tok_const) || match(Tok_volatile)) dataType->append(previousLexeme()); - while (match(Tok_signed) || match(Tok_unsigned) || - match(Tok_short) || match(Tok_long) || match(Tok_int64)) { - dataType->append(previousLexeme()); + QString pending; + while (tok == Tok_signed || tok == Tok_int || tok == Tok_unsigned || + tok == Tok_short || tok == Tok_long || tok == Tok_int64) { + if (tok == Tok_signed) + pending = lexeme(); + else { + if (tok == Tok_unsigned && !pending.isEmpty()) + dataType->append(pending); + pending.clear(); + dataType->append(lexeme()); + } + readToken(); virgin = false; } + if (!pending.isEmpty()) { + dataType->append(pending); + pending.clear(); + } while (match(Tok_const) || match(Tok_volatile)) dataType->append(previousLexeme()); @@ -1274,22 +1000,29 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) in some cases (e.g., 'operator int()'). The tokenizer recognizes '(*' as a single token. */ + dataType->append(" "); // force a space after the type dataType->append(previousLexeme()); dataType->appendHotspot(); if (var != 0 && match(Tok_Ident)) *var = previousLexeme(); - if (!match(Tok_RightParen) || tok != Tok_LeftParen) { + if (!match(Tok_RightParen)) + return false; + dataType->append(previousLexeme()); + if (!match(Tok_LeftParen)) return false; - } dataType->append(previousLexeme()); - int parenDepth0 = tokenizer->parenDepth(); - while (tokenizer->parenDepth() >= parenDepth0 && tok != Tok_Eoi) { - dataType->append(lexeme()); - readToken(); + /* parse the parameters. Ignore the parameter name from the type */ + while (tok != Tok_RightParen && tok != Tok_Eoi) { + QString dummy; + if (!matchDataType(dataType, &dummy)) + return false; + if (match(Tok_Comma)) + dataType->append(previousLexeme()); } - if (match(Tok_RightParen)) - dataType->append(previousLexeme()); + if (!match(Tok_RightParen)) + return false; + dataType->append(previousLexeme()); } else { /* @@ -1314,6 +1047,24 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) if (varComment.exactMatch(previousLexeme())) *var = varComment.cap(1); } + else if (match(Tok_LeftParen)) { + *var = "("; + while (tok != Tok_RightParen && tok != Tok_Eoi) { + (*var).append(lexeme()); + readToken(); + } + (*var).append(")"); + readToken(); + if (match(Tok_LeftBracket)) { + (*var).append("["); + while (tok != Tok_RightBracket && tok != Tok_Eoi) { + (*var).append(lexeme()); + readToken(); + } + (*var).append("]"); + readToken(); + } + } else if (qProp && (match(Tok_default) || match(Tok_final) || match(Tok_override))) { // Hack to make 'default', 'final' and 'override' work again in Q_PROPERTY *var = previousLexeme(); @@ -1369,495 +1120,6 @@ bool CppCodeParser::matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSi } /*! - If the current token is any of several function modifiers, - return that token value after reading the next token. If it - is not one of the function modieifer tokens, return -1 but - don\t read the next token. - */ -int CppCodeParser::matchFunctionModifier() -{ - switch (tok) { - case Tok_friend: - case Tok_inline: - case Tok_explicit: - case Tok_static: - case Tok_QT_DEPRECATED: - readToken(); - return tok; - case Tok_QT_COMPAT: - case Tok_QT_COMPAT_CONSTRUCTOR: - case Tok_QT_MOC_COMPAT: - case Tok_QT3_SUPPORT: - case Tok_QT3_SUPPORT_CONSTRUCTOR: - case Tok_QT3_MOC_SUPPORT: - readToken(); - return Tok_QT_COMPAT; - default: - break; - } - return -1; -} - -bool CppCodeParser::matchFunctionDecl(Aggregate *parent, - QStringList *parentPathPtr, - FunctionNode **funcPtr, - const QString &templateStuff, - ExtraFuncData& extra) -{ - CodeChunk returnType; - QStringList parentPath; - QString name; - - bool matched_QT_DEPRECATED = false; - bool matched_friend = false; - bool matched_static = false; - bool matched_inline = false; - bool matched_explicit = false; - bool matched_compat = false; - - int token = tok; - while (token != -1) { - switch (token) { - case Tok_friend: - matched_friend = true; - break; - case Tok_inline: - matched_inline = true; - break; - case Tok_explicit: - matched_explicit = true; - break; - case Tok_static: - matched_static = true; - break; - case Tok_QT_DEPRECATED: - matched_QT_DEPRECATED = true; - Q_FALLTHROUGH(); // no break here. - case Tok_QT_COMPAT: - matched_compat = true; - break; - } - token = matchFunctionModifier(); - } - - FunctionNode::Virtualness virtuality = FunctionNode::NonVirtual; - if (match(Tok_virtual)) { - virtuality = FunctionNode::NormalVirtual; - if (!matched_compat) - matched_compat = matchCompat(); - } - - if (!matchDataType(&returnType)) { - if (tokenizer->parsingFnOrMacro() - && (match(Tok_Q_DECLARE_FLAGS) || - match(Tok_Q_PROPERTY) || - match(Tok_Q_PRIVATE_PROPERTY))) - returnType = CodeChunk(previousLexeme()); - else { - return false; - } - } - - if (returnType.toString() == "QBool") - returnType = CodeChunk("bool"); - - if (!matched_compat) - matched_compat = matchCompat(); - - if (tok == Tok_operator && - (returnType.toString().isEmpty() || - returnType.toString().endsWith("::"))) { - // 'QString::operator const char *()' - parentPath = returnType.toString().split(sep); - parentPath.removeAll(QString()); - returnType = CodeChunk(); - readToken(); - - CodeChunk restOfName; - if (tok != Tok_Tilde && matchDataType(&restOfName)) { - name = "operator " + restOfName.toString(); - } - else { - name = previousLexeme() + lexeme(); - readToken(); - while (tok != Tok_LeftParen && tok != Tok_Eoi) { - name += lexeme(); - readToken(); - } - } - if (tok != Tok_LeftParen) { - return false; - } - } - else if (tok == Tok_LeftParen) { - // constructor or destructor - parentPath = returnType.toString().split(sep); - if (!parentPath.isEmpty()) { - name = parentPath.last(); - parentPath.erase(parentPath.end() - 1); - } - returnType = CodeChunk(); - } - else { - while (match(Tok_Ident)) { - name = previousLexeme(); - /* - This is a hack to let QML module identifiers through. - */ - matchModuleQualifier(name); - matchTemplateAngles(); - - if (match(Tok_Gulbrandsen)) - parentPath.append(name); - else - break; - } - - if (tok == Tok_operator) { - name = lexeme(); - readToken(); - while (tok != Tok_Eoi) { - name += lexeme(); - readToken(); - if (tok == Tok_LeftParen) - break; - } - } - if (parent && (tok == Tok_Semicolon || - tok == Tok_LeftBracket || - tok == Tok_Colon || tok == Tok_Equal) - && access != Node::Private) { - if (tok == Tok_LeftBracket) { - returnType.appendHotspot(); - - int bracketDepth0 = tokenizer->bracketDepth(); - while ((tokenizer->bracketDepth() >= bracketDepth0 && - tok != Tok_Eoi) || - tok == Tok_RightBracket) { - returnType.append(lexeme()); - readToken(); - } - if (tok != Tok_Semicolon) { - return false; - } - } - else if (tok == Tok_Colon || tok == Tok_Equal) { - returnType.appendHotspot(); - - while (tok != Tok_Semicolon && tok != Tok_Eoi) { - returnType.append(lexeme()); - readToken(); - } - if (tok != Tok_Semicolon) { - return false; - } - } - - VariableNode *var = new VariableNode(parent, name); - var->setAccess(access); - if (parsingHeaderFile_) - var->setLocation(declLoc()); - else - var->setLocation(location()); - var->setLeftType(returnType.left()); - var->setRightType(returnType.right()); - if (matched_compat) - var->setStatus(Node::Compat); - var->setStatic(matched_static); - return false; - } - if (tok != Tok_LeftParen) - return false; - } - readToken(); - - // A left paren was seen. Parse the parameters - bool isQPrivateSignal = false; - QVector<Parameter> pvect; - if (tok != Tok_RightParen) { - do { - if (!matchParameter(pvect, isQPrivateSignal)) - return false; - } while (match(Tok_Comma)); - } - // The parameters must end with a right paren - if (!match(Tok_RightParen)) - return false; - - // look for const - bool matchedConst = match(Tok_const); - bool matchFinal = match(Tok_final); - bool matchOverride = match(Tok_override); - - bool isDeleted = false; - bool isDefaulted = false; - if (match(Tok_Equal)) { - if (match(Tok_Number)) // look for 0 indicating pure virtual - virtuality = FunctionNode::PureVirtual; - else if (match(Tok_delete)) - isDeleted = true; - else if (match(Tok_default)) - isDefaulted = true; - } - // look for colon indicating ctors which must be skipped - if (match(Tok_Colon)) { - while (tok != Tok_LeftBrace && tok != Tok_Eoi) - readToken(); - } - - // If no ';' expect a body, which must be skipped. - bool body_expected = false; - bool body_present = false; - if (!match(Tok_Semicolon) && tok != Tok_Eoi) { - body_expected = true; - int nesting = tokenizer->braceDepth(); - if (!match(Tok_LeftBrace)) - return false; - // skip the body - while (tokenizer->braceDepth() >= nesting && tok != Tok_Eoi) - readToken(); - body_present = true; - match(Tok_RightBrace); - } - - FunctionNode *func = 0; - bool createFunctionNode = false; - if (parsingHeaderFile_) { - if (matched_friend) { - if (matched_inline) { - // nothing yet - } - if (body_present) { - if (body_expected) { - // nothing yet - } - createFunctionNode = true; - if (parent && parent->parent()) - parent = parent->parent(); - else - return false; - } - } - else - createFunctionNode = true; - } - else - createFunctionNode = true; - - if (createFunctionNode) { - func = new FunctionNode(extra.type, parent, name, extra.isAttached); - if (matched_friend) - access = Node::Public; - func->setAccess(access); - if (parsingHeaderFile_) - func->setLocation(declLoc()); - else - func->setLocation(location()); - func->setReturnType(returnType.toString()); - func->setParentPath(parentPath); - func->setTemplateStuff(templateStuff); - if (matched_compat) - func->setStatus(Node::Compat); - if (matched_QT_DEPRECATED) - func->setStatus(Node::Deprecated); - if (matched_explicit) { /* What can be done? */ } - if (!pvect.isEmpty()) { - func->setParameters(pvect); - } - func->setMetaness(metaness_); - if (parent && (name == parent->name())) { - FunctionNode::Metaness m = FunctionNode::Ctor; - if (!pvect.isEmpty()) { - for (int i=0; i<pvect.size(); i++) { - const Parameter& p = pvect.at(i); - if (p.dataType().contains(name)) { - if (p.dataType().endsWith(QLatin1String("&&"))) { - m = FunctionNode::MCtor; - break; - } - if (p.dataType().endsWith(QLatin1String("&"))) { - m = FunctionNode::CCtor; - break; - } - } - } - } - func->setMetaness(m); - } - else if (name.startsWith(QLatin1Char('~'))) - func->setMetaness(FunctionNode::Dtor); - else if (name == QLatin1String("operator=")) { - FunctionNode::Metaness m = FunctionNode::Plain; - if (parent && pvect.size() == 1) { - const Parameter& p = pvect.at(0); - if (p.dataType().contains(parent->name())) { - if (p.dataType().endsWith(QLatin1String("&&"))) { - m = FunctionNode::MAssign; - } - else if (p.dataType().endsWith(QLatin1String("&"))) { - m = FunctionNode::CAssign; - } - } - } - func->setMetaness(m); - } - func->setStatic(matched_static); - func->setConst(matchedConst); - func->setVirtualness(virtuality); - func->setIsDeleted(isDeleted); - func->setIsDefaulted(isDefaulted); - func->setFinal(matchFinal); - func->setOverride(matchOverride); - if (isQPrivateSignal) - func->setPrivateSignal(); - } - if (parentPathPtr != 0) - *parentPathPtr = parentPath; - if (funcPtr != 0) - *funcPtr = func; - return true; -} - -bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass) -{ - Node::Access access; - - switch (tok) { - case Tok_public: - access = Node::Public; - readToken(); - break; - case Tok_protected: - access = Node::Protected; - readToken(); - break; - case Tok_private: - access = Node::Private; - readToken(); - break; - default: - access = isClass ? Node::Private : Node::Public; - } - - if (tok == Tok_virtual) - readToken(); - - CodeChunk baseClass; - if (!matchDataType(&baseClass)) - return false; - - classe->addUnresolvedBaseClass(access, baseClass.toPath(), baseClass.toString()); - return true; -} - -bool CppCodeParser::matchBaseList(ClassNode *classe, bool isClass) -{ - for (;;) { - if (!matchBaseSpecifier(classe, isClass)) - return false; - if (tok == Tok_LeftBrace) - return true; - if (!match(Tok_Comma)) - return false; - } -} - -/*! - Parse a C++ class, union, or struct declaration. - - This function only handles one level of class nesting, but that is - sufficient for Qt because there are no cases of class nesting more - than one level deep. - */ -bool CppCodeParser::matchClassDecl(Aggregate *parent, - const QString &templateStuff) -{ - bool isClass = (tok == Tok_class); - readToken(); - - bool compat = matchCompat(); - - if (tok != Tok_Ident) - return false; - while (tok == Tok_Ident) - readToken(); - if (tok == Tok_Gulbrandsen) { - Node* n = parent->findChildNode(previousLexeme(),Node::Class); - if (n) { - parent = static_cast<Aggregate*>(n); - if (parent) { - readToken(); - if (tok != Tok_Ident) - return false; - readToken(); - } - } - } - - const QString className = previousLexeme(); - match(Tok_final); // ignore C++11 final class-virt-specifier - if (tok != Tok_Colon && tok != Tok_LeftBrace) - return false; - - /* - So far, so good. We have 'class Foo {' or 'class Foo :'. - This is enough to recognize a class definition. - */ - ClassNode *classe = new ClassNode(parent, className); - classe->setAccess(access); - classe->setLocation(declLoc()); - if (compat) - classe->setStatus(Node::Compat); - if (!physicalModuleName.isEmpty()) - classe->setPhysicalModuleName(physicalModuleName); - classe->setTemplateStuff(templateStuff); - - if (match(Tok_Colon) && !matchBaseList(classe, isClass)) - return false; - if (!match(Tok_LeftBrace)) - return false; - - Node::Access outerAccess = access; - access = isClass ? Node::Private : Node::Public; - FunctionNode::Metaness outerMetaness = metaness_; - metaness_ = FunctionNode::Plain; - - bool matches = (matchDeclList(classe) && match(Tok_RightBrace) && - match(Tok_Semicolon)); - access = outerAccess; - metaness_ = outerMetaness; - return matches; -} - -bool CppCodeParser::matchNamespaceDecl(Aggregate *parent) -{ - readToken(); // skip 'namespace' - if (tok != Tok_Ident) - return false; - while (tok == Tok_Ident) - readToken(); - if (tok != Tok_LeftBrace) - return false; - - /* - So far, so good. We have 'namespace Foo {'. - */ - QString namespaceName = previousLexeme(); - NamespaceNode* ns = 0; - if (parent) - ns = static_cast<NamespaceNode*>(parent->findChildNode(namespaceName, Node::Namespace)); - if (!ns) { - ns = new NamespaceNode(parent, namespaceName); - ns->setAccess(access); - ns->setLocation(declLoc()); - } - - readToken(); // skip '{' - bool matched = matchDeclList(ns); - return matched && match(Tok_RightBrace); -} - -/*! Match a C++ \c using clause. Return \c true if the match is successful. Otherwise false. @@ -1930,585 +1192,6 @@ bool CppCodeParser::matchUsingDecl(Aggregate* parent) return true; } -bool CppCodeParser::matchEnumItem(Aggregate *parent, EnumNode *enume) -{ - if (!match(Tok_Ident)) - return false; - - QString name = previousLexeme(); - CodeChunk val; - int parenLevel = 0; - - if (match(Tok_Equal)) { - while (tok != Tok_RightBrace && tok != Tok_Eoi) { - if (tok == Tok_LeftParen) - parenLevel++; - else if (tok == Tok_RightParen) - parenLevel--; - else if (tok == Tok_Comma) { - if (parenLevel <= 0) - break; - } - val.append(lexeme()); - readToken(); - } - } - - if (enume) { - QString strVal = val.toString(); - if (strVal.isEmpty()) { - if (enume->items().isEmpty()) { - strVal = "0"; - } - else { - QString last = enume->items().last().value(); - bool ok; - int n = last.toInt(&ok); - if (ok) { - if (last.startsWith(QLatin1Char('0')) && last.size() > 1) { - if (last.startsWith("0x") || last.startsWith("0X")) - strVal = last.left(2) + QString::number(n + 1, 16); - else - strVal = QLatin1Char('0') + QString::number(n + 1, 8); - } - else - strVal = QString::number(n + 1); - } - } - } - - enume->addItem(EnumItem(name, strVal)); - } - else { - VariableNode *var = new VariableNode(parent, name); - var->setAccess(access); - var->setLocation(location()); - var->setLeftType("const int"); - var->setStatic(true); - } - return true; -} - -bool CppCodeParser::matchEnumDecl(Aggregate *parent) -{ - QString name; - - if (!match(Tok_enum)) - return false; - if (tok == Tok_struct || tok == Tok_class) - readToken(); // ignore C++11 struct or class attribute - if (match(Tok_Ident)) - name = previousLexeme(); - if (match(Tok_Colon)) { // ignore C++11 enum-base - CodeChunk dataType; - if (!matchDataType(&dataType)) - return false; - } - if (tok != Tok_LeftBrace) - return false; - - EnumNode *enume = 0; - - if (!name.isEmpty()) { - enume = new EnumNode(parent, name); - enume->setAccess(access); - enume->setLocation(declLoc()); - } - - readToken(); - - if (!matchEnumItem(parent, enume)) - return false; - - while (match(Tok_Comma)) { - if (!matchEnumItem(parent, enume)) - return false; - } - return match(Tok_RightBrace) && match(Tok_Semicolon); -} - -bool CppCodeParser::matchTypedefDecl(Aggregate *parent) -{ - CodeChunk dataType; - QString name; - - if (!match(Tok_typedef)) - return false; - if (!matchDataType(&dataType, &name)) - return false; - if (!match(Tok_Semicolon)) - return false; - - if (parent && !parent->findChildNode(name, Node::Typedef)) { - TypedefNode* td = new TypedefNode(parent, name); - td->setAccess(access); - td->setLocation(declLoc()); - } - return true; -} - -bool CppCodeParser::matchProperty(Aggregate *parent) -{ - int expected_tok = Tok_LeftParen; - if (match(Tok_Q_PRIVATE_PROPERTY)) { - expected_tok = Tok_Comma; - if (!skipTo(Tok_Comma)) - return false; - } - else if (!match(Tok_Q_PROPERTY) && - !match(Tok_Q_OVERRIDE) && - !match(Tok_QDOC_PROPERTY)) { - return false; - } - - if (!match(expected_tok)) - return false; - - QString name; - CodeChunk dataType; - if (!matchDataType(&dataType, &name, true)) - return false; - - PropertyNode *property = new PropertyNode(parent, name); - property->setAccess(Node::Public); - property->setLocation(declLoc()); - property->setDataType(dataType.toString()); - - while (tok != Tok_RightParen && tok != Tok_Eoi) { - if (!match(Tok_Ident) && !match(Tok_default) && !match(Tok_final) && !match(Tok_override)) - return false; - QString key = previousLexeme(); - QString value; - - // Keywords with no associated values - if (key == "CONSTANT") { - property->setConstant(); - continue; - } - else if (key == "FINAL") { - property->setFinal(); - continue; - } - - if (match(Tok_Ident) || match(Tok_Number)) { - value = previousLexeme(); - } - else if (match(Tok_LeftParen)) { - int depth = 1; - while (tok != Tok_Eoi) { - if (tok == Tok_LeftParen) { - readToken(); - ++depth; - } else if (tok == Tok_RightParen) { - readToken(); - if (--depth == 0) - break; - } else { - readToken(); - } - } - value = "?"; - } - - if (key == "READ") - qdb_->addPropertyFunction(property, value, PropertyNode::Getter); - else if (key == "WRITE") { - qdb_->addPropertyFunction(property, value, PropertyNode::Setter); - property->setWritable(true); - } - else if (key == "STORED") - property->setStored(value.toLower() == "true"); - else if (key == "DESIGNABLE") { - QString v = value.toLower(); - if (v == "true") - property->setDesignable(true); - else if (v == "false") - property->setDesignable(false); - else { - property->setDesignable(false); - property->setRuntimeDesFunc(value); - } - } - else if (key == "RESET") - qdb_->addPropertyFunction(property, value, PropertyNode::Resetter); - else if (key == "NOTIFY") { - qdb_->addPropertyFunction(property, value, PropertyNode::Notifier); - } else if (key == "REVISION") { - int revision; - bool ok; - revision = value.toInt(&ok); - if (ok) - property->setRevision(revision); - else - location().warning(tr("Invalid revision number: %1").arg(value)); - } else if (key == "SCRIPTABLE") { - QString v = value.toLower(); - if (v == "true") - property->setScriptable(true); - else if (v == "false") - property->setScriptable(false); - else { - property->setScriptable(false); - property->setRuntimeScrFunc(value); - } - } - } - match(Tok_RightParen); - return true; -} - -/*! - Parse a C++ declaration. - */ -bool CppCodeParser::matchDeclList(Aggregate *parent) -{ - ExtraFuncData extra; - QString templateStuff; - int braceDepth0 = tokenizer->braceDepth(); - if (tok == Tok_RightBrace) // prevents failure on empty body - braceDepth0++; - - while (tokenizer->braceDepth() >= braceDepth0 && tok != Tok_Eoi) { - switch (tok) { - case Tok_Colon: - readToken(); - break; - case Tok_class: - case Tok_struct: - case Tok_union: - setDeclLoc(); - matchClassDecl(parent, templateStuff); - break; - case Tok_namespace: - setDeclLoc(); - matchNamespaceDecl(parent); - break; - case Tok_using: - setDeclLoc(); - matchUsingDecl(parent); - break; - case Tok_template: - { - CodeChunk dataType; - readToken(); - matchTemplateAngles(&dataType); - templateStuff = dataType.toString(); - } - continue; - case Tok_enum: - setDeclLoc(); - matchEnumDecl(parent); - break; - case Tok_typedef: - setDeclLoc(); - matchTypedefDecl(parent); - break; - case Tok_private: - readToken(); - access = Node::Private; - metaness_ = FunctionNode::Plain; - break; - case Tok_protected: - readToken(); - access = Node::Protected; - metaness_ = FunctionNode::Plain; - break; - case Tok_public: - readToken(); - access = Node::Public; - metaness_ = FunctionNode::Plain; - break; - case Tok_signals: - case Tok_Q_SIGNALS: - readToken(); - access = Node::Public; - metaness_ = FunctionNode::Signal; - break; - case Tok_slots: - case Tok_Q_SLOTS: - readToken(); - metaness_ = FunctionNode::Slot; - break; - case Tok_Q_OBJECT: - readToken(); - break; - case Tok_Q_OVERRIDE: - case Tok_Q_PROPERTY: - case Tok_Q_PRIVATE_PROPERTY: - case Tok_QDOC_PROPERTY: - setDeclLoc(); - if (!matchProperty(parent)) { - location().warning(tr("Failed to parse token %1 in property declaration").arg(lexeme())); - skipTo(Tok_RightParen); - match(Tok_RightParen); - } - break; - case Tok_Q_DECLARE_SEQUENTIAL_ITERATOR: - readToken(); - if (match(Tok_LeftParen) && match(Tok_Ident)) - sequentialIteratorClasses.insert(previousLexeme(), location().fileName()); - match(Tok_RightParen); - break; - case Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR: - readToken(); - if (match(Tok_LeftParen) && match(Tok_Ident)) - mutableSequentialIteratorClasses.insert(previousLexeme(), location().fileName()); - match(Tok_RightParen); - break; - case Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR: - readToken(); - if (match(Tok_LeftParen) && match(Tok_Ident)) - associativeIteratorClasses.insert(previousLexeme(), location().fileName()); - match(Tok_RightParen); - break; - case Tok_Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR: - readToken(); - if (match(Tok_LeftParen) && match(Tok_Ident)) - mutableAssociativeIteratorClasses.insert(previousLexeme(), location().fileName()); - match(Tok_RightParen); - break; - case Tok_Q_DECLARE_FLAGS: - readToken(); - setDeclLoc(); - if (match(Tok_LeftParen) && match(Tok_Ident)) { - QString flagsType = previousLexeme(); - if (match(Tok_Comma) && match(Tok_Ident)) { - QString name = previousLexeme(); - TypedefNode *flagsNode = new TypedefNode(parent, flagsType); - flagsNode->setAccess(access); - flagsNode->setLocation(declLoc()); - EnumNode* en = static_cast<EnumNode*>(parent->findChildNode(name, Node::Enum)); - if (en) - en->setFlagsType(flagsNode); - } - } - match(Tok_RightParen); - break; - case Tok_QT_MODULE: - readToken(); - setDeclLoc(); - if (match(Tok_LeftParen) && match(Tok_Ident)) - physicalModuleName = previousLexeme(); - if (!physicalModuleName.startsWith("Qt")) - physicalModuleName.prepend("Qt"); - match(Tok_RightParen); - break; - default: - if (parsingHeaderFile_) - setDeclLoc(); - if (!matchFunctionDecl(parent, 0, 0, templateStuff, extra)) { - while (tok != Tok_Eoi && - (tokenizer->braceDepth() > braceDepth0 || - (!match(Tok_Semicolon) && - tok != Tok_public && tok != Tok_protected && - tok != Tok_private))) { - readToken(); - } - } - } - templateStuff.clear(); - } - return true; -} - -/*! - This is called by parseSourceFile() to do the actual parsing - and tree building. - */ -bool CppCodeParser::matchDocsAndStuff() -{ - ExtraFuncData extra; - const QSet<QString>& topicCommandsAllowed = topicCommands(); - const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); - const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; - - while (tok != Tok_Eoi) { - if (tok == Tok_Doc) { - /* - lexeme() returns an entire qdoc comment. - */ - QString comment = lexeme(); - Location start_loc(location()); - readToken(); - - Doc::trimCStyleComment(start_loc,comment); - Location end_loc(location()); - - /* - Doc parses the comment. - */ - Doc doc(start_loc,end_loc,comment,metacommandsAllowed, topicCommandsAllowed); - QString topic; - bool isQmlPropertyTopic = false; - bool isJsPropertyTopic = false; - - const TopicList& topics = doc.topicsUsed(); - if (!topics.isEmpty()) { - topic = topics[0].topic; - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLPROPERTYGROUP) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { - isQmlPropertyTopic = true; - } - else if ((topic == COMMAND_JSPROPERTY) || - (topic == COMMAND_JSPROPERTYGROUP) || - (topic == COMMAND_JSATTACHEDPROPERTY)) { - isJsPropertyTopic = true; - } - } - NodeList nodes; - DocList docs; - - if (topic.isEmpty()) { - QStringList parentPath; - FunctionNode *clone; - FunctionNode *func = 0; - - if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { - func = qdb_->findFunctionNode(parentPath, clone); - /* - If the node was not found, then search for it in the - open C++ namespaces. We don't expect this search to - be necessary often. Nor do we expect it to succeed - very often. - */ - if (func == 0) - func = qdb_->findNodeInOpenNamespace(parentPath, clone); - - if (func) { - func->borrowParameterNames(clone); - nodes.append(func); - docs.append(doc); - } - delete clone; - } - else { - doc.location().warning(tr("Cannot tie this documentation to anything"), - tr("I found a /*! ... */ comment, but there was no " - "topic command (e.g., '\\%1', '\\%2') in the " - "comment and no function definition following " - "the comment.") - .arg(COMMAND_FN).arg(COMMAND_PAGE)); - } - } - else if (isQmlPropertyTopic || isJsPropertyTopic) { - Doc nodeDoc = doc; - processQmlProperties(nodeDoc, nodes, docs, isJsPropertyTopic); - } - else { - ArgList args; - const QSet<QString>& topicCommandsUsed = topicCommandsAllowed & doc.metaCommandsUsed(); - if (topicCommandsUsed.count() > 0) { - topic = *topicCommandsUsed.constBegin(); - args = doc.metaCommandArgs(topic); - } - if (topicCommandsUsed.count() > 1) { - QString topics; - QSet<QString>::ConstIterator t = topicCommandsUsed.constBegin(); - while (t != topicCommandsUsed.constEnd()) { - topics += " \\" + *t + QLatin1Char(','); - ++t; - } - topics[topics.lastIndexOf(',')] = '.'; - int i = topics.lastIndexOf(','); - topics[i] = ' '; - topics.insert(i+1,"and"); - doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); - } - ArgList::ConstIterator a = args.constBegin(); - while (a != args.constEnd()) { - Doc nodeDoc = doc; - Node *node = processTopicCommand(nodeDoc,topic,*a); - if (node != 0) { - nodes.append(node); - docs.append(nodeDoc); - } - ++a; - } - } - - NodeList::Iterator n = nodes.begin(); - QList<Doc>::Iterator d = docs.begin(); - while (n != nodes.end()) { - processOtherMetaCommands(*d, *n); - (*n)->setDoc(*d); - checkModuleInclusion(*n); - if ((*n)->isAggregate() && ((Aggregate *)*n)->includes().isEmpty()) { - Aggregate *m = static_cast<Aggregate *>(*n); - while (m->parent() && m->physicalModuleName().isEmpty()) { - m = m->parent(); - } - if (m == *n) - ((Aggregate *)*n)->addInclude((*n)->name()); - else - ((Aggregate *)*n)->setIncludes(m->includes()); - } - ++d; - ++n; - } - } - else if (tok == Tok_using) { - matchUsingDecl(0); - } - else { - QStringList parentPath; - FunctionNode *clone; - FunctionNode *fnode = 0; - - if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { - /* - The location of the definition is more interesting - than that of the declaration. People equipped with - a sophisticated text editor can respond to warnings - concerning undocumented functions very quickly. - - Signals are implemented in uninteresting files - generated by moc. - */ - fnode = qdb_->findFunctionNode(parentPath, clone); - if (fnode != 0 && !fnode->isSignal()) - fnode->setLocation(clone->location()); - delete clone; - } - else { - if (tok != Tok_Doc) - readToken(); - } - } - } - return true; -} - -/*! - This function uses a Tokenizer to parse the function \a signature - in an attempt to match it to the signature of a child node of \a root. - If a match is found, \a funcPtr is set to point to the matching node - and true is returned. - */ -bool CppCodeParser::makeFunctionNode(const QString& signature, - QStringList* parentPathPtr, - FunctionNode** funcPtr, - ExtraFuncData& extra) -{ - Tokenizer* outerTokenizer = tokenizer; - int outerTok = tok; - - QByteArray latin1 = signature.toLatin1(); - Tokenizer stringTokenizer(location(), latin1); - stringTokenizer.setParsingFnOrMacro(true); - tokenizer = &stringTokenizer; - readToken(); - - inMacroCommand_ = extra.isMacro; - bool ok = matchFunctionDecl(extra.root, parentPathPtr, funcPtr, QString(), extra); - inMacroCommand_ = false; - // potential memory leak with funcPtr - - tokenizer = outerTokenizer; - tok = outerTok; - return ok; -} - /*! This function uses a Tokenizer to parse the \a parameters of a function into the parameter vector \a {pvect}. @@ -2537,74 +1220,6 @@ bool CppCodeParser::parseParameters(const QString& parameters, return true; } -/*! - Create a new FunctionNode for a QML method or signal, as - specified by \a type, as a child of \a parent. \a sig is - the complete signature, and if \a attached is true, the - method or signal is "attached". \a qdoctag is the text of - the \a type. - - \a parent is the QML class node. The QML module and QML - type names have already been consumed to find \a parent. - What remains in \a sig is the method signature. The method - must be a child of \a parent. - */ -FunctionNode* CppCodeParser::makeFunctionNode(const Doc& doc, - const QString& sig, - Aggregate* parent, - Node::NodeType type, - bool attached, - QString qdoctag) -{ - QStringList pp; - FunctionNode* fn = 0; - ExtraFuncData extra(parent, type, attached); - if (!makeFunctionNode(sig, &pp, &fn, extra) && !makeFunctionNode("void " + sig, &pp, &fn, extra)) { - doc.location().warning(tr("Invalid syntax in '\\%1'").arg(qdoctag)); - } - return fn; -} - -void CppCodeParser::parseQiteratorDotH(const Location &location, const QString &filePath) -{ - QFile file(filePath); - if (!file.open(QFile::ReadOnly)) - return; - - QString text = file.readAll(); - text.remove("\r"); - text.remove("\\\n"); - QStringList lines = text.split(QLatin1Char('\n')); - lines = lines.filter("Q_DECLARE"); - lines.replaceInStrings(QRegExp("#define Q[A-Z_]*\\(C\\)"), QString()); - - if (lines.size() == 4) { - sequentialIteratorDefinition = lines[0]; - mutableSequentialIteratorDefinition = lines[1]; - associativeIteratorDefinition = lines[2]; - mutableAssociativeIteratorDefinition = lines[3]; - } - else { - location.warning(tr("The qiterator.h hack failed")); - } -} - -void CppCodeParser::instantiateIteratorMacro(const QString &container, - const QString &includeFile, - const QString ¯oDef) -{ - QString resultingCode = macroDef; - resultingCode.replace(QRegExp("\\bC\\b"), container); - resultingCode.remove(QRegExp("\\s*##\\s*")); - - Location loc(includeFile); // hack to get the include file for free - QByteArray latin1 = resultingCode.toLatin1(); - Tokenizer stringTokenizer(loc, latin1); - tokenizer = &stringTokenizer; - readToken(); - matchDeclList(QDocDatabase::qdocDB()->primaryTreeRoot()); -} - void CppCodeParser::createExampleFileNodes(DocumentNode *dn) { QString examplePath = dn->name(); |