summaryrefslogtreecommitdiffstats
path: root/src/qdoc
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@qt.io>2018-04-20 12:46:35 +0200
committerMartin Smith <martin.smith@qt.io>2018-06-01 12:14:21 +0000
commit03b8f9d935ec0c4227c02fee1b73db037cc1932a (patch)
treeb8376a6d0f94a99e7f7b71ffadc71350be61711c /src/qdoc
parent489ae563fdea7e5739bdfe75ce652b1c6d2b5f79 (diff)
qdoc: Document a namespace in multiple modules
qdoc didn't handle this. This update fixes most of what was wrong, but tuning the details of the namespace reference pages might follow. We have namespace Qt as an example. Most of the elements in the Qt namespace are in QtCore, but a few functions are declared in QtGui. Before this update, qdoc used the hack of using #ifdef to remove the declarations from qtextdocument.h in QtGui and .cpp and then added them back into qtnamespace.h and .cpp in QtCore. Now that hack is no longer necessary. The functions in the Qt namespace that are declared in QtGui are documented there, but the documentation is linked to from the namespace reference page, which remains in QtCore. That is, only one \namespace command is used to document the Qt namespace, and it appears in qnamespace.qdoc where it always did, but the documentation for the Qt namespace functions declared in QtGui is now appears in qtextdocument.cpp where it belongs. This also allows qdoc to report when a namespace contains elements that are public and documented, but the namespace itself is not documented, which was not possible before this change. qdoc also reports if a namespace is documented in more than one module. That is, for example, when \namespace Qt is used in both QtCore and QtGui. Note that this change will increase the number of qdoc warnings in QtBase, but the new warnings are expacted. Change-Id: If978a59209b7b2ae90713d3ae809ae03361df72f Task-number: QTBUG-67267 Reviewed-by: Martin Smith <martin.smith@qt.io>
Diffstat (limited to 'src/qdoc')
-rw-r--r--src/qdoc/clangcodeparser.cpp2
-rw-r--r--src/qdoc/codemarker.cpp2
-rw-r--r--src/qdoc/cppcodemarker.cpp214
-rw-r--r--src/qdoc/cppcodeparser.cpp5
-rw-r--r--src/qdoc/doc/qdoc-manual-topiccmds.qdoc14
-rw-r--r--src/qdoc/generator.cpp18
-rw-r--r--src/qdoc/generator.h2
-rw-r--r--src/qdoc/htmlgenerator.cpp188
-rw-r--r--src/qdoc/htmlgenerator.h2
-rw-r--r--src/qdoc/node.cpp85
-rw-r--r--src/qdoc/node.h24
-rw-r--r--src/qdoc/qdocdatabase.cpp119
-rw-r--r--src/qdoc/qdocindexfiles.cpp21
-rw-r--r--src/qdoc/webxmlgenerator.cpp10
-rw-r--r--src/qdoc/webxmlgenerator.h2
15 files changed, 413 insertions, 295 deletions
diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp
index e64e2e223..330697082 100644
--- a/src/qdoc/clangcodeparser.cpp
+++ b/src/qdoc/clangcodeparser.cpp
@@ -1386,7 +1386,7 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin
docs.append(doc);
} else if (CodeParser::isWorthWarningAbout(doc)) {
doc.location().warning(tr("Cannot tie this documentation to anything"),
- tr("I found a /*! ... */ comment, but there was no "
+ tr("qdoc found a /*! ... */ comment, but there was no "
"topic command (e.g., '\\%1', '\\%2') in the "
"comment and no function definition following "
"the comment.")
diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp
index 44d05053e..563e2821b 100644
--- a/src/qdoc/codemarker.cpp
+++ b/src/qdoc/codemarker.cpp
@@ -408,7 +408,7 @@ void CodeMarker::insert(FastSection &fastSection,
Aggregate* p = node->parent();
if (p->isQmlPropertyGroup())
p = p->parent();
- if (p != fastSection.parent_) {
+ if (!p->isNamespace() && p != fastSection.parent_) {
if ((!p->isQmlType() && !p->isJsType()) || !p->isAbstract())
inheritedMember = true;
}
diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp
index 5e8c3a37b..e1a5040dd 100644
--- a/src/qdoc/cppcodemarker.cpp
+++ b/src/qdoc/cppcodemarker.cpp
@@ -455,80 +455,83 @@ QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */)
return "^\\}$";
}
-QList<Section> CppCodeMarker::sections(const Aggregate *inner,
+QList<Section> CppCodeMarker::sections(const Aggregate *aggregate,
SynopsisStyle style,
Status status)
{
QList<Section> sections;
- if (inner->isClass()) {
+ bool documentAll = true;
+ if (aggregate->isClass()) {
+ if (aggregate->parent() && !aggregate->name().isEmpty() && !aggregate->hasDoc())
+ documentAll = false;
if (style == Summary) {
- FastSection privateFunctions(inner,
+ FastSection privateFunctions(aggregate,
"Private Functions",
QString(),
"private function",
"private functions");
- FastSection privateSlots(inner, "Private Slots", QString(), "private slot", "private slots");
- FastSection privateTypes(inner, "Private Types", QString(), "private type", "private types");
- FastSection protectedFunctions(inner,
+ FastSection privateSlots(aggregate, "Private Slots", QString(), "private slot", "private slots");
+ FastSection privateTypes(aggregate, "Private Types", QString(), "private type", "private types");
+ FastSection protectedFunctions(aggregate,
"Protected Functions",
QString(),
"protected function",
"protected functions");
- FastSection protectedSlots(inner,
+ FastSection protectedSlots(aggregate,
"Protected Slots",
QString(),
"protected slot",
"protected slots");
- FastSection protectedTypes(inner,
+ FastSection protectedTypes(aggregate,
"Protected Types",
QString(),
"protected type",
"protected types");
- FastSection protectedVariables(inner,
+ FastSection protectedVariables(aggregate,
"Protected Variables",
QString(),
"protected type",
"protected variables");
- FastSection publicFunctions(inner,
+ FastSection publicFunctions(aggregate,
"Public Functions",
QString(),
"public function",
"public functions");
- FastSection publicSignals(inner, "Signals", QString(), "signal", "signals");
- FastSection publicSlots(inner, "Public Slots", QString(), "public slot", "public slots");
- FastSection publicTypes(inner, "Public Types", QString(), "public type", "public types");
- FastSection publicVariables(inner,
+ FastSection publicSignals(aggregate, "Signals", QString(), "signal", "signals");
+ FastSection publicSlots(aggregate, "Public Slots", QString(), "public slot", "public slots");
+ FastSection publicTypes(aggregate, "Public Types", QString(), "public type", "public types");
+ FastSection publicVariables(aggregate,
"Public Variables",
QString(),
"public variable",
"public variables");
- FastSection properties(inner, "Properties", QString(), "property", "properties");
- FastSection relatedNonMembers(inner,
+ FastSection properties(aggregate, "Properties", QString(), "property", "properties");
+ FastSection relatedNonMembers(aggregate,
"Related Non-Members",
QString(),
"related non-member",
"related non-members");
- FastSection staticPrivateMembers(inner,
+ FastSection staticPrivateMembers(aggregate,
"Static Private Members",
QString(),
"static private member",
"static private members");
- FastSection staticProtectedMembers(inner,
+ FastSection staticProtectedMembers(aggregate,
"Static Protected Members",
QString(),
"static protected member",
"static protected members");
- FastSection staticPublicMembers(inner,
+ FastSection staticPublicMembers(aggregate,
"Static Public Members",
QString(),
"static public member",
"static public members");
- FastSection macros(inner, "Macros", QString(), "macro", "macros");
+ FastSection macros(aggregate, "Macros", QString(), "macro", "macros");
- NodeList::ConstIterator r = inner->relatedNodes().constBegin();
- while (r != inner->relatedNodes().constEnd()) {
- if ((*r)->type() == Node::Function) {
+ NodeList::ConstIterator r = aggregate->relatedNodes().constBegin();
+ while (r != aggregate->relatedNodes().constEnd()) {
+ if ((*r)->isFunction()) {
FunctionNode *func = static_cast<FunctionNode *>(*r);
if (func->isMacro())
insert(macros, *r, style, status);
@@ -542,12 +545,16 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
}
QStack<const Aggregate *> stack;
- stack.push(inner);
+ stack.push(aggregate);
while (!stack.isEmpty()) {
const Aggregate* ancestor = stack.pop();
NodeList::ConstIterator c = ancestor->childNodes().constBegin();
while (c != ancestor->childNodes().constEnd()) {
+ if (!documentAll && !(*c)->hasDoc()) {
+ ++c;
+ continue;
+ }
bool isSlot = false;
bool isSignal = false;
bool isStatic = false;
@@ -675,15 +682,15 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
append(sections, macros);
}
else if (style == Detailed) {
- FastSection memberFunctions(inner,"Member Function Documentation","func","member","members");
- FastSection memberTypes(inner,"Member Type Documentation","types","member","members");
- FastSection memberVariables(inner,"Member Variable Documentation","vars","member","members");
- FastSection properties(inner,"Property Documentation","prop","member","members");
- FastSection relatedNonMembers(inner,"Related Non-Members","relnonmem","member","members");
- FastSection macros(inner,"Macro Documentation","macros","member","members");
-
- NodeList::ConstIterator r = inner->relatedNodes().constBegin();
- while (r != inner->relatedNodes().constEnd()) {
+ FastSection memberFunctions(aggregate,"Member Function Documentation","func","member","members");
+ FastSection memberTypes(aggregate,"Member Type Documentation","types","member","members");
+ FastSection memberVariables(aggregate,"Member Variable Documentation","vars","member","members");
+ FastSection properties(aggregate,"Property Documentation","prop","member","members");
+ FastSection relatedNonMembers(aggregate,"Related Non-Members","relnonmem","member","members");
+ FastSection macros(aggregate,"Macro Documentation","macros","member","members");
+
+ NodeList::ConstIterator r = aggregate->relatedNodes().constBegin();
+ while (r != aggregate->relatedNodes().constEnd()) {
if ((*r)->isFunction()) {
FunctionNode *func = static_cast<FunctionNode *>(*r);
if (func->isMacro())
@@ -697,10 +704,13 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
++r;
}
- NodeList::ConstIterator c = inner->childNodes().constBegin();
- while (c != inner->childNodes().constEnd()) {
+ NodeList::ConstIterator c = aggregate->childNodes().constBegin();
+ while (c != aggregate->childNodes().constEnd()) {
if ((*c)->isSharingComment()) {
// do nothing
+ } else if (!documentAll && !(*c)->hasDoc()) {
+ ++c;
+ continue;
} else if ((*c)->isEnumType() || (*c)->isTypedef()) {
if ((*c)->name() == QLatin1String("QtGadgetHelper")) {
++c;
@@ -738,10 +748,10 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
append(sections, macros);
}
else {
- FastSection all(inner,QString(),QString(),"member","members");
+ FastSection all(aggregate,QString(),QString(),"member","members");
QStack<const Aggregate*> stack;
- stack.push(inner);
+ stack.push(aggregate);
while (!stack.isEmpty()) {
const Aggregate* ancestor = stack.pop();
@@ -764,52 +774,59 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
}
append(sections, all);
}
- }
- else {
- if (style == Summary || style == Detailed) {
- FastSection namespaces(inner,
- "Namespaces",
- style == Detailed ? "nmspace" : QString(),
- "namespace",
- "namespaces");
- FastSection classes(inner,
- "Classes",
- style == Detailed ? "classes" : QString(),
- "class",
- "classes");
- FastSection types(inner,
- style == Summary ? "Types" : "Type Documentation",
- style == Detailed ? "types" : QString(),
- "type",
- "types");
- FastSection variables(inner,
- style == Summary ? "Variables" : "Variable Documentation",
- style == Detailed ? "vars" : QString(),
- "variable",
- "variables");
- FastSection staticVariables(inner,
- "Static Variables",
- QString(),
- "static variable",
- "static variables");
- FastSection functions(inner,
- style == Summary ?
- "Functions" : "Function Documentation",
- style == Detailed ? "func" : QString(),
- "function",
- "functions");
- FastSection macros(inner,
- style == Summary ?
- "Macros" : "Macro Documentation",
- style == Detailed ? "macros" : QString(),
- "macro",
- "macros");
-
- NodeList nodeList = inner->childNodes();
- nodeList += inner->relatedNodes();
-
- NodeList::ConstIterator n = nodeList.constBegin();
- while (n != nodeList.constEnd()) {
+ } else if (style == Summary || style == Detailed) {
+ FastSection namespaces(aggregate,
+ "Namespaces",
+ style == Detailed ? "nmspace" : QString(),
+ "namespace",
+ "namespaces");
+ FastSection classes(aggregate,
+ "Classes",
+ style == Detailed ? "classes" : QString(),
+ "class",
+ "classes");
+ FastSection types(aggregate,
+ style == Summary ? "Types" : "Type Documentation",
+ style == Detailed ? "types" : QString(),
+ "type",
+ "types");
+ FastSection variables(aggregate,
+ style == Summary ? "Variables" : "Variable Documentation",
+ style == Detailed ? "vars" : QString(),
+ "variable",
+ "variables");
+ FastSection staticVariables(aggregate,
+ "Static Variables",
+ QString(),
+ "static variable",
+ "static variables");
+ FastSection functions(aggregate,
+ style == Summary ?
+ "Functions" : "Function Documentation",
+ style == Detailed ? "func" : QString(),
+ "function",
+ "functions");
+ FastSection macros(aggregate,
+ style == Summary ?
+ "Macros" : "Macro Documentation",
+ style == Detailed ? "macros" : QString(),
+ "macro",
+ "macros");
+
+ NodeList nodeList = aggregate->childNodes();
+ nodeList += aggregate->relatedNodes();
+ if (aggregate->isNamespace()) {
+ const NamespaceNode* ns = static_cast<const NamespaceNode*>(aggregate);
+ if (!ns->hasDoc())
+ documentAll = false;
+ if (style == Summary) {
+ if (!ns->orphans().isEmpty())
+ nodeList += ns->orphans();
+ }
+ }
+ NodeList::ConstIterator n = nodeList.constBegin();
+ while (n != nodeList.constEnd()) {
+ if (documentAll || (*n)->hasDoc()) {
switch ((*n)->type()) {
case Node::Namespace:
insert(namespaces, *n, style, status);
@@ -851,31 +868,16 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner,
default:
break;
}
- ++n;
}
- if (inner->isNamespace()) {
- const NamespaceNode* ns = static_cast<const NamespaceNode*>(inner);
- if (!ns->orphans().isEmpty()) {
- foreach (Node* n, ns->orphans()) {
- // Use inner as a temporary parent when inserting orphans
- Aggregate* p = n->parent();
- n->setParent(const_cast<Aggregate*>(inner));
- if (n->isClass())
- insert(classes, n, style, status);
- else if (n->isNamespace())
- insert(namespaces, n, style, status);
- n->setParent(p);
- }
- }
- }
- append(sections, namespaces);
- append(sections, classes);
- append(sections, types);
- append(sections, variables);
- append(sections, staticVariables);
- append(sections, functions);
- append(sections, macros);
+ ++n;
}
+ append(sections, namespaces);
+ append(sections, classes);
+ append(sections, types);
+ append(sections, variables);
+ append(sections, staticVariables);
+ append(sections, functions);
+ append(sections, macros);
}
return sections;
diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp
index 9df4cc678..3471e2cc1 100644
--- a/src/qdoc/cppcodeparser.cpp
+++ b/src/qdoc/cppcodeparser.cpp
@@ -239,8 +239,8 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
without including the namespace qualifier.
*/
Node::NodeType type = nodeTypeMap[command];
- QStringList paths = arg.first.split(QLatin1Char(' '));
- QStringList path = paths[0].split("::");
+ QStringList words = arg.first.split(QLatin1Char(' '));
+ QStringList path = words[0].split("::");
Node *node = 0;
node = qdb_->findNodeInOpenNamespace(path, type);
@@ -258,6 +258,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
if (type == Node::Namespace) {
NamespaceNode* ns = static_cast<NamespaceNode*>(node);
ns->markSeen();
+ ns->setWhereDocumented(ns->tree()->camelCaseModuleName());
}
/*
This treats a class as a namespace.
diff --git a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc
index b2ae67dbf..05e7b331b 100644
--- a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc
+++ b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc
@@ -865,9 +865,9 @@
\section1 \\namespace
The \\namespace command is for documenting the contents of the C++
- namespace named as its argument. The documentation outline QDoc
- generates for a namespace is similar to the outline it generates
- for a C++ class.
+ namespace named as its argument. The reference page QDoc generates
+ for a namespace is similar to the reference page it generates for a
+ C++ class.
\code
/ *!
@@ -914,6 +914,14 @@
...
\endquotation
+ Note that in C++, a particular namespace can be used in more
+ than one module, but when C++ elements from different modules
+ are declared in the same namespace, the namespace itself must
+ be documented in one module only. For example, namespace Qt in
+ the example above contains types and functions from both QtCore
+ and QtGui, but it is documented with the \\namespace command
+ only in QtCore.
+
\target page-command
\section1 \\page
diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp
index 1e28ce5ef..b9292dbbb 100644
--- a/src/qdoc/generator.cpp
+++ b/src/qdoc/generator.cpp
@@ -403,6 +403,13 @@ QString Generator::fileBase(const Node *node) const
base.prepend(QLatin1Char('-'));
p = pp;
}
+ if (node->isNamespace() && !node->name().isEmpty()) {
+ const NamespaceNode* ns = static_cast<const NamespaceNode*>(node);
+ if (!ns->isDocumentedHere()) {
+ base.append(QLatin1String("-sub-"));
+ base.append(ns->tree()->camelCaseModuleName());
+ }
+ }
}
// the code below is effectively equivalent to:
@@ -973,7 +980,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
-void Generator::generateClassLikeNode(Node* /* node */, CodeMarker* /* marker */)
+void Generator::generateCppReferencePage(Node* /* node */, CodeMarker* /* marker */)
{
}
@@ -1156,13 +1163,12 @@ void Generator::generateDocumentation(Node* node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent() != 0) {
- if ((node->isNamespace() && node->status() != Node::Intermediate)
- || node->isClass()) {
+ if (node->isClass() || (node->isNamespace() && node->docMustBeGenerated())) {
beginSubPage(node, fileName(node));
- generateClassLikeNode(static_cast<Aggregate*>(node), marker);
+ generateCppReferencePage(static_cast<Aggregate*>(node), marker);
endSubPage();
}
- if (node->isQmlType() || node->isJsType()) {
+ else if (node->isQmlType() || node->isJsType()) {
beginSubPage(node, fileName(node));
QmlTypeNode* qcn = static_cast<QmlTypeNode*>(node);
generateQmlTypePage(qcn, marker);
@@ -1186,7 +1192,7 @@ void Generator::generateDocumentation(Node* node)
int i = 0;
while (i < aggregate->childNodes().count()) {
Node *c = aggregate->childNodes().at(i);
- if (c->isAggregate() && c->access() != Node::Private) {
+ if (c->isAggregate() && !c->isPrivate()) {
generateDocumentation((Aggregate*)c);
}
else if (c->isCollectionNode()) {
diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h
index 0bcabc90f..9087a747a 100644
--- a/src/qdoc/generator.h
+++ b/src/qdoc/generator.h
@@ -110,7 +110,7 @@ protected:
virtual void generateAlsoList(const Node *node, CodeMarker *marker);
virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker);
virtual void generateBody(const Node *node, CodeMarker *marker);
- virtual void generateClassLikeNode(Node* node, CodeMarker* marker);
+ virtual void generateCppReferencePage(Node* node, CodeMarker* marker);
virtual void generateQmlTypePage(QmlTypeNode* , CodeMarker* ) { }
virtual void generateQmlBasicTypePage(QmlBasicTypeNode* , CodeMarker* ) { }
virtual void generateDocumentNode(DocumentNode* dn, CodeMarker* marker);
diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp
index 60ed94981..dc879b829 100644
--- a/src/qdoc/htmlgenerator.cpp
+++ b/src/qdoc/htmlgenerator.cpp
@@ -1390,26 +1390,29 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
/*!
- Generate a reference page for a C++ class or a C++ namespace.
+ Generate a reference page for the C++ class or C++ namespace
+ documented in \a node using the \a marker.
*/
-void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
+void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker)
{
Q_ASSERT(node->isAggregate());
- Aggregate* inner = static_cast<Aggregate*>(node);
+ Aggregate* aggregate = static_cast<Aggregate*>(node);
QList<Section> sections;
QList<Section>::ConstIterator s;
QString title;
QString rawTitle;
QString fullTitle;
- if (inner->type() == Node::Namespace) {
- rawTitle = inner->plainName();
- fullTitle = inner->plainFullName();
+ NamespaceNode* ns = 0;
+ if (aggregate->isNamespace()) {
+ rawTitle = aggregate->plainName();
+ fullTitle = aggregate->plainFullName();
title = rawTitle + " Namespace";
+ ns = static_cast<NamespaceNode*>(aggregate);
}
- else if (inner->type() == Node::Class) {
- rawTitle = inner->plainName();
- fullTitle = inner->plainFullName();
+ else if (aggregate->isClass()) {
+ rawTitle = aggregate->plainName();
+ fullTitle = aggregate->plainFullName();
title = rawTitle + " Class";
}
@@ -1417,24 +1420,39 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
if (rawTitle != fullTitle)
subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak);
- generateHeader(title, inner, marker);
-
- sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
- generateTableOfContents(inner,marker,&sections);
- generateKeywordAnchors(inner);
- generateTitle(title, subtitleText, SmallSubTitle, inner, marker);
- generateBrief(inner, marker);
- generateRequisites(inner, marker);
- generateStatus(inner, marker);
+ generateHeader(title, aggregate, marker);
+
+ sections = marker->sections(aggregate, CodeMarker::Summary, CodeMarker::Okay);
+ generateTableOfContents(aggregate,marker,&sections);
+ generateKeywordAnchors(aggregate);
+ generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
+ if (ns && !ns->hasDoc() && ns->docNode()) {
+ NamespaceNode* NS = ns->docNode();
+ Text brief;
+ brief << "The " << ns->name() << " namespace includes the following elements from module "
+ << ns->tree()->camelCaseModuleName() << ". The full namespace is "
+ << "documented in module " << NS->tree()->camelCaseModuleName()
+ << Atom(Atom::LinkNode, CodeMarker::stringForNode(NS))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, " here.")
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ out() << "<p>";
+ generateText(brief, ns, marker);
+ out() << "</p>\n";
+ }
+ else
+ generateBrief(aggregate, marker);
+ generateRequisites(aggregate, marker);
+ generateStatus(aggregate, marker);
out() << "<ul>\n";
- QString membersLink = generateListOfAllMemberFile(inner, marker);
+ QString membersLink = generateListOfAllMemberFile(aggregate, marker);
if (!membersLink.isEmpty())
out() << "<li><a href=\"" << membersLink << "\">"
<< "List of all members, including inherited members</a></li>\n";
- QString obsoleteLink = generateLowStatusMemberFile(inner,
+ QString obsoleteLink = generateLowStatusMemberFile(aggregate,
marker,
CodeMarker::Obsolete);
if (!obsoleteLink.isEmpty()) {
@@ -1442,7 +1460,7 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
<< "Obsolete members</a></li>\n";
}
- QString compatLink = generateLowStatusMemberFile(inner,
+ QString compatLink = generateLowStatusMemberFile(aggregate,
marker,
CodeMarker::Compat);
if (!compatLink.isEmpty())
@@ -1450,7 +1468,7 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
<< "Compatibility members</a></li>\n";
out() << "</ul>\n";
- generateThreadSafeness(inner, marker);
+ generateThreadSafeness(aggregate, marker);
bool needOtherSection = false;
@@ -1469,7 +1487,7 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
QString ref = registerRef((*s).name.toLower());
out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n";
out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateSection(s->members, inner, marker, CodeMarker::Summary);
+ generateSection(s->members, aggregate, marker, CodeMarker::Summary);
}
if (!s->reimpMembers.isEmpty()) {
QString name = QString("Reimplemented ") + (*s).name;
@@ -1477,12 +1495,12 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
// out() << "<hr />\n";
out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n";
out() << "<h2 id=\"" << ref << "\">" << protectEnc(name) << "</h2>\n";
- generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
+ generateSection(s->reimpMembers, aggregate, marker, CodeMarker::Summary);
}
if (!s->inherited.isEmpty()) {
out() << "<ul>\n";
- generateSectionInheritedList(*s, inner);
+ generateSectionInheritedList(*s, aggregate);
out() << "</ul>\n";
}
}
@@ -1496,7 +1514,7 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
s = sections.constBegin();
while (s != sections.constEnd()) {
if (s->members.isEmpty() && !s->inherited.isEmpty())
- generateSectionInheritedList(*s, inner);
+ generateSectionInheritedList(*s, aggregate);
++s;
}
out() << "</ul>\n";
@@ -1505,19 +1523,19 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
QString detailsRef = registerRef("details");
out() << "<a name=\"" << detailsRef << "\"></a>" << divNavTop << '\n';
- if (!inner->doc().isEmpty()) {
- generateExtractionMark(inner, DetailedDescriptionMark);
+ if (!aggregate->doc().isEmpty()) {
+ generateExtractionMark(aggregate, DetailedDescriptionMark);
//out() << "<hr />\n"
out() << "<div class=\"descr\">\n" // QTBUG-9504
<< "<h2 id=\"" << detailsRef << "\">" << "Detailed Description" << "</h2>\n";
- generateBody(inner, marker);
+ generateBody(aggregate, marker);
out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(inner, marker);
- generateMaintainerList(inner, marker);
- generateExtractionMark(inner, EndMark);
+ generateAlsoList(aggregate, marker);
+ generateMaintainerList(aggregate, marker);
+ generateExtractionMark(aggregate, EndMark);
}
- sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
+ sections = marker->sections(aggregate, CodeMarker::Detailed, CodeMarker::Okay);
s = sections.constBegin();
while (s != sections.constEnd()) {
//out() << "<hr />\n";
@@ -1529,12 +1547,12 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
while (m != (*s).members.constEnd()) {
if ((*m)->access() != Node::Private) { // ### check necessary?
if ((*m)->type() != Node::Class)
- generateDetailedMember(*m, inner, marker);
+ generateDetailedMember(*m, aggregate, marker);
else {
out() << "<h3> class ";
- generateFullName(*m, inner);
+ generateFullName(*m, aggregate);
out() << "</h3>";
- generateBrief(*m, marker, inner);
+ generateBrief(*m, marker, aggregate);
}
QStringList names;
@@ -1574,7 +1592,7 @@ void HtmlGenerator::generateClassLikeNode(Node* node, CodeMarker* marker)
out() << "</div>\n"; // QTBUG-9504
++s;
}
- generateFooter(inner);
+ generateFooter(aggregate);
}
/*!
@@ -2187,7 +2205,7 @@ void HtmlGenerator::generateFooter(const Node *node)
Lists the required imports and includes in a table.
The number of rows is known, so this path is simpler than the generateSection() path.
*/
-void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
+void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker)
{
QMap<QString, Text> requisites;
Text text;
@@ -2200,11 +2218,11 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
const QString qtVariableText = "qmake";
//add the includes to the map
- if (!inner->includes().isEmpty()) {
+ if (!aggregate->includes().isEmpty()) {
text.clear();
text << highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(inner->includes())),
- inner);
+ marker->markedUpIncludes(aggregate->includes())),
+ aggregate);
requisites.insert(headerText, text);
}
@@ -2218,9 +2236,9 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
<< inheritedBytext;
//add the since and project into the map
- if (!inner->since().isEmpty()) {
+ if (!aggregate->since().isEmpty()) {
text.clear();
- QStringList since = inner->since().split(QLatin1Char(' '));
+ QStringList since = aggregate->since().split(QLatin1Char(' '));
if (since.count() == 1) {
// If there is only one argument, assume it is the Qt version number.
text << " Qt " << since[0];
@@ -2233,10 +2251,10 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
requisites.insert(sinceText, text);
}
- if (inner->type() == Node::Class || inner->type() == Node::Namespace) {
+ if (aggregate->type() == Node::Class || aggregate->type() == Node::Namespace) {
//add the QT variable to the map
- if (!inner->physicalModuleName().isEmpty()) {
- const CollectionNode* cn = qdb_->getCollectionNode(inner->physicalModuleName(), Node::CPP);
+ if (!aggregate->physicalModuleName().isEmpty()) {
+ const CollectionNode* cn = qdb_->getCollectionNode(aggregate->physicalModuleName(), Node::CPP);
if (cn && !cn->qtVariable().isEmpty()) {
text.clear();
text << "QT += " + cn->qtVariable();
@@ -2245,8 +2263,8 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
}
}
- if (inner->type() == Node::Class) {
- ClassNode* classe = static_cast<ClassNode*>(inner);
+ if (aggregate->type() == Node::Class) {
+ ClassNode* classe = static_cast<ClassNode*>(aggregate);
if (classe->qmlElement() != 0 && classe->status() != Node::Internal) {
text.clear();
text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement()))
@@ -2310,7 +2328,7 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker)
if (*i == headerText)
out() << requisites.value(*i).toString();
else
- generateText(requisites.value(*i), inner, marker);
+ generateText(requisites.value(*i), aggregate, marker);
out() << "</td></tr>";
}
}
@@ -2455,13 +2473,13 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
}
}
-void HtmlGenerator::generateIncludes(const Aggregate *inner, CodeMarker *marker)
+void HtmlGenerator::generateIncludes(const Aggregate *aggregate, CodeMarker *marker)
{
- if (!inner->includes().isEmpty()) {
+ if (!aggregate->includes().isEmpty()) {
out() << "<pre class=\"cpp\">"
<< trimmedTrailing(highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(inner->includes())),
- inner), codePrefix, codeSuffix)
+ marker->markedUpIncludes(aggregate->includes())),
+ aggregate), codePrefix, codeSuffix)
<< "</pre>";
}
}
@@ -2546,11 +2564,13 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
}
++s;
}
- out() << "<li class=\"level"
- << sectionNumber
- << "\"><a href=\"#"
- << registerRef("details")
- << "\">Detailed Description</a></li>\n";
+ if (!node->isNamespace() || node->hasDoc()) {
+ out() << "<li class=\"level"
+ << sectionNumber
+ << "\"><a href=\"#"
+ << registerRef("details")
+ << "\">Detailed Description</a></li>\n";
+ }
for (int i = 0; i < toc.size(); ++i) {
if (toc.at(i)->string().toInt() == 1) {
detailsBase = 1;
@@ -2596,30 +2616,30 @@ void HtmlGenerator::generateSidebar() {
out() << "</div>\n";
}
-QString HtmlGenerator::generateListOfAllMemberFile(const Aggregate *inner,
+QString HtmlGenerator::generateListOfAllMemberFile(const Aggregate *aggregate,
CodeMarker *marker)
{
QList<Section> sections;
QList<Section>::ConstIterator s;
- sections = marker->sections(inner,
+ sections = marker->sections(aggregate,
CodeMarker::Subpage,
CodeMarker::Okay);
if (sections.isEmpty())
return QString();
- QString fileName = fileBase(inner) + "-members." + fileExtension();
- beginSubPage(inner, fileName);
- QString title = "List of All Members for " + inner->name();
- generateHeader(title, inner, marker);
+ QString fileName = fileBase(aggregate) + "-members." + fileExtension();
+ beginSubPage(aggregate, fileName);
+ QString title = "List of All Members for " + aggregate->name();
+ generateHeader(title, aggregate, marker);
generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, inner, marker);
+ generateTitle(title, Text(), SmallSubTitle, aggregate, marker);
out() << "<p>This is the complete list of members for ";
- generateFullName(inner, 0);
+ generateFullName(aggregate, 0);
out() << ", including inherited members.</p>\n";
Section section = sections.first();
- generateSectionList(section, inner, marker, CodeMarker::Subpage);
+ generateSectionList(section, aggregate, marker, CodeMarker::Subpage);
generateFooter();
endSubPage();
@@ -2691,11 +2711,11 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlTypeNode* qml_cn, CodeMarker
return fileName;
}
-QString HtmlGenerator::generateLowStatusMemberFile(Aggregate *inner,
+QString HtmlGenerator::generateLowStatusMemberFile(Aggregate *aggregate,
CodeMarker *marker,
CodeMarker::Status status)
{
- QList<Section> sections = marker->sections(inner,
+ QList<Section> sections = marker->sections(aggregate,
CodeMarker::Summary,
status);
QMutableListIterator<Section> j(sections);
@@ -2712,38 +2732,38 @@ QString HtmlGenerator::generateLowStatusMemberFile(Aggregate *inner,
QString fileName;
if (status == CodeMarker::Compat) {
- title = "Compatibility Members for " + inner->name();
- fileName = fileBase(inner) + "-compat." + fileExtension();
+ title = "Compatibility Members for " + aggregate->name();
+ fileName = fileBase(aggregate) + "-compat." + fileExtension();
}
else {
- title = "Obsolete Members for " + inner->name();
- fileName = fileBase(inner) + "-obsolete." + fileExtension();
+ title = "Obsolete Members for " + aggregate->name();
+ fileName = fileBase(aggregate) + "-obsolete." + fileExtension();
}
if (status == CodeMarker::Obsolete) {
QString link;
if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty())
link = QString("../" + Generator::outputSubdir() + QLatin1Char('/'));
link += fileName;
- inner->setObsoleteLink(link);
+ aggregate->setObsoleteLink(link);
}
- beginSubPage(inner, fileName);
- generateHeader(title, inner, marker);
+ beginSubPage(aggregate, fileName);
+ generateHeader(title, aggregate, marker);
generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, inner, marker);
+ generateTitle(title, Text(), SmallSubTitle, aggregate, marker);
if (status == CodeMarker::Compat) {
out() << "<p><b>The following members of class "
- << "<a href=\"" << linkForNode(inner, 0) << "\">"
- << protectEnc(inner->name()) << "</a>"
+ << "<a href=\"" << linkForNode(aggregate, 0) << "\">"
+ << protectEnc(aggregate->name()) << "</a>"
<< " are part of the "
"Qt compatibility layer.</b> We advise against "
"using them in new code.</p>\n";
}
else {
out() << "<p><b>The following members of class "
- << "<a href=\"" << linkForNode(inner, 0) << "\">"
- << protectEnc(inner->name()) << "</a>"
+ << "<a href=\"" << linkForNode(aggregate, 0) << "\">"
+ << protectEnc(aggregate->name()) << "</a>"
<< " are obsolete.</b> "
<< "They are provided to keep old source code working. "
<< "We strongly advise against using them in new code.</p>\n";
@@ -2751,10 +2771,10 @@ QString HtmlGenerator::generateLowStatusMemberFile(Aggregate *inner,
for (i = 0; i < sections.size(); ++i) {
out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
- generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
+ generateSectionList(sections.at(i), aggregate, marker, CodeMarker::Summary);
}
- sections = marker->sections(inner, CodeMarker::Detailed, status);
+ sections = marker->sections(aggregate, CodeMarker::Detailed, status);
for (i = 0; i < sections.size(); ++i) {
//out() << "<hr />\n";
out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
@@ -2762,7 +2782,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(Aggregate *inner,
NodeList::ConstIterator m = sections.at(i).members.constBegin();
while (m != sections.at(i).members.constEnd()) {
if ((*m)->access() != Node::Private)
- generateDetailedMember(*m, inner, marker);
+ generateDetailedMember(*m, aggregate, marker);
++m;
}
}
diff --git a/src/qdoc/htmlgenerator.h b/src/qdoc/htmlgenerator.h
index 37d6f47ae..aa9ef2903 100644
--- a/src/qdoc/htmlgenerator.h
+++ b/src/qdoc/htmlgenerator.h
@@ -89,7 +89,7 @@ protected:
virtual int generateAtom(const Atom *atom,
const Node *relative,
CodeMarker *marker) override;
- void generateClassLikeNode(Node* node, CodeMarker* marker) override;
+ void generateCppReferencePage(Node* node, CodeMarker* marker) override;
void generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker) override;
void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker) override;
void generateDocumentNode(DocumentNode* dn, CodeMarker* marker) override;
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index de2fec53d..926c8ebdb 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -755,19 +755,19 @@ bool Node::isInternal() const
}
/*!
- Returns a pointer to the Tree this node is in.
+ Returns a pointer to the root of the Tree this node is in.
*/
-Tree* Node::tree() const
+const Node* Node::root() const
{
- return (parent() ? parent()->tree() : 0);
+ return (parent() ? parent()->root() : this);
}
/*!
- Returns a pointer to the root of the Tree this node is in.
+ Returns a pointer to the Tree this node is in.
*/
-const Node* Node::root() const
+Tree* Node::tree() const
{
- return (parent() ? parent()->root() : this);
+ return root()->tree();
}
/*!
@@ -1046,14 +1046,12 @@ QStringList Aggregate::secondaryKeys()
/*!
Mark all child nodes that have no documentation as having
private access and internal status. qdoc will then ignore
- them for documentation purposes. Some nodes have an
- Intermediate status, meaning that they should be ignored,
- but not their children.
+ them for documentation purposes.
*/
void Aggregate::makeUndocumentedChildrenInternal()
{
foreach (Node *child, childNodes()) {
- if (!child->isSharingComment() && child->doc().isEmpty() && child->status() != Node::Intermediate) {
+ if (!child->isSharingComment() && !child->hasDoc() && !child->docMustBeGenerated()) {
child->setAccess(Node::Private);
child->setStatus(Node::Internal);
}
@@ -1605,19 +1603,82 @@ LeafNode::LeafNode(Aggregate* parent, NodeType type, const QString& name)
/*!
\class NamespaceNode
+ \brief This class represents a C++ namespace.
+
+ A namespace can be used in multiple C++ modules, so there
+ can be a NamespaceNode for namespace Xxx in more than one
+ Node tree.
*/
/*!
- Constructs a namespace node.
+ Constructs a namespace node for a namespace named \a name.
+ The namespace node has the specified \a parent.
*/
NamespaceNode::NamespaceNode(Aggregate *parent, const QString& name)
- : Aggregate(Namespace, parent, name), seen_(false), tree_(0)
+ : Aggregate(Namespace, parent, name), seen_(false), documented_(false), tree_(0), docNode_(0)
{
setGenus(Node::CPP);
setPageType(ApiPage);
}
/*!
+ Returns true if this namespace is to be documented in the
+ current module. There can be elements declared in this
+ namespace spread over multiple modules. Those elements are
+ documented in the modules where they are declared, but they
+ are linked to from the namespace page in the module where
+ the namespace itself is documented.
+ */
+bool NamespaceNode::isDocumentedHere() const
+{
+ return whereDocumented_ == tree()->camelCaseModuleName();
+}
+
+/*!
+ Returns true if this namespace node contains at least one
+ child that has documentation and is not private or internal.
+ */
+bool NamespaceNode::hasDocumentedChildren() const
+{
+ foreach (Node* n, childNodes()) {
+ if (n->hasDoc() && !n->isPrivate() && !n->isInternal())
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Report qdoc warning for each documented child in a namespace
+ that is not documented. This function should only be called
+ when the namespace is not documented.
+ */
+void NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace() const
+{
+ foreach (Node* n, childNodes()) {
+ if (n->hasDoc() && !n->isPrivate() && !n->isInternal()) {
+ QString msg1 = n->name();
+ if (n->isFunction())
+ msg1 += "()";
+ msg1 += tr(" is documented, but namespace %1 is not documented in any module.").arg(name());
+ QString msg2 = tr("Add /*! '\\%1 %2' ... */ or remove the qdoc comment marker (!) at that line number.").arg(COMMAND_NAMESPACE).arg(name());
+
+ n->doc().location().warning(msg1, msg2);
+ }
+ }
+}
+
+/*!
+ Returns true if this namespace node is not private and
+ contains at least one public child node with documentation.
+ */
+bool NamespaceNode::docMustBeGenerated() const
+{
+ if (hasDoc() && !isInternal() && !isPrivate())
+ return true;
+ return (hasDocumentedChildren() ? true : false);
+}
+
+/*!
\class ClassNode
\brief This class represents a C++ class.
*/
diff --git a/src/qdoc/node.h b/src/qdoc/node.h
index 14c214e93..e6d6d2de8 100644
--- a/src/qdoc/node.h
+++ b/src/qdoc/node.h
@@ -115,8 +115,7 @@ public:
Deprecated,
Preliminary,
Active,
- Internal,
- Intermediate
+ Internal
}; // don't reorder this enum
enum ThreadSafeness {
@@ -264,6 +263,7 @@ public:
virtual Tree* tree() const;
virtual void findChildren(const QString& , NodeList& nodes) const { nodes.clear(); }
virtual void setNoAutoList(bool ) { }
+ virtual bool docMustBeGenerated() const { return false; }
bool isIndexNode() const { return indexNodeFlag_; }
NodeType type() const { return (NodeType) nodeType_; }
virtual DocSubtype docSubtype() const { return NoSubtype; }
@@ -287,6 +287,7 @@ public:
void setLink(LinkType linkType, const QString &link, const QString &desc);
Access access() const { return (Access) access_; }
+ bool isPublic() const { return (Access) access_ == Public; }
bool isPrivate() const { return (Access) access_ == Private; }
QString accessString() const;
const Location& declLocation() const { return declLocation_; }
@@ -489,11 +490,24 @@ public:
void setTree(Tree* t) { tree_ = t; }
const NodeList& orphans() const { return orphans_; }
void addOrphan(Node* child) { orphans_.append(child); }
+ QString whereDocumented() const { return whereDocumented_; }
+ void setWhereDocumented(const QString &t) { whereDocumented_ = t; }
+ bool isDocumentedHere() const;
+ bool hasDocumentedChildren() const;
+ void reportDocumentedChildrenInUndocumentedNamespace() const;
+ bool docMustBeGenerated() const override;
+ void setDocumented() { documented_ = true; }
+ bool wasDocumented() const { return documented_; }
+ void setDocNode(NamespaceNode* ns) { docNode_ = ns; }
+ NamespaceNode* docNode() const { return docNode_; }
private:
- bool seen_;
- Tree* tree_;
- NodeList orphans_;
+ bool seen_;
+ bool documented_;
+ Tree* tree_;
+ QString whereDocumented_;
+ NamespaceNode* docNode_;
+ NodeList orphans_;
};
struct RelatedClass
diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp
index 8a4b276e8..564cd4609 100644
--- a/src/qdoc/qdocdatabase.cpp
+++ b/src/qdoc/qdocdatabase.cpp
@@ -1131,25 +1131,21 @@ void QDocDatabase::findAllLegaleseTexts(Aggregate* node)
}
/*!
- Finds all the namespace nodes and puts them in an index.
+ Finds all the namespace nodes in the tree beginning at
+ \a node and puts them in a map to be used later as an
+ index.
+
+ Ensure each namespace node has a name before inserting
+ it into the map, because the root namespace node has no
+ name, and we are not interested in it.
*/
void QDocDatabase::findAllNamespaces(Aggregate* node)
{
- NodeList::ConstIterator c = node->childNodes().constBegin();
- while (c != node->childNodes().constEnd()) {
- if ((*c)->access() != Node::Private || (*c)->isNamespace()) {
- if ((*c)->isAggregate()) {
- findAllNamespaces(static_cast<Aggregate *>(*c));
- if ((*c)->isNamespace()) {
- // Ensure that the namespace's name is not empty (the root
- // namespace has no name).
- if (!(*c)->name().isEmpty()) {
- nmm_.insert((*c)->name(), *c);
- }
- }
- }
- }
- ++c;
+ foreach (Node* n, node->childNodes()) {
+ if (n->isNamespace() && !n->name().isEmpty())
+ nmm_.insert(n->name(), n);
+ if (n->isNamespace() || (n->isAggregate() && n->access() != Node::Private))
+ findAllNamespaces(static_cast<Aggregate *>(n));
}
}
@@ -1400,6 +1396,12 @@ void QDocDatabase::resolveStuff()
}
/*!
+ Multiple namespace nodes for a particular namespace can be
+ created in multiple places. This function first finds all
+ namespace nodes and inserts them into a multimap. Then it
+ combines all the namespace nodes with the same name into a
+ single node and inserts that combined namespace node into
+ a namespace index.
*/
void QDocDatabase::resolveNamespaces()
{
@@ -1413,62 +1415,61 @@ void QDocDatabase::resolveNamespaces()
QList<QString> keys = nmm_.uniqueKeys();
foreach (const QString &s, keys) {
NamespaceNode* ns = 0;
+ NamespaceNode* somewhere = 0;
QList<Node*> nodes = nmm_.values(s);
int count = nmm_.remove(s);
- if (count > 1) {
+ if (count > 0) {
foreach (Node* n, nodes) {
- // Treat public namespaces from index trees as 'seen'
- if (n->isNamespace() && (n->wasSeen() || (n->isIndexNode() && n->access() == Node::Public))) {
- ns = static_cast<NamespaceNode*>(n);
- ns->markSeen();
+ ns = static_cast<NamespaceNode*>(n);
+ if (ns->isDocumentedHere())
break;
+ else if (ns->wasDocumented())
+ somewhere = ns;
+ ns = 0;
+ }
+ if (ns) {
+ foreach (Node* n, nodes) {
+ NamespaceNode* NS = static_cast<NamespaceNode*>(n);
+ if (NS->wasDocumented() && NS != ns) {
+ ns->doc().location().warning(tr("Namespace %1 documented more than once").arg(NS->name()));
+ NS->doc().location().warning(tr("...also seen here"));
+ }
+ }
+
+ } else if (somewhere == 0) {
+ foreach (Node* n, nodes) {
+ NamespaceNode* NS = static_cast<NamespaceNode*>(n);
+ NS->reportDocumentedChildrenInUndocumentedNamespace();
}
}
- }
- else if (count == 1)
- ns = static_cast<NamespaceNode*>(nodes.at(0));
- if (ns && ns->wasSeen()) {
- if (count >1) {
+ if (somewhere) {
foreach (Node* n, nodes) {
- if (n->isNamespace()) {
- NamespaceNode* NS = static_cast<NamespaceNode*>(n);
- if ((NS != ns) && !NS->childNodes().isEmpty()) {
- const NodeList& children = NS->childNodes();
- int i = children.size() - 1;
- while (i >= 0) {
- Node* child = children.at(i--);
- if (!child)
- continue;
- if (!child->isClass()
- && !child->isQmlType()
- && !child->isNamespace()) {
- NS->removeChild(child);
- ns->addChild(child);
- }
- else {
- NS->setStatus(Node::Intermediate);
- NS->setAccess(Node::Public);
- ns->addOrphan(child);
- }
- }
- }
+ NamespaceNode* NS = static_cast<NamespaceNode*>(n);
+ if (NS != somewhere)
+ NS->setDocNode(somewhere);
+ }
+ }
+ }
+ if (ns && count > 1) {
+ foreach (Node* n, nodes) {
+ NamespaceNode* NS = static_cast<NamespaceNode*>(n);
+ if ((NS != ns) && !NS->childNodes().isEmpty()) {
+ const NodeList& children = NS->childNodes();
+ int i = children.size() - 1;
+ while (i >= 0) {
+ Node* child = children.at(i--);
+ if (child && child->isPublic() && !child->isInternal())
+ ns->addOrphan(child);
}
}
}
- namespaceIndex_.insert(ns->name(), ns);
}
+ if (ns == 0)
+ ns = static_cast<NamespaceNode*>(nodes.at(0));
+ namespaceIndex_.insert(ns->name(), ns);
}
}
-#if 0
-/*!
- */
-const Node* QDocDatabase::findFunctionNode(const QString& target,
- const Node* relative,
- Node::Genus genus)
-{
- return forest_.findFunctionNode(target, relative, genus);
-}
-#endif
+
/*!
This function is called for autolinking to a \a type,
which could be a function return type or a parameter
diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp
index 5f646b82c..42c2cbc1d 100644
--- a/src/qdoc/qdocindexfiles.cpp
+++ b/src/qdoc/qdocindexfiles.cpp
@@ -189,12 +189,16 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
lineNo = attributes.value("lineno").toInt();
}
if (elementName == QLatin1String("namespace")) {
- node = new NamespaceNode(parent, name);
-
+ NamespaceNode* ns = new NamespaceNode(parent, name);
+ node = ns;
if (!indexUrl.isEmpty())
location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
else if (!indexUrl.isNull())
location = Location(name.toLower() + ".html");
+ if (attributes.hasAttribute(QLatin1String("documented"))) {
+ if (attributes.value(QLatin1String("documented")) == QLatin1String("true"))
+ ns->setDocumented();
+ }
}
else if (elementName == QLatin1String("class")) {
@@ -641,7 +645,7 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader,
node->setLocation(t);
location = t;
}
- Doc doc(location, location, " ", emptySet, emptySet); // placeholder
+ Doc doc(location, location, QString(), emptySet, emptySet); // placeholder
node->setDoc(doc);
node->setIndexNodeFlag();
node->setOutputSubdirectory(project_.toLower());
@@ -1043,11 +1047,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
break;
case Node::Namespace:
{
- const NamespaceNode* namespaceNode = static_cast<const NamespaceNode*>(node);
- if (!namespaceNode->physicalModuleName().isEmpty())
- writer.writeAttribute("module", namespaceNode->physicalModuleName());
- if (!namespaceNode->groupNames().isEmpty())
- writer.writeAttribute("groups", namespaceNode->groupNames().join(QLatin1Char(',')));
+ const NamespaceNode* ns = static_cast<const NamespaceNode*>(node);
+ writer.writeAttribute("documented", ns->hasDoc() ? "true" : "false");
+ if (!ns->physicalModuleName().isEmpty())
+ writer.writeAttribute("module", ns->physicalModuleName());
+ if (!ns->groupNames().isEmpty())
+ writer.writeAttribute("groups", ns->groupNames().join(QLatin1Char(',')));
if (!brief.isEmpty())
writer.writeAttribute("brief", brief);
}
diff --git a/src/qdoc/webxmlgenerator.cpp b/src/qdoc/webxmlgenerator.cpp
index a58a1c913..3b925a5a8 100644
--- a/src/qdoc/webxmlgenerator.cpp
+++ b/src/qdoc/webxmlgenerator.cpp
@@ -71,7 +71,7 @@ int WebXMLGenerator::generateAtom(const Atom * /* atom, */,
return 0;
}
-void WebXMLGenerator::generateClassLikeNode(Node *node, CodeMarker *marker)
+void WebXMLGenerator::generateCppReferencePage(Node *node, CodeMarker *marker)
{
QByteArray data;
QXmlStreamWriter writer(&data);
@@ -93,7 +93,7 @@ void WebXMLGenerator::generateClassLikeNode(Node *node, CodeMarker *marker)
void WebXMLGenerator::generateDocumentNode(DocumentNode *dn, CodeMarker *marker)
{
- generateClassLikeNode(dn, marker);
+ generateCppReferencePage(dn, marker);
}
void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer,
@@ -189,14 +189,14 @@ void WebXMLGenerator::generateDocumentation(Node *node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent()) {
- if ((node->isNamespace() && node->status() != Node::Intermediate) || node->isClass())
- generateClassLikeNode(static_cast<Aggregate*>(node), marker);
+ if (node->isNamespace() || node->isClass())
+ generateCppReferencePage(static_cast<Aggregate*>(node), marker);
else if (node->isDocumentNode())
generateDocumentNode(static_cast<DocumentNode *>(node), marker);
else if (node->isCollectionNode() && node->wasSeen()) {
// see remarks in base class impl.
qdb_->mergeCollections(static_cast<CollectionNode *>(node));
- generateClassLikeNode(node, marker);
+ generateCppReferencePage(node, marker);
}
// else if TODO: anything else?
}
diff --git a/src/qdoc/webxmlgenerator.h b/src/qdoc/webxmlgenerator.h
index c9e2205b6..84da52323 100644
--- a/src/qdoc/webxmlgenerator.h
+++ b/src/qdoc/webxmlgenerator.h
@@ -50,7 +50,7 @@ public:
protected:
int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override;
- void generateClassLikeNode(Node *node, CodeMarker *marker) override;
+ void generateCppReferencePage(Node *node, CodeMarker *marker) override;
void generateDocumentNode(DocumentNode *dn, CodeMarker *marker) override;
void generateDocumentation(Node *node) override;
QString fileExtension() const override;