From 4866fcf0081e0c416c0dc6f85f11eac66cde57ff Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 6 Feb 2013 13:41:04 +0100 Subject: qdoc: Missing links to qRegisterMetaType() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A serious problem in the design of qdoc is its C++ parser. It is an ad hoc recursive descent parser, which has not kept pace with Qt's use of the more esoteric aspects of C++. Part of the problem is that qdoc does not send files through the preprocessor before processing them. The bottom line is qdoc needs the C++ parser used in Qt Creator. But that is a long-term solution. In the short term, we have to introduce minor hacks like this one to keep qdoc going until the parser can be replaced. The problem in this case is that qdoc doesn't handle the QT_PREPEND_NAMESPACE macro in function declarations. The solution is to let qdoc ignore the macro and just use the macro's parameter, which is what qdoc wants anyway. Task-number: QTBUG-28953 Change-Id: I5b9efcc10fa8fb500a44854ee995c2e50e9e16b5 Reviewed-by: Topi Reiniƶ Reviewed-by: Jerome Pasion --- src/tools/qdoc/cppcodeparser.cpp | 88 ++++++++++++++++++++++++++-------------- src/tools/qdoc/cppcodeparser.h | 23 +++++++---- 2 files changed, 72 insertions(+), 39 deletions(-) (limited to 'src/tools') diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index e83147776f..0af5a841eb 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ +static bool inMacroCommand_ = false; QStringList CppCodeParser::exampleFiles; QStringList CppCodeParser::exampleDirs; @@ -311,13 +312,14 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, const QString& command, const ArgLocPair& arg) { + ExtraFuncData extra; if (command == COMMAND_FN) { QStringList parentPath; FunctionNode *func = 0; FunctionNode *clone = 0; - if (!makeFunctionNode(arg.first, &parentPath, &clone) && - !makeFunctionNode("void " + arg.first, &parentPath, &clone)) { + 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 { @@ -368,7 +370,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, QStringList parentPath; FunctionNode *func = 0; - if (makeFunctionNode(arg.first, &parentPath, &func, qdb_->treeRoot())) { + extra.root = qdb_->treeRoot(); + 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; @@ -1152,7 +1156,6 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType) if (--parenAndBraceDepth < 0) return false; } - if (dataType != 0) dataType->append(lexeme()); readToken(); @@ -1161,6 +1164,9 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType) return matches; } +/* + This function is no longer used. + */ bool CppCodeParser::matchTemplateHeader() { readToken(); @@ -1204,13 +1210,27 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) } if (virgin) { - if (match(Tok_Ident)) - dataType->append(previousLexeme()); + if (match(Tok_Ident)) { + /* + This is a hack until we replace this "parser" + with the real one used in Qt Creator. + */ + if (!inMacroCommand_ && lexeme() == "(" && + ((previousLexeme() == "QT_PREPEND_NAMESPACE") || (previousLexeme() == "NS"))) { + readToken(); + readToken(); + dataType->append(previousLexeme()); + readToken(); + } + else + dataType->append(previousLexeme()); + } else if (match(Tok_void) || match(Tok_int) || match(Tok_char) || match(Tok_double) || match(Tok_Ellipsis)) dataType->append(previousLexeme()); - else + else { return false; + } } else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) { dataType->append(previousLexeme()); @@ -1242,8 +1262,9 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) dataType->appendHotspot(); if (var != 0 && match(Tok_Ident)) *var = previousLexeme(); - if (!match(Tok_RightParen) || tok != Tok_LeftParen) + if (!match(Tok_RightParen) || tok != Tok_LeftParen) { return false; + } dataType->append(previousLexeme()); int parenDepth0 = tokenizer->parenDepth(); @@ -1298,8 +1319,9 @@ bool CppCodeParser::matchParameter(FunctionNode *func) QString name; CodeChunk defaultValue; - if (!matchDataType(&dataType, &name)) + if (!matchDataType(&dataType, &name)) { return false; + } match(Tok_Comment); if (match(Tok_Equal)) { int parenDepth0 = tokenizer->parenDepth(); @@ -1312,10 +1334,7 @@ bool CppCodeParser::matchParameter(FunctionNode *func) readToken(); } } - func->addParameter(Parameter(dataType.toString(), - "", - name, - defaultValue.toString())); // ### + func->addParameter(Parameter(dataType.toString(), "", name, defaultValue.toString())); // ### return true; } @@ -1323,16 +1342,16 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, QStringList *parentPathPtr, FunctionNode **funcPtr, const QString &templateStuff, - Node::Type type, - bool attached) + ExtraFuncData& extra) { CodeChunk returnType; QStringList parentPath; QString name; - bool compat = false; - if (match(Tok_friend)) + + if (match(Tok_friend)) { return false; + } match(Tok_explicit); if (matchCompat()) compat = true; @@ -1473,7 +1492,7 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, } readToken(); - FunctionNode *func = new FunctionNode(type, parent, name, attached); + FunctionNode *func = new FunctionNode(extra.type, parent, name, extra.isAttached); func->setAccess(access); func->setLocation(location()); func->setReturnType(returnType.toString()); @@ -1899,6 +1918,7 @@ bool CppCodeParser::matchProperty(InnerNode *parent) */ bool CppCodeParser::matchDeclList(InnerNode *parent) { + ExtraFuncData extra; QString templateStuff; int braceDepth0 = tokenizer->braceDepth(); if (tok == Tok_RightBrace) // prevents failure on empty body @@ -1921,7 +1941,12 @@ bool CppCodeParser::matchDeclList(InnerNode *parent) matchUsingDecl(); break; case Tok_template: - templateStuff = matchTemplateHeader(); + { + CodeChunk dataType; + readToken(); + matchTemplateAngles(&dataType); + templateStuff = dataType.toString(); + } continue; case Tok_enum: matchEnumDecl(parent); @@ -2017,13 +2042,14 @@ bool CppCodeParser::matchDeclList(InnerNode *parent) match(Tok_RightParen); break; default: - if (!matchFunctionDecl(parent, 0, 0, templateStuff)) { + 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))) + tok != Tok_private))) { readToken(); + } } } templateStuff.clear(); @@ -2037,6 +2063,7 @@ bool CppCodeParser::matchDeclList(InnerNode *parent) */ bool CppCodeParser::matchDocsAndStuff() { + ExtraFuncData extra; QSet topicCommandsAllowed = topicCommands(); QSet otherMetacommandsAllowed = otherMetaCommands(); QSet metacommandsAllowed = topicCommandsAllowed + @@ -2082,7 +2109,7 @@ bool CppCodeParser::matchDocsAndStuff() FunctionNode *clone; FunctionNode *func = 0; - if (matchFunctionDecl(0, &parentPath, &clone)) { + if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { foreach (const QString& usedNamespace_, activeNamespaces_) { QStringList newPath = usedNamespace_.split("::") + parentPath; func = qdb_->findFunctionNode(newPath, clone); @@ -2176,7 +2203,7 @@ bool CppCodeParser::matchDocsAndStuff() FunctionNode *clone; FunctionNode *node = 0; - if (matchFunctionDecl(0, &parentPath, &clone)) { + if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { /* The location of the definition is more interesting than that of the declaration. People equipped with @@ -2209,9 +2236,7 @@ bool CppCodeParser::matchDocsAndStuff() bool CppCodeParser::makeFunctionNode(const QString& signature, QStringList* parentPathPtr, FunctionNode** funcPtr, - InnerNode* root, - Node::Type type, - bool attached) + ExtraFuncData& extra) { Tokenizer* outerTokenizer = tokenizer; int outerTok = tok; @@ -2223,7 +2248,9 @@ bool CppCodeParser::makeFunctionNode(const QString& signature, tokenizer = &stringTokenizer; readToken(); - bool ok = matchFunctionDecl(root, parentPathPtr, funcPtr, QString(), type, attached); + inMacroCommand_ = extra.isMacro; + bool ok = matchFunctionDecl(extra.root, parentPathPtr, funcPtr, QString(), extra); + inMacroCommand_ = false; // potential memory leak with funcPtr tokenizer = outerTokenizer; @@ -2252,15 +2279,14 @@ FunctionNode* CppCodeParser::makeFunctionNode(const Doc& doc, { QStringList pp; FunctionNode* fn = 0; - if (!makeFunctionNode(sig,&pp,&fn,parent,type,attached) && - !makeFunctionNode("void "+sig,&pp,&fn,parent,type,attached)) { + 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) +void CppCodeParser::parseQiteratorDotH(const Location &location, const QString &filePath) { QFile file(filePath); if (!file.open(QFile::ReadOnly)) diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h index 24b1f4c05a..eae5d1e97d 100644 --- a/src/tools/qdoc/cppcodeparser.h +++ b/src/tools/qdoc/cppcodeparser.h @@ -59,6 +59,16 @@ class CppCodeParser : public CodeParser { Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) + struct ExtraFuncData { + InnerNode* root; // Used as the parent. + Node::Type type; // The node type: Function, etc. + bool isAttached; // If true, the method is attached. + bool isMacro; // If true, we are parsing a macro signature. + ExtraFuncData() : root(0), type(Node::Function), isAttached(false), isMacro(false) { } + ExtraFuncData(InnerNode* r, Node::Type t, bool a) + : root(r), type(t), isAttached(a), isMacro(false) { } + }; + public: CppCodeParser(); ~CppCodeParser(); @@ -114,11 +124,10 @@ protected: bool matchDataType(CodeChunk *type, QString *var = 0); bool matchParameter(FunctionNode *func); bool matchFunctionDecl(InnerNode *parent, - QStringList *parentPathPtr = 0, - FunctionNode **funcPtr = 0, - const QString &templateStuff = QString(), - Node::Type type = Node::Function, - bool attached = false); + QStringList *parentPathPtr, + FunctionNode **funcPtr, + const QString &templateStuff, + ExtraFuncData& extra); bool matchBaseSpecifier(ClassNode *classe, bool isClass); bool matchBaseList(ClassNode *classe, bool isClass); bool matchClassDecl(InnerNode *parent, @@ -134,9 +143,7 @@ protected: bool makeFunctionNode(const QString &synopsis, QStringList *parentPathPtr, FunctionNode **funcPtr, - InnerNode *root = 0, - Node::Type type = Node::Function, - bool attached = false); + ExtraFuncData& params); FunctionNode* makeFunctionNode(const Doc& doc, const QString& sig, InnerNode* parent, -- cgit v1.2.3