qdoc: Improve resolving related non-members and their overload numbers
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ö <topi.reinio@digia.com>
This commit is contained in:
parent
53762b102b
commit
d558100aa7
@ -924,8 +924,14 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
|
|||||||
else if (command == COMMAND_RELATES) {
|
else if (command == COMMAND_RELATES) {
|
||||||
QStringList path = arg.split("::");
|
QStringList path = arg.split("::");
|
||||||
Node* n = qdb_->findRelatesNode(path);
|
Node* n = qdb_->findRelatesNode(path);
|
||||||
if (!n)
|
if (!n) {
|
||||||
doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES));
|
// 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
|
else
|
||||||
node->setRelates(static_cast<Aggregate*>(n));
|
node->setRelates(static_cast<Aggregate*>(n));
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,24 @@ Node::~Node()
|
|||||||
{
|
{
|
||||||
if (parent_)
|
if (parent_)
|
||||||
parent_->removeChild(this);
|
parent_->removeChild(this);
|
||||||
|
|
||||||
if (relatesTo_)
|
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);
|
relatesTo_->removeRelated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,11 +480,19 @@ bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
|
|||||||
*/
|
*/
|
||||||
void Node::setRelates(Aggregate *pseudoParent)
|
void Node::setRelates(Aggregate *pseudoParent)
|
||||||
{
|
{
|
||||||
if (relatesTo_) {
|
removeRelates();
|
||||||
relatesTo_->removeRelated(this);
|
|
||||||
}
|
|
||||||
relatesTo_ = pseudoParent;
|
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
|
This is where we set the overload numbers for function nodes.
|
||||||
the related non-members.
|
\note Overload numbers for related non-members are handled
|
||||||
|
separately.
|
||||||
*/
|
*/
|
||||||
void Aggregate::normalizeOverloads()
|
void Aggregate::normalizeOverloads()
|
||||||
{
|
{
|
||||||
@ -1006,23 +1032,6 @@ void Aggregate::normalizeOverloads()
|
|||||||
}
|
}
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
Add the related non-members here.
|
|
||||||
*/
|
|
||||||
if (!related_.isEmpty()) {
|
|
||||||
foreach (Node* n, related_) {
|
|
||||||
if (n->isFunction()) {
|
|
||||||
FunctionNode* fn = static_cast<FunctionNode*>(n);
|
|
||||||
QMap<QString, Node *>::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.
|
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)
|
void Aggregate::removeRelated(Node *pseudoChild)
|
||||||
{
|
{
|
||||||
related_.removeAll(pseudoChild);
|
related_.removeAll(pseudoChild);
|
||||||
|
|
||||||
|
if (pseudoChild->isFunction()) {
|
||||||
|
QMap<QString, Node *>::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<FunctionNode*>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -178,6 +178,7 @@ public:
|
|||||||
void setThreadSafeness(ThreadSafeness t) { safeness_ = (unsigned char) t; }
|
void setThreadSafeness(ThreadSafeness t) { safeness_ = (unsigned char) t; }
|
||||||
void setSince(const QString &since);
|
void setSince(const QString &since);
|
||||||
void setRelates(Aggregate* pseudoParent);
|
void setRelates(Aggregate* pseudoParent);
|
||||||
|
void setRelates(const QString &name);
|
||||||
void setPhysicalModuleName(const QString &name) { physicalModuleName_ = name; }
|
void setPhysicalModuleName(const QString &name) { physicalModuleName_ = name; }
|
||||||
void setUrl(const QString& url) { url_ = url; }
|
void setUrl(const QString& url) { url_ = url; }
|
||||||
void setTemplateStuff(const QString &t) { templateStuff_ = t; }
|
void setTemplateStuff(const QString &t) { templateStuff_ = t; }
|
||||||
@ -336,6 +337,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
Node(NodeType type, Aggregate* parent, const QString& name);
|
Node(NodeType type, Aggregate* parent, const QString& name);
|
||||||
|
void removeRelates();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -421,6 +423,7 @@ private:
|
|||||||
|
|
||||||
static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2);
|
static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2);
|
||||||
void removeRelated(Node* pseudoChild);
|
void removeRelated(Node* pseudoChild);
|
||||||
|
void addRelated(Node* pseudoChild);
|
||||||
|
|
||||||
QString outputFileName_;
|
QString outputFileName_;
|
||||||
QStringList pageKeywds;
|
QStringList pageKeywds;
|
||||||
|
@ -1295,6 +1295,10 @@ void QDocDatabase::resolveIssues() {
|
|||||||
resolveQmlInheritance(primaryTreeRoot());
|
resolveQmlInheritance(primaryTreeRoot());
|
||||||
primaryTree()->resolveTargets(primaryTreeRoot());
|
primaryTree()->resolveTargets(primaryTreeRoot());
|
||||||
primaryTree()->resolveCppToQmlLinks();
|
primaryTree()->resolveCppToQmlLinks();
|
||||||
|
if (!Generator::singleExec()) {
|
||||||
|
QDocIndexFiles::qdocIndexFiles()->resolveRelates();
|
||||||
|
QDocIndexFiles::destroyQDocIndexFiles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDocDatabase::resolveStuff()
|
void QDocDatabase::resolveStuff()
|
||||||
@ -1305,7 +1309,6 @@ void QDocDatabase::resolveStuff()
|
|||||||
primaryTree()->resolveCppToQmlLinks();
|
primaryTree()->resolveCppToQmlLinks();
|
||||||
primaryTree()->resolveUsingClauses();
|
primaryTree()->resolveUsingClauses();
|
||||||
resolveNamespaces();
|
resolveNamespaces();
|
||||||
primaryTreeRoot()->normalizeOverloads();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1495,7 +1498,6 @@ void QDocDatabase::readIndexes(const QStringList& t)
|
|||||||
qDebug() << "This index file is already in memory:" << f;
|
qDebug() << "This index file is already in memory:" << f;
|
||||||
}
|
}
|
||||||
QDocIndexFiles::qdocIndexFiles()->readIndexes(indexFiles);
|
QDocIndexFiles::qdocIndexFiles()->readIndexes(indexFiles);
|
||||||
QDocIndexFiles::destroyQDocIndexFiles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -100,6 +100,7 @@ void QDocIndexFiles::destroyQDocIndexFiles()
|
|||||||
*/
|
*/
|
||||||
void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
|
void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
|
||||||
{
|
{
|
||||||
|
relatedList_.clear();
|
||||||
foreach (const QString& indexFile, indexFiles) {
|
foreach (const QString& indexFile, indexFiles) {
|
||||||
QString msg = "Loading index file: " + indexFile;
|
QString msg = "Loading index file: " + indexFile;
|
||||||
Location::logToStdErr(msg);
|
Location::logToStdErr(msg);
|
||||||
@ -146,9 +147,7 @@ void QDocIndexFiles::readIndexFile(const QString& path)
|
|||||||
indexUrl = installDir.relativeFilePath(path).section('/', 0, -2);
|
indexUrl = installDir.relativeFilePath(path).section('/', 0, -2);
|
||||||
}
|
}
|
||||||
project_ = attrs.value(QLatin1String("project")).toString();
|
project_ = attrs.value(QLatin1String("project")).toString();
|
||||||
|
|
||||||
basesList_.clear();
|
basesList_.clear();
|
||||||
relatedList_.clear();
|
|
||||||
|
|
||||||
NamespaceNode* root = qdb_->newIndexTree(project_);
|
NamespaceNode* root = qdb_->newIndexTree(project_);
|
||||||
|
|
||||||
@ -730,17 +729,37 @@ void QDocIndexFiles::resolveIndex()
|
|||||||
pair.first->addUnresolvedBaseClass(Node::Public, basePath, QString());
|
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<Tree*> searchOrder = qdb_->searchOrder();
|
||||||
|
qdb_->setLocalSearch();
|
||||||
|
|
||||||
QPair<FunctionNode*,QString> relatedPair;
|
QPair<FunctionNode*,QString> relatedPair;
|
||||||
foreach (relatedPair, relatedList_) {
|
foreach (relatedPair, relatedList_) {
|
||||||
QStringList path = relatedPair.second.split("::");
|
QStringList path = relatedPair.second.split("::");
|
||||||
Node* n = qdb_->findRelatesNode(path);
|
Node* n = qdb_->findRelatesNode(path);
|
||||||
if (n)
|
if (n)
|
||||||
relatedPair.first->setRelates(static_cast<ClassNode*>(n));
|
relatedPair.first->setRelates(static_cast<Aggregate*>(n));
|
||||||
}
|
}
|
||||||
|
// Restore original search order
|
||||||
// No longer needed.
|
qdb_->setSearchOrder(searchOrder);
|
||||||
basesList_.clear();
|
|
||||||
relatedList_.clear();
|
relatedList_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ class QDocIndexFiles
|
|||||||
void readIndexFile(const QString& path);
|
void readIndexFile(const QString& path);
|
||||||
void readIndexSection(QXmlStreamReader &reader, Node* current, const QString& indexUrl);
|
void readIndexSection(QXmlStreamReader &reader, Node* current, const QString& indexUrl);
|
||||||
void resolveIndex();
|
void resolveIndex();
|
||||||
|
void resolveRelates();
|
||||||
bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
||||||
void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user