qdoc: qdoc was too slow

The hard-coded search order is now removed. The search order
is now constructed from the depends variable in the qdocconf
file.

The basic idea is that qdoc is run once. It gets a list of all the
qdocconf files for the modules in Qt5.
First, qdoc runs in -prepare mode for each qdocconf file in the list. It
generates the index file for each module, but these index files are
never used. At the end of the -prepare phase for each module, qdoc keeps
the tree structure for the module in a collection of trees.
Second, qdoc runs in -generate mode for each qdocconf file in the list.
But now it uses the existing tree for that module, so it doesn't have to
read the sources files again, and it doesn't have to read any index
files. Now it generates the docs for each module.

The runtime for qdoc has been reduced
by 90% when running qdoc for all of Qt5 on a not so new iMac.
Before this update, qdoc took about 10 minutes to generate
docs for Qt5. Now it takes a little over 1 minute. The new
way to run qdoc is described in the Qt bug report referenced
here.

Note that running qdoc this new (old) way also generates
fewer qdoc errors than when running qdoc the old way. This
indicates that the index files qdoc uses when running the
old way are incomplete.

Note also that the old way of running qdoc is not affected
by this update. The old way is still required for running
qdoc in the current qmake/make system. That process must be
changed to be able to use the faster qdoc. The details are
provided in the Qt bug report.

Change-Id: Ibec41d6fbaa9fc8cd070a05d04357bd02c4478f0
Task-number: QTBUG-41705
Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
This commit is contained in:
Martin Smith 2014-10-01 11:48:29 +02:00
parent 880986be23
commit 77165553af
18 changed files with 565 additions and 385 deletions

View File

@ -65,9 +65,9 @@ QT_BEGIN_NAMESPACE
#define COMMAND_TITLE Doc::alias(QLatin1String("title")) #define COMMAND_TITLE Doc::alias(QLatin1String("title"))
#define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper")) #define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper"))
QString CodeParser::currentSubDir_;
QList<CodeParser *> CodeParser::parsers; QList<CodeParser *> CodeParser::parsers;
bool CodeParser::showInternal = false; bool CodeParser::showInternal_ = false;
bool CodeParser::singleExec_ = false;
/*! /*!
The constructor adds this code parser to the static The constructor adds this code parser to the static
@ -93,7 +93,8 @@ CodeParser::~CodeParser()
*/ */
void CodeParser::initializeParser(const Config& config) void CodeParser::initializeParser(const Config& config)
{ {
showInternal = config.getBool(CONFIG_SHOWINTERNAL); showInternal_ = config.getBool(CONFIG_SHOWINTERNAL);
singleExec_ = config.getBool(CONFIG_SINGLEEXEC);
} }
/*! /*!
@ -262,7 +263,7 @@ void CodeParser::processCommonMetaCommand(const Location& location,
node->setStatus(Node::Preliminary); node->setStatus(Node::Preliminary);
} }
else if (command == COMMAND_INTERNAL) { else if (command == COMMAND_INTERNAL) {
if (!showInternal) { if (!showInternal_) {
node->setAccess(Node::Private); node->setAccess(Node::Private);
node->setStatus(Node::Internal); node->setStatus(Node::Internal);
if (node->type() == Node::QmlPropertyGroup) { if (node->type() == Node::QmlPropertyGroup) {

View File

@ -74,7 +74,6 @@ public:
static CodeParser *parserForHeaderFile(const QString &filePath); static CodeParser *parserForHeaderFile(const QString &filePath);
static CodeParser *parserForSourceFile(const QString &filePath); static CodeParser *parserForSourceFile(const QString &filePath);
static void setLink(Node* node, Node::LinkType linkType, const QString& arg); static void setLink(Node* node, Node::LinkType linkType, const QString& arg);
static const QString& currentOutputSubdirectory() { return currentSubDir_; }
protected: protected:
const QSet<QString>& commonMetaCommands(); const QSet<QString>& commonMetaCommands();
@ -89,9 +88,9 @@ protected:
QDocDatabase* qdb_; QDocDatabase* qdb_;
private: private:
static QString currentSubDir_;
static QList<CodeParser *> parsers; static QList<CodeParser *> parsers;
static bool showInternal; static bool showInternal_;
static bool singleExec_;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -98,6 +98,7 @@ QString ConfigStrings::QUOTINGINFORMATION = QStringLiteral("quotinginformation")
QString ConfigStrings::SCRIPTDIRS = QStringLiteral("scriptdirs"); QString ConfigStrings::SCRIPTDIRS = QStringLiteral("scriptdirs");
QString ConfigStrings::SCRIPTS = QStringLiteral("scripts"); QString ConfigStrings::SCRIPTS = QStringLiteral("scripts");
QString ConfigStrings::SHOWINTERNAL = QStringLiteral("showinternal"); QString ConfigStrings::SHOWINTERNAL = QStringLiteral("showinternal");
QString ConfigStrings::SINGLEEXEC = QStringLiteral("singleexec");
QString ConfigStrings::SOURCEDIRS = QStringLiteral("sourcedirs"); QString ConfigStrings::SOURCEDIRS = QStringLiteral("sourcedirs");
QString ConfigStrings::SOURCEENCODING = QStringLiteral("sourceencoding"); QString ConfigStrings::SOURCEENCODING = QStringLiteral("sourceencoding");
QString ConfigStrings::SOURCES = QStringLiteral("sources"); QString ConfigStrings::SOURCES = QStringLiteral("sources");
@ -350,6 +351,10 @@ QString Config::getOutputDir() const
t = getString(CONFIG_OUTPUTDIR); t = getString(CONFIG_OUTPUTDIR);
else else
t = overrideOutputDir; t = overrideOutputDir;
if (Generator::singleExec()) {
QString project = getString(CONFIG_PROJECT);
t += QLatin1Char('/') + project.toLower();
}
if (!Generator::useOutputSubdirs()) { if (!Generator::useOutputSubdirs()) {
t = t.left(t.lastIndexOf('/')); t = t.left(t.lastIndexOf('/'));
QString singleOutputSubdir = getString("HTML.outputsubdir"); QString singleOutputSubdir = getString("HTML.outputsubdir");
@ -868,6 +873,36 @@ bool Config::isMetaKeyChar(QChar ch)
|| ch == QLatin1Char(','); || ch == QLatin1Char(',');
} }
/*!
\a fileName is a master qdocconf file. It contains a list of
qdocconf files and nothing else. Read the list and return it.
*/
QStringList Config::loadMaster(const QString& fileName)
{
Location location = Location::null;
QFile fin(fileName);
if (!fin.open(QFile::ReadOnly | QFile::Text)) {
if (!Config::installDir.isEmpty()) {
int prefix = location.filePath().length() - location.fileName().length();
fin.setFileName(Config::installDir + "/" + fileName.right(fileName.length() - prefix));
}
if (!fin.open(QFile::ReadOnly | QFile::Text))
location.fatal(tr("Cannot open master qdocconf file '%1': %2").arg(fileName).arg(fin.errorString()));
}
QTextStream stream(&fin);
#ifndef QT_NO_TEXTCODEC
stream.setCodec("UTF-8");
#endif
QStringList qdocFiles;
QString line = stream.readLine();
while (!line.isNull()) {
qdocFiles.append(line);
line = stream.readLine();
}
fin.close();
return qdocFiles;
}
/*! /*!
Load, parse, and process a qdoc configuration file. This Load, parse, and process a qdoc configuration file. This
function is only called by the other load() function, but function is only called by the other load() function, but

View File

@ -108,6 +108,7 @@ public:
QStringList getExampleQdocFiles(const QSet<QString> &excludedDirs, const QSet<QString> &excludedFiles); QStringList getExampleQdocFiles(const QSet<QString> &excludedDirs, const QSet<QString> &excludedFiles);
QStringList getExampleImageFiles(const QSet<QString> &excludedDirs, const QSet<QString> &excludedFiles); QStringList getExampleImageFiles(const QSet<QString> &excludedDirs, const QSet<QString> &excludedFiles);
static QStringList loadMaster(const QString& fileName);
static QStringList getFilesHere(const QString& dir, static QStringList getFilesHere(const QString& dir,
const QString& nameFilter, const QString& nameFilter,
const Location &location = Location(), const Location &location = Location(),
@ -209,6 +210,7 @@ struct ConfigStrings
static QString SCRIPTDIRS; static QString SCRIPTDIRS;
static QString SCRIPTS; static QString SCRIPTS;
static QString SHOWINTERNAL; static QString SHOWINTERNAL;
static QString SINGLEEXEC;
static QString SOURCEDIRS; static QString SOURCEDIRS;
static QString SOURCEENCODING; static QString SOURCEENCODING;
static QString SOURCES; static QString SOURCES;
@ -282,6 +284,7 @@ struct ConfigStrings
#define CONFIG_SCRIPTDIRS ConfigStrings::SCRIPTDIRS #define CONFIG_SCRIPTDIRS ConfigStrings::SCRIPTDIRS
#define CONFIG_SCRIPTS ConfigStrings::SCRIPTS #define CONFIG_SCRIPTS ConfigStrings::SCRIPTS
#define CONFIG_SHOWINTERNAL ConfigStrings::SHOWINTERNAL #define CONFIG_SHOWINTERNAL ConfigStrings::SHOWINTERNAL
#define CONFIG_SINGLEEXEC ConfigStrings::SINGLEEXEC
#define CONFIG_SOURCEDIRS ConfigStrings::SOURCEDIRS #define CONFIG_SOURCEDIRS ConfigStrings::SOURCEDIRS
#define CONFIG_SOURCEENCODING ConfigStrings::SOURCEENCODING #define CONFIG_SOURCEENCODING ConfigStrings::SOURCEENCODING
#define CONFIG_SOURCES ConfigStrings::SOURCES #define CONFIG_SOURCES ConfigStrings::SOURCES

View File

@ -663,10 +663,10 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
*/ */
void DitaXmlGenerator::generateDocs() void DitaXmlGenerator::generateDocs()
{ {
if (!runPrepareOnly()) if (!preparing())
Generator::generateDocs(); Generator::generateDocs();
if (!runGenerateOnly()) { if (!generating()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-')); QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
projectUrl, projectUrl,
@ -675,7 +675,7 @@ void DitaXmlGenerator::generateDocs()
true); true);
} }
if (!runPrepareOnly()) { if (!preparing()) {
writeDitaMap(); writeDitaMap();
/* /*
Generate the XML tag file, if it was requested. Generate the XML tag file, if it was requested.

View File

@ -2816,18 +2816,6 @@ QString DocParser::slashed(const QString& str)
#define COMMAND_BRIEF Doc::alias("brief") #define COMMAND_BRIEF Doc::alias("brief")
#define COMMAND_QMLBRIEF Doc::alias("qmlbrief") #define COMMAND_QMLBRIEF Doc::alias("qmlbrief")
#if 0
Doc::Doc(const Location& start_loc,
const Location& end_loc,
const QString& source,
const QSet<QString>& metaCommandSet)
{
priv = new DocPrivate(start_loc,end_loc,source);
DocParser parser;
parser.parse(source,priv,metaCommandSet,QSet<QString>());
}
#endif
/*! /*!
Parse the qdoc comment \a source. Build up a list of all the topic Parse the qdoc comment \a source. Build up a list of all the topic
commands found including their arguments. This constructor is used commands found including their arguments. This constructor is used
@ -3234,6 +3222,9 @@ void Doc::initialize(const Config& config)
} }
} }
/*!
All the heap allocated variables are deleted.
*/
void Doc::terminate() void Doc::terminate()
{ {
DocParser::exampleFiles.clear(); DocParser::exampleFiles.clear();

View File

@ -92,7 +92,8 @@ bool Generator::debugging_ = false;
bool Generator::noLinkErrors_ = false; bool Generator::noLinkErrors_ = false;
bool Generator::autolinkErrors_ = false; bool Generator::autolinkErrors_ = false;
bool Generator::redirectDocumentationToDevNull_ = false; bool Generator::redirectDocumentationToDevNull_ = false;
Generator::Passes Generator::qdocPass_ = Both; Generator::QDocPass Generator::qdocPass_ = Generator::Neither;
bool Generator::qdocSingleExec_ = false;
bool Generator::useOutputSubdirs_ = true; bool Generator::useOutputSubdirs_ = true;
void Generator::startDebugging(const QString& message) void Generator::startDebugging(const QString& message)
@ -134,6 +135,7 @@ Generator::Generator()
inTableHeader_(false), inTableHeader_(false),
threeColumnEnumValueTable_(true), threeColumnEnumValueTable_(true),
showInternal_(false), showInternal_(false),
singleExec_(false),
numTableRows_(0) numTableRows_(0)
{ {
qdb_ = QDocDatabase::qdocDB(); qdb_ = QDocDatabase::qdocDB();
@ -259,7 +261,8 @@ void Generator::writeOutFileNames()
void Generator::beginSubPage(const InnerNode* node, const QString& fileName) void Generator::beginSubPage(const InnerNode* node, const QString& fileName)
{ {
QString path = outputDir() + QLatin1Char('/'); QString path = outputDir() + QLatin1Char('/');
if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty()) if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty() &&
!outputDir().endsWith(node->outputSubdirectory()))
path += node->outputSubdirectory() + QLatin1Char('/'); path += node->outputSubdirectory() + QLatin1Char('/');
path += fileName; path += fileName;
@ -1529,7 +1532,7 @@ void Generator::initialize(const Config &config)
QDir dirInfo; QDir dirInfo;
if (dirInfo.exists(outDir_)) { if (dirInfo.exists(outDir_)) {
if (!runGenerateOnly() && Generator::useOutputSubdirs()) { if (!generating() && Generator::useOutputSubdirs()) {
if (!Config::removeDirContents(outDir_)) if (!Config::removeDirContents(outDir_))
config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_)); config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_));
} }
@ -1678,6 +1681,7 @@ void Generator::initializeGenerator(const Config& config)
{ {
config_ = &config; config_ = &config;
showInternal_ = config.getBool(CONFIG_SHOWINTERNAL); showInternal_ = config.getBool(CONFIG_SHOWINTERNAL);
singleExec_ = config.getBool(CONFIG_SINGLEEXEC);
} }
bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType) bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType)

View File

@ -61,7 +61,7 @@ class Generator
Q_DECLARE_TR_FUNCTIONS(QDoc::Generator) Q_DECLARE_TR_FUNCTIONS(QDoc::Generator)
public: public:
enum Passes { Both, Prepare, Generate }; enum QDocPass { Neither, Prepare, Generate };
enum ListType { Generic, Obsolete }; enum ListType { Generic, Obsolete };
Generator(); Generator();
@ -91,9 +91,11 @@ public:
static bool debugging() { return debugging_; } static bool debugging() { return debugging_; }
static bool noLinkErrors() { return noLinkErrors_; } static bool noLinkErrors() { return noLinkErrors_; }
static bool autolinkErrors() { return autolinkErrors_; } static bool autolinkErrors() { return autolinkErrors_; }
static void setQDocPass(Passes pass) { qdocPass_ = pass; } static void setQDocPass(QDocPass t) { qdocPass_ = t; }
static bool runPrepareOnly() { return (qdocPass_ == Prepare); } static bool preparing() { return (qdocPass_ == Prepare); }
static bool runGenerateOnly() { return (qdocPass_ == Generate); } static bool generating() { return (qdocPass_ == Generate); }
static bool singleExec() { return qdocSingleExec_; }
static void setSingleExec() { qdocSingleExec_ = true; }
static QString defaultModuleName() { return project; } static QString defaultModuleName() { return project; }
static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; } static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; }
static bool useOutputSubdirs() { return useOutputSubdirs_; } static bool useOutputSubdirs() { return useOutputSubdirs_; }
@ -212,7 +214,8 @@ private:
static bool noLinkErrors_; static bool noLinkErrors_;
static bool autolinkErrors_; static bool autolinkErrors_;
static bool redirectDocumentationToDevNull_; static bool redirectDocumentationToDevNull_;
static Passes qdocPass_; static QDocPass qdocPass_;
static bool qdocSingleExec_;
static bool useOutputSubdirs_; static bool useOutputSubdirs_;
void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker); void generateReimplementedFrom(const FunctionNode *func, CodeMarker *marker);
@ -232,6 +235,7 @@ private:
bool inTableHeader_; bool inTableHeader_;
bool threeColumnEnumValueTable_; bool threeColumnEnumValueTable_;
bool showInternal_; bool showInternal_;
bool singleExec_;
int numTableRows_; int numTableRows_;
QString link_; QString link_;
QString sectionNumber_; QString sectionNumber_;

View File

@ -100,8 +100,10 @@ HtmlGenerator::HtmlGenerator()
*/ */
HtmlGenerator::~HtmlGenerator() HtmlGenerator::~HtmlGenerator()
{ {
if (helpProjectWriter) if (helpProjectWriter) {
delete helpProjectWriter; delete helpProjectWriter;
helpProjectWriter = 0;
}
} }
/*! /*!
@ -130,6 +132,11 @@ void HtmlGenerator::initializeGenerator(const Config &config)
Generator::initializeGenerator(config); Generator::initializeGenerator(config);
obsoleteLinks = config.getBool(CONFIG_OBSOLETELINKS); obsoleteLinks = config.getBool(CONFIG_OBSOLETELINKS);
setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");
/*
The formatting maps are owned by Generator. They are cleared in
Generator::terminate().
*/
int i = 0; int i = 0;
while (defaults[i].key) { while (defaults[i].key) {
formattingLeftMap().insert(defaults[i].key, defaults[i].left); formattingLeftMap().insert(defaults[i].key, defaults[i].left);
@ -211,6 +218,11 @@ void HtmlGenerator::initializeGenerator(const Config &config)
// The following line was changed to fix QTBUG-27798 // The following line was changed to fix QTBUG-27798
//codeIndent = config.getInt(CONFIG_CODEINDENT); //codeIndent = config.getInt(CONFIG_CODEINDENT);
/*
The help file write should be allocated once and only once
per qdoc execution.
*/
if (helpProjectWriter == 0)
helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp", this); helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp", this);
// Documentation template handling // Documentation template handling
@ -266,10 +278,10 @@ void HtmlGenerator::generateDocs()
Node* qflags = qdb_->findClassNode(QStringList("QFlags")); Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags) if (qflags)
qflagsHref_ = linkForNode(qflags,0); qflagsHref_ = linkForNode(qflags,0);
if (!runPrepareOnly()) if (!preparing())
Generator::generateDocs(); Generator::generateDocs();
if (!runGenerateOnly()) { if (!generating()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-')); QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
projectUrl, projectUrl,
@ -278,7 +290,7 @@ void HtmlGenerator::generateDocs()
true); true);
} }
if (!runPrepareOnly()) { if (!preparing()) {
helpProjectWriter->generate(); helpProjectWriter->generate();
generateManifestFiles(); generateManifestFiles();
/* /*
@ -2313,7 +2325,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
out() << ", including inherited members.</p>\n"; out() << ", including inherited members.</p>\n";
Section section = sections.first(); Section section = sections.first();
generateSectionList(section, 0, marker, CodeMarker::Subpage); generateSectionList(section, inner, marker, CodeMarker::Subpage);
generateFooter(); generateFooter();
endSubPage(); endSubPage();
@ -2369,7 +2381,7 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarke
prefix = keys.at(j).mid(1); prefix = keys.at(j).mid(1);
prefix = prefix.left(keys.at(j).indexOf("::")+1); prefix = prefix.left(keys.at(j).indexOf("::")+1);
} }
generateQmlItem(nodes[j], qcn, marker, true); generateQmlItem(nodes[j], qml_cn, marker, true);
if (nodes[j]->isAttached()) if (nodes[j]->isAttached())
out() << " [attached]"; out() << " [attached]";
//generateSynopsis(nodes[j], qcn, marker, CodeMarker::Subpage, false, &prefix); //generateSynopsis(nodes[j], qcn, marker, CodeMarker::Subpage, false, &prefix);
@ -2796,8 +2808,9 @@ void HtmlGenerator::generateCompactList(ListType listType,
else if (listType == Obsolete) { else if (listType == Obsolete) {
QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension(); QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension();
QString link; QString link;
if (useOutputSubdirs()) if (useOutputSubdirs()) {
link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/')); link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/'));
}
link += fileName; link += fileName;
out() << "<a href=\"" << link << "\">"; out() << "<a href=\"" << link << "\">";
} }
@ -2837,7 +2850,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative)
char currentLetter; char currentLetter;
out() << "<ul>\n"; out() << "<ul>\n";
NodeMapMap funcIndex = qdb_->getFunctionIndex(); NodeMapMap& funcIndex = qdb_->getFunctionIndex();
QMap<QString, NodeMap >::ConstIterator f = funcIndex.constBegin(); QMap<QString, NodeMap >::ConstIterator f = funcIndex.constBegin();
while (f != funcIndex.constEnd()) { while (f != funcIndex.constEnd()) {
out() << "<li>"; out() << "<li>";
@ -3723,7 +3736,6 @@ QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const
return link; return link;
} }
/*! /*!
Construct the link string for the \a node and return it. Construct the link string for the \a node and return it.
The \a relative node is use to decide the link we are The \a relative node is use to decide the link we are
@ -3778,6 +3790,9 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
if (node && relative && (node != relative)) { if (node && relative && (node != relative)) {
if (useOutputSubdirs() && !node->isExternalPage() && if (useOutputSubdirs() && !node->isExternalPage() &&
node->outputSubdirectory() != relative->outputSubdirectory()) { node->outputSubdirectory() != relative->outputSubdirectory()) {
if (link.startsWith(node->outputSubdirectory()))
link.prepend(QString("../"));
else
link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
} }
} }
@ -4507,6 +4522,9 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element)
Reads metacontent - additional attributes and tags to apply Reads metacontent - additional attributes and tags to apply
when generating manifest files, read from config. Takes the when generating manifest files, read from config. Takes the
configuration class \a config as a parameter. configuration class \a config as a parameter.
The manifest metacontent map is cleared immediately after
the manifest files have been generated.
*/ */
void HtmlGenerator::readManifestMetaContent(const Config &config) void HtmlGenerator::readManifestMetaContent(const Config &config)
{ {

View File

@ -256,7 +256,7 @@ QString Location::canonicalRelativePath(const QString &path)
*/ */
void Location::warning(const QString& message, const QString& details) const void Location::warning(const QString& message, const QString& details) const
{ {
if (!Generator::runPrepareOnly()) if (!Generator::preparing())
emitMessage(Warning, message, details); emitMessage(Warning, message, details);
} }
@ -267,7 +267,7 @@ void Location::warning(const QString& message, const QString& details) const
*/ */
void Location::error(const QString& message, const QString& details) const void Location::error(const QString& message, const QString& details) const
{ {
if (!Generator::runPrepareOnly()) if (!Generator::preparing())
emitMessage(Error, message, details); emitMessage(Error, message, details);
} }

View File

@ -63,7 +63,6 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2) bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2)
{ {
return fi1.lastModified() < fi2.lastModified(); return fi1.lastModified() < fi2.lastModified();
@ -71,6 +70,7 @@ bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2)
static bool highlighting = false; static bool highlighting = false;
static bool showInternal = false; static bool showInternal = false;
static bool singleExec = false;
static bool redirectDocumentationToDevNull = false; static bool redirectDocumentationToDevNull = false;
static bool noLinkErrors = false; static bool noLinkErrors = false;
static bool autolinkErrors = false; static bool autolinkErrors = false;
@ -80,14 +80,22 @@ static QStringList dependModules;
static QStringList indexDirs; static QStringList indexDirs;
static QString currentDir; static QString currentDir;
static QString prevCurrentDir; static QString prevCurrentDir;
static QHash<QString,QString> defaults;
#ifndef QT_NO_TRANSLATION
typedef QPair<QString, QTranslator*> Translator;
static QList<Translator> translators;
#endif
/*!
Read some XML indexes containing definitions from other
documentation sets. \a config contains a variable that
lists directories where index files can bge found. It also
contains the \c depends variable, which lists the modules
that the current module depends on.
*/
static void loadIndexFiles(Config& config) static void loadIndexFiles(Config& config)
{ {
QDocDatabase* qdb = QDocDatabase::qdocDB(); QDocDatabase* qdb = QDocDatabase::qdocDB();
/*
Read some XML indexes containing definitions from other documentation sets.
*/
QStringList indexFiles; QStringList indexFiles;
QStringList configIndexes = config.getStringList(CONFIG_INDEXES); QStringList configIndexes = config.getStringList(CONFIG_INDEXES);
foreach (const QString &index, configIndexes) { foreach (const QString &index, configIndexes) {
@ -194,42 +202,25 @@ static void loadIndexFiles(Config& config)
*/ */
static void processQdocconfFile(const QString &fileName) static void processQdocconfFile(const QString &fileName)
{ {
#ifndef QT_NO_TRANSLATION
QList<QTranslator *> translators;
#endif
/* /*
The Config instance represents the configuration data for qdoc. The Config instance represents the configuration data for qdoc.
All the other classes are initialized with the config. Here we All the other classes are initialized with the config. Below, we
initialize the configuration with some default values. initialize the configuration with some default values.
I don't think the call to translate() does anything here. For one
thing, the translators haven't been installed at this point. And
I doubt any translator would translate QDoc anyway. But I left it
here because it does no harm.
*/ */
Config config(QCoreApplication::translate("QDoc", "qdoc")); Config config(QCoreApplication::translate("QDoc", "qdoc"));
/*
The default indent for code is 4.
The default value for false is 0.
The default supported file extensions are cpp, h, qdoc and qml.
The default language is c++.
The default output format is html.
The default tab size is 8.
And those are all the default values for configuration variables.
*/
static QHash<QString,QString> defaults;
if (defaults.isEmpty()) {
defaults.insert(CONFIG_CODEINDENT, QLatin1String("4"));
defaults.insert(CONFIG_FALSEHOODS, QLatin1String("0"));
defaults.insert(CONFIG_FILEEXTENSIONS, QLatin1String("*.cpp *.h *.qdoc *.qml"));
defaults.insert(CONFIG_LANGUAGE, QLatin1String("Cpp"));
defaults.insert(CONFIG_OUTPUTFORMATS, QLatin1String("HTML"));
defaults.insert(CONFIG_TABSIZE, QLatin1String("8"));
}
QHash<QString,QString>::iterator iter; QHash<QString,QString>::iterator iter;
for (iter = defaults.begin(); iter != defaults.end(); ++iter) for (iter = defaults.begin(); iter != defaults.end(); ++iter)
config.setStringList(iter.key(), QStringList() << iter.value()); config.setStringList(iter.key(), QStringList() << iter.value());
config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false")); config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false"));
config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false")); config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false"));
config.setStringList(CONFIG_SINGLEEXEC, QStringList(singleExec ? "true" : "false"));
config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false")); config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false"));
config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false")); config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false"));
config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false")); config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false"));
@ -247,8 +238,8 @@ static void processQdocconfFile(const QString &fileName)
currentDir = QFileInfo(fileName).path(); currentDir = QFileInfo(fileName).path();
Location::initialize(config); Location::initialize(config);
config.load(fileName); config.load(fileName);
QString project = config.getString(CONFIG_PROJECT).toLower(); QString project = config.getString(CONFIG_PROJECT);
//qDebug() << "\nStart project:" << project; //qDebug() << "Start project:" << project;
/* /*
Add the defines to the configuration variables. Add the defines to the configuration variables.
*/ */
@ -261,17 +252,24 @@ static void processQdocconfFile(const QString &fileName)
if (!currentDir.isEmpty()) if (!currentDir.isEmpty())
QDir::setCurrent(currentDir); QDir::setCurrent(currentDir);
QString phase; QString phase = " in -";
if (Generator::runPrepareOnly()) if (Generator::singleExec())
phase = " in -prepare mode "; phase += "single exec mode, ";
else if (Generator::runGenerateOnly()) else
phase = " in -generate mode "; phase += "separate exec mode, ";
if (Generator::preparing())
phase += "prepare phase ";
else if (Generator::generating())
phase += "generate phase ";
QString msg = "Running qdoc for " + config.getString(CONFIG_PROJECT) + phase; QString msg = "Running qdoc for " + config.getString(CONFIG_PROJECT) + phase;
Location::logToStdErr(msg); Location::logToStdErr(msg);
/* /*
Initialize all the classes and data structures with the Initialize all the classes and data structures with the
qdoc configuration. qdoc configuration. This is safe to do for each qdocconf
file processed, because all the data structures created
are either cleared after they have been used, or they
are cleared in the terminate() functions below.
*/ */
Location::initialize(config); Location::initialize(config);
Tokenizer::initialize(config); Tokenizer::initialize(config);
@ -282,16 +280,32 @@ static void processQdocconfFile(const QString &fileName)
#ifndef QT_NO_TRANSLATION #ifndef QT_NO_TRANSLATION
/* /*
Load the language translators, if the configuration specifies any. Load the language translators, if the configuration specifies any,
but only if they haven't already been loaded. This works in both
-prepare/-generate mode and -singleexec mode.
*/ */
QStringList fileNames = config.getStringList(CONFIG_TRANSLATORS); QStringList fileNames = config.getStringList(CONFIG_TRANSLATORS);
QStringList::ConstIterator fn = fileNames.constBegin(); QStringList::ConstIterator fn = fileNames.constBegin();
while (fn != fileNames.constEnd()) { while (fn != fileNames.constEnd()) {
bool found = false;
if (!translators.isEmpty()) {
for (int i=0; i<translators.size(); ++i) {
if (translators.at(i).first == *fn) {
found = true;
break;
}
}
}
if (!found) {
QTranslator *translator = new QTranslator(0); QTranslator *translator = new QTranslator(0);
if (!translator->load(*fn)) if (!translator->load(*fn)) {
config.lastLocation().error(QCoreApplication::translate("QDoc", "Cannot load translator '%1'").arg(*fn)); config.lastLocation().error(QCoreApplication::translate("QDoc", "Cannot load translator '%1'").arg(*fn));
}
else {
QCoreApplication::instance()->installTranslator(translator); QCoreApplication::instance()->installTranslator(translator);
translators.append(translator); translators.append(Translator(*fn, translator));
}
}
++fn; ++fn;
} }
#endif #endif
@ -311,30 +325,46 @@ static void processQdocconfFile(const QString &fileName)
will be stored. The database includes a tree of nodes, which gets will be stored. The database includes a tree of nodes, which gets
built as the source files are parsed. The documentation output is built as the source files are parsed. The documentation output is
generated by traversing that tree. generated by traversing that tree.
Note: qdocDB() allocates a new instance only if no instance exists.
So it is safe to call qdocDB() any time.
*/ */
QDocDatabase* qdb = QDocDatabase::qdocDB(); QDocDatabase* qdb = QDocDatabase::qdocDB();
qdb->setVersion(config.getString(CONFIG_VERSION)); qdb->setVersion(config.getString(CONFIG_VERSION));
qdb->setShowInternal(config.getBool(CONFIG_SHOWINTERNAL)); qdb->setShowInternal(config.getBool(CONFIG_SHOWINTERNAL));
qdb->setSingleExec(config.getBool(CONFIG_SINGLEEXEC));
/* /*
By default, the only output format is HTML. By default, the only output format is HTML.
*/ */
QSet<QString> outputFormats = config.getOutputFormats(); QSet<QString> outputFormats = config.getOutputFormats();
Location outputFormatsLocation = config.lastLocation(); Location outputFormatsLocation = config.lastLocation();
//if (!Generator::runPrepareOnly()) qdb->clearSearchOrder();
QString p = config.getString(CONFIG_PROJECT).toLower();
if (!Generator::singleExec()) {
Generator::debug(" loading index files"); Generator::debug(" loading index files");
loadIndexFiles(config); loadIndexFiles(config);
qdb->newPrimaryTree(config.getString(CONFIG_PROJECT));
qdb->setSearchOrder();
Generator::debug(" done loading index files"); Generator::debug(" done loading index files");
qdb->newPrimaryTree(p);
}
else if (Generator::preparing())
qdb->newPrimaryTree(p);
else
qdb->setPrimaryTree(p);
dependModules = config.getStringList(CONFIG_DEPENDS);
dependModules.removeDuplicates();
qdb->setSearchOrder(dependModules);
QSet<QString> excludedDirs; QSet<QString> excludedDirs;
QSet<QString> excludedFiles; QSet<QString> excludedFiles;
QStringList headerList;
QStringList sourceList;
QStringList excludedDirsList; QStringList excludedDirsList;
QStringList excludedFilesList; QStringList excludedFilesList;
if (!Generator::singleExec() || !Generator::generating()) {
QStringList headerList;
QStringList sourceList;
Generator::debug("Reading excludedirs"); Generator::debug("Reading excludedirs");
excludedDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS); excludedDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS);
foreach (const QString &excludeDir, excludedDirsList) { foreach (const QString &excludeDir, excludedDirsList) {
@ -429,6 +459,7 @@ static void processQdocconfFile(const QString &fileName)
codeParser->doneParsingHeaderFiles(); codeParser->doneParsingHeaderFiles();
usedParsers.clear(); usedParsers.clear();
//qDebug() << "CALL: resolveInheritance()";
qdb->resolveInheritance(); qdb->resolveInheritance();
/* /*
@ -454,32 +485,67 @@ static void processQdocconfFile(const QString &fileName)
codeParser->doneParsingSourceFiles(); codeParser->doneParsingSourceFiles();
/* /*
Now the big tree has been built from all the header and Now the primary tree has been built from all the header and
source files. Resolve all the class names, function names, source files. Resolve all the class names, function names,
targets, URLs, links, and other stuff that needs resolving. targets, URLs, links, and other stuff that needs resolving.
*/ */
Generator::debug("Resolving stuff prior to generating docs"); Generator::debug("Resolving stuff prior to generating docs");
//qDebug() << "CALL: resolveIssues()";
qdb->resolveIssues(); qdb->resolveIssues();
}
else {
Generator::debug("Reading excludedirs");
excludedDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS);
foreach (const QString &excludeDir, excludedDirsList) {
QString p = QDir::fromNativeSeparators(excludeDir);
QDir tmp(p);
if (tmp.exists())
excludedDirs.insert(p);
}
Generator::debug("Reading excludefiles");
excludedFilesList = config.getCanonicalPathList(CONFIG_EXCLUDEFILES);
foreach (const QString& excludeFile, excludedFilesList) {
QString p = QDir::fromNativeSeparators(excludeFile);
excludedFiles.insert(p);
}
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) {
if (exampleImageList[i].contains("doc/images")) {
QString t = exampleImageList[i].left(exampleImageList[i].lastIndexOf("doc/images")+10);
if (!exampleImageDirs.contains(t)) {
exampleImageDirs.insert(t);
}
}
}
Generator::augmentImageDirs(exampleImageDirs);
qdb->resolveStuff();
}
/* /*
The tree is built and all the stuff that needed resolving The primary tree is built and all the stuff that needed
has been resolved. Now traverse the tree and generate the resolving has been resolved. Now traverse the tree and
documentation output. More than one output format can be generate the documentation output. More than one output
requested. The tree is traversed for each one. format can be requested. The tree is traversed for each
one.
*/ */
Generator::debug("Generating docs"); Generator::debug("Generating docs");
//qDebug() << "CALL: generateDocs()";
QSet<QString>::ConstIterator of = outputFormats.constBegin(); QSet<QString>::ConstIterator of = outputFormats.constBegin();
while (of != outputFormats.constEnd()) { while (of != outputFormats.constEnd()) {
Generator* generator = Generator::generatorForFormat(*of); Generator* generator = Generator::generatorForFormat(*of);
if (generator == 0) if (generator == 0)
outputFormatsLocation.fatal(QCoreApplication::translate("QDoc", "Unknown output format '%1'").arg(*of)); outputFormatsLocation.fatal(QCoreApplication::translate("QDoc",
"Unknown output format '%1'").arg(*of));
generator->generateDocs(); generator->generateDocs();
++of; ++of;
} }
//Generator::writeOutFileNames(); //Generator::writeOutFileNames();
Generator::debug("Shutting down qdoc"); Generator::debug("Terminating qdoc classes");
if (Generator::debugging()) if (Generator::debugging())
Generator::stopDebugging(project); Generator::stopDebugging(project);
@ -492,17 +558,7 @@ static void processQdocconfFile(const QString &fileName)
Location::terminate(); Location::terminate();
QDir::setCurrent(prevCurrentDir); QDir::setCurrent(prevCurrentDir);
#ifndef QT_NO_TRANSLATION Generator::debug("qdoc classes terminated");
qDeleteAll(translators);
#endif
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): Delete qdoc database";
#endif
QDocDatabase::destroyQdocDB();
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): qdoc database deleted";
#endif
Generator::debug("qdoc finished!");
} }
extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed; extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
@ -621,12 +677,17 @@ int main(int argc, char **argv)
logProgressOption.setDescription(QCoreApplication::translate("qdoc", "Log progress on stderr.")); logProgressOption.setDescription(QCoreApplication::translate("qdoc", "Log progress on stderr."));
parser.addOption(logProgressOption); parser.addOption(logProgressOption);
QCommandLineOption singleExecOption(QStringList() << QStringLiteral("single-exec"));
singleExecOption.setDescription(QCoreApplication::translate("qdoc", "Run qdoc once over all the qdoc conf files."));
parser.addOption(singleExecOption);
parser.process(app); parser.process(app);
defines += parser.values(defineOption); defines += parser.values(defineOption);
dependModules += parser.values(dependsOption); dependModules += parser.values(dependsOption);
highlighting = parser.isSet(highlightingOption); highlighting = parser.isSet(highlightingOption);
showInternal = parser.isSet(showInternalOption); showInternal = parser.isSet(showInternalOption);
singleExec = parser.isSet(singleExecOption);
redirectDocumentationToDevNull = parser.isSet(redirectDocumentationToDevNullOption); redirectDocumentationToDevNull = parser.isSet(redirectDocumentationToDevNullOption);
Config::generateExamples = !parser.isSet(noExamplesOption); Config::generateExamples = !parser.isSet(noExamplesOption);
foreach (const QString &indexDir, parser.values(indexDirOption)) { foreach (const QString &indexDir, parser.values(indexDirOption)) {
@ -650,21 +711,71 @@ int main(int argc, char **argv)
Generator::setQDocPass(Generator::Prepare); Generator::setQDocPass(Generator::Prepare);
if (parser.isSet(generateOption)) if (parser.isSet(generateOption))
Generator::setQDocPass(Generator::Generate); Generator::setQDocPass(Generator::Generate);
if (parser.isSet(singleExecOption))
Generator::setSingleExec();
if (parser.isSet(logProgressOption)) if (parser.isSet(logProgressOption))
Location::startLoggingProgress(); Location::startLoggingProgress();
const QStringList qdocFiles = parser.positionalArguments(); /*
The default indent for code is 4.
The default value for false is 0.
The default supported file extensions are cpp, h, qdoc and qml.
The default language is c++.
The default output format is html.
The default tab size is 8.
And those are all the default values for configuration variables.
*/
if (defaults.isEmpty()) {
defaults.insert(CONFIG_CODEINDENT, QLatin1String("4"));
defaults.insert(CONFIG_FALSEHOODS, QLatin1String("0"));
defaults.insert(CONFIG_FILEEXTENSIONS, QLatin1String("*.cpp *.h *.qdoc *.qml"));
defaults.insert(CONFIG_LANGUAGE, QLatin1String("Cpp"));
defaults.insert(CONFIG_OUTPUTFORMATS, QLatin1String("HTML"));
defaults.insert(CONFIG_TABSIZE, QLatin1String("8"));
}
QStringList qdocFiles = parser.positionalArguments();
if (qdocFiles.isEmpty()) if (qdocFiles.isEmpty())
parser.showHelp(); parser.showHelp();
if (singleExec)
qdocFiles = Config::loadMaster(qdocFiles.at(0));
/* /*
Main loop. Main loop is now modified to handle single exec mode.
*/ */
if (Generator::singleExec())
Generator::setQDocPass(Generator::Prepare);
foreach (const QString &qf, qdocFiles) { foreach (const QString &qf, qdocFiles) {
//qDebug() << "PROCESSING:" << qf; dependModules.clear();
processQdocconfFile(qf); processQdocconfFile(qf);
} }
if (Generator::singleExec()) {
Generator::setQDocPass(Generator::Generate);
QDocDatabase* qdb = QDocDatabase::qdocDB();
qdb->processForest();
foreach (const QString &qf, qdocFiles) {
dependModules.clear();
processQdocconfFile(qf);
}
}
#ifndef QT_NO_TRANSLATION
if (!translators.isEmpty()) {
for (int i=0; i<translators.size(); ++i) {
delete translators.at(i).second;
}
}
translators.clear();
#endif
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): Delete qdoc database";
#endif
QDocDatabase::destroyQdocDB();
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): qdoc database deleted";
#endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -218,7 +218,7 @@ Node::Node(Type type, InnerNode *parent, const QString& name)
{ {
if (parent_) if (parent_)
parent_->addChild(this); parent_->addChild(this);
outSubDir_ = CodeParser::currentOutputSubdirectory(); outSubDir_ = Generator::outputSubdir();
if (operators_.isEmpty()) { if (operators_.isEmpty()) {
operators_.insert("++","inc"); operators_.insert("++","inc");
operators_.insert("--","dec"); operators_.insert("--","dec");

View File

@ -127,143 +127,55 @@ Tree* QDocForest::nextTree()
Returns the pointer to the primary tree. Returns the pointer to the primary tree.
*/ */
/*!
Finds the tree for module \a t in the forest and
sets the primary tree to be that tree. After the
primary tree is set, that tree is removed from the
forest.
\node It gets re-inserted into the forest after the
search order is built.
*/
void QDocForest::setPrimaryTree(const QString& t)
{
primaryTree_ = findTree(t);
forest_.remove(t);
if (!primaryTree_)
qDebug() << "ERROR: Could not set primary tree to:" << t;
}
/*! /*!
If the search order array is empty, create the search order. If the search order array is empty, create the search order.
If the search order array is not empty, do nothing. If the search order array is not empty, do nothing.
*/ */
void QDocForest::setSearchOrder() void QDocForest::setSearchOrder(QStringList& t)
{ {
if (!searchOrder_.isEmpty()) if (!searchOrder_.isEmpty())
return; return;
QString primaryName = primaryTree()->moduleName();
searchOrder_.clear(); /* Allocate space for the search order. */
searchOrder_.reserve(forest_.size()+1); searchOrder_.reserve(forest_.size()+1);
searchOrder_.clear();
moduleNames_.reserve(forest_.size()+1); moduleNames_.reserve(forest_.size()+1);
moduleNames_.clear();
/* The primary tree is always first in the search order. */
QString primaryName = primaryTree()->moduleName();
searchOrder_.append(primaryTree_); searchOrder_.append(primaryTree_);
moduleNames_.append(primaryName); moduleNames_.append(primaryName);
forest_.remove(primaryName);
QMap<QString, Tree*>::iterator i; QMap<QString, Tree*>::iterator i;
if (primaryName != "QtCore") { foreach (QString m, t) {
i = forest_.find("QtCore"); if (primaryName != m) {
i = forest_.find(m);
if (i != forest_.end()) { if (i != forest_.end()) {
searchOrder_.append(i.value()); searchOrder_.append(i.value());
moduleNames_.append("QtCore"); moduleNames_.append(m);
forest_.erase(i); forest_.remove(m);
} }
} }
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 If any trees remain in the forest, just add them
to the search order sequentially, because we don't to the search order sequentially, because we don't
@ -283,15 +195,21 @@ void QDocForest::setSearchOrder()
Rebuild the forest after constructing the search order. Rebuild the forest after constructing the search order.
It was destroyed during construction of the search order, It was destroyed during construction of the search order,
but it is needed for module-specific searches. but it is needed for module-specific searches.
Note that this loop also inserts the primary tree into the
forrest. That is a requirement.
*/ */
for (int i=0; i<searchOrder_.size(); ++i) { for (int i=0; i<searchOrder_.size(); ++i) {
forest_.insert(moduleNames_.at(i).toLower(), searchOrder_.at(i)); if (!forest_.contains(moduleNames_.at(i))) {
forest_.insert(moduleNames_.at(i), searchOrder_.at(i));
}
} }
#if 0 #if 0
qDebug() << " SEARCH ORDER:"; qDebug() << " SEARCH ORDER:";
for (int i=0; i<moduleNames_.size(); ++i) for (int i=0; i<moduleNames_.size(); ++i)
qDebug() << " " << i+1 << "." << moduleNames_.at(i); qDebug() << " " << i+1 << "." << moduleNames_.at(i);
qDebug() << " FOREST:" << forest_.keys();
qDebug() << "SEARCH ORDER:" << moduleNames_;
#endif #endif
} }
@ -356,6 +274,7 @@ const QVector<Tree*>& QDocForest::indexSearchOrder()
*/ */
NamespaceNode* QDocForest::newIndexTree(const QString& module) NamespaceNode* QDocForest::newIndexTree(const QString& module)
{ {
//qDebug() << " New index tree:" << module;
primaryTree_ = new Tree(module, qdb_); primaryTree_ = new Tree(module, qdb_);
forest_.insert(module, primaryTree_); forest_.insert(module, primaryTree_);
return primaryTree_->root(); return primaryTree_->root();
@ -363,10 +282,11 @@ NamespaceNode* QDocForest::newIndexTree(const QString& module)
/*! /*!
Create a new Tree for use as the primary tree. This tree Create a new Tree for use as the primary tree. This tree
will represent the primary module. will represent the primary module. \a module is camel case.
*/ */
void QDocForest::newPrimaryTree(const QString& module) void QDocForest::newPrimaryTree(const QString& module)
{ {
//qDebug() << " New primary tree:" << module;
primaryTree_ = new Tree(module, qdb_); primaryTree_ = new Tree(module, qdb_);
} }
@ -445,8 +365,19 @@ NodeMap QDocDatabase::typeNodeMap_;
constructs the \a forest_ object, which is also a singleton. constructs the \a forest_ object, which is also a singleton.
\a showInternal_ is normally false. If it is true, qdoc will \a showInternal_ is normally false. If it is true, qdoc will
write documentation for nodes marked \c internal. write documentation for nodes marked \c internal.
\a singleExec_ is false when qdoc is being used in the standard
way of running qdoc twices for each module, first with -prepare
and then with -generate. First the -prepare phase is run for
each module, then the -generate phase is run for each module.
When \a singleExec_ is true, qdoc is run only once. During the
single execution, qdoc processes the qdocconf files for all the
modules sequentially in a loop. Each source file for each module
is read exactly once.
*/ */
QDocDatabase::QDocDatabase() : showInternal_(false), forest_(this) QDocDatabase::QDocDatabase()
: showInternal_(false), singleExec_(false), forest_(this)
{ {
// nothing // nothing
} }
@ -809,13 +740,41 @@ QmlClassNode* QDocDatabase::findQmlType(const ImportRec& import, const QString&
} }
/*! /*!
This function calls \a func for each tree in the forest. This function calls a set of functions for each tree in the
forest that has not already been analyzed. In this way, when
running qdoc in \e singleExec mode, each tree is analyzed in
turn, and its classes and types are added to the appropriate
node maps.
*/
void QDocDatabase::processForest()
{
Tree* t = forest_.firstTree();
while (t) {
findAllNamespaces(t->root());
findAllClasses(t->root());
findAllFunctions(t->root());
findAllObsoleteThings(t->root());
findAllLegaleseTexts(t->root());
findAllSince(t->root());
t->setTreeHasBeenAnalyzed();
t = forest_.nextTree();
}
}
/*!
This function calls \a func for each tree in the forest,
but only if Tree::treeHasBeenAnalyzed() returns false for
the tree. In this way, when running qdoc in \e singleExec
mode, each tree is analyzed in turn, and its classes and
types are added to the appropriate node maps.
*/ */
void QDocDatabase::processForest(void (QDocDatabase::*func) (InnerNode*)) void QDocDatabase::processForest(void (QDocDatabase::*func) (InnerNode*))
{ {
Tree* t = forest_.firstTree(); Tree* t = forest_.firstTree();
while (t) { while (t) {
if (!t->treeHasBeenAnalyzed()) {
(this->*(func))(t->root()); (this->*(func))(t->root());
}
t = forest_.nextTree(); t = forest_.nextTree();
} }
} }
@ -887,7 +846,7 @@ NodeMap& QDocDatabase::getNamespaces()
*/ */
NodeMap& QDocDatabase::getServiceClasses() NodeMap& QDocDatabase::getServiceClasses()
{ {
if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty()) if (cppClasses_.isEmpty() && qmlTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return serviceClasses_; return serviceClasses_;
} }
@ -899,7 +858,7 @@ NodeMap& QDocDatabase::getServiceClasses()
*/ */
NodeMap& QDocDatabase::getQmlBasicTypes() NodeMap& QDocDatabase::getQmlBasicTypes()
{ {
if (nonCompatClasses_.isEmpty() && qmlBasicTypes_.isEmpty()) if (cppClasses_.isEmpty() && qmlBasicTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return qmlBasicTypes_; return qmlBasicTypes_;
} }
@ -911,9 +870,9 @@ NodeMap& QDocDatabase::getQmlBasicTypes()
*/ */
NodeMap& QDocDatabase::getQmlTypes() NodeMap& QDocDatabase::getQmlTypes()
{ {
if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty()) if (cppClasses_.isEmpty() && qmlTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return qmlClasses_; return qmlTypes_;
} }
/*! /*!
@ -935,7 +894,7 @@ NodeMap& QDocDatabase::getObsoleteClasses()
*/ */
NodeMap& QDocDatabase::getCompatibilityClasses() NodeMap& QDocDatabase::getCompatibilityClasses()
{ {
if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty()) if (cppClasses_.isEmpty() && qmlTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return compatClasses_; return compatClasses_;
} }
@ -950,7 +909,7 @@ NodeMap& QDocDatabase::getCompatibilityClasses()
*/ */
NodeMap& QDocDatabase::getMainClasses() NodeMap& QDocDatabase::getMainClasses()
{ {
if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty()) if (cppClasses_.isEmpty() && qmlTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return mainClasses_; return mainClasses_;
} }
@ -962,9 +921,9 @@ NodeMap& QDocDatabase::getMainClasses()
*/ */
NodeMap& QDocDatabase::getCppClasses() NodeMap& QDocDatabase::getCppClasses()
{ {
if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty()) if (cppClasses_.isEmpty() && qmlTypes_.isEmpty())
processForest(&QDocDatabase::findAllClasses); processForest(&QDocDatabase::findAllClasses);
return nonCompatClasses_; return cppClasses_;
} }
/*! /*!
@ -987,7 +946,7 @@ void QDocDatabase::findAllClasses(InnerNode* node)
compatClasses_.insert(className, *c); compatClasses_.insert(className, *c);
} }
else { else {
nonCompatClasses_.insert(className, *c); cppClasses_.insert(className, *c);
if ((*c)->status() == Node::Main) if ((*c)->status() == Node::Main)
mainClasses_.insert(className, *c); mainClasses_.insert(className, *c);
} }
@ -1000,9 +959,9 @@ void QDocDatabase::findAllClasses(InnerNode* node)
else if (((*c)->isQmlType() || (*c)->isQmlBasicType())&& !(*c)->doc().isEmpty()) { else if (((*c)->isQmlType() || (*c)->isQmlBasicType())&& !(*c)->doc().isEmpty()) {
QString qmlTypeName = (*c)->name(); QString qmlTypeName = (*c)->name();
if (qmlTypeName.startsWith(QLatin1String("QML:"))) if (qmlTypeName.startsWith(QLatin1String("QML:")))
qmlClasses_.insert(qmlTypeName.mid(4),*c); qmlTypes_.insert(qmlTypeName.mid(4),*c);
else else
qmlClasses_.insert(qmlTypeName,*c); qmlTypes_.insert(qmlTypeName,*c);
//also add to the QML basic type map //also add to the QML basic type map
if ((*c)->isQmlBasicType()) if ((*c)->isQmlBasicType())
@ -1022,7 +981,6 @@ void QDocDatabase::findAllClasses(InnerNode* node)
*/ */
NodeMapMap& QDocDatabase::getFunctionIndex() NodeMapMap& QDocDatabase::getFunctionIndex()
{ {
funcIndex_.clear();
processForest(&QDocDatabase::findAllFunctions); processForest(&QDocDatabase::findAllFunctions);
return funcIndex_; return funcIndex_;
} }
@ -1314,7 +1272,15 @@ const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key)
*/ */
void QDocDatabase::resolveIssues() { void QDocDatabase::resolveIssues() {
resolveQmlInheritance(primaryTreeRoot()); resolveQmlInheritance(primaryTreeRoot());
resolveTargets(); primaryTree()->resolveTargets(primaryTreeRoot());
primaryTree()->resolveCppToQmlLinks();
}
void QDocDatabase::resolveStuff()
{
primaryTree()->resolveInheritance();
resolveQmlInheritance(primaryTreeRoot());
//primaryTree()->resolveTargets(primaryTreeRoot());
primaryTree()->resolveCppToQmlLinks(); primaryTree()->resolveCppToQmlLinks();
} }
@ -1424,10 +1390,18 @@ void QDocDatabase::generateTagFile(const QString& name, Generator* g)
} }
/*! /*!
Reads and parses the qdoc index files listed in \a indexFiles. Reads and parses the qdoc index files listed in \a t.
*/ */
void QDocDatabase::readIndexes(const QStringList& indexFiles) void QDocDatabase::readIndexes(const QStringList& t)
{ {
QStringList indexFiles;
foreach (const QString& f, t) {
QString fn = f.mid(f.lastIndexOf(QChar('/'))+1);
if (!isLoaded(fn))
indexFiles << f;
else
qDebug() << "This index file is already in memory:" << f;
}
QDocIndexFiles::qdocIndexFiles()->readIndexes(indexFiles); QDocIndexFiles::qdocIndexFiles()->readIndexes(indexFiles);
QDocIndexFiles::destroyQDocIndexFiles(); QDocIndexFiles::destroyQDocIndexFiles();
} }
@ -1443,6 +1417,8 @@ void QDocDatabase::generateIndex(const QString& fileName,
Generator* g, Generator* g,
bool generateInternalNodes) bool generateInternalNodes)
{ {
QString t = fileName.mid(fileName.lastIndexOf(QChar('/'))+1);
primaryTree()->setIndexFileName(t);
QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, g, generateInternalNodes); QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, g, generateInternalNodes);
QDocIndexFiles::destroyQDocIndexFiles(); QDocIndexFiles::destroyQDocIndexFiles();
} }

View File

@ -78,7 +78,14 @@ class QDocForest
bool done() { return (currentIndex_ >= searchOrder().size()); } bool done() { return (currentIndex_ >= searchOrder().size()); }
const QVector<Tree*>& searchOrder(); const QVector<Tree*>& searchOrder();
const QVector<Tree*>& indexSearchOrder(); const QVector<Tree*>& indexSearchOrder();
void setSearchOrder(); void setSearchOrder(QStringList& t);
bool isLoaded(const QString& fn) {
foreach (Tree* t, searchOrder()) {
if (fn == t->indexFileName())
return true;
}
return false;
}
const Node* findNode(const QStringList& path, const Node* findNode(const QStringList& path,
const Node* relative, const Node* relative,
@ -186,8 +193,11 @@ class QDocForest
} }
} }
void clearSearchOrder() { searchOrder_.clear(); }
private: private:
void newPrimaryTree(const QString& module); void newPrimaryTree(const QString& module);
void setPrimaryTree(const QString& t);
NamespaceNode* newIndexTree(const QString& module); NamespaceNode* newIndexTree(const QString& module);
private: private:
@ -274,12 +284,10 @@ class QDocDatabase
void resolveInheritance() { primaryTree()->resolveInheritance(); } void resolveInheritance() { primaryTree()->resolveInheritance(); }
void resolveQmlInheritance(InnerNode* root); void resolveQmlInheritance(InnerNode* root);
void resolveIssues(); void resolveIssues();
void resolveStuff();
void fixInheritance() { primaryTree()->fixInheritance(); } void fixInheritance() { primaryTree()->fixInheritance(); }
void resolveProperties() { primaryTree()->resolveProperties(); } void resolveProperties() { primaryTree()->resolveProperties(); }
void resolveTargets() {
primaryTree()->resolveTargets(primaryTreeRoot());
}
void insertTarget(const QString& name, void insertTarget(const QString& name,
const QString& title, const QString& title,
TargetRec::Type type, TargetRec::Type type,
@ -355,18 +363,22 @@ class QDocDatabase
void clearOpenNamespaces() { openNamespaces_.clear(); } void clearOpenNamespaces() { openNamespaces_.clear(); }
void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); } void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); }
void setShowInternal(bool value) { showInternal_ = value; } void setShowInternal(bool value) { showInternal_ = value; }
void setSingleExec(bool value) { singleExec_ = value; }
void processForest();
// Try to make this function private. // Try to make this function private.
QDocForest& forest() { return forest_; } QDocForest& forest() { return forest_; }
NamespaceNode* primaryTreeRoot() { return forest_.primaryTreeRoot(); } NamespaceNode* primaryTreeRoot() { return forest_.primaryTreeRoot(); }
void newPrimaryTree(const QString& module) { forest_.newPrimaryTree(module); } void newPrimaryTree(const QString& module) { forest_.newPrimaryTree(module); }
void setPrimaryTree(const QString& t) { forest_.setPrimaryTree(t); }
NamespaceNode* newIndexTree(const QString& module) { return forest_.newIndexTree(module); } NamespaceNode* newIndexTree(const QString& module) { return forest_.newIndexTree(module); }
const QVector<Tree*>& searchOrder() { return forest_.searchOrder(); } const QVector<Tree*>& searchOrder() { return forest_.searchOrder(); }
void setLocalSearch() { forest_.searchOrder_ = QVector<Tree*>(1, primaryTree()); } void setLocalSearch() { forest_.searchOrder_ = QVector<Tree*>(1, primaryTree()); }
void setSearchOrder(const QVector<Tree*>& searchOrder) { forest_.searchOrder_ = searchOrder; } void setSearchOrder(const QVector<Tree*>& searchOrder) { forest_.searchOrder_ = searchOrder; }
void setSearchOrder() { forest_.setSearchOrder(); } void setSearchOrder(QStringList& t) { forest_.setSearchOrder(t); }
void mergeCollections(Node::Type nt, CNMap& cnm, const Node* relative); void mergeCollections(Node::Type nt, CNMap& cnm, const Node* relative);
void mergeCollections(CollectionNode* cn); void mergeCollections(CollectionNode* cn);
void clearSearchOrder() { forest_.clearSearchOrder(); }
private: private:
friend class QDocIndexFiles; friend class QDocIndexFiles;
@ -379,6 +391,7 @@ class QDocDatabase
return forest_.findNode(path, relative, findFlags, genus); return forest_.findNode(path, relative, findFlags, genus);
} }
void processForest(void (QDocDatabase::*) (InnerNode*)); void processForest(void (QDocDatabase::*) (InnerNode*));
bool isLoaded(const QString& t) { return forest_.isLoaded(t); }
static void initializeDB(); static void initializeDB();
private: private:
@ -394,20 +407,21 @@ class QDocDatabase
static QDocDatabase* qdocDB_; static QDocDatabase* qdocDB_;
static NodeMap typeNodeMap_; static NodeMap typeNodeMap_;
bool showInternal_; bool showInternal_;
bool singleExec_;
QString version_; QString version_;
QDocForest forest_; QDocForest forest_;
NodeMap nonCompatClasses_; NodeMap cppClasses_;
NodeMap mainClasses_; NodeMap mainClasses_; // MWS: not needed, should be delete
NodeMap compatClasses_; NodeMap compatClasses_;
NodeMap obsoleteClasses_; NodeMap obsoleteClasses_;
NodeMap classesWithObsoleteMembers_; NodeMap classesWithObsoleteMembers_;
NodeMap obsoleteQmlTypes_; NodeMap obsoleteQmlTypes_;
NodeMap qmlTypesWithObsoleteMembers_; NodeMap qmlTypesWithObsoleteMembers_;
NodeMap namespaceIndex_; NodeMap namespaceIndex_;
NodeMap serviceClasses_; NodeMap serviceClasses_; // MWS: not needed, should be deleted
NodeMap qmlBasicTypes_; NodeMap qmlBasicTypes_;
NodeMap qmlClasses_; NodeMap qmlTypes_;
NodeMapMap newClassMaps_; NodeMapMap newClassMaps_;
NodeMapMap newQmlTypeMaps_; NodeMapMap newQmlTypeMaps_;
NodeMultiMapMap newSinceMaps_; NodeMultiMapMap newSinceMaps_;

View File

@ -564,7 +564,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
node->setReconstitutedBrief(briefAttr); node->setReconstitutedBrief(briefAttr);
} }
// zzz
bool useParent = (element.nodeName() == "namespace" && name.isEmpty()); bool useParent = (element.nodeName() == "namespace" && name.isEmpty());
if (element.hasChildNodes()) { if (element.hasChildNodes()) {
QDomElement child = element.firstChildElement(); QDomElement child = element.firstChildElement();
@ -806,11 +805,14 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QString fullName = node->fullDocumentName(); QString fullName = node->fullDocumentName();
if (fullName != objName) if (fullName != objName)
writer.writeAttribute("fullname", fullName); writer.writeAttribute("fullname", fullName);
#if 0
if (Generator::useOutputSubdirs()) if (Generator::useOutputSubdirs())
href = node->outputSubdirectory(); href = node->outputSubdirectory();
if (!href.isEmpty()) if (!href.isEmpty())
href.append(QLatin1Char('/')); href.append(QLatin1Char('/'));
href.append(gen_->fullDocumentLocation(node)); href.append(gen_->fullDocumentLocation(node));
#endif
href = gen_->fullDocumentLocation(node);
} }
else else
href = node->name(); href = node->name();

View File

@ -511,6 +511,9 @@ void Tokenizer::initialize(const Config &config)
defines = new QRegExp(d.join('|')); defines = new QRegExp(d.join('|'));
falsehoods = new QRegExp(config.getStringList(CONFIG_FALSEHOODS).join('|')); falsehoods = new QRegExp(config.getStringList(CONFIG_FALSEHOODS).join('|'));
/*
The keyword hash table is always cleared before any words are inserted.
*/
memset(kwordHashTable, 0, sizeof(kwordHashTable)); memset(kwordHashTable, 0, sizeof(kwordHashTable));
for (int i = 0; i < Tok_LastKeyword - Tok_FirstKeyword + 1; i++) for (int i = 0; i < Tok_LastKeyword - Tok_FirstKeyword + 1; i++)
insertKwordIntoHash(kwords[i], i + 1); insertKwordIntoHash(kwords[i], i + 1);
@ -533,6 +536,11 @@ void Tokenizer::initialize(const Config &config)
} }
} }
/*!
The heap allocated variables are freed here. The keyword
hash table is not cleared here, but it is cleared in the
initialize() function, before any keywords are inserted.
*/
void Tokenizer::terminate() void Tokenizer::terminate()
{ {
delete comment; delete comment;

View File

@ -66,7 +66,11 @@ QT_BEGIN_NAMESPACE
be necessary, and it might be removed later. be necessary, and it might be removed later.
*/ */
Tree::Tree(const QString& module, QDocDatabase* qdb) Tree::Tree(const QString& module, QDocDatabase* qdb)
: module_(module), qdb_(qdb), root_(0, QString()) : treeHasBeenAnalyzed_(false),
docsHaveBeenGenerated_(false),
module_(module),
qdb_(qdb),
root_(0, QString())
{ {
root_.setModuleName(module_); root_.setModuleName(module_);
root_.setTree(this); root_.setTree(this);

View File

@ -187,12 +187,22 @@ class Tree
void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); } void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); }
ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; } ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; }
const Node* checkForCollision(const QString& name); const Node* checkForCollision(const QString& name);
void setIndexFileName(const QString& t) { indexFileName_ = t; }
bool treeHasBeenAnalyzed() const { return treeHasBeenAnalyzed_; }
bool docsHaveBeenGenerated() const { return docsHaveBeenGenerated_; }
void setTreeHasBeenAnalyzed() { treeHasBeenAnalyzed_ = true; }
void setdocsHaveBeenGenerated() { docsHaveBeenGenerated_ = true; }
public: public:
const QString& moduleName() const { return module_; } const QString& moduleName() const { return module_; }
const QString& indexFileName() const { return indexFileName_; }
private: private:
bool treeHasBeenAnalyzed_;
bool docsHaveBeenGenerated_;
QString module_; QString module_;
QString indexFileName_;
QDocDatabase* qdb_; QDocDatabase* qdb_;
NamespaceNode root_; NamespaceNode root_;
PropertyMap unresolvedPropertyMap; PropertyMap unresolvedPropertyMap;