From d558100aa71f714342526c072005ad3bcef88d0f Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Wed, 12 Aug 2015 11:00:19 +0200 Subject: qdoc: Improve resolving related non-members and their overload numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were several problems related to resolving related non-member (RNM) functions for classes. This commit does the following changes: - Overload numbers for RNMs are now calculated at the time the \relates command is processed, instead of a separate step. - If a \relates refers to an entity outside the module boundary, write the argument passed to it as-is into the index file. - Delay the destruction of QDocIndexFiles singleton, to resolve the RNMs read from the index files prior to generating docs. - Remove the redundant call to normalizeOverloads() for single- exec mode as unnecessary. These changes ensure that all RNMs are listed in the documentation for the node that they belong to. A remaining issue is that if a function relates to a class outside the module boundary, that function documentation will be empty because the doc content is not stored into the index file (for obvious reasons). Single-exec mode does not have this problem. Change-Id: I33f038120728932cd9fd70da28d9090023068bd6 Task-number: QTBUG-47589 Reviewed-by: Topi Reiniƶ --- src/tools/qdoc/cppcodeparser.cpp | 10 ++++- src/tools/qdoc/node.cpp | 94 +++++++++++++++++++++++++++++---------- src/tools/qdoc/node.h | 3 ++ src/tools/qdoc/qdocdatabase.cpp | 6 ++- src/tools/qdoc/qdocindexfiles.cpp | 31 ++++++++++--- src/tools/qdoc/qdocindexfiles.h | 1 + 6 files changed, 112 insertions(+), 33 deletions(-) (limited to 'src/tools') diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index 0f70777256..46a62d629f 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -924,8 +924,14 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (command == COMMAND_RELATES) { QStringList path = arg.split("::"); Node* n = qdb_->findRelatesNode(path); - if (!n) - doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES)); + if (!n) { + // Store just a string to write to the index file + if (Generator::preparing()) + node->setRelates(arg); + else + doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES)); + + } else node->setRelates(static_cast(n)); } diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index c803acbf60..c879d1d9b4 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -106,7 +106,24 @@ Node::~Node() { if (parent_) parent_->removeChild(this); + if (relatesTo_) + removeRelates(); +} + +/*! + Removes this node from the aggregate's list of related + nodes, or if this node has created a dummy "relates" + aggregate, deletes it. +*/ +void Node::removeRelates() +{ + if (!relatesTo_) + return; + + if (relatesTo_->isDocumentNode() && !relatesTo_->parent()) + delete relatesTo_; + else relatesTo_->removeRelated(this); } @@ -463,11 +480,19 @@ bool Node::fromFlagValue(FlagValue fv, bool defaultValue) */ void Node::setRelates(Aggregate *pseudoParent) { - if (relatesTo_) { - relatesTo_->removeRelated(this); - } + removeRelates(); relatesTo_ = pseudoParent; - pseudoParent->related_.append(this); + pseudoParent->addRelated(this); +} + +/*! + Sets the (unresolved) entity \a name that this node relates to. + */ +void Node::setRelates(const QString& name) +{ + removeRelates(); + // Create a dummy aggregate for writing the name into the index + relatesTo_ = new DocumentNode(0, name, Node::NoSubtype, Node::NoPageType); } /*! @@ -934,8 +959,9 @@ void Aggregate::makeUndocumentedChildrenInternal() } /*! - This is where we should set the overload numbers, including - the related non-members. + This is where we set the overload numbers for function nodes. + \note Overload numbers for related non-members are handled + separately. */ void Aggregate::normalizeOverloads() { @@ -1006,23 +1032,6 @@ void Aggregate::normalizeOverloads() } ++p; } - /* - Add the related non-members here. - */ - if (!related_.isEmpty()) { - foreach (Node* n, related_) { - if (n->isFunction()) { - FunctionNode* fn = static_cast(n); - QMap::Iterator p = primaryFunctionMap_.find(fn->name()); - if (p != primaryFunctionMap_.end()) { - secondaryFunctionMap_[fn->name()].append(fn); - fn->setOverloadNumber(secondaryFunctionMap_[fn->name()].size()); - } - else - fn->setOverloadNumber(0); - } - } - } /* Recursive part. */ @@ -1322,10 +1331,49 @@ QString Node::physicalModuleName() const } /*! + Removes a node from the list of nodes related to this one. + If it is a function node, also remove from the primary/ + secondary function maps. */ void Aggregate::removeRelated(Node *pseudoChild) { related_.removeAll(pseudoChild); + + if (pseudoChild->isFunction()) { + QMap::Iterator p = primaryFunctionMap_.find(pseudoChild->name()); + while (p != primaryFunctionMap_.end()) { + if (p.value() == pseudoChild) { + primaryFunctionMap_.erase(p); + break; + } + ++p; + } + NodeList& overloads = secondaryFunctionMap_[pseudoChild->name()]; + overloads.removeAll(pseudoChild); + } +} + +/*! + Adds \a pseudoChild to the list of nodes related to this one. Resolve a correct + overload number for a related non-member function. + */ +void Aggregate::addRelated(Node *pseudoChild) +{ + related_.append(pseudoChild); + + if (pseudoChild->isFunction()) { + FunctionNode* fn = static_cast(pseudoChild); + if (primaryFunctionMap_.contains(pseudoChild->name())) { + secondaryFunctionMap_[pseudoChild->name()].append(pseudoChild); + fn->setOverloadNumber(secondaryFunctionMap_[pseudoChild->name()].size()); + fn->setOverloadFlag(true); + } + else { + primaryFunctionMap_.insert(pseudoChild->name(), pseudoChild); + fn->setOverloadNumber(0); + fn->setOverloadFlag(false); + } + } } /*! diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index 596a71b6d5..6262cee0ab 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -178,6 +178,7 @@ public: void setThreadSafeness(ThreadSafeness t) { safeness_ = (unsigned char) t; } void setSince(const QString &since); void setRelates(Aggregate* pseudoParent); + void setRelates(const QString &name); void setPhysicalModuleName(const QString &name) { physicalModuleName_ = name; } void setUrl(const QString& url) { url_ = url; } void setTemplateStuff(const QString &t) { templateStuff_ = t; } @@ -336,6 +337,7 @@ public: protected: Node(NodeType type, Aggregate* parent, const QString& name); + void removeRelates(); private: @@ -421,6 +423,7 @@ private: static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2); void removeRelated(Node* pseudoChild); + void addRelated(Node* pseudoChild); QString outputFileName_; QStringList pageKeywds; diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index 7f2e64b00c..97f1929fb4 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -1295,6 +1295,10 @@ void QDocDatabase::resolveIssues() { resolveQmlInheritance(primaryTreeRoot()); primaryTree()->resolveTargets(primaryTreeRoot()); primaryTree()->resolveCppToQmlLinks(); + if (!Generator::singleExec()) { + QDocIndexFiles::qdocIndexFiles()->resolveRelates(); + QDocIndexFiles::destroyQDocIndexFiles(); + } } void QDocDatabase::resolveStuff() @@ -1305,7 +1309,6 @@ void QDocDatabase::resolveStuff() primaryTree()->resolveCppToQmlLinks(); primaryTree()->resolveUsingClauses(); resolveNamespaces(); - primaryTreeRoot()->normalizeOverloads(); } /*! @@ -1495,7 +1498,6 @@ void QDocDatabase::readIndexes(const QStringList& t) qDebug() << "This index file is already in memory:" << f; } QDocIndexFiles::qdocIndexFiles()->readIndexes(indexFiles); - QDocIndexFiles::destroyQDocIndexFiles(); } /*! diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 8db901bbc7..fc262d9834 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -100,6 +100,7 @@ void QDocIndexFiles::destroyQDocIndexFiles() */ void QDocIndexFiles::readIndexes(const QStringList& indexFiles) { + relatedList_.clear(); foreach (const QString& indexFile, indexFiles) { QString msg = "Loading index file: " + indexFile; Location::logToStdErr(msg); @@ -146,9 +147,7 @@ void QDocIndexFiles::readIndexFile(const QString& path) indexUrl = installDir.relativeFilePath(path).section('/', 0, -2); } project_ = attrs.value(QLatin1String("project")).toString(); - basesList_.clear(); - relatedList_.clear(); NamespaceNode* root = qdb_->newIndexTree(project_); @@ -730,17 +729,37 @@ void QDocIndexFiles::resolveIndex() pair.first->addUnresolvedBaseClass(Node::Public, basePath, QString()); } } + // No longer needed. + basesList_.clear(); +} + +/* + Goes though the list of nodes that are related to other aggregates + that were read from all index files, and tries to find the aggregate + nodes from the database. Calls the node's setRelates() for each + aggregate that is found in the local module (primary tree). + + This function is meant to be called before starting the doc generation, + after all the index files are read. + */ +void QDocIndexFiles::resolveRelates() +{ + if (relatedList_.isEmpty()) + return; + + // Restrict searching only to the local (primary) tree + QVector searchOrder = qdb_->searchOrder(); + qdb_->setLocalSearch(); QPair relatedPair; foreach (relatedPair, relatedList_) { QStringList path = relatedPair.second.split("::"); Node* n = qdb_->findRelatesNode(path); if (n) - relatedPair.first->setRelates(static_cast(n)); + relatedPair.first->setRelates(static_cast(n)); } - - // No longer needed. - basesList_.clear(); + // Restore original search order + qdb_->setSearchOrder(searchOrder); relatedList_.clear(); } diff --git a/src/tools/qdoc/qdocindexfiles.h b/src/tools/qdoc/qdocindexfiles.h index 1b9b6afc40..67a7e7226e 100644 --- a/src/tools/qdoc/qdocindexfiles.h +++ b/src/tools/qdoc/qdocindexfiles.h @@ -65,6 +65,7 @@ class QDocIndexFiles void readIndexFile(const QString& path); void readIndexSection(QXmlStreamReader &reader, Node* current, const QString& indexUrl); void resolveIndex(); + void resolveRelates(); bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false); void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false); -- cgit v1.2.3