diff options
author | Martin Smith <martin.smith@qt.io> | 2017-05-08 10:48:15 +0200 |
---|---|---|
committer | Martin Smith <martin.smith@qt.io> | 2017-08-10 07:35:38 +0000 |
commit | fd3976142ca2ec4fb555917cad92135a2070eb0b (patch) | |
tree | 9b19ca7caa966ff69aa45ab42ca410b5af2b7af5 | |
parent | da183316a39979f42070759eecb9062fcf240ac5 (diff) |
qdoc: Better support for multi-\fn documentation blocks
This change is a partial fix for the multi-\fn documentation concept.
It outputs the documentation once but listing all the function signatures
from the \fn commands found in the qdoc comment.
Multiple \since commands are not implemented; the \until command is not
implemented, and providing text applicable to a specific \fn signature is
not implemented.
This change requires clang, which means it requires a sequence of other
updates as well, so you can't test it unless you have all that stuff.
Task-number: QTBUG-60420
Change-Id: Ib316b6f97fa427ef730c4badfc785101bff55dce
Reviewed-by: Topi Reiniƶ <topi.reinio@qt.io>
-rw-r--r-- | src/qdoc/clangcodeparser.cpp | 25 | ||||
-rw-r--r-- | src/qdoc/cppcodemarker.cpp | 13 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.cpp | 109 | ||||
-rw-r--r-- | src/qdoc/cppcodeparser.h | 1 | ||||
-rw-r--r-- | src/qdoc/generator.cpp | 2 | ||||
-rw-r--r-- | src/qdoc/htmlgenerator.cpp | 52 | ||||
-rw-r--r-- | src/qdoc/node.cpp | 20 | ||||
-rw-r--r-- | src/qdoc/node.h | 31 |
8 files changed, 161 insertions, 92 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index 18727ebde..3ef696367 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -1207,12 +1207,29 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topicList)); } ArgList::ConstIterator a = args.constBegin(); + Node *node = 0; + SharedCommentNode* scn = 0; + int count = args.size(); while (a != args.constEnd()) { Doc nodeDoc = doc; - Node *node = processTopicCommand(nodeDoc, topic, *a); - if (node != 0) { - nodes.append(node); - docs.append(nodeDoc); + if ((count > 1) && (topic == COMMAND_FN)) { + node = processFnCommand(*a, doc); + if (node != 0) { + if (scn == 0) { + scn = new SharedCommentNode(node->parent(), count); + nodes.append(scn); + docs.append(nodeDoc); + } + scn->append(node); + node->setCollectiveNode(scn); + } + } + else { + node = processTopicCommand(nodeDoc, topic, *a); + if (node != 0) { + nodes.append(node); + docs.append(nodeDoc); + } } ++a; } diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp index 0f1137fa8..8234f8676 100644 --- a/src/qdoc/cppcodemarker.cpp +++ b/src/qdoc/cppcodemarker.cpp @@ -590,7 +590,7 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner, insert(publicFunctions, *c, style, status); } } - else { + else if ((*c)->type() != Node::SharedComment) { insert(publicTypes, *c, style, status); } break; @@ -702,8 +702,15 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner, } else if ((*c)->type() == Node::Function) { FunctionNode *function = static_cast<FunctionNode *>(*c); - if (!function->hasAssociatedProperties() || !function->doc().isEmpty()) - insert(memberFunctions, function, style, status); + if (!function->isInCollective()) { + if (!function->hasAssociatedProperties() || !function->doc().isEmpty()) + insert(memberFunctions, function, style, status); + } + } + else if ((*c)->type() == Node::SharedComment) { + SharedCommentNode *scn = static_cast<SharedCommentNode *>(*c); + if (!scn->doc().isEmpty()) + insert(memberFunctions, scn, style, status); } ++c; } diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 219b39fbb..07d0f8d4a 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -201,65 +201,72 @@ const QSet<QString>& CppCodeParser::topicCommands() } /*! - Process the topic \a command found in the \a doc with argument \a arg. + */ -Node* CppCodeParser::processTopicCommand(const Doc& doc, - const QString& command, - const ArgLocPair& arg) +Node* CppCodeParser::processFnCommand(const ArgLocPair& arg, const Doc& doc) { ExtraFuncData extra; - if (command == COMMAND_FN) { - QStringList parentPath; - FunctionNode *func = 0; - FunctionNode *clone = 0; + 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)); + 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); } - 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) { - lastPath_ = parentPath; - } else if (isWorthWarningAbout(doc)) { - if (clone && clone->isSpecialMemberFunction()) { - ClassNode* cn = qdb_->findClassNode(parentPath); - if (cn) { - cn->addChild(clone); - clone->setImplicit(true); - return 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) { + lastPath_ = parentPath; + } else if (isWorthWarningAbout(doc)) { + if (clone && clone->isSpecialMemberFunction()) { + ClassNode* cn = qdb_->findClassNode(parentPath); + if (cn) { + cn->addChild(clone); + clone->setImplicit(true); + return clone; } - 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.")); - } - if (func) { - func->borrowParameterNames(clone); - func->setParentPath(clone->parentPath()); } - delete clone; + 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.")); } - return func; + if (func) { + func->borrowParameterNames(clone); + func->setParentPath(clone->parentPath()); + } + delete clone; + } + return func; +} + +/*! + Process the topic \a command found in the \a doc with argument \a arg. + */ +Node* CppCodeParser::processTopicCommand(const Doc& doc, + const QString& command, + const ArgLocPair& arg) +{ + ExtraFuncData extra; + if (command == COMMAND_FN) { + return processFnCommand(arg, doc); } else if (command == COMMAND_MACRO) { QStringList parentPath; diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h index 8d217e3fe..61c68853a 100644 --- a/src/qdoc/cppcodeparser.h +++ b/src/qdoc/cppcodeparser.h @@ -72,6 +72,7 @@ public: protected: const QSet<QString>& topicCommands(); const QSet<QString>& otherMetaCommands(); + Node* processFnCommand(const ArgLocPair& arg, const Doc& doc); virtual Node* processTopicCommand(const Doc& doc, const QString& command, const ArgLocPair& arg); diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index 25ab39c4b..4965bc368 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -303,7 +303,7 @@ void Generator::beginSubPage(const Aggregate* node, const QString& fileName) QFile* outFile = new QFile(redirectDocumentationToDevNull_ ? QStringLiteral("/dev/null") : path); if (!redirectDocumentationToDevNull_ && outFile->exists()) - node->location().error(tr("HTML file already exists; overwriting %1").arg(outFile->fileName())); + node->location().error(tr("Output file already exists; overwriting %1").arg(outFile->fileName())); if (!outFile->open(QFile::WriteOnly)) node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName())); Generator::debug("Writing: " + path); diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index a0f8eacde..aa3b0061d 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -3986,26 +3986,42 @@ void HtmlGenerator::generateDetailedMember(const Node *node, #endif generateExtractionMark(node, MemberMark); generateKeywordAnchors(node); - QString nodeRef = refForNode(node); - if (node->isEnumType() && (etn = static_cast<const EnumNode *>(node))->flagsType()) { -#ifdef GENERATE_MAC_REFS - generateMacRef(etn->flagsType(), marker); -#endif - out() << "<h3 class=\"flags\" id=\"" << nodeRef << "\">"; - out() << "<a name=\"" + nodeRef + "\"></a>"; - generateSynopsis(etn, relative, marker, CodeMarker::Detailed); - out() << "<br/>"; - generateSynopsis(etn->flagsType(), - relative, - marker, - CodeMarker::Detailed); - out() << "</h3>\n"; + QString nodeRef = 0; + if (node->isSharedCommentNode()) { + const SharedCommentNode *scn = reinterpret_cast<const SharedCommentNode*>(node); + const QVector<Node*>& collective = scn->collective(); + out() << "<div class=\"fngroup\">\n"; + foreach (const Node* n, collective) { + if (n->isFunction()) { + nodeRef = refForNode(n); + out() << "<h3 class=\"fn fngroupitem\" id=\"" << nodeRef << "\">"; + out() << "<a name=\"" + nodeRef + "\"></a>"; + generateSynopsis(n, relative, marker, CodeMarker::Detailed); + out() << "</h3>"; + } + } + out() << "</div>"; + out() << divNavTop << '\n'; } else { - out() << "<h3 class=\"fn\" id=\"" << nodeRef << "\">"; - out() << "<a name=\"" + nodeRef + "\"></a>"; - generateSynopsis(node, relative, marker, CodeMarker::Detailed); - out() << "</h3>" << divNavTop << '\n'; + nodeRef = refForNode(node); + if (node->isEnumType() && (etn = static_cast<const EnumNode *>(node))->flagsType()) { +#ifdef GENERATE_MAC_REFS + generateMacRef(etn->flagsType(), marker); +#endif + out() << "<h3 class=\"flags\" id=\"" << nodeRef << "\">"; + out() << "<a name=\"" + nodeRef + "\"></a>"; + generateSynopsis(etn, relative, marker, CodeMarker::Detailed); + out() << "<br/>"; + generateSynopsis(etn->flagsType(), relative, marker, CodeMarker::Detailed); + out() << "</h3>\n"; + } + else { + out() << "<h3 class=\"fn\" id=\"" << nodeRef << "\">"; + out() << "<a name=\"" + nodeRef + "\"></a>"; + generateSynopsis(node, relative, marker, CodeMarker::Detailed); + out() << "</h3>" << divNavTop << '\n'; + } } generateStatus(node, marker); diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 45a729824..a4fca58c6 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -457,6 +457,8 @@ QString Node::nodeTypeString(unsigned char t) return "QML signal handler"; case QmlMethod: return "QML method"; + case SharedComment: + return "shared comment"; default: break; } @@ -1533,6 +1535,7 @@ LeafNode::LeafNode(NodeType type, Aggregate *parent, const QString& name) case QmlSignalHandler: case QmlMethod: case QmlBasicType: + case SharedComment: setPageType(ApiPage); break; default: @@ -1560,6 +1563,7 @@ LeafNode::LeafNode(Aggregate* parent, NodeType type, const QString& name) case QmlSignal: case QmlSignalHandler: case QmlMethod: + case SharedComment: setPageType(ApiPage); break; default: @@ -2030,7 +2034,8 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString& name) isImplicit_(false), isRef_(false), isRefRef_(false), - reimplementedFrom_(0) + reimplementedFrom_(0), + collective_(0) { setGenus(Node::CPP); } @@ -2060,7 +2065,8 @@ FunctionNode::FunctionNode(NodeType type, Aggregate *parent, const QString& name isImplicit_(false), isRef_(false), isRefRef_(false), - reimplementedFrom_(0) + reimplementedFrom_(0), + collective_(0) { setGenus(Node::QML); if (type == QmlMethod || type == QmlSignal) { @@ -2228,16 +2234,6 @@ void FunctionNode::borrowParameterNames(const FunctionNode *source) } /*! - If this function is a reimplementation, \a from points - to the FunctionNode of the function being reimplemented. - */ -void FunctionNode::setReimplementedFrom(FunctionNode *f) -{ - reimplementedFrom_ = f; - f->reimplementedBy_.append(this); -} - -/*! Adds the "associated" property \a p to this function node. The function might be the setter or getter for a property, for example. diff --git a/src/qdoc/node.h b/src/qdoc/node.h index f428da44c..89223260b 100644 --- a/src/qdoc/node.h +++ b/src/qdoc/node.h @@ -52,6 +52,7 @@ class FunctionNode; class PropertyNode; class CollectionNode; class QmlPropertyNode; +class SharedCommentNode; typedef QList<Node*> NodeList; typedef QList<PropertyNode*> PropNodeList; @@ -87,6 +88,7 @@ public: QmlSignalHandler, QmlMethod, QmlBasicType, + SharedComment, LastType }; @@ -217,6 +219,7 @@ public: virtual bool isQtQuickNode() const { return false; } virtual bool isAbstract() const { return false; } virtual bool isProperty() const { return false; } + virtual bool isVariable() const { return false; } virtual bool isQmlProperty() const { return false; } virtual bool isJsProperty() const { return false; } virtual bool isQmlPropertyGroup() const { return false; } @@ -234,6 +237,8 @@ public: virtual bool isDefault() const { return false; } virtual bool isExternalPage() const { return false; } virtual bool isImplicit() const { return false; } + virtual bool isInCollective() const { return false; } + virtual bool isSharedCommentNode() const { return false; } virtual void addMember(Node* ) { } virtual bool hasMembers() const { return false; } virtual bool hasNamespaces() const { return false; } @@ -259,6 +264,7 @@ public: virtual Tree* tree() const; virtual void findChildren(const QString& , NodeList& nodes) const { nodes.clear(); } virtual void setNoAutoList(bool ) { } + virtual void setCollectiveNode(SharedCommentNode* ) { } bool isIndexNode() const { return indexNodeFlag_; } NodeType type() const { return (NodeType) nodeType_; } virtual DocSubtype docSubtype() const { return NoSubtype; } @@ -871,6 +877,21 @@ public: QString defaultValue_; }; +class SharedCommentNode : public LeafNode +{ + public: + SharedCommentNode(Aggregate* parent, int count) + : LeafNode(Node::SharedComment, parent, QString()) { collective_.reserve(count); } + virtual ~SharedCommentNode() { collective_.clear(); } + + virtual bool isSharedCommentNode() const Q_DECL_OVERRIDE { return true; } + void append(Node* n) { collective_.append(n); } + const QVector<Node*>& collective() const { return collective_; } + + private: + QVector<Node*> collective_; +}; + //friend class QTypeInfo<Parameter>; //Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE); @@ -914,7 +935,7 @@ public: void addParameter(const Parameter& parameter); inline void setParameters(const QVector<Parameter>& parameters); void borrowParameterNames(const FunctionNode* source); - void setReimplementedFrom(FunctionNode* from); + void setReimplementedFrom(FunctionNode* from) { reimplementedFrom_ = from; } const QString& returnType() const { return returnType_; } QString metaness() const; @@ -965,7 +986,6 @@ public: QStringList parameterNames() const; QString rawParameters(bool names = false, bool values = false) const; const FunctionNode* reimplementedFrom() const { return reimplementedFrom_; } - const QList<FunctionNode*> &reimplementedBy() const { return reimplementedBy_; } const PropNodeList& associatedProperties() const { return associatedProperties_; } const QStringList& parentPath() const { return parentPath_; } bool hasAssociatedProperties() const { return !associatedProperties_.isEmpty(); } @@ -1014,6 +1034,10 @@ public: void setRefRef(bool b) { isRefRef_ = b; } bool isRefRef() const { return isRefRef_; } + bool isInCollective() const Q_DECL_OVERRIDE { return (collective_ != 0); } + const SharedCommentNode* collective() const { return collective_; } + void setCollectiveNode(SharedCommentNode* t) Q_DECL_OVERRIDE { collective_ = t; } + private: void addAssociatedProperty(PropertyNode* property); @@ -1041,7 +1065,7 @@ private: QVector<Parameter> parameters_; const FunctionNode* reimplementedFrom_; PropNodeList associatedProperties_; - QList<FunctionNode*> reimplementedBy_; + SharedCommentNode* collective_; }; class PropertyNode : public LeafNode @@ -1150,6 +1174,7 @@ public: const QString &rightType() const { return rightType_; } QString dataType() const { return leftType_ + rightType_; } bool isStatic() const { return static_; } + virtual bool isVariable() const { return true; } private: QString leftType_; |