diff options
author | Martin Smith <martin.smith@qt.io> | 2017-09-19 14:11:11 +0200 |
---|---|---|
committer | Martin Smith <martin.smith@qt.io> | 2017-11-16 09:08:11 +0000 |
commit | b7a6bbf420d1eed9daefd232dc48933e7d6f7c4e (patch) | |
tree | 3f1a7a76feceecb88eab6280a58eb2e531bef5df /src/qdoc/cppcodeparser.cpp | |
parent | d39f463b90d2668138b37f2fc5fdf67296c753bb (diff) | |
download | qttools-b7a6bbf420d1eed9daefd232dc48933e7d6f7c4e.tar.gz |
qdoc: Handle shared comments better
The shared comment in qdoc was originally meant only for
use with the \fn command, and only for multiple \fn commands
in the same class. But it proved to be useful for other things,
so people started using it in other contexts, even though it
didn't work there. This update should handle them all.
For example, when listing multiple \fn commands, they no longer
need be for functions in the same class. Also, multiple \typedef
commands are handled correctly.
Change-Id: I4be86026a227d74822f5f2295577adf0fe170d49
Reviewed-by: Martin Smith <martin.smith@qt.io>
Diffstat (limited to 'src/qdoc/cppcodeparser.cpp')
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 266 |
1 files changed, 204 insertions, 62 deletions
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index c81a385a3..360e5fef4 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -51,6 +51,9 @@ QStringList CppCodeParser::exampleDirs; QSet<QString> CppCodeParser::excludeDirs; QSet<QString> CppCodeParser::excludeFiles; +static QSet<QString> topicCommands_; +static QSet<QString> otherMetaCommands_; + /*! The constructor initializes some regular expressions and calls reset(). @@ -59,6 +62,63 @@ CppCodeParser::CppCodeParser() : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::") { reset(); + if (topicCommands_.isEmpty()) { + topicCommands_ << COMMAND_CLASS + << COMMAND_DITAMAP + << COMMAND_ENUM + << COMMAND_EXAMPLE + << COMMAND_EXTERNALPAGE + << COMMAND_FILE + << COMMAND_FN + << COMMAND_GROUP + << COMMAND_HEADERFILE + << COMMAND_MACRO + << COMMAND_MODULE + << COMMAND_NAMESPACE + << COMMAND_PAGE + << COMMAND_PROPERTY + << COMMAND_TYPEALIAS + << COMMAND_TYPEDEF + << COMMAND_VARIABLE + << COMMAND_QMLTYPE + << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP + << COMMAND_QMLATTACHEDPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL + << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD + << COMMAND_QMLBASICTYPE + << COMMAND_QMLMODULE + << COMMAND_JSTYPE + << COMMAND_JSPROPERTY + << COMMAND_JSPROPERTYGROUP + << COMMAND_JSATTACHEDPROPERTY + << COMMAND_JSSIGNAL + << COMMAND_JSATTACHEDSIGNAL + << COMMAND_JSMETHOD + << COMMAND_JSATTACHEDMETHOD + << COMMAND_JSBASICTYPE + << COMMAND_JSMODULE; + } + if (otherMetaCommands_.isEmpty()) { + otherMetaCommands_ = commonMetaCommands(); + otherMetaCommands_ << COMMAND_INHEADERFILE + << COMMAND_OVERLOAD + << COMMAND_REIMP + << COMMAND_RELATES + << COMMAND_CONTENTSPAGE + << COMMAND_NEXTPAGE + << COMMAND_PREVIOUSPAGE + << COMMAND_INDEXPAGE + << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLINSTANTIATES + << COMMAND_QMLDEFAULT + << COMMAND_QMLREADONLY + << COMMAND_QMLABSTRACT + << COMMAND_ABSTRACT; + } } /*! @@ -150,52 +210,11 @@ QStringList CppCodeParser::sourceFileNameFilter() return QStringList(); } - -static QSet<QString> topicCommands_; /*! Returns the set of strings reopresenting the topic commands. */ const QSet<QString>& CppCodeParser::topicCommands() { - if (topicCommands_.isEmpty()) { - topicCommands_ << COMMAND_CLASS - << COMMAND_DITAMAP - << COMMAND_ENUM - << COMMAND_EXAMPLE - << COMMAND_EXTERNALPAGE - << COMMAND_FILE - << COMMAND_FN - << COMMAND_GROUP - << COMMAND_HEADERFILE - << COMMAND_MACRO - << COMMAND_MODULE - << COMMAND_NAMESPACE - << COMMAND_PAGE - << COMMAND_PROPERTY - << COMMAND_TYPEALIAS - << COMMAND_TYPEDEF - << COMMAND_VARIABLE - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLPROPERTYGROUP - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE - << COMMAND_QMLMODULE - << COMMAND_JSTYPE - << COMMAND_JSPROPERTY - << COMMAND_JSPROPERTYGROUP - << COMMAND_JSATTACHEDPROPERTY - << COMMAND_JSSIGNAL - << COMMAND_JSATTACHEDSIGNAL - << COMMAND_JSMETHOD - << COMMAND_JSATTACHEDMETHOD - << COMMAND_JSBASICTYPE - << COMMAND_JSMODULE; - } return topicCommands_; } @@ -569,31 +588,12 @@ void CppCodeParser::processQmlProperties(const Doc& doc, } } -static QSet<QString> otherMetaCommands_; /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ const QSet<QString>& CppCodeParser::otherMetaCommands() { - if (otherMetaCommands_.isEmpty()) { - otherMetaCommands_ = commonMetaCommands(); - otherMetaCommands_ << COMMAND_INHEADERFILE - << COMMAND_OVERLOAD - << COMMAND_REIMP - << COMMAND_RELATES - << COMMAND_CONTENTSPAGE - << COMMAND_NEXTPAGE - << COMMAND_PREVIOUSPAGE - << COMMAND_INDEXPAGE - << COMMAND_STARTPAGE - << COMMAND_QMLINHERITS - << COMMAND_QMLINSTANTIATES - << COMMAND_QMLDEFAULT - << COMMAND_QMLREADONLY - << COMMAND_QMLABSTRACT - << COMMAND_ABSTRACT; - } return otherMetaCommands_; } @@ -617,8 +617,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, } } else if (command == COMMAND_OVERLOAD) { - if (node && node->isFunction()) - ((FunctionNode *) node)->setOverloadFlag(true); + if (node && (node->isFunction() || node->isSharedCommentNode())) + node->setOverloadFlag(true); else doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_OVERLOAD)); } @@ -1308,4 +1308,146 @@ void CppCodeParser::createExampleFileNodes(DocumentNode *dn) } } +/*! + returns true if \a t is \e {jssignal}, \e {jsmethod}, + \e {jsattachedsignal}, or \e {jsattachedmethod}. + */ +bool CppCodeParser::isJSMethodTopic(const QString &t) +{ + return (t == COMMAND_JSSIGNAL || + t == COMMAND_JSMETHOD || + t == COMMAND_JSATTACHEDSIGNAL || + t == COMMAND_JSATTACHEDMETHOD); +} + +/*! + returns true if \a t is \e {qmlsignal}, \e {qmlmethod}, + \e {qmlattachedsignal}, or \e {qmlattachedmethod}. + */ +bool CppCodeParser::isQMLMethodTopic(const QString &t) +{ + return (t == COMMAND_QMLSIGNAL || + t == COMMAND_QMLMETHOD || + t == COMMAND_QMLATTACHEDSIGNAL || + t == COMMAND_QMLATTACHEDMETHOD); +} + +/*! + Returns true if \a t is \e {jsproperty}, \e {jspropertygroup}, + or \e {jsattachedproperty}. + */ +bool CppCodeParser::isJSPropertyTopic(const QString &t) +{ + return (t == COMMAND_JSPROPERTY || + t == COMMAND_JSPROPERTYGROUP || + t == COMMAND_JSATTACHEDPROPERTY); +} + +/*! + Returns true if \a t is \e {qmlproperty}, \e {qmlpropertygroup}, + or \e {qmlattachedproperty}. + */ +bool CppCodeParser::isQMLPropertyTopic(const QString &t) +{ + return (t == COMMAND_QMLPROPERTY || + t == COMMAND_QMLPROPERTYGROUP || + t == COMMAND_QMLATTACHEDPROPERTY); +} + +void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, DocList &docs) +{ + if (isQMLPropertyTopic(topic)) { + processQmlProperties(doc, nodes, docs, false); + } else if (isJSPropertyTopic(topic)) { + processQmlProperties(doc, nodes, docs, true); + } else { + ArgList args = doc.metaCommandArgs(topic); + Node *node = 0; + if (args.size() == 1) { + if (topic == COMMAND_FN) + node = parserForLanguage("Clang")->parseFnArg(doc.location(), args[0].first); + else if (topic == COMMAND_MACRO) + node = parseMacroArg(doc.location(), args[0].first); + else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic)) + node = parseOtherFuncArg(topic, doc.location(), args[0].first); + else + node = processTopicCommand(doc, topic, args[0]); + if (node != 0) { + nodes.append(node); + docs.append(doc); + } + } else if (args.size() > 1) { + QVector<SharedCommentNode*> sharedCommentNodes; + ArgList::ConstIterator arg = args.constBegin(); + while (arg != args.constEnd()) { + if (topic == COMMAND_FN) + node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg->first); + else if (topic == COMMAND_MACRO) + node = parseMacroArg(doc.location(), arg->first); + else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic)) + node = parseOtherFuncArg(topic, doc.location(), arg->first); + else + node = processTopicCommand(doc, topic, *arg); + if (node != 0) { + bool found = false; + for (SharedCommentNode *scn : sharedCommentNodes) { + if (scn->parent() == node->parent()) { + node->setSharedCommentNode(scn); + found = true; + break; + } + } + if (!found) { + SharedCommentNode *scn = new SharedCommentNode(node); + sharedCommentNodes.append(scn); + nodes.append(scn); + docs.append(doc); + } + } + ++arg; + } + } + } +} + +void CppCodeParser::processOtherMetaCommands(NodeList &nodes, DocList& docs) +{ + 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; + } +} + +bool CppCodeParser::hasTooManyTopics(const Doc &doc) const +{ + QSet<QString> topicCommandsUsed = topicCommands() & doc.metaCommandsUsed(); + if (topicCommandsUsed.count() > 1) { + QString topicList; + for (const auto &t : topicCommandsUsed) + topicList += QLatin1String(" \\") + t + QLatin1Char(','); + topicList[topicList.lastIndexOf(',')] = '.'; + int i = topicList.lastIndexOf(','); + Q_ASSERT(i >= 0); // we had at least two commas + topicList[i] = ' '; + topicList.insert(i + 1, "and"); + doc.location().warning(tr("Multiple topic commands found in comment:%1").arg(topicList)); + return true; + } + return false; +} + QT_END_NAMESPACE |