qdoc: Added module attribute to most index elements

The index file generated by qdoc when it is run in
-prepare mode has been modified so that most elements
have a module attribute. The value of the module
attribute either came from an \inmodule command, or
it is the value of the project variable specified in
the qdocconf file that was read by qdoc.

Task number: QTBUG-27626

Change-Id: I44198bbbc1738fafc110c6b905eb1d67bc745323
Reviewed-by: Jerome Pasion <jerome.pasion@digia.com>
This commit is contained in:
Martin Smith 2012-11-06 13:44:35 +01:00
parent c808dd2745
commit 2efbf2dbbe
7 changed files with 100 additions and 10 deletions

View File

@ -387,4 +387,80 @@ bool CodeParser::isParsingQdoc() const
return currentFile_.endsWith(".qdoc");
}
/*!
For each node that will produce a documentation page, this function
ensures that the node belongs to a module. Normally, the qdoc comment
for an entity that will produce a documentation page will contain an
\inmodule command to tell qdoc which module the entity belongs to.
But now that we normally run qdoc on each module in two passes. The
first produces an index file; the second pass generates the docs
after reading all the index files it needs.
This means that all the pages generated during each pass 2 run of
qdoc almost certainly belong to a single module, and the name of
that module is, as a rule, used as the project name in the qdocconf
file used when running qdoc on the module.
So this function first asks if the node \a n has a non-empty module
name. If it it does not have a non-empty module name, it sets the
module name to be the project name.
In some cases it prints a qdoc warning that it has done this. Namely,
for C++ classes and namespaces.
*/
void CodeParser::checkModuleInclusion(Node* n)
{
if (n->moduleName().isEmpty()) {
switch (n->type()) {
case Node::Class:
if (n->access() != Node::Private && !n->doc().isEmpty()) {
n->setModuleName(Generator::defaultModuleName());
n->doc().location().warning(tr("Class %1 has no \\inmodule command; "
"using project name by default: %2")
.arg(n->name()).arg(Generator::defaultModuleName()));
}
break;
case Node::Namespace:
if (n->access() != Node::Private && !n->name().isEmpty() && !n->doc().isEmpty()) {
n->setModuleName(Generator::defaultModuleName());
n->doc().location().warning(tr("Namespace %1 has no \\inmodule command; "
"using project name by default: %2")
.arg(n->name()).arg(Generator::defaultModuleName()));
}
break;
case Node::Document:
if (n->access() != Node::Private && !n->doc().isEmpty()) {
if (n->subType() == Node::HeaderFile) {
n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Header file with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
.arg(n->title()).arg(Generator::defaultModuleName()));
#endif
}
else if (n->subType() == Node::Page) {
n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Page with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
.arg(n->title()).arg(Generator::defaultModuleName()));
#endif
}
else if (n->subType() == Node::Example) {
n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Example with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
.arg(n->title()).arg(Generator::defaultModuleName()));
#endif
}
}
break;
default:
break;
}
}
}
QT_END_NAMESPACE

View File

@ -72,6 +72,7 @@ public:
bool isParsingCpp() const;
bool isParsingQdoc() const;
const QString& currentFile() const { return currentFile_; }
void checkModuleInclusion(Node* n);
static void initialize(const Config& config);
static void terminate();

View File

@ -2156,8 +2156,8 @@ bool CppCodeParser::matchDocsAndStuff()
while (n != nodes.end()) {
processOtherMetaCommands(*d, *n);
(*n)->setDoc(*d);
if ((*n)->isInnerNode() &&
((InnerNode *)*n)->includes().isEmpty()) {
checkModuleInclusion(*n);
if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast<InnerNode *>(*n);
while (m->parent() != qdb_->treeRoot())
m = m->parent();

View File

@ -95,6 +95,7 @@ public:
static void setQDocPass(Passes pass) { qdocPass_ = pass; }
static bool runPrepareOnly() { return (qdocPass_ == Prepare); }
static bool runGenerateOnly() { return (qdocPass_ == Generate); }
static QString defaultModuleName() { return project; }
protected:
virtual void beginSubPage(const InnerNode* node, const QString& fileName);

View File

@ -195,6 +195,7 @@ bool PureDocParser::processQdocComments()
while (n != nodes.end()) {
processOtherMetaCommands(*d, *n);
(*n)->setDoc(*d);
checkModuleInclusion(*n);
if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast<InnerNode *>(*n);
while (m->parent() && m->parent() != treeRoot)

View File

@ -344,8 +344,9 @@ void QDocDatabase::findAllClasses(const InnerNode* node)
}
QString serviceName = (static_cast<const ClassNode *>(*c))->serviceName();
if (!serviceName.isEmpty())
if (!serviceName.isEmpty()) {
serviceClasses_.insert(serviceName, *c);
}
}
else if ((*c)->type() == Node::Document &&
(*c)->subType() == Node::QmlClass &&
@ -418,12 +419,10 @@ void QDocDatabase::findAllNamespaces(const InnerNode* node)
if ((*c)->isInnerNode()) {
findAllNamespaces(static_cast<const InnerNode *>(*c));
if ((*c)->type() == Node::Namespace) {
const NamespaceNode* nspace = static_cast<const NamespaceNode *>(*c);
// Ensure that the namespace's name is not empty (the root
// namespace has no name).
if (!nspace->name().isEmpty()) {
namespaceIndex_.insert(nspace->name(), *c);
}
if (!(*c)->name().isEmpty())
namespaceIndex_.insert((*c)->name(), *c);
}
}
}

View File

@ -435,7 +435,9 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
else
section->setStatus(Node::Commendable);
section->setModuleName(element.attribute("module"));
QString moduleName = element.attribute("module");
if (!moduleName.isEmpty())
section->setModuleName(moduleName);
if (!indexUrl.isEmpty()) {
section->setUrl(indexUrl + QLatin1Char('/') + href);
}
@ -660,11 +662,13 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
baseStrings.insert(baseClassNode->name());
}
writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(","));
writer.writeAttribute("module", node->moduleName());
if (!node->moduleName().isEmpty())
writer.writeAttribute("module", node->moduleName());
}
break;
case Node::Namespace:
writer.writeAttribute("module", node->moduleName());
if (!node->moduleName().isEmpty())
writer.writeAttribute("module", node->moduleName());
break;
case Node::Document:
{
@ -672,25 +676,30 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
Document nodes (such as manual pages) contain subtypes,
titles and other attributes.
*/
bool writeModuleName = false;
const DocNode* docNode = static_cast<const DocNode*>(node);
switch (docNode->subType()) {
case Node::Example:
writer.writeAttribute("subtype", "example");
writeModuleName = true;
break;
case Node::HeaderFile:
writer.writeAttribute("subtype", "header");
writeModuleName = true;
break;
case Node::File:
writer.writeAttribute("subtype", "file");
break;
case Node::Group:
writer.writeAttribute("subtype", "group");
writeModuleName = true;
break;
case Node::Module:
writer.writeAttribute("subtype", "module");
break;
case Node::Page:
writer.writeAttribute("subtype", "page");
writeModuleName = true;
break;
case Node::ExternalPage:
writer.writeAttribute("subtype", "externalpage");
@ -708,6 +717,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("fulltitle", docNode->fullTitle());
writer.writeAttribute("subtitle", docNode->subTitle());
writer.writeAttribute("location", docNode->doc().location().fileName());
if (!node->moduleName().isEmpty() && writeModuleName) {
writer.writeAttribute("module", node->moduleName());
}
}
break;
case Node::Function: