summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2017-05-08 10:48:15 +0200
committerMartin Smith <martin.smith@qt.io>2017-08-10 07:35:38 +0000
commitfd3976142ca2ec4fb555917cad92135a2070eb0b (patch)
tree9b19ca7caa966ff69aa45ab42ca410b5af2b7af5
parentda183316a39979f42070759eecb9062fcf240ac5 (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.cpp25
-rw-r--r--src/qdoc/cppcodemarker.cpp13
-rw-r--r--src/qdoc/cppcodeparser.cpp109
-rw-r--r--src/qdoc/cppcodeparser.h1
-rw-r--r--src/qdoc/generator.cpp2
-rw-r--r--src/qdoc/htmlgenerator.cpp52
-rw-r--r--src/qdoc/node.cpp20
-rw-r--r--src/qdoc/node.h31
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_;