summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@digia.com>2014-01-31 11:56:10 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-03-31 21:04:52 +0200
commit5fecc6512f0e869713658502674665f9077cc340 (patch)
tree523f6ae6de75862b61694d9e090f62b42e5dff7d
parente9954e31624c77d986077ec5431c7ec4a9b058e0 (diff)
qdoc: Teach qdoc to use multiple trees (part 2)
qdoc now knows how to search the forrest of node trees in an optimal order. But there remain some problems with specific searches that cross module boundaries. These include group membership and C++ and QML module membership, as well ass C++ base class resolution. Part 3 will be concerned with fixing these remaining bugs. With this update, qdoc now takes less time to generate the docs for Qt 5. Testing indicates that qdoc run time has dropped from about 14 minutes to about 7.5 minutes on an iMac. Task-number: QTBUG-35377 Change-Id: I6bded6ef54124b4f6e5914cad4548f0b600209b0 Reviewed-by: Martin Smith <martin.smith@digia.com>
-rw-r--r--src/tools/qdoc/codemarker.h1
-rw-r--r--src/tools/qdoc/codeparser.cpp14
-rw-r--r--src/tools/qdoc/config.cpp2
-rw-r--r--src/tools/qdoc/config.h4
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp138
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.cpp18
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.h2
-rw-r--r--src/tools/qdoc/doc.cpp64
-rw-r--r--src/tools/qdoc/generator.cpp16
-rw-r--r--src/tools/qdoc/generator.h8
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp2
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp53
-rw-r--r--src/tools/qdoc/htmlgenerator.h2
-rw-r--r--src/tools/qdoc/main.cpp40
-rw-r--r--src/tools/qdoc/node.cpp156
-rw-r--r--src/tools/qdoc/node.h11
-rw-r--r--src/tools/qdoc/puredocparser.cpp2
-rw-r--r--src/tools/qdoc/puredocparser.h1
-rw-r--r--src/tools/qdoc/qdocdatabase.cpp872
-rw-r--r--src/tools/qdoc/qdocdatabase.h265
-rw-r--r--src/tools/qdoc/qdocindexfiles.cpp15
-rw-r--r--src/tools/qdoc/qdoctagfiles.cpp6
-rw-r--r--src/tools/qdoc/qmlcodeparser.h1
-rw-r--r--src/tools/qdoc/qmlvisitor.cpp2
-rw-r--r--src/tools/qdoc/tree.cpp269
-rw-r--r--src/tools/qdoc/tree.h37
26 files changed, 1375 insertions, 626 deletions
diff --git a/src/tools/qdoc/codemarker.h b/src/tools/qdoc/codemarker.h
index 02caedf9b8..f7524735b5 100644
--- a/src/tools/qdoc/codemarker.h
+++ b/src/tools/qdoc/codemarker.h
@@ -54,7 +54,6 @@
QT_BEGIN_NAMESPACE
class Config;
-class Tree;
typedef QMultiMap<QString, Node*> MemberMap; // the string is the member signature
typedef QPair<const QmlClassNode*, MemberMap> ClassMap; // the node is the QML type
diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp
index a0ea561b28..5811dc8afc 100644
--- a/src/tools/qdoc/codeparser.cpp
+++ b/src/tools/qdoc/codeparser.cpp
@@ -412,9 +412,9 @@ bool CodeParser::isParsingQdoc() const
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.
+ But now 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
@@ -431,10 +431,10 @@ bool CodeParser::isParsingQdoc() const
void CodeParser::checkModuleInclusion(Node* n)
{
if (n->moduleName().isEmpty()) {
+ n->setModuleName(Generator::defaultModuleName());
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()));
@@ -442,16 +442,15 @@ void CodeParser::checkModuleInclusion(Node* n)
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;
+#if 0
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")
@@ -459,7 +458,6 @@ void CodeParser::checkModuleInclusion(Node* n)
#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")
@@ -467,7 +465,6 @@ void CodeParser::checkModuleInclusion(Node* n)
#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")
@@ -476,6 +473,7 @@ void CodeParser::checkModuleInclusion(Node* n)
}
}
break;
+#endif
default:
break;
}
diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp
index 56e7287c40..185c1c77f1 100644
--- a/src/tools/qdoc/config.cpp
+++ b/src/tools/qdoc/config.cpp
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
QString ConfigStrings::ALIAS = QStringLiteral("alias");
+QString ConfigStrings::AUTOLINKERRORS = QStringLiteral("autolinkerrors");
QString ConfigStrings::BASE = QStringLiteral("base");
QString ConfigStrings::BASEDIR = QStringLiteral("basedir");
QString ConfigStrings::BUILDVERSION = QStringLiteral("buildversion");
@@ -242,6 +243,7 @@ QStringList MetaStack::getExpanded(const Location& location)
}
QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String(".");
+bool Config::debug_ = false;
bool Config::generateExamples = true;
QString Config::overrideOutputDir;
QString Config::installDir;
diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h
index 54ee8de47f..ebe7956907 100644
--- a/src/tools/qdoc/config.h
+++ b/src/tools/qdoc/config.h
@@ -88,6 +88,8 @@ public:
Config(const QString& programName);
~Config();
+ static bool debug_;
+
void load(const QString& fileName);
void setStringList(const QString& var, const QStringList& values);
@@ -167,6 +169,7 @@ private:
struct ConfigStrings
{
static QString ALIAS;
+ static QString AUTOLINKERRORS;
static QString BASE;
static QString BASEDIR;
static QString BUILDVERSION;
@@ -239,6 +242,7 @@ struct ConfigStrings
};
#define CONFIG_ALIAS ConfigStrings::ALIAS
+#define CONFIG_AUTOLINKERRORS ConfigStrings::AUTOLINKERRORS
#define CONFIG_BASE ConfigStrings::BASE
#define CONFIG_BASEDIR ConfigStrings::BASEDIR
#define CONFIG_BUILDVERSION ConfigStrings::BUILDVERSION
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index c22a5227a6..73fe16fb46 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -52,6 +52,7 @@
#include "tokenizer.h"
#include "qdocdatabase.h"
#include <qdebug.h>
+#include "generator.h"
QT_BEGIN_NAMESPACE
@@ -173,7 +174,7 @@ void CppCodeParser::parseHeaderFile(const Location& location, const QString& fil
Tokenizer fileTokenizer(fileLocation, in);
tokenizer = &fileTokenizer;
readToken();
- matchDeclList(qdb_->treeRoot());
+ matchDeclList(qdb_->primaryTreeRoot());
if (!fileTokenizer.version().isEmpty())
qdb_->setVersion(fileTokenizer.version());
in.close();
@@ -218,10 +219,10 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& fil
}
/*!
- This is called after all the header files have been parsed.
- I think the most important thing it does is resolve class
- inheritance links in the tree. But it also initializes a
- bunch of stuff.
+ This is called after all the C++ header files have been
+ parsed. The most important thing it does is resolve C++
+ class inheritance links in the tree. It also initializes
+ a bunch of other collections.
*/
void CppCodeParser::doneParsingHeaderFiles()
{
@@ -263,11 +264,11 @@ void CppCodeParser::doneParsingHeaderFiles()
*/
void CppCodeParser::doneParsingSourceFiles()
{
- qdb_->treeRoot()->clearCurrentChildPointers();
- qdb_->treeRoot()->normalizeOverloads();
+ qdb_->primaryTreeRoot()->clearCurrentChildPointers();
+ qdb_->primaryTreeRoot()->normalizeOverloads();
qdb_->fixInheritance();
qdb_->resolveProperties();
- qdb_->treeRoot()->makeUndocumentedChildrenInternal();
+ qdb_->primaryTreeRoot()->makeUndocumentedChildrenInternal();
}
static QSet<QString> topicCommands_;
@@ -326,38 +327,33 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN));
}
else {
- func = qdb_->findNodeInOpenNamespace(parentPath, clone);
- /*
- Search the root namespace if no match was found.
- */
+ func = qdb_->findFunctionNode(parentPath, clone);
if (func == 0) {
- func = qdb_->findFunctionNode(parentPath, clone);
+ 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 == 0) {
- if (parentPath.isEmpty() && !lastPath_.isEmpty()) {
- func = qdb_->findFunctionNode(lastPath_, clone);
- }
- if (func == 0) {
- 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."));
- }
- else {
- doc.location().warning(tr("Missing '%1::' for '%2' in '\\%3'")
- .arg(lastPath_.join("::"))
- .arg(clone->name() + "()")
- .arg(COMMAND_FN));
- }
+ 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."));
}
- else {
+ else
lastPath_ = parentPath;
- }
if (func) {
func->borrowParameterNames(clone);
func->setParentPath(clone->parentPath());
@@ -370,7 +366,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QStringList parentPath;
FunctionNode *func = 0;
- extra.root = qdb_->treeRoot();
+ extra.root = qdb_->primaryTreeRoot();
extra.isMacro = true;
if (makeFunctionNode(arg.first, &parentPath, &func, extra)) {
if (!parentPath.isEmpty()) {
@@ -392,7 +388,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return func;
}
else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg.first)) {
- func = new FunctionNode(qdb_->treeRoot(), arg.first);
+ func = new FunctionNode(qdb_->primaryTreeRoot(), arg.first);
func->setAccess(Node::Public);
func->setLocation(doc.startLocation());
func->setMetaness(FunctionNode::MacroWithoutParams);
@@ -421,21 +417,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QStringList path = paths[0].split("::");
Node *node = 0;
- /*
- If the command refers to something that can be in a
- C++ namespace, search for it first in all the known
- C++ namespaces.
- */
node = qdb_->findNodeInOpenNamespace(path, type, subtype);
-
- /*
- If the node was not found in a C++ namespace, search
- for it in the root namespace.
- */
- if (node == 0) {
+ if (node == 0)
node = qdb_->findNodeByNameAndType(path, type, subtype);
- }
-
if (node == 0) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
.arg(arg.first).arg(command));
@@ -444,31 +428,33 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
else if (node->isInnerNode()) {
/*
- This treets a class as a namespace.
+ This treats a class as a namespace.
*/
- if (path.size() > 1) {
- path.pop_back();
- QString ns = path.join("::");
- qdb_->insertOpenNamespace(ns);
+ if ((type == Node::Class) || (type == Node::Namespace)) {
+ if (path.size() > 1) {
+ path.pop_back();
+ QString ns = path.join("::");
+ qdb_->insertOpenNamespace(ns);
+ }
}
}
return node;
}
else if (command == COMMAND_EXAMPLE) {
if (Config::generateExamples) {
- ExampleNode* en = new ExampleNode(qdb_->treeRoot(), arg.first);
+ ExampleNode* en = new ExampleNode(qdb_->primaryTreeRoot(), arg.first);
en->setLocation(doc.startLocation());
createExampleFileNodes(en);
return en;
}
}
else if (command == COMMAND_EXTERNALPAGE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::ExternalPage, Node::ArticlePage);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::ExternalPage, Node::ArticlePage);
dn->setLocation(doc.startLocation());
return dn;
}
else if (command == COMMAND_FILE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::File, Node::NoPageType);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::File, Node::NoPageType);
dn->setLocation(doc.startLocation());
return dn;
}
@@ -478,7 +464,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return dn;
}
else if (command == COMMAND_HEADERFILE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::HeaderFile, Node::ApiPage);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::HeaderFile, Node::ApiPage);
dn->setLocation(doc.startLocation());
return dn;
}
@@ -527,9 +513,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
NameCollisionNode* ncn = qdb_->checkForCollision(args[0]);
DocNode* dn = 0;
if (ptype == Node::DitaMapPage)
- dn = new DitaMapNode(qdb_->treeRoot(), args[0]);
+ dn = new DitaMapNode(qdb_->primaryTreeRoot(), args[0]);
else
- dn = new DocNode(qdb_->treeRoot(), args[0], Node::Page, ptype);
+ dn = new DocNode(qdb_->primaryTreeRoot(), args[0], Node::Page, ptype);
dn->setLocation(doc.startLocation());
if (ncn) {
ncn->addCollision(dn);
@@ -537,7 +523,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return dn;
}
else if (command == COMMAND_DITAMAP) {
- DocNode* dn = new DitaMapNode(qdb_->treeRoot(), arg.first);
+ DocNode* dn = new DitaMapNode(qdb_->primaryTreeRoot(), arg.first);
dn->setLocation(doc.startLocation());
return dn;
}
@@ -577,7 +563,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
node and return that one.
*/
NameCollisionNode* ncn = qdb_->checkForCollision(names[0]);
- QmlClassNode* qcn = new QmlClassNode(qdb_->treeRoot(), names[0]);
+ QmlClassNode* qcn = new QmlClassNode(qdb_->primaryTreeRoot(), names[0]);
qcn->setClassNode(classNode);
qcn->setLocation(doc.startLocation());
#if 0
@@ -596,12 +582,13 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
}
#endif
- if (ncn)
+ if (ncn) {
ncn->addCollision(qcn);
+ }
return qcn;
}
else if (command == COMMAND_QMLBASICTYPE) {
- QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->treeRoot(), arg.first);
+ QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first);
n->setLocation(doc.startLocation());
return n;
}
@@ -1644,7 +1631,7 @@ bool CppCodeParser::matchClassDecl(InnerNode *parent,
while (tok == Tok_Ident)
readToken();
if (tok == Tok_Gulbrandsen) {
- Node* n = parent->findChildNodeByNameAndType(previousLexeme(),Node::Class);
+ Node* n = parent->findChildNode(previousLexeme(),Node::Class);
if (n) {
parent = static_cast<InnerNode*>(n);
if (parent) {
@@ -1704,7 +1691,7 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
QString namespaceName = previousLexeme();
NamespaceNode* ns = 0;
if (parent)
- ns = static_cast<NamespaceNode*>(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace));
+ ns = static_cast<NamespaceNode*>(parent->findChildNode(namespaceName, Node::Namespace));
if (!ns) {
ns = new NamespaceNode(parent, namespaceName);
ns->setAccess(access);
@@ -1842,7 +1829,7 @@ bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
if (!match(Tok_Semicolon))
return false;
- if (parent && !parent->findChildNodeByNameAndType(name, Node::Typedef)) {
+ if (parent && !parent->findChildNode(name, Node::Typedef)) {
TypedefNode* td = new TypedefNode(parent, name);
td->setAccess(access);
td->setLocation(location());
@@ -2077,7 +2064,7 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
TypedefNode *flagsNode = new TypedefNode(parent, flagsType);
flagsNode->setAccess(access);
flagsNode->setLocation(location());
- EnumNode* en = static_cast<EnumNode*>(parent->findChildNodeByNameAndType(name, Node::Enum));
+ EnumNode* en = static_cast<EnumNode*>(parent->findChildNode(name, Node::Enum));
if (en)
en->setFlagsType(flagsNode);
}
@@ -2156,9 +2143,15 @@ bool CppCodeParser::matchDocsAndStuff()
FunctionNode *func = 0;
if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) {
- func = qdb_->findNodeInOpenNamespace(parentPath, clone);
+ func = qdb_->findFunctionNode(parentPath, 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_->findFunctionNode(parentPath, clone);
+ func = qdb_->findNodeInOpenNamespace(parentPath, clone);
if (func) {
func->borrowParameterNames(clone);
@@ -2220,8 +2213,9 @@ bool CppCodeParser::matchDocsAndStuff()
checkModuleInclusion(*n);
if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast<InnerNode *>(*n);
- while (m->parent() != qdb_->treeRoot())
+ while (m->parent() && m->moduleName().isEmpty()) {
m = m->parent();
+ }
if (m == *n)
((InnerNode *)*n)->addInclude((*n)->name());
else
@@ -2358,7 +2352,7 @@ void CppCodeParser::instantiateIteratorMacro(const QString &container,
Tokenizer stringTokenizer(loc, latin1);
tokenizer = &stringTokenizer;
readToken();
- matchDeclList(QDocDatabase::qdocDB()->treeRoot());
+ matchDeclList(QDocDatabase::qdocDB()->primaryTreeRoot());
}
void CppCodeParser::createExampleFileNodes(DocNode *dn)
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
index c4f08e45df..b341decbb6 100644
--- a/src/tools/qdoc/ditaxmlgenerator.cpp
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -667,13 +667,13 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
}
/*!
- Traverses the database generating all the DITA XML documentation.
+ Traverses the current tree generating all the DITA XML documentation.
*/
-void DitaXmlGenerator::generateTree()
+void DitaXmlGenerator::generateDocs()
{
qdb_->buildCollections();
if (!runPrepareOnly()) {
- Generator::generateTree();
+ Generator::generateDocs();
generateCollisionPages();
}
@@ -3111,7 +3111,7 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative)
QMap<QString, DocNode*> uncategorizedNodeMap;
QRegExp singleDigit("\\b([0-9])\\b");
- const NodeList children = qdb_->treeRoot()->childNodes();
+ const NodeList children = qdb_->primaryTreeRoot()->childNodes();
foreach (Node* child, children) {
if (child->type() == Node::Document && child != relative) {
DocNode* docNode = static_cast<DocNode*>(child);
@@ -5511,7 +5511,7 @@ void DitaXmlGenerator::writeDitaMap()
Remove #if 0 to get a flat ditamap.
*/
#if 0
- beginSubPage(qdb_->treeRoot(),"qt.ditamap");
+ beginSubPage(qdb_->primaryTreeRoot(),"qt.ditamap");
doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
xmlWriter().writeDTD(doctype);
writeStartTag(DT_map);
@@ -5537,9 +5537,9 @@ void DitaXmlGenerator::writeDitaMap()
nodeSubtypeMaps[i] = new NodeMultiMap;
for (unsigned i=0; i<Node::OnBeyondZebra; ++i)
pageTypeMaps[i] = new NodeMultiMap;
- Node* rootPageNode = collectNodesByTypeAndSubtype(qdb_->treeRoot());
+ Node* rootPageNode = collectNodesByTypeAndSubtype(qdb_->primaryTreeRoot());
- beginSubPage(qdb_->treeRoot(),"qt.ditamap");
+ beginSubPage(qdb_->primaryTreeRoot(),"qt.ditamap");
doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
xmlWriter().writeDTD(doctype);
@@ -6132,7 +6132,7 @@ void DitaXmlGenerator::generateCollisionPages()
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNodeByName(t.key())) {
+ if (n->findChildNode(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
@@ -6154,7 +6154,7 @@ void DitaXmlGenerator::generateCollisionPages()
writeStartTag(DT_ul);
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNodeByName(*t);
+ Node* p = n->findChildNode(*t);
if (p) {
QString link = linkForNode(p,0);
QString label;
diff --git a/src/tools/qdoc/ditaxmlgenerator.h b/src/tools/qdoc/ditaxmlgenerator.h
index da05bb0274..a2a0bf5020 100644
--- a/src/tools/qdoc/ditaxmlgenerator.h
+++ b/src/tools/qdoc/ditaxmlgenerator.h
@@ -302,7 +302,7 @@ public:
virtual void terminateGenerator();
virtual QString format();
virtual bool canHandleFormat(const QString& format);
- virtual void generateTree();
+ virtual void generateDocs();
void generateCollisionPages();
QString protectEnc(const QString& string);
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp
index 6e70671d1d..afc21bb518 100644
--- a/src/tools/qdoc/doc.cpp
+++ b/src/tools/qdoc/doc.cpp
@@ -316,17 +316,17 @@ Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash)
class DocPrivateExtra
{
public:
- Doc::Sections granularity;
- Doc::Sections section; // ###
- QList<Atom*> tableOfContents;
- QList<int> tableOfContentsLevels;
- QList<Atom*> keywords;
- QList<Atom*> targets;
- QStringMultiMap metaMap;
+ Doc::Sections granularity_;
+ Doc::Sections section_; // ###
+ QList<Atom*> tableOfContents_;
+ QList<int> tableOfContentsLevels_;
+ QList<Atom*> keywords_;
+ QList<Atom*> targets_;
+ QStringMultiMap metaMap_;
DocPrivateExtra()
- : granularity(Doc::Part)
- , section(Doc::NoSection)
+ : granularity_(Doc::Part)
+ , section_(Doc::NoSection)
{ }
};
@@ -535,7 +535,7 @@ private:
int braceDepth;
int minIndent;
Doc::Sections currentSection;
- QMap<QString, Location> targetMap;
+ QMap<QString, Location> targetMap_;
QMap<int, QString> pendingFormats;
QStack<int> openedCommands;
QStack<OpenedList> openedLists;
@@ -880,7 +880,7 @@ void DocParser::parse(const QString& source,
break;
case CMD_GRANULARITY:
priv->constructExtra();
- priv->extra->granularity = getSectioningUnit();
+ priv->extra->granularity_ = getSectioningUnit();
break;
case CMD_HEADER:
if (openedCommands.top() == CMD_TABLE) {
@@ -1025,7 +1025,7 @@ void DocParser::parse(const QString& source,
case CMD_META:
priv->constructExtra();
p1 = getArgument();
- priv->extra->metaMap.insert(p1, getArgument());
+ priv->extra->metaMap_.insert(p1, getArgument());
break;
case CMD_NEWCODE:
location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE)));
@@ -1626,8 +1626,8 @@ void DocParser::parse(const QString& source,
currentSection = Doc::NoSection;
}
- if (priv->extra && priv->extra->granularity < priv->extra->section)
- priv->extra->granularity = priv->extra->section;
+ if (priv->extra && priv->extra->granularity_ < priv->extra->section_)
+ priv->extra->granularity_ = priv->extra->section_;
priv->text.stripFirstAtom();
}
@@ -1668,18 +1668,18 @@ QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet,
void DocParser::insertTarget(const QString &target, bool keyword)
{
- if (targetMap.contains(target)) {
+ if (targetMap_.contains(target)) {
location().warning(tr("Duplicate target name '%1'").arg(target));
- targetMap[target].warning(tr("(The previous occurrence is here)"));
+ targetMap_[target].warning(tr("(The previous occurrence is here)"));
}
else {
- targetMap.insert(target, location());
+ targetMap_.insert(target, location());
append(Atom::Target, target);
priv->constructExtra();
if (keyword)
- priv->extra->keywords.append(priv->text.lastAtom());
+ priv->extra->keywords_.append(priv->text.lastAtom());
else
- priv->extra->targets.append(priv->text.lastAtom());
+ priv->extra->targets_.append(priv->text.lastAtom());
}
}
@@ -1883,15 +1883,15 @@ void DocParser::startSection(Doc::Sections unit, int cmd)
if (currentSection == Doc::NoSection) {
currentSection = (Doc::Sections) (unit);
priv->constructExtra();
- priv->extra->section = currentSection;
+ priv->extra->section_ = currentSection;
}
else
endSection(unit,cmd);
append(Atom::SectionLeft, QString::number(unit));
priv->constructExtra();
- priv->extra->tableOfContents.append(priv->text.lastAtom());
- priv->extra->tableOfContentsLevels.append(unit);
+ priv->extra->tableOfContents_.append(priv->text.lastAtom());
+ priv->extra->tableOfContentsLevels_.append(unit);
enterPara(Atom::SectionHeadingLeft,
Atom::SectionHeadingRight,
QString::number(unit));
@@ -2958,10 +2958,10 @@ Text Doc::legaleseText() const
Doc::Sections Doc::granularity() const
{
if (priv == 0 || priv->extra == 0) {
- return DocPrivateExtra().granularity;
+ return DocPrivateExtra().granularity_;
}
else {
- return priv->extra->granularity;
+ return priv->extra->granularity_;
}
}
@@ -3007,46 +3007,46 @@ const QList<Text> &Doc::alsoList() const
bool Doc::hasTableOfContents() const
{
- return priv && priv->extra && !priv->extra->tableOfContents.isEmpty();
+ return priv && priv->extra && !priv->extra->tableOfContents_.isEmpty();
}
bool Doc::hasKeywords() const
{
- return priv && priv->extra && !priv->extra->keywords.isEmpty();
+ return priv && priv->extra && !priv->extra->keywords_.isEmpty();
}
bool Doc::hasTargets() const
{
- return priv && priv->extra && !priv->extra->targets.isEmpty();
+ return priv && priv->extra && !priv->extra->targets_.isEmpty();
}
const QList<Atom *> &Doc::tableOfContents() const
{
priv->constructExtra();
- return priv->extra->tableOfContents;
+ return priv->extra->tableOfContents_;
}
const QList<int> &Doc::tableOfContentsLevels() const
{
priv->constructExtra();
- return priv->extra->tableOfContentsLevels;
+ return priv->extra->tableOfContentsLevels_;
}
const QList<Atom *> &Doc::keywords() const
{
priv->constructExtra();
- return priv->extra->keywords;
+ return priv->extra->keywords_;
}
const QList<Atom *> &Doc::targets() const
{
priv->constructExtra();
- return priv->extra->targets;
+ return priv->extra->targets_;
}
const QStringMultiMap &Doc::metaTagMap() const
{
- return priv && priv->extra ? priv->extra->metaMap : *null_QStringMultiMap();
+ return priv && priv->extra ? priv->extra->metaMap_ : *null_QStringMultiMap();
}
const Config* Doc::config_ = 0;
diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
index d563546192..ec8eb14aa9 100644
--- a/src/tools/qdoc/generator.cpp
+++ b/src/tools/qdoc/generator.cpp
@@ -97,23 +97,26 @@ QStringList Generator::styleDirs;
QStringList Generator::styleFiles;
bool Generator::debugging_ = false;
bool Generator::noLinkErrors_ = false;
+bool Generator::autolinkErrors_ = false;
bool Generator::redirectDocumentationToDevNull_ = false;
Generator::Passes Generator::qdocPass_ = Both;
bool Generator::useOutputSubdirs_ = true;
-void Generator::setDebugSegfaultFlag(bool b)
+void Generator::setDebugFlag(bool b)
{
+#if 0
if (b)
qDebug() << "DEBUG: Setting debug flag.";
else
qDebug() << "DEBUG: Clearing debug flag.";
+#endif
debugging_ = b;
}
/*!
Prints \a message as an aid to debugging the release version.
*/
-void Generator::debugSegfault(const QString& message)
+void Generator::debug(const QString& message)
{
if (debugging())
qDebug() << "DEBUG:" << message;
@@ -275,7 +278,7 @@ void Generator::beginSubPage(const InnerNode* node, const QString& fileName)
node->location().error(tr("HTML 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::debugSegfault("Writing: " + path);
+ Generator::debug("Writing: " + path);
outFileNames.insert(fileName,fileName);
QTextStream* out = new QTextStream(outFile);
@@ -1365,11 +1368,11 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
}
/*!
- Traverses the database recursivly to generate all the documentation.
+ Traverses the current tree to generate all the documentation.
*/
-void Generator::generateTree()
+void Generator::generateDocs()
{
- generateInnerNode(qdb_->treeRoot());
+ generateInnerNode(qdb_->primaryTreeRoot());
}
Generator *Generator::generatorForFormat(const QString& format)
@@ -1653,6 +1656,7 @@ void Generator::initialize(const Config &config)
else
outputPrefixes[QLatin1String("QML")] = QLatin1String("qml-");
noLinkErrors_ = config.getBool(CONFIG_NOLINKERRORS);
+ autolinkErrors_ = config.getBool(CONFIG_AUTOLINKERRORS);
}
/*!
diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h
index b464014308..1042105e15 100644
--- a/src/tools/qdoc/generator.h
+++ b/src/tools/qdoc/generator.h
@@ -77,7 +77,7 @@ public:
virtual bool canHandleFormat(const QString &format) { return format == this->format(); }
virtual QString format() = 0;
- virtual void generateTree();
+ virtual void generateDocs();
virtual void initializeGenerator(const Config &config);
virtual void terminateGenerator();
@@ -92,10 +92,11 @@ public:
static void terminate();
static void writeOutFileNames();
static void augmentImageDirs(QSet<QString>& moreImageDirs);
- static void debugSegfault(const QString& message);
- static void setDebugSegfaultFlag(bool b);
+ static void debug(const QString& message);
+ static void setDebugFlag(bool b);
static bool debugging() { return debugging_; }
static bool noLinkErrors() { return noLinkErrors_; }
+ static bool autolinkErrors() { return autolinkErrors_; }
static void setQDocPass(Passes pass) { qdocPass_ = pass; }
static bool runPrepareOnly() { return (qdocPass_ == Prepare); }
static bool runGenerateOnly() { return (qdocPass_ == Generate); }
@@ -219,6 +220,7 @@ private:
static QStringList styleFiles;
static bool debugging_;
static bool noLinkErrors_;
+ static bool autolinkErrors_;
static bool redirectDocumentationToDevNull_;
static Passes qdocPass_;
static bool useOutputSubdirs_;
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
index 2057bcd3bc..1e414578cd 100644
--- a/src/tools/qdoc/helpprojectwriter.cpp
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -612,7 +612,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
if (!project.indexRoot.isEmpty())
rootNode = qdb_->findDocNodeByTitle(project.indexRoot);
else
- rootNode = qdb_->treeRoot();
+ rootNode = qdb_->primaryTreeRoot();
if (!rootNode)
return;
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index ca52d98596..b4ea771fcc 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -264,16 +264,16 @@ QString HtmlGenerator::format()
}
/*!
- Traverses the database generating all the HTML documentation.
+ Traverses the current tree generating all the HTML documentation.
*/
-void HtmlGenerator::generateTree()
+void HtmlGenerator::generateDocs()
{
qdb_->buildCollections();
Node* qflags = qdb_->findNodeByNameAndType(QStringList("QFlags"), Node::Class, Node::NoSubType);
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
if (!runPrepareOnly()) {
- Generator::generateTree();
+ Generator::generateDocs();
generateCollisionPages();
}
@@ -303,10 +303,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
{
int skipAhead = 0;
static bool in_para = false;
-
+#if 0
if (Generator::debugging()) {
atom->dump();
}
+#endif
switch (atom->type()) {
case Atom::AbstractLeft:
if (relative)
@@ -327,6 +328,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
else {
out() << protectEnc(atom->string());
+ if (autolinkErrors())
+ relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
}
}
else {
@@ -1374,7 +1377,7 @@ void HtmlGenerator::generateCollisionPages()
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNodeByName(t.key())) {
+ if (n->findChildNode(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
@@ -1393,7 +1396,7 @@ void HtmlGenerator::generateCollisionPages()
out() << "<ul>\n";
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNodeByName(*t);
+ Node* p = n->findChildNode(*t);
if (p) {
QString link = linkForNode(p,0);
QString label;
@@ -2798,7 +2801,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative)
QMap<QString, DocNode *> uncategorizedNodeMap;
QRegExp singleDigit("\\b([0-9])\\b");
- const NodeList children = qdb_->treeRoot()->childNodes();
+ const NodeList children = qdb_->primaryTreeRoot()->childNodes();
foreach (Node *child, children) {
if (child->type() == Node::Document && child != relative) {
DocNode *docNode = static_cast<DocNode *>(child);
@@ -3149,7 +3152,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
-
const Node* n = qdb_->resolveTarget(par1.toString(), relative);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
@@ -3165,7 +3167,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
}
- // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
+ // replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
src = html;
html = QString();
@@ -3175,7 +3177,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
bool handled = false;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
- const Node* n = qdb_->resolveTarget(arg.toString(), relative);
+ const Node* n = qdb_->resolveType(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass)
@@ -3194,13 +3196,16 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
addLink(linkForNode(n,relative), arg, &html);
handled = true;
}
+#if 0
+ // Apparently, this clause was never used.
+ // <@func> is taken out above.
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = qdb_->resolveTarget(arg.toString(), relative);
addLink(linkForNode(n,relative), arg, &html);
handled = true;
}
-
+#endif
if (!handled) {
html += charLangle;
html += charAt;
@@ -3755,11 +3760,11 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
}
else {
- *node = qdb_->resolveTarget(first, relative);
- if (!*node) {
+ if (!(*node))
+ *node = qdb_->resolveTarget(first, relative);
+ if (!(*node))
*node = qdb_->findDocNodeByTitle(first, relative);
- }
- if (!*node) {
+ if (!(*node)) {
*node = qdb_->findUnambiguousTarget(first, ref, relative);
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
QString final = (*node)->url() + "#" + ref;
@@ -3768,16 +3773,13 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
}
}
if (*node) {
- if (!(*node)->url().isEmpty()) {
+ if (!(*node)->url().isEmpty())
return (*node)->url();
- }
- else {
+ else
path.removeFirst();
- }
}
- else {
+ else
*node = relative;
- }
if (*node) {
if ((*node)->status() == Node::Obsolete) {
@@ -3802,10 +3804,8 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
}
}
}
- else {
- qDebug() << "Link to Obsolete entity"
- << (*node)->name() << "no relative";
- }
+ else
+ qDebug() << "Link to Obsolete entity" << (*node)->name() << "no relative";
}
}
@@ -3833,9 +3833,8 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
link = linkForNode(*node, relative);
if (*node && (*node)->subType() == Node::Image)
link = "images/used-in-examples/" + link;
- if (!ref.isEmpty()) {
+ if (!ref.isEmpty())
link += QLatin1Char('#') + ref;
- }
}
}
return link;
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index 476bd58452..45b1a327cf 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -88,7 +88,7 @@ public:
virtual void initializeGenerator(const Config& config);
virtual void terminateGenerator();
virtual QString format();
- virtual void generateTree();
+ virtual void generateDocs();
void generateCollisionPages();
void generateManifestFiles();
diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp
index a5da6b3edd..9e0aecf393 100644
--- a/src/tools/qdoc/main.cpp
+++ b/src/tools/qdoc/main.cpp
@@ -78,6 +78,7 @@ static bool highlighting = false;
static bool showInternal = false;
static bool redirectDocumentationToDevNull = false;
static bool noLinkErrors = false;
+static bool autolinkErrors = false;
static bool obsoleteLinks = false;
static QStringList defines;
static QStringList dependModules;
@@ -282,6 +283,7 @@ static void processQdocconfFile(const QString &fileName)
config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false"));
config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false"));
config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false"));
+ config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false"));
config.setStringList(CONFIG_OBSOLETELINKS, QStringList(obsoleteLinks ? "true" : "false"));
/*
@@ -371,6 +373,8 @@ static void processQdocconfFile(const QString &fileName)
//if (!Generator::runPrepareOnly())
loadIndexFiles(config);
+ qdb->newPrimaryTree(config.getString(CONFIG_PROJECT));
+ qdb->setSearchOrder();
QSet<QString> excludedDirs;
QSet<QString> excludedFiles;
@@ -379,7 +383,7 @@ static void processQdocconfFile(const QString &fileName)
QStringList excludedDirsList;
QStringList excludedFilesList;
- Generator::debugSegfault("Reading excludedirs");
+ Generator::debug("Reading excludedirs");
excludedDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS);
foreach (const QString &excludeDir, excludedDirsList) {
QString p = QDir::fromNativeSeparators(excludeDir);
@@ -388,14 +392,14 @@ static void processQdocconfFile(const QString &fileName)
excludedDirs.insert(p);
}
- Generator::debugSegfault("Reading excludefiles");
+ Generator::debug("Reading excludefiles");
excludedFilesList = config.getCleanPathList(CONFIG_EXCLUDEFILES);
foreach (const QString& excludeFile, excludedFilesList) {
QString p = QDir::fromNativeSeparators(excludeFile);
excludedFiles.insert(p);
}
- Generator::debugSegfault("Reading headerdirs");
+ Generator::debug("Reading headerdirs");
headerList = config.getAllFiles(CONFIG_HEADERS,CONFIG_HEADERDIRS,excludedDirs,excludedFiles);
QMap<QString,QString> headers;
QMultiMap<QString,QString> headerFileNames;
@@ -409,7 +413,7 @@ static void processQdocconfFile(const QString &fileName)
headerFileNames.insert(t,t);
}
- Generator::debugSegfault("Reading sourcedirs");
+ Generator::debug("Reading sourcedirs");
sourceList = config.getAllFiles(CONFIG_SOURCES,CONFIG_SOURCEDIRS,excludedDirs,excludedFiles);
QMap<QString,QString> sources;
QMultiMap<QString,QString> sourceFileNames;
@@ -426,7 +430,7 @@ static void processQdocconfFile(const QString &fileName)
Find all the qdoc files in the example dirs, and add
them to the source files to be parsed.
*/
- Generator::debugSegfault("Reading exampledirs");
+ Generator::debug("Reading exampledirs");
QStringList exampleQdocList = config.getExampleQdocFiles(excludedDirs, excludedFiles);
for (int i=0; i<exampleQdocList.size(); ++i) {
if (!sources.contains(exampleQdocList[i])) {
@@ -436,7 +440,7 @@ static void processQdocconfFile(const QString &fileName)
}
}
- Generator::debugSegfault("Adding doc/image dirs found in exampledirs to imagedirs");
+ Generator::debug("Adding doc/image dirs found in exampledirs to imagedirs");
QSet<QString> exampleImageDirs;
QStringList exampleImageList = config.getExampleImageFiles(excludedDirs, excludedFiles);
for (int i=0; i<exampleImageList.size(); ++i) {
@@ -454,8 +458,9 @@ static void processQdocconfFile(const QString &fileName)
to the big tree.
*/
QSet<CodeParser *> usedParsers;
+ //Config::debug_ = true;
- Generator::debugSegfault("Parsing header files");
+ Generator::debug("Parsing header files");
int parsed = 0;
QMap<QString,QString>::ConstIterator h = headers.constBegin();
while (h != headers.constEnd()) {
@@ -479,17 +484,21 @@ static void processQdocconfFile(const QString &fileName)
add it to the big tree.
*/
parsed = 0;
- Generator::debugSegfault("Parsing source files");
+ Generator::debug("Parsing source files");
QMap<QString,QString>::ConstIterator s = sources.constBegin();
while (s != sources.constEnd()) {
CodeParser *codeParser = CodeParser::parserForSourceFile(s.key());
if (codeParser) {
++parsed;
+ //Generator::setDebugFlag(true);
+ Generator::debug(QString("Parsing " + s.key()));
codeParser->parseSourceFile(config.location(), s.key());
usedParsers.insert(codeParser);
}
++s;
}
+ Generator::debug(QString("Parsing done."));
+ //Generator::setDebugFlag(false);
foreach (CodeParser *codeParser, usedParsers)
codeParser->doneParsingSourceFiles();
@@ -499,7 +508,7 @@ static void processQdocconfFile(const QString &fileName)
source files. Resolve all the class names, function names,
targets, URLs, links, and other stuff that needs resolving.
*/
- Generator::debugSegfault("Resolving stuff prior to generating docs");
+ Generator::debug("Resolving stuff prior to generating docs");
qdb->resolveIssues();
/*
@@ -508,19 +517,19 @@ static void processQdocconfFile(const QString &fileName)
documentation output. More than one output format can be
requested. The tree is traversed for each one.
*/
- Generator::debugSegfault("Generating docs");
+ Generator::debug("Generating docs");
QSet<QString>::ConstIterator of = outputFormats.constBegin();
while (of != outputFormats.constEnd()) {
Generator* generator = Generator::generatorForFormat(*of);
if (generator == 0)
outputFormatsLocation.fatal(QCoreApplication::translate("QDoc", "Unknown output format '%1'").arg(*of));
- generator->generateTree();
+ generator->generateDocs();
++of;
}
//Generator::writeOutFileNames();
- Generator::debugSegfault("Shutting down qdoc");
+ Generator::debug("Shutting down qdoc");
QDocDatabase::qdocDB()->setVersion(QString());
Generator::terminate();
@@ -541,7 +550,7 @@ static void processQdocconfFile(const QString &fileName)
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): qdoc database deleted";
#endif
- Generator::debugSegfault("qdoc finished!");
+ Generator::debug("qdoc finished!");
}
QT_END_NAMESPACE
@@ -641,8 +650,11 @@ int main(int argc, char **argv)
else if (opt == "-no-link-errors") {
noLinkErrors = true;
}
+ else if (opt == "-autolink-errors") {
+ autolinkErrors = true;
+ }
else if (opt == "-debug") {
- Generator::setDebugSegfaultFlag(true);
+ Generator::setDebugFlag(true);
}
else if (opt == "-prepare") {
Generator::setQDocPass(Generator::Prepare);
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
index 6399616725..fcc79ff11c 100644
--- a/src/tools/qdoc/node.cpp
+++ b/src/tools/qdoc/node.cpp
@@ -764,7 +764,7 @@ void InnerNode::getMemberClasses(NodeMap& out)
sure to also look in the children of its property
group nodes. Return the matching node or 0.
*/
-Node *InnerNode::findChildNodeByName(const QString& name) const
+Node *InnerNode::findChildNode(const QString& name) const
{
Node *node = childMap.value(name);
if (node && !node->isQmlPropertyGroup())
@@ -773,7 +773,7 @@ Node *InnerNode::findChildNodeByName(const QString& name) const
for (int i=0; i<children_.size(); ++i) {
Node* n = children_.at(i);
if (n->isQmlPropertyGroup()) {
- node = static_cast<InnerNode*>(n)->findChildNodeByName(name);
+ node = static_cast<InnerNode*>(n)->findChildNode(name);
if (node)
return node;
}
@@ -783,61 +783,6 @@ Node *InnerNode::findChildNodeByName(const QString& name) const
}
/*!
- */
-void InnerNode::findNodes(const QString& name, QList<Node*>& n)
-{
- n.clear();
- Node* node = 0;
- QList<Node*> nodes = childMap.values(name);
- /*
- <sigh> If this node's child map contains no nodes named
- name, then if this node is a QML class, search each of its
- property group nodes for a node named name. If a match is
- found, append it to the output list and return immediately.
- */
- if (nodes.isEmpty()) {
- if (isQmlType()) {
- for (int i=0; i<children_.size(); ++i) {
- node = children_.at(i);
- if (node->isQmlPropertyGroup()) {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
- if (node) {
- n.append(node);
- return;
- }
- }
- }
- }
- }
- else {
- /*
- If the childMap does contain one or more nodes named
- name, traverse the list of matching nodes. Append each
- matching node that is not a property group node to the
- output list. Search each property group node for a node
- named name and append that node to the output list.
- This is overkill, I think, but should produce a useful
- list.
- */
- for (int i=0; i<nodes.size(); ++i) {
- node = nodes.at(i);
- if (!node->isQmlPropertyGroup())
- n.append(node);
- else {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
- if (node)
- n.append(node);
- }
- }
- }
- if (!n.isEmpty())
- return;
- node = primaryFunctionMap.value(name);
- if (node)
- n.append(node);
-}
-
-/*!
Find the node in this node's children that has the given \a name. If
this node is a QML class node, be sure to also look in the children
of its property group nodes. Return the matching node or 0. This is
@@ -847,7 +792,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
returns \c true. If \a qml is false, only match a node for which
node->isQmlNode() returns \c false.
*/
-Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
+Node* InnerNode::findChildNode(const QString& name, bool qml) const
{
QList<Node*> nodes = childMap.values(name);
if (!nodes.isEmpty()) {
@@ -865,7 +810,7 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
for (int i=0; i<children_.size(); ++i) {
Node* node = children_.at(i);
if (node->isQmlPropertyGroup()) {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
if (node)
return node;
}
@@ -875,7 +820,7 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
}
/*!
- This function is like findChildNodeByName(), but if a node
+ This function is like findChildNode(), but if a node
with the specified \a name is found but it is not of the
specified \a type, 0 is returned.
@@ -885,7 +830,7 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
node because it looks up \a name in the child map, not the
list.
*/
-Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
+Node* InnerNode::findChildNode(const QString& name, Type type)
{
if (type == Function)
return primaryFunctionMap.value(name);
@@ -901,6 +846,61 @@ Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
}
/*!
+ */
+void InnerNode::findNodes(const QString& name, QList<Node*>& n)
+{
+ n.clear();
+ Node* node = 0;
+ QList<Node*> nodes = childMap.values(name);
+ /*
+ <sigh> If this node's child map contains no nodes named
+ name, then if this node is a QML class, search each of its
+ property group nodes for a node named name. If a match is
+ found, append it to the output list and return immediately.
+ */
+ if (nodes.isEmpty()) {
+ if (isQmlType()) {
+ for (int i=0; i<children_.size(); ++i) {
+ node = children_.at(i);
+ if (node->isQmlPropertyGroup()) {
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
+ if (node) {
+ n.append(node);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /*
+ If the childMap does contain one or more nodes named
+ name, traverse the list of matching nodes. Append each
+ matching node that is not a property group node to the
+ output list. Search each property group node for a node
+ named name and append that node to the output list.
+ This is overkill, I think, but should produce a useful
+ list.
+ */
+ for (int i=0; i<nodes.size(); ++i) {
+ node = nodes.at(i);
+ if (!node->isQmlPropertyGroup())
+ n.append(node);
+ else {
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
+ if (node)
+ n.append(node);
+ }
+ }
+ }
+ if (!n.isEmpty())
+ return;
+ node = primaryFunctionMap.value(name);
+ if (node)
+ n.append(node);
+}
+
+/*!
Find a function node that is a child of this nose, such
that the function node has the specified \a name.
*/
@@ -1259,6 +1259,17 @@ void InnerNode::addChild(Node *child)
}
/*!
+ Adds the \a child to this node's child map using \a title
+ as the key. The \a child is not added to the child list
+ again, because it is presumed to already be there. We just
+ want to be able to find the child by its \a title.
+ */
+void InnerNode::addChild(Node* child, const QString& title)
+{
+ childMap.insertMulti(title, child);
+}
+
+/*!
*/
void InnerNode::removeChild(Node *child)
{
@@ -1288,6 +1299,16 @@ void InnerNode::removeChild(Node *child)
}
++ent;
}
+ if (child->title().isEmpty())
+ return;
+ ent = childMap.find(child->title());
+ while (ent != childMap.end() && ent.key() == child->title()) {
+ if (*ent == child) {
+ childMap.erase(ent);
+ break;
+ }
+ ++ent;
+ }
}
/*!
@@ -1533,7 +1554,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
while (bc != baseClasses().constEnd()) {
ClassNode* cn = bc->node_;
if (cn) {
- Node* n = cn->findChildNodeByNameAndType(pn->name(), Node::Property);
+ Node* n = cn->findChildNode(pn->name(), Node::Property);
if (n) {
PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
cn->fixPropertyUsingBaseClasses(baseProperty);
@@ -1552,7 +1573,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
*/
PropertyNode* ClassNode::findPropertyNode(const QString& name)
{
- Node* n = findChildNodeByNameAndType(name, Node::Property);
+ Node* n = findChildNode(name, Node::Property);
if (n)
return static_cast<PropertyNode*>(n);
@@ -1666,6 +1687,15 @@ QString DocNode::title() const
}
/*!
+ Sets the document node's \a title. This is used for the page title.
+ */
+void DocNode::setTitle(const QString &title)
+{
+ title_ = title;
+ parent()->addChild(this, title);
+}
+
+/*!
Returns the document node's full title, which is usually
just title(), but for some SubType values is different
from title()
diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h
index ea21e9dcd9..487da9f10e 100644
--- a/src/tools/qdoc/node.h
+++ b/src/tools/qdoc/node.h
@@ -339,9 +339,9 @@ class InnerNode : public Node
public:
virtual ~InnerNode();
- Node* findChildNodeByName(const QString& name) const;
- Node* findChildNodeByName(const QString& name, bool qml) const;
- Node* findChildNodeByNameAndType(const QString& name, Type type);
+ Node* findChildNode(const QString& name) const;
+ Node* findChildNode(const QString& name, bool qml) const;
+ Node* findChildNode(const QString& name, Type type);
void findNodes(const QString& name, QList<Node*>& n);
FunctionNode* findFunctionNode(const QString& name) const;
FunctionNode* findFunctionNode(const FunctionNode* clone);
@@ -382,6 +382,7 @@ public:
virtual void setOutputFileName(const QString& f) { outputFileName_ = f; }
virtual QString outputFileName() const { return outputFileName_; }
virtual QmlPropertyNode* hasQmlProperty(const QString& ) const;
+ void addChild(Node* child, const QString& title);
void printChildren(const QString& title);
void printMembers(const QString& title);
@@ -508,7 +509,7 @@ public:
virtual ~DocNode() { }
void setQtVariable(const QString &variable) { qtVariable_ = variable; }
- void setTitle(const QString &title) { title_ = title; }
+ void setTitle(const QString &title);
void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
QString qtVariable() const { return qtVariable_; }
@@ -838,8 +839,6 @@ private:
QString def;
};
-class PropertyNode;
-
class FunctionNode : public LeafNode
{
public:
diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp
index 644fe05438..e8292e787e 100644
--- a/src/tools/qdoc/puredocparser.cpp
+++ b/src/tools/qdoc/puredocparser.cpp
@@ -202,7 +202,7 @@ bool PureDocParser::processQdocComments()
}
}
- Node* treeRoot = QDocDatabase::qdocDB()->treeRoot();
+ Node* treeRoot = QDocDatabase::qdocDB()->primaryTreeRoot();
NodeList::Iterator n = nodes.begin();
QList<Doc>::Iterator d = docs.begin();
while (n != nodes.end()) {
diff --git a/src/tools/qdoc/puredocparser.h b/src/tools/qdoc/puredocparser.h
index 0174af7a4e..b664367527 100644
--- a/src/tools/qdoc/puredocparser.h
+++ b/src/tools/qdoc/puredocparser.h
@@ -56,7 +56,6 @@ QT_BEGIN_NAMESPACE
class Config;
class Node;
class QString;
-class Tree;
class PureDocParser : public CppCodeParser
{
diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp
index bbcb92c30d..79e323f0b0 100644
--- a/src/tools/qdoc/qdocdatabase.cpp
+++ b/src/tools/qdoc/qdocdatabase.cpp
@@ -52,45 +52,378 @@ QT_BEGIN_NAMESPACE
static NodeMap emptyNodeMap_;
static NodeMultiMap emptyNodeMultiMap_;
+/*! \class QDocForest
+ This class manages a collection of trees. Each tree is an
+ instance of class Tree, which is a private class.
+
+ The forest is populated as each index file is loaded.
+ Each index file adds a tree to the forest. Each tree
+ is named with the name of the module it represents.
+
+ The search order is created by searchOrder(), if it has
+ not already been created. The search order and module
+ names arrays have parallel structure, i.e. modulNames_[i]
+ is the module name of the Tree at searchOrder_[i].
+ */
+
+/*!
+ Destroys the qdoc forest. This requires deleting
+ each Tree in the forest. Note that the forest has
+ been transferred into the search order array, so
+ what is really being used to destroy the forest
+ is the search order array.
+ */
+QDocForest::~QDocForest()
+{
+ for (int i=0; i<searchOrder_.size(); ++i)
+ delete searchOrder_.at(i);
+ forest_.clear();
+ searchOrder_.clear();
+ moduleNames_.clear();
+ primaryTree_ = 0;
+}
+
+/*!
+ Initializes the forest prior to a traversal and
+ returns a pointer to the root node of the primary
+ tree. If the forest is empty, it return 0
+ */
+NamespaceNode* QDocForest::firstRoot()
+{
+ currentIndex_ = 0;
+ return (!searchOrder_.isEmpty() ? searchOrder_[0]->root() : 0);
+}
+
+/*!
+ Increments the forest's current tree index. If the current
+ tree index is still within the forest, the function returns
+ the root node of the current tree. Otherwise it returns 0.
+ */
+NamespaceNode* QDocForest::nextRoot()
+{
+ ++currentIndex_;
+ return (currentIndex_ < searchOrder_.size() ? searchOrder_[currentIndex_]->root() : 0);
+}
+
+/*!
+ Initializes the forest prior to a traversal and
+ returns a pointer to the primary tree. If the
+ forest is empty, it returns 0.
+ */
+Tree* QDocForest::firstTree()
+{
+ currentIndex_ = 0;
+ return (!searchOrder_.isEmpty() ? searchOrder_[0] : 0);
+}
+
+/*!
+ Increments the forest's current tree index. If the current
+ tree index is still within the forest, the function returns
+ the pointer to the current tree. Otherwise it returns 0.
+ */
+Tree* QDocForest::nextTree()
+{
+ ++currentIndex_;
+ return (currentIndex_ < searchOrder_.size() ? searchOrder_[currentIndex_] : 0);
+}
+
+/*!
+ \fn Tree* QDocForest::primaryTree()
+
+ Returns the pointer to the primary tree.
+ */
+
+/*!
+ If the search order array is empty, create the search order.
+ If the search order array is not empty, do nothing.
+ */
+void QDocForest::setSearchOrder()
+{
+ if (!searchOrder_.isEmpty())
+ return;
+ QString primaryName = primaryTree()->moduleName();
+ searchOrder_.clear();
+ searchOrder_.reserve(forest_.size()+1);
+ moduleNames_.reserve(forest_.size()+1);
+ searchOrder_.append(primaryTree_);
+ moduleNames_.append(primaryName);
+ QMap<QString, Tree*>::iterator i;
+ if (primaryName != "QtCore") {
+ i = forest_.find("QtCore");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtCore");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtGui") {
+ i = forest_.find("QtGui");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtGui");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtNetwork") {
+ i = forest_.find("QtNetwork");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtNetwork");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtOpenGL") {
+ i = forest_.find("QtOpenGL");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtOpenGL");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtWidgets") {
+ i = forest_.find("QtWidgets");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtWidgets");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtSql") {
+ i = forest_.find("QtSql");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtSql");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtXml") {
+ i = forest_.find("QtXml");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtXml");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtSvg") {
+ i = forest_.find("QtSvg");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtSvg");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtDoc") {
+ i = forest_.find("QtDoc");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtDoc");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtQuick") {
+ i = forest_.find("QtQuick");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtQuick");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtQml") {
+ i = forest_.find("QtQml");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtQml");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtPrintSupport") {
+ i = forest_.find("QtPrintSupport");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtPrintSupport");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtGraphicalEffects") {
+ i = forest_.find("QtGraphicalEffects");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtGraphicalEffects");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtConcurrent") {
+ i = forest_.find("QtConcurrent");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtConcurrent");
+ forest_.erase(i);
+ }
+ }
+#if 0
+ if (primaryName != "zzz") {
+ i = forest_.find("zzz");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("zzz");
+ forest_.erase(i);
+ }
+ }
+#endif
+ /*
+ If any trees remain in the forest, just add them
+ to the search order sequentially, because we don't
+ know any better at this point.
+ */
+ if (!forest_.isEmpty()) {
+ i = forest_.begin();
+ while (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append(i.key());
+ ++i;
+ }
+ forest_.clear();
+ }
+#if 0
+ qDebug() << " SEARCH ORDER:";
+ for (int i=0; i<moduleNames_.size(); ++i)
+ qDebug() << " " << i+1 << "." << moduleNames_.at(i);
+#endif
+}
+
+/*!
+ Returns an ordered array of Tree pointers that represents
+ the order in which the trees should be searched. The first
+ Tree in the array is the tree for the current module, i.e.
+ the module for which qdoc is generating documentation.
+
+ The other Tree pointers in the array represent the index
+ files that were loaded in preparation for generating this
+ module's documentation. Each Tree pointer represents one
+ index file. The index file Tree points have been ordered
+ heuristically to, hopefully, minimize searching. Thr order
+ will probably be changed.
+
+ If the search order array is empty, this function calls
+ setSearchOrder() to create the search order.
+ */
+const QVector<Tree*>& QDocForest::searchOrder()
+{
+ if (searchOrder_.isEmpty())
+ setSearchOrder();
+ return searchOrder_;
+}
+
+/*!
+ Create a new Tree for the index file for the specified
+ \a module and add it to the forest. Return the pointer
+ to its root.
+ */
+NamespaceNode* QDocForest::newIndexTree(const QString& module)
+{
+ primaryTree_ = new Tree(module, qdb_);
+ forest_.insert(module, primaryTree_);
+ return primaryTree_->root();
+}
+
+/*!
+ Create a new Tree for use as the primary tree. This tree
+ will represent the primary module.
+ */
+void QDocForest::newPrimaryTree(const QString& module)
+{
+ primaryTree_ = new Tree(module, qdb_);
+}
+
+/*!
+ Searches the Tree \a t for a node named \a target and returns
+ a pointer to it if found. The \a relative node is the starting
+ point, but it only makes sense in the primary tree. Therefore,
+ when this function is called with \a t being an index tree,
+ \a relative is 0. When relative is 0, the root node of \a t is
+ the starting point.
+ */
+const Node* QDocForest::resolveTargetHelper(const QString& target,
+ const Node* relative,
+ Tree* t)
+{
+ const Node* node = 0;
+ if (target.endsWith("()")) {
+ QString funcName = target;
+ funcName.chop(2);
+ QStringList path = funcName.split("::");
+ const FunctionNode* fn = t->findFunctionNode(path, relative, SearchBaseClasses);
+ if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
+ node = fn;
+ }
+ else {
+ QStringList path = target.split("::");
+ int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+ node = t->findNode(path, relative, flags);
+ if (!node) {
+ QStringList path = target.split("::");
+ const FunctionNode* fn = t->findFunctionNode(path, relative, SearchBaseClasses);
+ if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
+ node = fn;
+ }
+ }
+ return node;
+}
+
+/*!
+ Searches the Tree \a t for a type node named by the \a path
+ and returns a pointer to it if found. The \a relative node
+ is the starting point, but it only makes sense when searching
+ the primary tree. Therefore, when this function is called with
+ \a t being an index tree, \a relative is 0. When relative is 0,
+ the root node of \a t is the starting point.
+ */
+const Node* QDocForest::resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t)
+{
+ int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+ return t->findNode(path, relative, flags);
+}
+
/*! \class QDocDatabase
+ This class provides exclusive access to the qdoc database,
+ which consists of a forrest of trees and a lot of maps and
+ other useful data structures.
*/
QDocDatabase* QDocDatabase::qdocDB_ = NULL;
+NodeMap QDocDatabase::typeNodeMap_;
/*!
- Constructs the singleton qdoc database object.
- It constructs a singleton Tree object with this
- qdoc database pointer.
+ Constructs the singleton qdoc database object. The singleton
+ constructs the \a forest_ object, which is also a singleton.
+ \a showInternal_ is normally false. If it is true, qdoc will
+ write documentation for nodes marked \c internal.
*/
-QDocDatabase::QDocDatabase() : showInternal_(false)
+QDocDatabase::QDocDatabase() : showInternal_(false), forest_(this)
{
- tree_ = new Tree(this);
+ // nothing
}
/*!
- Destroys the qdoc database object. This requires deleting
- the tree of nodes, which deletes each node.
+ Destroys the qdoc database object. This requires destroying
+ the forest object, which contains an array of tree pointers.
+ Each tree is deleted.
*/
QDocDatabase::~QDocDatabase()
{
masterMap_.clear();
- delete tree_;
}
-/*! \fn Tree* QDocDatabase::tree()
- Returns the pointer to the tree. This function is for compatibility
- with the current qdoc. It will be removed when the QDocDatabase class
- replaces the current structures.
- */
-
/*!
Creates the singleton. Allows only one instance of the class
to be created. Returns a pointer to the singleton.
*/
QDocDatabase* QDocDatabase::qdocDB()
{
- if (!qdocDB_)
+ if (!qdocDB_) {
qdocDB_ = new QDocDatabase;
+ initializeDB();
+ }
return qdocDB_;
}
@@ -106,6 +439,166 @@ void QDocDatabase::destroyQdocDB()
}
/*!
+ Initialize data structures in the singleton qdoc database.
+
+ In particular, the type node map is initialized with a lot
+ type names that don't refer to documented types. For example,
+ the C++ standard types are included. These might be documented
+ here at some point, but for now they are not. Other examples
+ include \c array and \c data, which are just generic names
+ used as place holders in function signatures that appear in
+ the documentation.
+ */
+void QDocDatabase::initializeDB()
+{
+ typeNodeMap_.insert( "accepted", 0);
+ typeNodeMap_.insert( "actionPerformed", 0);
+ typeNodeMap_.insert( "activated", 0);
+ typeNodeMap_.insert( "alias", 0);
+ typeNodeMap_.insert( "anchors", 0);
+ typeNodeMap_.insert( "any", 0);
+ typeNodeMap_.insert( "array", 0);
+ typeNodeMap_.insert( "autoSearch", 0);
+ typeNodeMap_.insert( "axis", 0);
+ typeNodeMap_.insert( "backClicked", 0);
+ typeNodeMap_.insert( "bool", 0);
+ typeNodeMap_.insert( "boomTime", 0);
+ typeNodeMap_.insert( "border", 0);
+ typeNodeMap_.insert( "buttonClicked", 0);
+ typeNodeMap_.insert( "callback", 0);
+ typeNodeMap_.insert( "char", 0);
+ typeNodeMap_.insert( "clicked", 0);
+ typeNodeMap_.insert( "close", 0);
+ typeNodeMap_.insert( "closed", 0);
+ typeNodeMap_.insert( "color", 0);
+ typeNodeMap_.insert( "cond", 0);
+ typeNodeMap_.insert( "data", 0);
+ typeNodeMap_.insert( "dataReady", 0);
+ typeNodeMap_.insert( "dateString", 0);
+ typeNodeMap_.insert( "dateTimeString", 0);
+ typeNodeMap_.insert( "datetime", 0);
+ typeNodeMap_.insert( "day", 0);
+ typeNodeMap_.insert( "deactivated", 0);
+ typeNodeMap_.insert( "double", 0);
+ typeNodeMap_.insert( "drag", 0);
+ typeNodeMap_.insert( "easing", 0);
+ typeNodeMap_.insert( "enumeration", 0);
+ typeNodeMap_.insert( "error", 0);
+ typeNodeMap_.insert( "exposure", 0);
+ typeNodeMap_.insert( "fatalError", 0);
+ typeNodeMap_.insert( "fileSelected", 0);
+ typeNodeMap_.insert( "flags", 0);
+ typeNodeMap_.insert( "float", 0);
+ typeNodeMap_.insert( "focus", 0);
+ typeNodeMap_.insert( "focusZone", 0);
+ typeNodeMap_.insert( "format", 0);
+ typeNodeMap_.insert( "framePainted", 0);
+ typeNodeMap_.insert( "from", 0);
+ typeNodeMap_.insert( "frontClicked", 0);
+ typeNodeMap_.insert( "function", 0);
+ typeNodeMap_.insert( "hasOpened", 0);
+ typeNodeMap_.insert( "hovered", 0);
+ typeNodeMap_.insert( "hoveredTitle", 0);
+ typeNodeMap_.insert( "hoveredUrl", 0);
+ typeNodeMap_.insert( "imageCapture", 0);
+ typeNodeMap_.insert( "imageProcessing", 0);
+ typeNodeMap_.insert( "index", 0);
+ typeNodeMap_.insert( "initialized", 0);
+ typeNodeMap_.insert( "int", 0);
+ typeNodeMap_.insert( "isLoaded", 0);
+ typeNodeMap_.insert( "item", 0);
+ typeNodeMap_.insert( "jsdict", 0);
+ typeNodeMap_.insert( "jsobject", 0);
+ typeNodeMap_.insert( "key", 0);
+ typeNodeMap_.insert( "keysequence", 0);
+ typeNodeMap_.insert( "list", 0);
+ typeNodeMap_.insert( "listViewClicked", 0);
+ typeNodeMap_.insert( "loadRequest", 0);
+ typeNodeMap_.insert( "locale", 0);
+ typeNodeMap_.insert( "location", 0);
+ typeNodeMap_.insert( "long", 0);
+ typeNodeMap_.insert( "message", 0);
+ typeNodeMap_.insert( "messageReceived", 0);
+ typeNodeMap_.insert( "mode", 0);
+ typeNodeMap_.insert( "month", 0);
+ typeNodeMap_.insert( "name", 0);
+ typeNodeMap_.insert( "number", 0);
+ typeNodeMap_.insert( "object", 0);
+ typeNodeMap_.insert( "offset", 0);
+ typeNodeMap_.insert( "ok", 0);
+ typeNodeMap_.insert( "openCamera", 0);
+ typeNodeMap_.insert( "openImage", 0);
+ typeNodeMap_.insert( "openVideo", 0);
+ typeNodeMap_.insert( "padding", 0);
+ typeNodeMap_.insert( "parent", 0);
+ typeNodeMap_.insert( "path", 0);
+ typeNodeMap_.insert( "photoModeSelected", 0);
+ typeNodeMap_.insert( "position", 0);
+ typeNodeMap_.insert( "precision", 0);
+ typeNodeMap_.insert( "presetClicked", 0);
+ typeNodeMap_.insert( "preview", 0);
+ typeNodeMap_.insert( "previewSelected", 0);
+ typeNodeMap_.insert( "progress", 0);
+ typeNodeMap_.insert( "puzzleLost", 0);
+ typeNodeMap_.insert( "qmlSignal", 0);
+ typeNodeMap_.insert( "real", 0);
+ typeNodeMap_.insert( "rectangle", 0);
+ typeNodeMap_.insert( "request", 0);
+ typeNodeMap_.insert( "requestId", 0);
+ typeNodeMap_.insert( "section", 0);
+ typeNodeMap_.insert( "selected", 0);
+ typeNodeMap_.insert( "send", 0);
+ typeNodeMap_.insert( "settingsClicked", 0);
+ typeNodeMap_.insert( "shoe", 0);
+ typeNodeMap_.insert( "short", 0);
+ typeNodeMap_.insert( "signed", 0);
+ typeNodeMap_.insert( "sizeChanged", 0);
+ typeNodeMap_.insert( "size_t", 0);
+ typeNodeMap_.insert( "sockaddr", 0);
+ typeNodeMap_.insert( "someOtherSignal", 0);
+ typeNodeMap_.insert( "sourceSize", 0);
+ typeNodeMap_.insert( "startButtonClicked", 0);
+ typeNodeMap_.insert( "state", 0);
+ typeNodeMap_.insert( "std::initializer_list", 0);
+ typeNodeMap_.insert( "std::list", 0);
+ typeNodeMap_.insert( "std::map", 0);
+ typeNodeMap_.insert( "std::pair", 0);
+ typeNodeMap_.insert( "std::string", 0);
+ typeNodeMap_.insert( "std::vector", 0);
+ typeNodeMap_.insert( "string", 0);
+ typeNodeMap_.insert( "stringlist", 0);
+ typeNodeMap_.insert( "swapPlayers", 0);
+ typeNodeMap_.insert( "symbol", 0);
+ typeNodeMap_.insert( "t", 0);
+ typeNodeMap_.insert( "T", 0);
+ typeNodeMap_.insert( "tagChanged", 0);
+ typeNodeMap_.insert( "timeString", 0);
+ typeNodeMap_.insert( "timeout", 0);
+ typeNodeMap_.insert( "to", 0);
+ typeNodeMap_.insert( "toggled", 0);
+ typeNodeMap_.insert( "type", 0);
+ typeNodeMap_.insert( "unsigned", 0);
+ typeNodeMap_.insert( "urllist", 0);
+ typeNodeMap_.insert( "va_list", 0);
+ typeNodeMap_.insert( "value", 0);
+ typeNodeMap_.insert( "valueEmitted", 0);
+ typeNodeMap_.insert( "videoFramePainted", 0);
+ typeNodeMap_.insert( "videoModeSelected", 0);
+ typeNodeMap_.insert( "videoRecorder", 0);
+ typeNodeMap_.insert( "void", 0);
+ typeNodeMap_.insert( "volatile", 0);
+ typeNodeMap_.insert( "wchar_t", 0);
+ typeNodeMap_.insert( "x", 0);
+ typeNodeMap_.insert( "y", 0);
+ typeNodeMap_.insert( "zoom", 0);
+ typeNodeMap_.insert( "zoomTo", 0);
+}
+
+/*! \fn NamespaceNode* QDocDatabase::primaryTreeRoot()
+ Returns a pointer to the root node of the primary tree.
+ */
+
+/*!
\fn const DocNodeMap& QDocDatabase::groups() const
Returns a const reference to the collection of all
group nodes.
@@ -148,7 +641,7 @@ DocNode* QDocDatabase::findGroup(const QString& name)
DocNodeMap::const_iterator i = groups_.find(name);
if (i != groups_.end())
return i.value();
- DocNode* dn = new DocNode(tree_->root(), name, Node::Group, Node::OverviewPage);
+ DocNode* dn = new DocNode(primaryTreeRoot(), name, Node::Group, Node::OverviewPage);
dn->markNotSeen();
groups_.insert(name,dn);
if (!masterMap_.contains(name,dn))
@@ -169,7 +662,7 @@ DocNode* QDocDatabase::findModule(const QString& name)
DocNodeMap::const_iterator i = modules_.find(name);
if (i != modules_.end())
return i.value();
- DocNode* dn = new DocNode(tree_->root(), name, Node::Module, Node::OverviewPage);
+ DocNode* dn = new DocNode(primaryTreeRoot(), name, Node::Module, Node::OverviewPage);
dn->markNotSeen();
modules_.insert(name,dn);
if (!masterMap_.contains(name,dn))
@@ -190,7 +683,7 @@ QmlModuleNode* QDocDatabase::findQmlModule(const QString& name)
if (qmlModules_.contains(name))
return static_cast<QmlModuleNode*>(qmlModules_.value(name));
- QmlModuleNode* qmn = new QmlModuleNode(tree_->root(), name);
+ QmlModuleNode* qmn = new QmlModuleNode(primaryTreeRoot(), name);
qmn->markNotSeen();
qmn->setQmlModuleInfo(name);
qmlModules_.insert(name, qmn);
@@ -321,13 +814,13 @@ void QDocDatabase::addToQmlModule(const QString& name, Node* node)
If the QML module id is empty, it looks up the QML type by
\a name only.
*/
-QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name) const
+QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name)
{
if (!qmid.isEmpty())
return qmlTypeMap_.value(qmid + "::" + name);
QStringList path(name);
- Node* n = tree_->findNodeByNameAndType(path, Node::Document, Node::QmlClass, 0, true);
+ Node* n = forest_.findNodeByNameAndType(path, Node::Document, Node::QmlClass, true);
if (n) {
if (n->subType() == Node::QmlClass)
return static_cast<QmlClassNode*>(n);
@@ -391,6 +884,18 @@ void QDocDatabase::printQmlModules() const
}
/*!
+ This function calls \a func for each tree in the forest.
+ */
+void QDocDatabase::processForest(void (QDocDatabase::*func) (InnerNode*))
+{
+ Tree* t = forest_.firstTree();
+ while (t) {
+ (this->*(func))(t->root());
+ t = forest_.nextTree();
+ }
+}
+
+/*!
Traverses the database to construct useful data structures
for use when outputting certain significant collections of
things, C++ classes, QML types, "since" lists, and other
@@ -407,19 +912,27 @@ void QDocDatabase::buildCollections()
serviceClasses_.clear();
qmlClasses_.clear();
+ /*
findAllClasses(treeRoot());
findAllFunctions(treeRoot());
findAllLegaleseTexts(treeRoot());
findAllNamespaces(treeRoot());
findAllSince(treeRoot());
findAllObsoleteThings(treeRoot());
+ */
+ processForest(&QDocDatabase::findAllClasses);
+ processForest(&QDocDatabase::findAllFunctions);
+ processForest(&QDocDatabase::findAllLegaleseTexts);
+ processForest(&QDocDatabase::findAllNamespaces);
+ processForest(&QDocDatabase::findAllSince);
+ processForest(&QDocDatabase::findAllObsoleteThings);
}
/*!
Finds all the C++ class nodes and QML type nodes and
sorts them into maps.
*/
-void QDocDatabase::findAllClasses(const InnerNode* node)
+void QDocDatabase::findAllClasses(InnerNode* node)
{
NodeList::const_iterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -465,13 +978,13 @@ void QDocDatabase::findAllClasses(const InnerNode* node)
/*!
Finds all the function nodes
*/
-void QDocDatabase::findAllFunctions(const InnerNode* node)
+void QDocDatabase::findAllFunctions(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
if ((*c)->access() != Node::Private) {
if ((*c)->isInnerNode()) {
- findAllFunctions(static_cast<const InnerNode*>(*c));
+ findAllFunctions(static_cast<InnerNode*>(*c));
}
else if ((*c)->type() == Node::Function) {
const FunctionNode* func = static_cast<const FunctionNode*>(*c);
@@ -491,7 +1004,7 @@ void QDocDatabase::findAllFunctions(const InnerNode* node)
Finds all the nodes containing legalese text and puts them
in a map.
*/
-void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
+void QDocDatabase::findAllLegaleseTexts(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -499,7 +1012,7 @@ void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
if (!(*c)->doc().legaleseText().isEmpty())
legaleseTexts_.insertMulti((*c)->doc().legaleseText(), *c);
if ((*c)->isInnerNode())
- findAllLegaleseTexts(static_cast<const InnerNode *>(*c));
+ findAllLegaleseTexts(static_cast<InnerNode *>(*c));
}
++c;
}
@@ -508,13 +1021,13 @@ void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
/*!
Finds all the namespace nodes and puts them in an index.
*/
-void QDocDatabase::findAllNamespaces(const InnerNode* node)
+void QDocDatabase::findAllNamespaces(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
if ((*c)->access() != Node::Private) {
if ((*c)->isInnerNode()) {
- findAllNamespaces(static_cast<const InnerNode *>(*c));
+ findAllNamespaces(static_cast<InnerNode *>(*c));
if ((*c)->type() == Node::Namespace) {
// Ensure that the namespace's name is not empty (the root
// namespace has no name).
@@ -532,7 +1045,7 @@ void QDocDatabase::findAllNamespaces(const InnerNode* node)
maps. They can be C++ classes, QML types, or they can be
functions, enum types, typedefs, methods, etc.
*/
-void QDocDatabase::findAllObsoleteThings(const InnerNode* node)
+void QDocDatabase::findAllObsoleteThings(InnerNode* node)
{
NodeList::const_iterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -627,7 +1140,7 @@ void QDocDatabase::findAllObsoleteThings(const InnerNode* node)
This function is used for generating the "New Classes... in x.y"
section on the \e{What's New in Qt x.y} page.
*/
-void QDocDatabase::findAllSince(const InnerNode* node)
+void QDocDatabase::findAllSince(InnerNode* node)
{
NodeList::const_iterator child = node->childNodes().constBegin();
while (child != node->childNodes().constEnd()) {
@@ -742,46 +1255,37 @@ const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key) const
to generating documentation.
*/
void QDocDatabase::resolveIssues() {
- resolveQmlInheritance(treeRoot());
- resolveTargets(treeRoot());
- tree_->resolveCppToQmlLinks();
+ resolveQmlInheritance(primaryTreeRoot());
+ resolveTargets();
+ primaryTree()->resolveCppToQmlLinks();
}
/*!
- Searches the \a database for a node named \a target and returns
- a pointer to it if found.
+ This function is called for autolinking to a \a type,
+ which could be a function return type or a parameter
+ type. The tree node that represents the \a type is
+ returned. All the trees are searched until a match is
+ found. When searching the primary tree, the search
+ begins at \a relative and proceeds up the parent chain.
+ When searching the index trees, the search begins at the
+ root.
*/
-const Node* QDocDatabase::resolveTarget(const QString& target, const Node* relative)
+const Node* QDocDatabase::resolveType(const QString& type, const Node* relative)
{
- const Node* node = 0;
- if (target.endsWith("()")) {
- QString funcName = target;
- funcName.chop(2);
- QStringList path = funcName.split("::");
- const FunctionNode* fn = tree_->findFunctionNode(path, relative, SearchBaseClasses);
- if (fn) {
- /*
- Why is this case not accepted?
- */
- if (fn->metaness() != FunctionNode::MacroWithoutParams)
- node = fn;
- }
+ QStringList path = type.split("::");
+ if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString("T"))) {
+ NodeMap::iterator i = typeNodeMap_.find(path.at(0));
+ if (i != typeNodeMap_.end())
+ return i.value();
}
- else if (target.contains(QLatin1Char('#'))) {
- // This error message is never printed; I think we can remove the case.
- qDebug() << "qdoc: target case not handled:" << target;
- }
- else {
- QStringList path = target.split("::");
- int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
- node = tree_->findNode(path, relative, flags);
- }
- return node;
+ return forest_.resolveType(path, relative);
}
/*!
Finds the node that will generate the documentation that
contains the \a target and returns a pointer to it.
+
+ Can this be improved by using the target map in Tree?
*/
const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* relative)
{
@@ -800,150 +1304,6 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
}
/*!
- Inserts a new target into the target table with the specified
- \a name, \a node, and \a priority.
- */
-void QDocDatabase::insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority)
-{
- TargetRec target;
- target.type_ = type;
- target.node_ = node;
- target.priority_ = priority;
- Atom a = Atom(Atom::Target, name);
- target.ref_ = refForAtom(&a);
- targetRecMultiMap_.insert(name, target);
-}
-
-/*!
- This function searches for a \a target anchor node. If it
- finds one, it sets \a ref and returns the found node.
- */
-const Node*
-QDocDatabase::findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
-{
- TargetRec bestTarget;
- int numBestTargets = 0;
- QList<TargetRec> bestTargetList;
-
- QString key = Doc::canonicalTitle(target);
- TargetRecMultiMap::iterator i = targetRecMultiMap_.find(key);
- while (i != targetRecMultiMap_.end()) {
- if (i.key() != key)
- break;
- const TargetRec& candidate = i.value();
- if (candidate.priority_ < bestTarget.priority_) {
- bestTarget = candidate;
- bestTargetList.clear();
- bestTargetList.append(candidate);
- numBestTargets = 1;
- } else if (candidate.priority_ == bestTarget.priority_) {
- bestTargetList.append(candidate);
- ++numBestTargets;
- }
- ++i;
- }
- if (numBestTargets > 0) {
- if (numBestTargets == 1) {
- ref = bestTarget.ref_;
- return bestTarget.node_;
- }
- else if (bestTargetList.size() > 1) {
- if (relative && !relative->qmlModuleName().isEmpty()) {
- for (int i=0; i<bestTargetList.size(); ++i) {
- const Node* n = bestTargetList.at(i).node_;
- if (n && relative->qmlModuleName() == n->qmlModuleName()) {
- ref = bestTargetList.at(i).ref_;
- return n;
- }
- }
- }
- }
- }
- ref.clear();
- return 0;
-}
-
-/*!
- This function searches for a node with the specified \a title.
- If \a relative node is provided, it is used to disambiguate if
- it has a QML module identifier.
- */
-const DocNode* QDocDatabase::findDocNodeByTitle(const QString& title, const Node* relative) const
-{
- QString key = Doc::canonicalTitle(title);
- DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
- if (i != docNodesByTitle_.constEnd()) {
- if (relative && !relative->qmlModuleName().isEmpty()) {
- const DocNode* dn = i.value();
- InnerNode* parent = dn->parent();
- if (parent && parent->type() == Node::Document && parent->subType() == Node::Collision) {
- const NodeList& nl = parent->childNodes();
- NodeList::ConstIterator it = nl.constBegin();
- while (it != nl.constEnd()) {
- if ((*it)->qmlModuleName() == relative->qmlModuleName()) {
- /*
- By returning here, we avoid printing
- all the duplicate header warnings,
- which are not really duplicates now,
- because of the QML module name being
- used as a namespace qualifier.
- */
- dn = static_cast<const DocNode*>(*it);
- return dn;
- }
- ++it;
- }
- }
- }
- /*
- Reporting all these duplicate section titles is probably
- overkill. We should report the duplicate file and let
- that suffice.
- */
- DocNodeMultiMap::const_iterator j = i;
- ++j;
- if (j != docNodesByTitle_.constEnd() && j.key() == i.key()) {
- QList<Location> internalLocations;
- while (j != docNodesByTitle_.constEnd()) {
- if (j.key() == i.key() && j.value()->url().isEmpty()) {
- internalLocations.append(j.value()->location());
- break; // Just report one duplicate for now.
- }
- ++j;
- }
- if (internalLocations.size() > 0) {
- i.value()->location().warning(tr("This page title exists in more than one file: \"%1\"").arg(title));
- foreach (const Location &location, internalLocations)
- location.warning(tr("[It also exists here]"));
- }
- }
- return i.value();
- }
- return 0;
-}
-
-/*!
- This function searches for a node with a canonical title
- constructed from \a target. If the node it finds is \a node,
- it returns the ref from that node. Otherwise it returns an
- empty string.
- */
-QString QDocDatabase::findTarget(const QString& target, const Node* node) const
-{
- QString key = Doc::canonicalTitle(target);
- TargetRecMultiMap::const_iterator i = targetRecMultiMap_.constFind(key);
-
- if (i != targetRecMultiMap_.constEnd()) {
- do {
- if (i.value().node_ == node)
- return i.value().ref_;
- ++i;
- } while (i != targetRecMultiMap_.constEnd() && i.key() == key);
- }
- return QString();
-}
-
-/*!
For each QML Type node in the tree beginning at \a root,
if it has a QML base type name but its QML base type node
pointer is 0, use the QML base type name to look up the
@@ -952,7 +1312,7 @@ QString QDocDatabase::findTarget(const QString& target, const Node* node) const
*/
void QDocDatabase::resolveQmlInheritance(InnerNode* root)
{
- // Dop we need recursion?
+ // Do we need recursion?
foreach (Node* child, root->childNodes()) {
if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
@@ -987,80 +1347,6 @@ void QDocDatabase::resolveQmlInheritance(InnerNode* root)
}
/*!
- */
-void QDocDatabase::resolveTargets(InnerNode* root)
-{
- // need recursion
-
- foreach (Node* child, root->childNodes()) {
- if (child->type() == Node::Document) {
- DocNode* node = static_cast<DocNode*>(child);
- if (!node->title().isEmpty()) {
- QString key = Doc::canonicalTitle(node->title());
- QList<DocNode*> nodes = docNodesByTitle_.values(key);
- bool alreadyThere = false;
- if (!nodes.empty()) {
- for (int i=0; i< nodes.size(); ++i) {
- if (nodes[i]->subType() == Node::ExternalPage) {
- if (node->name() == nodes[i]->name()) {
- alreadyThere = true;
- break;
- }
- }
- }
- }
- if (!alreadyThere) {
- docNodesByTitle_.insert(key, node);
- }
- }
- if (node->subType() == Node::Collision) {
- resolveTargets(node);
- }
- }
-
- if (child->doc().hasTableOfContents()) {
- const QList<Atom*>& toc = child->doc().tableOfContents();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 3;
-
- for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
- QString title = Text::sectionHeading(toc.at(i)).toString();
- if (!title.isEmpty()) {
- QString key = Doc::canonicalTitle(title);
- targetRecMultiMap_.insert(key, target);
- }
- }
- }
- if (child->doc().hasKeywords()) {
- const QList<Atom*>& keywords = child->doc().keywords();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 1;
-
- for (int i = 0; i < keywords.size(); ++i) {
- target.ref_ = refForAtom(keywords.at(i));
- QString key = Doc::canonicalTitle(keywords.at(i)->string());
- targetRecMultiMap_.insert(key, target);
- }
- }
- if (child->doc().hasTargets()) {
- const QList<Atom*>& toc = child->doc().targets();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 2;
-
- for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
- QString key = Doc::canonicalTitle(toc.at(i)->string());
- targetRecMultiMap_.insert(key, target);
- }
- }
- }
-}
-
-/*!
Generates a tag file and writes it to \a name.
*/
void QDocDatabase::generateTagFile(const QString& name, Generator* g)
@@ -1095,17 +1381,6 @@ void QDocDatabase::generateIndex(const QString& fileName,
QDocIndexFiles::destroyQDocIndexFiles();
}
-QString QDocDatabase::refForAtom(const Atom* atom)
-{
- if (atom) {
- if (atom->type() == Atom::SectionLeft)
- return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
- if (atom->type() == Atom::Target)
- return Doc::canonicalTitle(atom->string());
- }
- return QString();
-}
-
/*!
If there are open namespaces, search for the function node
having the same function name as the \a clone node in each
@@ -1135,20 +1410,29 @@ FunctionNode* QDocDatabase::findNodeInOpenNamespace(const QStringList& parentPat
/*!
Find a node of the specified \a type and \a subtype that is
- reached with the specified \a path. If such a node is found
- in an open namespace, prefix \a path with the name of the
- open namespace and "::" and return a pointer to the node.
- Othewrwise return 0.
+ reached with the specified \a path qualified with the name
+ of one of the open namespaces (might not be any open ones).
+ If the node is found in an open namespace, prefix \a path
+ with the name of the open namespace and "::" and return a
+ pointer to the node. Othewrwise return 0.
+
+ This function only searches in the current primary tree.
*/
Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
Node::Type type,
Node::SubType subtype)
{
+ if (path.isEmpty())
+ return 0;
Node* n = 0;
if (!openNamespaces_.isEmpty()) {
foreach (const QString& t, openNamespaces_) {
- QStringList p = t.split("::") + path;
- n = findNodeByNameAndType(p, type, subtype);
+ QStringList p;
+ if (t != path[0])
+ p = t.split("::") + path;
+ else
+ p = path;
+ n = primaryTree()->findNodeByNameAndType(p, type, subtype);
if (n) {
path = p;
break;
diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h
index 4e50396817..8541f03106 100644
--- a/src/tools/qdoc/qdocdatabase.h
+++ b/src/tools/qdoc/qdocdatabase.h
@@ -45,6 +45,8 @@
#include <qstring.h>
#include <qmap.h>
#include "tree.h"
+#include "config.h"
+#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -54,10 +56,10 @@ typedef QMap<QString, NodeMap> NodeMapMap;
typedef QMap<QString, NodeMultiMap> NodeMultiMapMap;
typedef QMultiMap<QString, Node*> QDocMultiMap;
typedef QMap<Text, const Node*> TextToNodeMap;
-typedef QMultiMap<QString, DocNode*> DocNodeMultiMap;
class Atom;
class Generator;
+class QDocDatabase;
enum FindFlag {
SearchBaseClasses = 0x1,
@@ -65,20 +67,159 @@ enum FindFlag {
NonFunction = 0x4
};
-struct TargetRec
+class QDocForest
{
public:
- enum Type { Unknown, Target, Keyword, Contents, Class, Function, Page, Subtitle };
- TargetRec() : node_(0), priority_(INT_MAX), type_(Unknown) { }
- bool isEmpty() const { return ref_.isEmpty(); }
- //void debug(int idx, const QString& key);
- Node* node_;
- QString ref_;
- int priority_;
- Type type_;
-};
-typedef QMultiMap<QString, TargetRec> TargetRecMultiMap;
+ friend class QDocDatabase;
+ QDocForest(QDocDatabase* qdb)
+ : qdb_(qdb), primaryTree_(0), currentIndex_(0) { }
+ ~QDocForest();
+
+ NamespaceNode* firstRoot();
+ NamespaceNode* nextRoot();
+ Tree* firstTree();
+ Tree* nextTree();
+ Tree* primaryTree() { return primaryTree_; }
+ NamespaceNode* primaryTreeRoot() { return (primaryTree_ ? primaryTree_->root() : 0); }
+ bool isEmpty() const { return searchOrder_.isEmpty(); }
+ bool done() const { return (currentIndex_ >= searchOrder_.size()); }
+ const QVector<Tree*>& searchOrder();
+ void setSearchOrder();
+
+ const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
+ foreach (Tree* t, searchOrder_) {
+ const Node* n = t->findNode(path, relative, findFlags);
+ if (n) {
+ return n;
+ }
+ relative = 0;
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 1" << path;
+ return 0;
+ }
+ Node* findNodeByNameAndType(const QStringList& path,
+ Node::Type type,
+ Node::SubType subtype,
+ bool acceptCollision = false) {
+ foreach (Tree* t, searchOrder_) {
+ Node* n = t->findNodeByNameAndType(path, type, subtype, acceptCollision);
+ if (n) {
+ return n;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 2" << path << type << subtype;
+ return 0;
+ }
+
+ ClassNode* findClassNode(const QStringList& path) {
+ foreach (Tree* t, searchOrder_) {
+ ClassNode* n = t->findClassNode(path);
+ if (n) {
+ return n;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 3" << path;
+ return 0;
+ }
+
+ InnerNode* findRelatesNode(const QStringList& path) {
+ foreach (Tree* t, searchOrder_) {
+ InnerNode* n = t->findRelatesNode(path);
+ if (n) {
+ return n;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 4" << path;
+ return 0;
+ }
+
+ const Node* resolveTarget(const QString& target, const Node* relative) {
+ const Node* r = relative;
+ foreach (Tree* t, searchOrder_) {
+ const Node* n = resolveTargetHelper(target, relative, t);
+ if (n) {
+ return n;
+ }
+ relative = 0;
+ }
+ if (Config::debug_) {
+ qDebug() << "FAILED SEARCH 6" << target << r;
+ }
+ return 0;
+ }
+
+ const Node* resolveType(const QStringList& path, const Node* relative)
+ {
+ foreach (Tree* t, searchOrder_) {
+ const Node* n = resolveTypeHelper(path, relative, t);
+ if (n) {
+ return n;
+ }
+ relative = 0;
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 5" << path;
+ return 0;
+ }
+
+ QString findTarget(const QString& target, const Node* node) const
+ {
+ foreach (Tree* t, searchOrder_) {
+ QString ref = t->findTarget(target, node);
+ if (!ref.isEmpty()) {
+ return ref;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 7" << target;
+ return QString();
+ }
+
+ const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
+ {
+ foreach (Tree* t, searchOrder_) {
+ const Node* n = t->findUnambiguousTarget(target, ref, relative);
+ if (n) {
+ return n;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 8" << target;
+ return 0;
+ }
+
+ const DocNode* findDocNodeByTitle(const QString& title, const Node* relative) const
+ {
+ foreach (Tree* t, searchOrder_) {
+ const DocNode* n = t->findDocNodeByTitle(title, relative);
+ if (n) {
+ return n;
+ }
+ }
+ if (Config::debug_)
+ qDebug() << "FAILED SEARCH 9" << title;
+ return 0;
+ }
+
+ private:
+ void newPrimaryTree(const QString& module);
+ NamespaceNode* newIndexTree(const QString& module);
+ const Node* resolveTargetHelper(const QString& target, const Node* relative, Tree* t);
+ const Node* resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t);
+
+ private:
+ QDocDatabase* qdb_;
+ Tree* primaryTree_;
+ int currentIndex_;
+ QMap<QString, Tree*> forest_;
+ QVector<Tree*> searchOrder_;
+ QVector<QString> moduleNames_;
+};
class QDocDatabase
{
@@ -90,8 +231,8 @@ class QDocDatabase
~QDocDatabase();
const DocNodeMap& groups() const { return groups_; }
- const DocNodeMap& modules() const { return modules_; }
- const DocNodeMap& qmlModules() const { return qmlModules_; }
+ //const DocNodeMap& modules() const { return modules_; } // not used
+ //const DocNodeMap& qmlModules() const { return qmlModules_; } // not used
DocNode* getGroup(const QString& name);
DocNode* findGroup(const QString& name);
@@ -106,15 +247,15 @@ class QDocDatabase
DocNode* addToModule(const QString& name, Node* node);
void addToQmlModule(const QString& name, Node* node);
- QmlClassNode* findQmlType(const QString& qmid, const QString& name) const;
+ QmlClassNode* findQmlType(const QString& qmid, const QString& name);
QmlClassNode* findQmlType(const ImportRec& import, const QString& name) const;
- void findAllClasses(const InnerNode *node);
- void findAllFunctions(const InnerNode *node);
- void findAllLegaleseTexts(const InnerNode *node);
- void findAllNamespaces(const InnerNode *node);
- void findAllObsoleteThings(const InnerNode* node);
- void findAllSince(const InnerNode *node);
+ void findAllClasses(InnerNode *node);
+ void findAllFunctions(InnerNode *node);
+ void findAllLegaleseTexts(InnerNode *node);
+ void findAllNamespaces(InnerNode *node);
+ void findAllObsoleteThings(InnerNode* node);
+ void findAllSince(InnerNode *node);
void buildCollections();
// special collection access functions
@@ -137,57 +278,63 @@ class QDocDatabase
/* convenience functions
Many of these will be either eliminated or replaced.
*/
- QString refForAtom(const Atom* atom);
- Tree* tree() { return tree_; }
- NamespaceNode* treeRoot() { return tree_->root(); }
- void resolveInheritance() { tree_->resolveInheritance(); }
+ void resolveInheritance() { primaryTree()->resolveInheritance(); }
void resolveQmlInheritance(InnerNode* root);
void resolveIssues();
- void fixInheritance() { tree_->fixInheritance(); }
- void resolveProperties() { tree_->resolveProperties(); }
+ void fixInheritance() { primaryTree()->fixInheritance(); }
+ void resolveProperties() { primaryTree()->resolveProperties(); }
- /*******************************************************************
- The functions declared below don't search in the tree(s).
- ********************************************************************/
- QString findTarget(const QString &target, const Node *node) const;
- void resolveTargets(InnerNode* root);
- void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
- /*******************************************************************/
+ void resolveTargets() {
+ primaryTree()->resolveTargets(primaryTreeRoot());
+ }
+ void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority) {
+ primaryTree()->insertTarget(name, type, node, priority);
+ }
/*******************************************************************
The functions declared below are called for the current tree only.
********************************************************************/
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) {
- return tree_->findFunctionNode(parentPath, clone);
+ return primaryTree()->findFunctionNode(parentPath, clone);
}
FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype);
- NameCollisionNode* findCollisionNode(const QString& name) const {
- return tree_->findCollisionNode(name);
+ NameCollisionNode* findCollisionNode(const QString& name) {
+ return primaryTree()->findCollisionNode(name);
+ }
+ NameCollisionNode* checkForCollision(const QString& name) {
+ return primaryTree()->checkForCollision(name);
}
/*******************************************************************/
/*******************************************************************
The functions declared below are called for all trees.
********************************************************************/
- ClassNode* findClassNode(const QStringList& path) { return tree_->findClassNode(path); }
- InnerNode* findRelatesNode(const QStringList& path) { return tree_->findRelatesNode(path); }
- const Node* resolveTarget(const QString& target, const Node* relative);
+ ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
+ InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
+ QString findTarget(const QString& target, const Node* node) const {
+ return forest_.findTarget(target, node);
+ }
+ const Node* resolveTarget(const QString& target, const Node* relative) {
+ return forest_.resolveTarget(target, relative);
+ }
+ const Node* resolveType(const QString& type, const Node* relative);
const Node* findNodeForTarget(const QString& target, const Node* relative);
- const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
- const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative);
- Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
- return tree_->findNodeByNameAndType(path, type, subtype, 0);
+ const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const {
+ return forest_.findDocNodeByTitle(title, relative);
+ }
+ const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative) {
+ return forest_.findUnambiguousTarget(target, ref, relative);
}
- NameCollisionNode* checkForCollision(const QString& name) const {
- return tree_->checkForCollision(name);
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
+ return forest_.findNodeByNameAndType(path, type, subtype, false);
}
/*******************************************************************/
void addPropertyFunction(PropertyNode* property,
const QString& funcName,
PropertyNode::FunctionRole funcRole) {
- tree_->addPropertyFunction(property, funcName, funcRole);
+ primaryTree()->addPropertyFunction(property, funcName, funcRole);
}
void setVersion(const QString& v) { version_ = v; }
@@ -205,6 +352,14 @@ class QDocDatabase
void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); }
void setShowInternal(bool value) { showInternal_ = value; }
+ // Try to make this function private.
+ QDocForest& forest() { return forest_; }
+ NamespaceNode* primaryTreeRoot() { return forest_.primaryTreeRoot(); }
+ void newPrimaryTree(const QString& module) { forest_.newPrimaryTree(module); }
+ NamespaceNode* newIndexTree(const QString& module) { return forest_.newIndexTree(module); }
+ const QVector<Tree*>& searchOrder() { return forest_.searchOrder(); }
+ void setSearchOrder() { forest_.setSearchOrder(); }
+
/* debugging functions */
void printModules() const;
void printQmlModules() const;
@@ -213,17 +368,25 @@ class QDocDatabase
friend class QDocIndexFiles;
friend class QDocTagFiles;
+ const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
+ return forest_.findNode(path, relative, findFlags);
+ }
+ void processForest(void (QDocDatabase::*) (InnerNode*));
+ static void initializeDB();
+
private:
QDocDatabase();
- QDocDatabase(QDocDatabase const& ) { }; // copy constructor is private
- QDocDatabase& operator=(QDocDatabase const& ); // assignment operator is private
+ QDocDatabase(QDocDatabase const& ) : showInternal_(false), forest_(this) { }
+ QDocDatabase& operator=(QDocDatabase const& );
+ Tree* primaryTree() { return forest_.primaryTree(); }
private:
static QDocDatabase* qdocDB_;
+ static NodeMap typeNodeMap_;
bool showInternal_;
QString version_;
QDocMultiMap masterMap_;
- Tree* tree_;
+ QDocForest forest_;
DocNodeMap groups_;
DocNodeMap modules_;
DocNodeMap qmlModules_;
@@ -244,8 +407,6 @@ class QDocDatabase
NodeMultiMapMap newSinceMaps_;
NodeMapMap funcIndex_;
TextToNodeMap legaleseTexts_;
- DocNodeMultiMap docNodesByTitle_;
- TargetRecMultiMap targetRecMultiMap_;
QSet<QString> openNamespaces_;
};
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp
index 55e580427f..8d33cdcdcd 100644
--- a/src/tools/qdoc/qdocindexfiles.cpp
+++ b/src/tools/qdoc/qdocindexfiles.cpp
@@ -77,6 +77,7 @@ QDocIndexFiles::QDocIndexFiles()
QDocIndexFiles::~QDocIndexFiles()
{
qdb_ = 0;
+ gen_ = 0;
}
/*!
@@ -109,10 +110,9 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
foreach (const QString& indexFile, indexFiles) {
QString msg = "Loading index file: " + indexFile;
Location::logToStdErr(msg);
- //qDebug() << "READING INDEX:" << indexFile;
+ //qDebug() << " LOAD INDEX FILE:" << indexFile;
readIndexFile(indexFile);
}
- //qDebug() << "DONE READING INDEX FILES";
}
/*!
@@ -146,12 +146,13 @@ void QDocIndexFiles::readIndexFile(const QString& path)
basesList_.clear();
relatedList_.clear();
+ NamespaceNode* root = qdb_->newIndexTree(project_);
+
// Scan all elements in the XML file, constructing a map that contains
// base classes for each class found.
-
QDomElement child = indexElement.firstChildElement();
while (!child.isNull()) {
- readIndexSection(child, qdb_->treeRoot(), indexUrl);
+ readIndexSection(child, root, indexUrl);
child = child.nextSiblingElement();
}
@@ -523,7 +524,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
QString moduleName = element.attribute("module");
if (!moduleName.isEmpty())
- node->setModuleName(moduleName);
+ qdb_->addToModule(moduleName, node);
if (!href.isEmpty()) {
if (node->isExternalPage())
node->setUrl(href);
@@ -768,7 +769,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
return false;
writer.writeStartElement(nodeName);
@@ -1325,7 +1326,7 @@ void QDocIndexFiles::generateIndex(const QString& fileName,
writer.writeAttribute("version", qdb_->version());
writer.writeAttribute("project", g->config()->getString(CONFIG_PROJECT));
- generateIndexSections(writer, qdb_->treeRoot(), generateInternalNodes);
+ generateIndexSections(writer, qdb_->primaryTreeRoot(), generateInternalNodes);
/*
We wait until the end of the index file to output the group elements.
diff --git a/src/tools/qdoc/qdoctagfiles.cpp b/src/tools/qdoc/qdoctagfiles.cpp
index 23c10c01b5..cc2bd3f1f0 100644
--- a/src/tools/qdoc/qdoctagfiles.cpp
+++ b/src/tools/qdoc/qdoctagfiles.cpp
@@ -147,7 +147,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
continue;
// *** Write the starting tag for the element here. ***
@@ -244,7 +244,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
continue;
// *** Write the starting tag for the element here. ***
@@ -373,7 +373,7 @@ void QDocTagFiles::generateTagFile(const QString& fileName, Generator* g)
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("tagfile");
- generateTagFileCompounds(writer, qdb_->treeRoot());
+ generateTagFileCompounds(writer, qdb_->primaryTreeRoot());
writer.writeEndElement(); // tagfile
writer.writeEndDocument();
file.close();
diff --git a/src/tools/qdoc/qmlcodeparser.h b/src/tools/qdoc/qmlcodeparser.h
index 71b4660fe7..7f6f8d1a81 100644
--- a/src/tools/qdoc/qmlcodeparser.h
+++ b/src/tools/qdoc/qmlcodeparser.h
@@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE
class Config;
class Node;
class QString;
-class Tree;
class QmlCodeParser : public CodeParser
{
diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp
index ec1ef41256..d16fdfa5d4 100644
--- a/src/tools/qdoc/qmlvisitor.cpp
+++ b/src/tools/qdoc/qmlvisitor.cpp
@@ -97,7 +97,7 @@ QmlDocVisitor::QmlDocVisitor(const QString &filePath,
this->engine = engine;
this->commands_ = commands;
this->topics_ = topics;
- current = QDocDatabase::qdocDB()->treeRoot();
+ current = QDocDatabase::qdocDB()->primaryTreeRoot();
}
/*!
diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp
index 98ac64246e..45faed8e2b 100644
--- a/src/tools/qdoc/tree.cpp
+++ b/src/tools/qdoc/tree.cpp
@@ -49,8 +49,6 @@
#include <limits.h>
#include <qdebug.h>
-bool Tree::debug_ = false;
-
QT_BEGIN_NAMESPACE
/*!
@@ -62,23 +60,35 @@ QT_BEGIN_NAMESPACE
This class is now private. Only class QDocDatabase has access.
Please don't change this. If you must access class Tree, do it
though the pointer to the singleton QDocDatabase.
+
+ Tree is being converted to a forest. A static member provides a
+ map of Tree* values with the module names as the keys. There is
+ one Tree in the map for each index file read, and there is one
+ tree that is not in the map for the module whose documentation
+ is being generated.
*/
/*!
- Constructs the singleton tree. \a qdb is the pointer to the
+ Constructs a Tree. \a qdb is the pointer to the singleton
qdoc database that is constructing the tree. This might not
be necessary, and it might be removed later.
*/
-Tree::Tree(QDocDatabase* qdb)
- : qdb_(qdb), root_(0, QString())
+Tree::Tree(const QString& module, QDocDatabase* qdb)
+ : module_(module), qdb_(qdb), root_(0, QString())
{
+ root_.setModuleName(module_);
}
/*!
- Destroys the singleton Tree.
+ Destroys the Tree. The root node is a data member
+ of this object, so its destructor is called. The
+ destructor of each child node is called, and these
+ destructors are recursive. Thus the entire tree is
+ destroyed.
*/
Tree::~Tree()
{
+ // nothing
}
/* API members */
@@ -163,7 +173,7 @@ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
node as its first child, and return a pointer to the new
NameCollisionNode. Otherwise return 0.
*/
-NameCollisionNode* Tree::checkForCollision(const QString& name) const
+NameCollisionNode* Tree::checkForCollision(const QString& name)
{
Node* n = const_cast<Node*>(findNode(QStringList(name)));
if (n) {
@@ -235,7 +245,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = ((InnerNode*) node)->findFunctionNode(path.at(i));
else
- next = ((InnerNode*) node)->findChildNodeByName(path.at(i));
+ next = ((InnerNode*) node)->findChildNode(path.at(i));
if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
@@ -243,7 +253,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findFunctionNode(path.at(i));
else
- next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
if (next)
break;
@@ -539,12 +549,9 @@ NodeList Tree::allBaseClasses(const ClassNode* classNode) const
Node* Tree::findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
- Node* start,
bool acceptCollision)
{
- if (!start)
- start = const_cast<NamespaceNode*>(root());
- Node* result = findNodeRecursive(path, 0, start, type, subtype, acceptCollision);
+ Node* result = findNodeRecursive(path, 0, root(), type, subtype, acceptCollision);
return result;
}
@@ -745,14 +752,14 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
if (node == 0 || !node->isInnerNode())
break;
- const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml);
+ const Node* next = static_cast<const InnerNode*>(node)->findChildNode(path.at(i), qml);
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1)
next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) {
- next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
if (next)
@@ -776,4 +783,236 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
return 0;
}
+/*!
+ This function searches for a node with a canonical title
+ constructed from \a target. If the node it finds is \a node,
+ it returns the ref from that node. Otherwise it returns an
+ empty string.
+ */
+QString Tree::findTarget(const QString& target, const Node* node) const
+{
+ QString key = Doc::canonicalTitle(target);
+ TargetMap::const_iterator i = nodesByTarget_.constFind(key);
+ if (i != nodesByTarget_.constEnd()) {
+ do {
+ if (i.value().node_ == node)
+ return i.value().ref_;
+ ++i;
+ } while (i != nodesByTarget_.constEnd() && i.key() == key);
+ }
+ return QString();
+}
+
+/*!
+ Inserts a new target into the target table. \a name is the
+ key. The target record contains the \a type, a pointer to
+ the \a node, the \a priority. and a canonicalized form of
+ the \a name, which is later used.
+ */
+void Tree::insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority)
+{
+ TargetRec target;
+ target.type_ = type;
+ target.node_ = node;
+ target.priority_ = priority;
+ target.ref_ = Doc::canonicalTitle(name);
+ nodesByTarget_.insert(name, target);
+}
+
+/*!
+ */
+void Tree::resolveTargets(InnerNode* root)
+{
+ // need recursion
+ foreach (Node* child, root->childNodes()) {
+ if (child->type() == Node::Document) {
+ DocNode* node = static_cast<DocNode*>(child);
+ if (!node->title().isEmpty()) {
+ QString key = Doc::canonicalTitle(node->title());
+ QList<DocNode*> nodes = docNodesByTitle_.values(key);
+ bool alreadyThere = false;
+ if (!nodes.empty()) {
+ for (int i=0; i< nodes.size(); ++i) {
+ if (nodes[i]->subType() == Node::ExternalPage) {
+ if (node->name() == nodes[i]->name()) {
+ alreadyThere = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!alreadyThere) {
+ docNodesByTitle_.insert(key, node);
+ }
+ }
+ if (node->subType() == Node::Collision) {
+ resolveTargets(node);
+ }
+ }
+
+ if (child->doc().hasTableOfContents()) {
+ const QList<Atom*>& toc = child->doc().tableOfContents();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 3;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.ref_ = refForAtom(toc.at(i));
+ QString title = Text::sectionHeading(toc.at(i)).toString();
+ if (!title.isEmpty()) {
+ QString key = Doc::canonicalTitle(title);
+ nodesByTarget_.insert(key, target);
+ }
+ }
+ }
+ if (child->doc().hasKeywords()) {
+ const QList<Atom*>& keywords = child->doc().keywords();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 1;
+
+ for (int i = 0; i < keywords.size(); ++i) {
+ target.ref_ = refForAtom(keywords.at(i));
+ QString key = Doc::canonicalTitle(keywords.at(i)->string());
+ nodesByTarget_.insert(key, target);
+ }
+ }
+ if (child->doc().hasTargets()) {
+ const QList<Atom*>& toc = child->doc().targets();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 2;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.ref_ = refForAtom(toc.at(i));
+ QString key = Doc::canonicalTitle(toc.at(i)->string());
+ nodesByTarget_.insert(key, target);
+ }
+ }
+ }
+}
+
+/*!
+ This function searches for a \a target anchor node. If it
+ finds one, it sets \a ref and returns the found node.
+ */
+const Node*
+Tree::findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
+{
+ TargetRec bestTarget;
+ int numBestTargets = 0;
+ QList<TargetRec> bestTargetList;
+
+ QString key = Doc::canonicalTitle(target);
+ TargetMap::iterator i = nodesByTarget_.find(key);
+ while (i != nodesByTarget_.end()) {
+ if (i.key() != key)
+ break;
+ const TargetRec& candidate = i.value();
+ if (candidate.priority_ < bestTarget.priority_) {
+ bestTarget = candidate;
+ bestTargetList.clear();
+ bestTargetList.append(candidate);
+ numBestTargets = 1;
+ } else if (candidate.priority_ == bestTarget.priority_) {
+ bestTargetList.append(candidate);
+ ++numBestTargets;
+ }
+ ++i;
+ }
+ if (numBestTargets > 0) {
+ if (numBestTargets == 1) {
+ ref = bestTarget.ref_;
+ return bestTarget.node_;
+ }
+ else if (bestTargetList.size() > 1) {
+ if (relative && !relative->qmlModuleName().isEmpty()) {
+ for (int i=0; i<bestTargetList.size(); ++i) {
+ const Node* n = bestTargetList.at(i).node_;
+ if (n && relative->qmlModuleName() == n->qmlModuleName()) {
+ ref = bestTargetList.at(i).ref_;
+ return n;
+ }
+ }
+ }
+ }
+ }
+ ref.clear();
+ return 0;
+}
+
+/*!
+ This function searches for a node with the specified \a title.
+ If \a relative node is provided, it is used to disambiguate if
+ it has a QML module identifier.
+ */
+const DocNode* Tree::findDocNodeByTitle(const QString& title, const Node* relative) const
+{
+ QString key = Doc::canonicalTitle(title);
+ DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
+ if (i != docNodesByTitle_.constEnd()) {
+ if (relative && !relative->qmlModuleName().isEmpty()) {
+ const DocNode* dn = i.value();
+ InnerNode* parent = dn->parent();
+ if (parent && parent->type() == Node::Document && parent->subType() == Node::Collision) {
+ const NodeList& nl = parent->childNodes();
+ NodeList::ConstIterator it = nl.constBegin();
+ while (it != nl.constEnd()) {
+ if ((*it)->qmlModuleName() == relative->qmlModuleName()) {
+ /*
+ By returning here, we avoid printing
+ all the duplicate header warnings,
+ which are not really duplicates now,
+ because of the QML module name being
+ used as a namespace qualifier.
+ */
+ dn = static_cast<const DocNode*>(*it);
+ return dn;
+ }
+ ++it;
+ }
+ }
+ }
+ /*
+ Reporting all these duplicate section titles is probably
+ overkill. We should report the duplicate file and let
+ that suffice.
+ */
+ DocNodeMultiMap::const_iterator j = i;
+ ++j;
+ if (j != docNodesByTitle_.constEnd() && j.key() == i.key()) {
+ QList<Location> internalLocations;
+ while (j != docNodesByTitle_.constEnd()) {
+ if (j.key() == i.key() && j.value()->url().isEmpty()) {
+ internalLocations.append(j.value()->location());
+ break; // Just report one duplicate for now.
+ }
+ ++j;
+ }
+ if (internalLocations.size() > 0) {
+ i.value()->location().warning("This page title exists in more than one file: " + title);
+ foreach (const Location &location, internalLocations)
+ location.warning("[It also exists here]");
+ }
+ }
+ return i.value();
+ }
+ return 0;
+}
+
+/*!
+ Returns a canonical title for the \a atom, if the \a atom
+ is a SectionLeft or a Target.
+ */
+QString Tree::refForAtom(const Atom* atom)
+{
+ if (atom) {
+ if (atom->type() == Atom::SectionLeft)
+ return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
+ if (atom->type() == Atom::Target)
+ return Doc::canonicalTitle(atom->string());
+ }
+ return QString();
+}
+
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h
index e1a08dd471..1fe0046ae5 100644
--- a/src/tools/qdoc/tree.h
+++ b/src/tools/qdoc/tree.h
@@ -46,6 +46,7 @@
#ifndef TREE_H
#define TREE_H
+#include <QtCore/qstack.h>
#include "node.h"
QT_BEGIN_NAMESPACE
@@ -53,23 +54,36 @@ QT_BEGIN_NAMESPACE
class QStringList;
class QDocDatabase;
+struct TargetRec
+{
+ public:
+ enum Type { Unknown, Target, Keyword, Contents, Class, Function, Page, Subtitle };
+ TargetRec() : node_(0), priority_(INT_MAX), type_(Unknown) { }
+ bool isEmpty() const { return ref_.isEmpty(); }
+ Node* node_;
+ QString ref_;
+ int priority_;
+ Type type_;
+};
+typedef QMultiMap<QString, TargetRec> TargetMap;
+typedef QMultiMap<QString, DocNode*> DocNodeMultiMap;
+
class Tree
{
private:
+ friend class QDocForest;
friend class QDocDatabase;
typedef QMap<PropertyNode::FunctionRole, QString> RoleMap;
typedef QMap<PropertyNode*, RoleMap> PropertyMap;
- Tree(QDocDatabase* qdb);
+ Tree(const QString& module, QDocDatabase* qdb);
~Tree();
- /* API members */
ClassNode* findClassNode(const QStringList& path, Node* start = 0) const;
NamespaceNode* findNamespaceNode(const QStringList& path) const;
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
- /* internal members */
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
@@ -90,19 +104,22 @@ class Tree
int findFlags,
bool qml) const;
-// ---------------------------------------------------------------------
QmlClassNode* findQmlTypeNode(const QStringList& path);
Node* findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
- Node* start,
bool acceptCollision = false);
InnerNode* findRelatesNode(const QStringList& path);
- NameCollisionNode* checkForCollision(const QString& name) const;
+ NameCollisionNode* checkForCollision(const QString& name);
NameCollisionNode* findCollisionNode(const QString& name) const;
+ QString findTarget(const QString& target, const Node* node) const;
+ void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
+ void resolveTargets(InnerNode* root);
+ const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative);
+ const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
void addPropertyFunction(PropertyNode *property,
const QString &funcName,
@@ -122,14 +139,20 @@ class Tree
FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe,
FunctionNode *clone);
NodeList allBaseClasses(const ClassNode *classe) const;
+ QString refForAtom(const Atom* atom);
public:
- static bool debug_;
+ const QString& moduleName() const { return module_; }
private:
+ QString module_;
QDocDatabase* qdb_;
NamespaceNode root_;
PropertyMap unresolvedPropertyMap;
+ DocNodeMultiMap docNodesByTitle_;
+ TargetMap nodesByTarget_;
+ //NodeMap nodesByName_;
+ //NodeMap nodesByTitle_;
};
QT_END_NAMESPACE