summaryrefslogtreecommitdiffstats
path: root/src/qdoc/node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/node.cpp')
-rw-r--r--src/qdoc/node.cpp1648
1 files changed, 995 insertions, 653 deletions
diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp
index f80a7bac3..f80aaf699 100644
--- a/src/qdoc/node.cpp
+++ b/src/qdoc/node.cpp
@@ -65,6 +65,7 @@ void Node::initialize()
goals_.insert("typedef", Node::Typedef);
goals_.insert("typealias", Node::Typedef);
goals_.insert("function", Node::Function);
+ goals_.insert("proxy", Node::Proxy);
goals_.insert("property", Node::Property);
goals_.insert("variable", Node::Variable);
goals_.insert("group", Node::Group);
@@ -149,9 +150,9 @@ bool Node::nodeNameLessThan(const Node *n1, const Node *n2)
else if (f1->isConst() > f2->isConst())
return false;
- if (f1->signature(false) < f2->signature(false))
+ if (f1->signature(false, false) < f2->signature(false, false))
return true;
- else if (f1->signature(false) > f2->signature(false))
+ else if (f1->signature(false, false) > f2->signature(false, false))
return false;
}
@@ -199,34 +200,11 @@ void Node::clearPropertyGroupCount() { propertyGroupCount_ = 0; }
*/
/*!
- When this Node is destroyed, if it has a parent Node, it
- removes itself from the parent node's child list.
+ The destructor does nothing.
*/
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_->isDummyNode() && !relatesTo_->parent()) {
- delete relatesTo_;
- relatesTo_ = 0;
- } else {
- relatesTo_->removeRelated(this);
- }
+ // nothing.
}
/*!
@@ -340,8 +318,8 @@ Node::Node(NodeType type, Aggregate *parent, const QString& name)
pageType_((unsigned char) NoPageType),
status_((unsigned char) Active),
indexNodeFlag_(false),
+ relatedNonmember_(false),
parent_(parent),
- relatesTo_(0),
sharedCommentNode_(0),
name_(name)
{
@@ -432,6 +410,7 @@ Node::PageType Node::getPageType(Node::NodeType t)
case Node::JsModule:
case Node::Collection:
return Node::OverviewPage;
+ case Node::Proxy:
default:
return Node::NoPageType;
}
@@ -478,6 +457,7 @@ Node::Genus Node::getGenus(Node::NodeType t)
return Node::DOC;
case Node::Collection:
case Node::SharedComment:
+ case Node::Proxy:
default:
return Node::DontCare;
}
@@ -568,6 +548,8 @@ QString Node::nodeTypeString(unsigned char t)
return QLatin1String("function");
case Property:
return QLatin1String("property");
+ case Proxy:
+ return QLatin1String("proxy");
case Variable:
return QLatin1String("variable");
case Group:
@@ -661,29 +643,6 @@ bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
}
/*!
- Sets the pointer to the node that this node relates to.
- */
-void Node::setRelates(PageNode *pseudoParent)
-{
- if (pseudoParent == parent())
- return;
-
- removeRelates();
- relatesTo_ = pseudoParent;
- 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 DummyNode(0, name);
-}
-
-/*!
This function creates a pair that describes a link.
The pair is composed from \a link and \a desc. The
\a linkType is the map index the pair is filed under.
@@ -848,17 +807,20 @@ bool Node::isInternal() const
return true;
if (parent() && parent()->status() == Internal)
return true;
- if (relates() && relates()->status() == Internal)
- return true;
return false;
}
/*!
Returns a pointer to the root of the Tree this node is in.
*/
-const Node* Node::root() const
+Aggregate *Node::root() const
{
- return (parent() ? parent()->root() : this);
+ if (parent() == nullptr)
+ return (this->isAggregate() ? static_cast<Aggregate*>(const_cast<Node*>(this)) : nullptr);
+ Aggregate *t = parent();
+ while (t->parent() != nullptr)
+ t = t->parent();
+ return t;
}
/*!
@@ -906,17 +868,91 @@ bool Node::hasSharedDoc() const
}
/*!
+ Returns the CPP node's qualified name by prepending the
+ namespaces name + "::" if there isw a namespace.
+ */
+QString Node::qualifyCppName()
+{
+ if (parent_ && parent_->isNamespace() && !parent_->name().isEmpty())
+ return parent_->name() + "::" + name_;
+ return name_;
+}
+
+/*!
+ Return the name of this node qualified with the parent name
+ and "::" if there is a parent name.
+ */
+QString Node::qualifyWithParentName()
+{
+ if (parent_ && !parent_->name().isEmpty())
+ return parent_->name() + "::" + name_;
+ return name_;
+}
+
+
+/*!
+ Returns the QML node's qualified name by stripping off the
+ "QML:" if present and prepending the logical module name.
+ */
+QString Node::qualifyQmlName()
+{
+ QString qualifiedName = name_;
+ if (name_.startsWith(QLatin1String("QML:")))
+ qualifiedName = name_.mid(4);
+ qualifiedName = logicalModuleName() + "::" + name_;
+ return qualifiedName;
+}
+
+/*!
+ Returns the QML node's name after stripping off the
+ "QML:" if present.
+ */
+QString Node::unqualifyQmlName()
+{
+ QString qmlTypeName = name_.toLower();
+ if (qmlTypeName.startsWith(QLatin1String("qml:")))
+ qmlTypeName = qmlTypeName.mid(4);
+ return qmlTypeName;
+}
+
+/*!
\class Aggregate
*/
/*!
- The inner node destructor deletes the children and removes
- this node from its related nodes.
+ Calls delete for each child of this Aggregate that has this
+ Aggregate as its parent. A child node that has some other
+ Aggregate as its parent is deleted by that Aggregate's
+ destructor.
+
+ The destructor no longer deletes the collection of children
+ by calling qDeleteAll() because the child list can contain
+ pointers to children that have some other Aggregate as their
+ parent. This is because of how the \e{\\relates} command is
+ processed. An Aggregate can have a pointer to, for example,
+ a FunctionNode in its child list, but that FunctionNode has
+ a differen Aggregate as its parent because a \e{\\relates}
+ command was used to relate it to that parent. In that case,
+ the other Aggregate's destructor must delete that node.
+
+ \note This function is the \b only place where delete is
+ called to delete any subclass of Node.
+
+ \note This strategy depends on the node tree being destroyed
+ by calling delete on the root node of the tree. This happens
+ in the destructor of class Tree.
*/
Aggregate::~Aggregate()
{
- removeFromRelated();
- deleteChildren();
+ enumChildren_.clear();
+ nonfunctionMap_.clear();
+ functionMap_.clear();
+ for (int i = 0; i < children_.size(); ++i) {
+ if ((children_[i] != nullptr) && (children_[i]->parent() == this))
+ delete children_[i];
+ children_[i] = 0;
+ }
+ children_.clear();
}
/*!
@@ -932,7 +968,7 @@ Aggregate::~Aggregate()
Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findFlags) const
{
if (genus == Node::DontCare) {
- Node *node = childMap_.value(name);
+ Node *node = nonfunctionMap_.value(name);
if (node && !node->isQmlPropertyGroup()) // mws asks: Why not property group?
return node;
if (isQmlType() || isJsType()) {
@@ -946,7 +982,7 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF
}
}
} else {
- NodeList nodes = childMap_.values(name);
+ NodeList nodes = nonfunctionMap_.values(name);
if (!nodes.isEmpty()) {
for (int i = 0; i < nodes.size(); ++i) {
Node* node = nodes.at(i);
@@ -969,37 +1005,54 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF
}
if (genus != Node::DontCare && this->genus() != genus)
return nullptr;
- return primaryFunctionMap_.value(name);
+ return functionMap_.value(name);
}
/*!
Find all the child nodes of this node that are named
\a name and return them in \a nodes.
*/
-void Aggregate::findChildren(const QString& name, NodeList& nodes) const
-{
- nodes = childMap_.values(name);
- Node* n = primaryFunctionMap_.value(name);
- if (n) {
- nodes.append(n);
- NodeList t = secondaryFunctionMap_.value(name);
- if (!t.isEmpty())
- nodes.append(t);
+void Aggregate::findChildren(const QString &name, NodeVector &nodes) const
+{
+ nodes.clear();
+ int nonfunctionCount = nonfunctionMap_.count(name);
+ FunctionMap::const_iterator i = functionMap_.find(name);
+ if (i != functionMap_.end()) {
+ int functionCount = 0;
+ FunctionNode *fn = i.value();
+ while (fn != nullptr) {
+ ++functionCount;
+ fn = fn->nextOverload();
+ }
+ nodes.reserve(nonfunctionCount + functionCount);
+ fn = i.value();
+ while (fn != nullptr) {
+ nodes.append(fn);
+ fn = fn->nextOverload();
+ }
+ } else {
+ nodes.reserve(nonfunctionCount);
}
- if (!nodes.isEmpty() || !(isQmlNode() || isJsNode()))
- return;
- int i = name.indexOf(QChar('.'));
- if (i < 0)
- return;
- QString qmlPropGroup = name.left(i);
- NodeList t = childMap_.values(qmlPropGroup);
- if (t.isEmpty())
- return;
- foreach (Node* n, t) {
- if (n->isQmlPropertyGroup() || n->isJsPropertyGroup()) {
- n->findChildren(name, nodes);
- if (!nodes.isEmpty())
- break;
+ if (nonfunctionCount > 0) {
+ NodeMap::const_iterator i = nonfunctionMap_.find(name);
+ while (i != nonfunctionMap_.end() && i.key() == name) {
+ nodes.append(i.value());
+ ++i;
+ }
+ }
+ if (nodes.isEmpty() && (isQmlNode() || isJsNode())) {
+ int idx = name.indexOf(QChar('.'));
+ if (idx < 0)
+ return;
+ QString qmlPropGroup = name.left(idx);
+ NodeMap::const_iterator i = nonfunctionMap_.find(qmlPropGroup);
+ while (i != nonfunctionMap_.end() && i.key() == qmlPropGroup) {
+ if (i.value()->isQmlPropertyGroup() || i.value()->isJsPropertyGroup()) {
+ static_cast<Aggregate*>(i.value())->findChildren(name, nodes);
+ if (!nodes.isEmpty())
+ return;
+ }
+ ++i;
}
}
}
@@ -1012,136 +1065,74 @@ void Aggregate::findChildren(const QString& name, NodeList& nodes) const
Node* Aggregate::findChildNode(const QString& name, NodeType type)
{
if (type == Function)
- return primaryFunctionMap_.value(name);
- else {
- NodeList nodes = childMap_.values(name);
- for (int i=0; i<nodes.size(); ++i) {
- Node* node = nodes.at(i);
- if (node->nodeType() == type)
- return node;
- }
+ return functionMap_.value(name);
+ NodeList nodes = nonfunctionMap_.values(name);
+ for (int i=0; i<nodes.size(); ++i) {
+ Node *node = nodes.at(i);
+ if (node->nodeType() == type)
+ return node;
}
- return 0;
+ return nullptr;
}
/*!
- Find a function node that is a child of this nose, such
- that the function node has the specified \a name.
+ Find a function node that is a child of this node, such that
+ the function node has the specified \a name and \a parameters.
+ If \a parameters is empty but no matching function is found
+ that has no parameters, return the primary function whether
+ it has parameters or not.
*/
-FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const
+FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters &parameters)
{
- FunctionNode* pfn = static_cast<FunctionNode*>(primaryFunctionMap_.value(name));
- FunctionNode* fn = pfn;
- if (fn) {
- const QVector<Parameter>* funcParams = &(fn->parameters());
- if (params.isEmpty() && funcParams->isEmpty() && !fn->isInternal())
- return fn;
- bool isQPrivateSignal = false; // Not used in the search
- QVector<Parameter> testParams;
- if (!params.isEmpty()) {
- CppCodeParser* cppParser = PureDocParser::pureDocParser();
- cppParser->parseParameters(params, testParams, isQPrivateSignal);
- }
- NodeList funcs = secondaryFunctionMap_.value(name);
- int i = -1;
- while (fn) {
- if (testParams.size() == funcParams->size()) {
- if (testParams.isEmpty() && !fn->isInternal())
- return fn;
- bool different = false;
- for (int j=0; j<testParams.size(); j++) {
- if (testParams.at(j).dataType() != funcParams->at(j).dataType()) {
- different = true;
- break;
- }
+ FunctionMap::iterator i = functionMap_.find(name);
+ if (i == functionMap_.end())
+ return nullptr;
+ FunctionNode *fn = i.value();
+
+ if (parameters.isEmpty() && fn->parameters().isEmpty() && !fn->isInternal())
+ return fn;
+
+ while (fn != nullptr) {
+ if (parameters.count() == fn->parameters().count() && !fn->isInternal()) {
+ if (parameters.isEmpty())
+ return fn;
+ bool matched = true;
+ for (int i = 0; i < parameters.count(); i++) {
+ if (parameters.at(i).type() != fn->parameters().at(i).type()) {
+ matched = false;
+ break;
}
- if (!different && !fn->isInternal())
- return fn;
- }
- if (++i < funcs.size()) {
- fn = static_cast<FunctionNode*>(funcs.at(i));
- funcParams = &(fn->parameters());
- }
- else
- fn = 0;
- }
- /*
- Most \l commands that link to functions don't include
- the parameter declarations in the function signature,
- so if the \l is meant to go to a function that does
- have parameters, the algorithm above won't find it.
- Therefore we must return the pointer to the function
- in the primary function map in the cases where the
- parameters should have been specified in the \l command.
- But if the primary function is marked internal, search
- the secondary list to find one that is not marked internal.
- */
- if (!fn) {
- if (!testParams.empty())
- return 0;
- if (pfn && !pfn->isInternal())
- return pfn;
- foreach (Node* n, funcs) {
- fn = static_cast<FunctionNode*>(n);
- if (!fn->isInternal())
- return fn;
}
+ if (matched)
+ return fn;
}
+ fn = fn->nextOverload();
}
- return fn;
+ return parameters.isEmpty() ? i.value() : nullptr;
}
/*!
Find the function node that is a child of this node, such
- that the function has the same name and signature as the
- \a clone node.
- */
-FunctionNode *Aggregate::findFunctionNode(const FunctionNode *clone) const
-{
- QMap<QString,Node*>::ConstIterator c = primaryFunctionMap_.constFind(clone->name());
- if (c != primaryFunctionMap_.constEnd()) {
- if (isSameSignature(clone, (FunctionNode *) *c)) {
- return (FunctionNode *) *c;
- }
- else if (secondaryFunctionMap_.contains(clone->name())) {
- const NodeList& secs = secondaryFunctionMap_[clone->name()];
- NodeList::ConstIterator s = secs.constBegin();
- while (s != secs.constEnd()) {
- if (isSameSignature(clone, (FunctionNode *) *s))
- return (FunctionNode *) *s;
- ++s;
- }
- }
- }
- return 0;
-}
-
-/*!
- Returns the list of keys from the primary function map.
+ that the function described has the same name and signature
+ as the function described by the \a clone node.
*/
-QStringList Aggregate::primaryKeys()
+FunctionNode *Aggregate::findFunctionChild(const FunctionNode *clone)
{
- QStringList t;
- QMap<QString, Node*>::iterator i = primaryFunctionMap_.begin();
- while (i != primaryFunctionMap_.end()) {
- t.append(i.key());
- ++i;
+ FunctionNode *fn = functionMap_.value(clone->name());
+ while (fn != nullptr) {
+ if (isSameSignature(clone, fn))
+ return fn;
+ fn = fn->nextOverload();
}
- return t;
+ return nullptr;
}
/*!
- Returns the list of keys from the secondary function map.
+ Returns the list of keys from the primary function map.
*/
-QStringList Aggregate::secondaryKeys()
+QStringList Aggregate::primaryKeys()
{
- QStringList t;
- QMap<QString, NodeList>::iterator i = secondaryFunctionMap_.begin();
- while (i != secondaryFunctionMap_.end()) {
- t.append(i.key());
- ++i;
- }
- return t;
+ return functionMap_.keys();
}
/*!
@@ -1149,13 +1140,28 @@ QStringList Aggregate::secondaryKeys()
private access and internal status. qdoc will then ignore
them for documentation purposes.
*/
-void Aggregate::makeUndocumentedChildrenInternal()
+void Aggregate::markUndocumentedChildrenInternal()
{
- foreach (Node *child, childNodes()) {
+ // Property group children have no doc of their own but follow the
+ // the access/status of their parent
+ if (this->isQmlPropertyGroup() || this->isJsPropertyGroup())
+ return;
+
+ foreach (Node *child, children_) {
if (!child->isSharingComment() && !child->hasDoc() && !child->docMustBeGenerated()) {
+ if (child->isFunction()) {
+ if (static_cast<FunctionNode*>(child)->hasAssociatedProperties())
+ continue;
+ } else if (child->isTypedef()) {
+ if (static_cast<TypedefNode*>(child)->hasAssociatedEnum())
+ continue;
+ }
child->setAccess(Node::Private);
child->setStatus(Node::Internal);
}
+ if (child->isAggregate()) {
+ static_cast<Aggregate*>(child)->markUndocumentedChildrenInternal();
+ }
}
}
@@ -1166,97 +1172,50 @@ void Aggregate::makeUndocumentedChildrenInternal()
*/
void Aggregate::normalizeOverloads()
{
- QMap<QString, Node *>::Iterator p1 = primaryFunctionMap_.begin();
- while (p1 != primaryFunctionMap_.end()) {
- FunctionNode *primaryFunc = (FunctionNode *) *p1;
- if (primaryFunc->status() != Active || primaryFunc->access() == Private) {
- if (secondaryFunctionMap_.contains(primaryFunc->name())) {
- /*
- Either the primary function is not active or it is private.
- It therefore can't be the primary function. Search the list
- of overloads to find one that can be the primary function.
- */
- NodeList& overloads = secondaryFunctionMap_[primaryFunc->name()];
- NodeList::ConstIterator s = overloads.constBegin();
- while (s != overloads.constEnd()) {
- FunctionNode *overloadFunc = (FunctionNode *) *s;
- /*
- Any non-obsolete, non-private function (i.e., visible function)
- is preferable to the current primary function. Swap the primary
- and overload functions.
- */
- if (overloadFunc->status() == Active && overloadFunc->access() != Private) {
- primaryFunc->setOverloadNumber(overloadFunc->overloadNumber());
- overloads.replace(overloads.indexOf(overloadFunc), primaryFunc);
- *p1 = overloadFunc;
- overloadFunc->setOverloadFlag(false);
- overloadFunc->setOverloadNumber(0);
- break;
- }
- ++s;
- }
- }
- }
- ++p1;
- }
/*
- Ensure that none of the primary functions is marked with \overload.
- */
- QMap<QString, Node *>::Iterator p = primaryFunctionMap_.begin();
- while (p != primaryFunctionMap_.end()) {
- FunctionNode *primaryFunc = (FunctionNode *) *p;
- if (primaryFunc->isOverload()) {
- if (secondaryFunctionMap_.contains(primaryFunc->name())) {
- /*
- The primary function is marked with \overload. Find an
- overload in the secondary function map that is not marked
- with \overload but that is active and not private. Then
- swap it with the primary function.
- */
- NodeList& overloads = secondaryFunctionMap_[primaryFunc->name()];
- NodeList::ConstIterator s = overloads.constBegin();
- while (s != overloads.constEnd()) {
- FunctionNode *overloadFunc = (FunctionNode *) *s;
- if (!overloadFunc->isOverload()) {
- if (overloadFunc->status() == Active && overloadFunc->access() != Private) {
- primaryFunc->setOverloadNumber(overloadFunc->overloadNumber());
- overloads.replace(overloads.indexOf(overloadFunc), primaryFunc);
- *p = overloadFunc;
- overloadFunc->setOverloadFlag(false);
- overloadFunc->setOverloadNumber(0);
- break;
- }
- }
- ++s;
- }
+ Ensure that none of the primary functions is inactive, private,
+ or marked \e {overload}.
+ */
+ FunctionMap::Iterator i = functionMap_.begin();
+ while (i != functionMap_.end()) {
+ FunctionNode *fn = i.value();
+ if (fn->isOverload()) {
+ FunctionNode *primary = fn->findPrimaryFunction();
+ if (primary) {
+ primary->setNextOverload(fn);
+ i.value() = primary;
+ fn = primary;
+ } else {
+ fn->clearOverloadFlag();
}
}
- ++p;
+ int count = 0;
+ fn->setOverloadNumber(0);
+ fn = fn->nextOverload();
+ while (fn != nullptr) {
+ fn->setOverloadNumber(++count);
+ fn = fn->nextOverload();
+ }
+ ++i; // process next function in function map.
}
/*
Recursive part.
*/
- NodeList::ConstIterator c = childNodes().constBegin();
- while (c != childNodes().constEnd()) {
- if ((*c)->isAggregate())
- ((Aggregate *) *c)->normalizeOverloads();
- ++c;
+ foreach (Node *n, children_) {
+ if (n->isAggregate())
+ static_cast<Aggregate*>(n)->normalizeOverloads();
}
}
/*!
- Deletes all this node's children.
+ Returns a const reference to the list of child nodes of this
+ aggregate that are not function nodes.
*/
-void Aggregate::deleteChildren()
+const NodeList &Aggregate::nonfunctionList()
{
- NodeList childrenCopy = children_;
- // Clear internal collections before deleting child nodes
- children_.clear();
- childMap_.clear();
- enumChildren_.clear();
- primaryFunctionMap_.clear();
- secondaryFunctionMap_.clear();
- qDeleteAll(childrenCopy);
+ if (nonfunctionList_.isEmpty() || (nonfunctionList_.size() != nonfunctionMap_.size()))
+ nonfunctionList_ = nonfunctionMap_.values();
+ return nonfunctionList_;
}
/*! \fn bool Aggregate::isAggregate() const
@@ -1290,34 +1249,19 @@ const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
}
/*!
- Returns a node list containing all the member functions of
- some class such that the functions overload the name \a funcName.
+ Appends \a includeFile file to the list of include files.
*/
-NodeList Aggregate::overloads(const QString &funcName) const
+void Aggregate::addIncludeFile(const QString &includeFile)
{
- NodeList result;
- Node *primary = primaryFunctionMap_.value(funcName);
- if (primary) {
- result << primary;
- result += secondaryFunctionMap_[funcName];
- }
- return result;
+ includeFiles_.append(includeFile);
}
/*!
- Appends an \a include file to the list of include files.
+ Sets the list of include files to \a includeFiles.
*/
-void Aggregate::addInclude(const QString& include)
+void Aggregate::setIncludeFiles(const QStringList &includeFiles)
{
- includes_.append(include);
-}
-
-/*!
- Sets the list of include files to \a includes.
- */
-void Aggregate::setIncludes(const QStringList& includes)
-{
- includes_ = includes;
+ includeFiles_ = includeFiles;
}
/*!
@@ -1325,7 +1269,7 @@ void Aggregate::setIncludes(const QStringList& includes)
*/
bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
{
- if (f1->parameters().size() != f2->parameters().size())
+ if (f1->parameters().count() != f2->parameters().count())
return false;
if (f1->isConst() != f2->isConst())
return false;
@@ -1334,12 +1278,12 @@ bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
if (f1->isRefRef() != f2->isRefRef())
return false;
- QVector<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
- QVector<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
- while (p2 != f2->parameters().constEnd()) {
- if ((*p1).hasType() && (*p2).hasType()) {
- QString t1 = p1->dataType();
- QString t2 = p2->dataType();
+ const Parameters &p1 = f1->parameters();
+ const Parameters &p2 = f2->parameters();
+ for (int i = 0; i < p1.count(); i++) {
+ if (p1.at(i).hasType() && p2.at(i).hasType()) {
+ QString t1 = p1.at(i).type();
+ QString t2 = p2.at(i).type();
if (t1.length() < t2.length())
qSwap(t1, t2);
@@ -1360,44 +1304,60 @@ bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
return false;
}
}
- ++p1;
- ++p2;
}
return true;
}
/*!
- Adds the \a child to this node's child list. It might also
- be necessary to update this node's internal collections and
- the child's parent pointer and output subdirectory.
+ This function is only called by addChild(), when the child is a
+ FunctionNode. If the function map does not contain a function with
+ the name in \a fn, \a fn is inserted into the function map. If the
+ map already contains a function by that name, \a fn is appended to
+ that function's linked list of overloads.
+
+ \note A function's overloads appear in the linked list in the same
+ order they were created. The first overload in the list is the first
+ overload created. This order is maintained in the numbering of
+ overloads. In other words, the first overload in the linked list has
+ overload number 1, and the last overload in the list has overload
+ number n, where n is the number of overloads not including the
+ function in the function map.
+
+ \not Adding a function increments the aggregate's function count,
+ which is the total number of function nodes in the function map,
+ including the overloads. The overloads are not inserted into the map
+ but are in a linked list using the FunctionNode's nextOverload_
+ pointer.
+
+ \note The function's overload number and overload flag are set in
+ normalizeOverloads().
+
+ \sa normalizeOverloads()
*/
-void Aggregate::addChild(Node *child)
+void Aggregate::addFunction(FunctionNode *fn)
{
- children_.append(child);
- if (child->isFunction()) {
- FunctionNode *func = static_cast<FunctionNode*>(child);
- QString name = func->name();
- if (!primaryFunctionMap_.contains(name)) {
- primaryFunctionMap_.insert(name, func);
- func->setOverloadNumber(0);
- }
- else {
- NodeList &overloads = secondaryFunctionMap_[name];
- overloads.append(func);
- func->setOverloadNumber(overloads.size());
- }
- }
- else {
- if (child->isEnumType())
- enumChildren_.append(child);
- childMap_.insertMulti(child->name(), child);
- }
- if (child->parent() == 0) {
- child->setParent(this);
- child->setOutputSubdirectory(this->outputSubdirectory());
- child->setUrl(QString());
- child->setIndexNodeFlag(isIndexNode());
- }
+ FunctionMap::iterator i = functionMap_.find(fn->name());
+ if (i == functionMap_.end())
+ functionMap_.insert(fn->name(), fn);
+ else
+ i.value()->appendOverload(fn);
+ functionCount_++;
+}
+
+/*!
+ When an Aggregate adopts a function that is a child of
+ another Aggregate, the function is inserted into this
+ Aggregate's function map, if the function's name is not
+ already in the function map. If the function's name is
+ already in the function map, do nothing. The overload
+ link is already set correctly.
+ */
+void Aggregate::adoptFunction(FunctionNode *fn)
+{
+ FunctionMap::iterator i = functionMap_.find(fn->name());
+ if (i == functionMap_.end())
+ functionMap_.insert(fn->name(), fn);
+ functionCount_++;
}
/*!
@@ -1408,52 +1368,74 @@ void Aggregate::addChild(Node *child)
*/
void Aggregate::addChildByTitle(Node* child, const QString& title)
{
- childMap_.insertMulti(title, child);
+ nonfunctionMap_.insertMulti(title, child);
}
/*!
- The \a child is removed from this node's child list and
- from this node's internal collections. The child's parent
- pointer is set to 0, but its output subdirectory is not
- changed.
+ Adds the \a child to this node's child list and sets the child's
+ parent pointer to this Aggregate. It then mounts the child with
+ mountChild().
+
+ The \a child is then added to this Aggregate's searchable maps
+ and lists.
+
+ \note This function does not test the child's parent pointer
+ for null before changing it. If the child's parent pointer
+ is not null, then it is being reparented. The child becomes
+ a child of this Aggregate, but it also remains a child of
+ the Aggregate that is it's old parent. But the child will
+ only have one parent, and it will be this Aggregate. The is
+ because of the \c relates command.
+
+ \sa mountChild(), dismountChild()
*/
-void Aggregate::removeChild(Node *child)
+void Aggregate::addChild(Node *child)
{
- children_.removeAll(child);
- enumChildren_.removeAll(child);
+ children_.append(child);
+ child->setParent(this);
+ child->setOutputSubdirectory(this->outputSubdirectory());
+ child->setUrl(QString());
+ child->setIndexNodeFlag(isIndexNode());
if (child->isFunction()) {
- QMap<QString, Node *>::Iterator primary = primaryFunctionMap_.find(child->name());
- NodeList& overloads = secondaryFunctionMap_[child->name()];
- if (primary != primaryFunctionMap_.end() && *primary == child) {
- primaryFunctionMap_.erase(primary);
- if (!overloads.isEmpty()) {
- FunctionNode* fn = static_cast<FunctionNode*>(overloads.takeFirst());
- fn->setOverloadNumber(0);
- primaryFunctionMap_.insert(child->name(), fn);
- }
- }
- else
- overloads.removeAll(child);
+ addFunction(static_cast<FunctionNode*>(child));
}
- QMap<QString, Node *>::Iterator ent = childMap_.find(child->name());
- while (ent != childMap_.end() && ent.key() == child->name()) {
- if (*ent == child) {
- childMap_.erase(ent);
- break;
- }
- ++ent;
+ else {
+ nonfunctionMap_.insertMulti(child->name(), child);
+ if (child->isEnumType())
+ enumChildren_.append(child);
}
- 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;
+}
+
+/*!
+ This Aggregate becomes the adoptive parent of \a child. The
+ \a child knows this Aggregate as its parent, but its former
+ parent continues to have pointers to the child in its child
+ list and in its searchable data structures. But the child is
+ also added to the child list and searchable data structures
+ of this Aggregate.
+
+ The one caveat is that if the child being adopted is a function
+ node, it's next overload pointer is not altered.
+ */
+void Aggregate::adoptChild(Node *child)
+{
+ if (child->parent() != this) {
+ children_.append(child);
+ child->setParent(this);
+ if (child->isFunction()) {
+ adoptFunction(static_cast<FunctionNode*>(child));
+ }
+ else {
+ nonfunctionMap_.insertMulti(child->name(), child);
+ if (child->isEnumType()) {
+ enumChildren_.append(child);
+ } else if (child->isSharedCommentNode()) {
+ SharedCommentNode *scn = static_cast<SharedCommentNode*>(child);
+ for (Node *n : scn->collective())
+ adoptChild(n);
+ }
}
- ++ent;
}
- child->setParent(0);
}
/*!
@@ -1462,8 +1444,8 @@ void Aggregate::removeChild(Node *child)
void Aggregate::setOutputSubdirectory(const QString &t)
{
Node::setOutputSubdirectory(t);
- for (int i = 0; i < childNodes().size(); ++i)
- childNodes().at(i)->setOutputSubdirectory(t);
+ foreach (Node *n, children_)
+ n->setOutputSubdirectory(t);
}
/*!
@@ -1532,7 +1514,7 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n) const
goal1 = Node::JsProperty;
goal2 = Node::JsPropertyGroup;
}
- foreach (Node* child, childNodes()) {
+ foreach (Node *child, children_) {
if (child->nodeType() == goal1) {
if (child->name() == n)
return static_cast<QmlPropertyNode*>(child);
@@ -1558,7 +1540,7 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
goal1 = Node::JsProperty;
goal2 = Node::JsPropertyGroup;
}
- foreach (Node* child, childNodes()) {
+ foreach (Node *child, children_) {
if (child->nodeType() == goal1) {
if (child->name() == n && child->isAttached() == attached)
return static_cast<QmlPropertyNode*>(child);
@@ -1572,6 +1554,28 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
}
/*!
+ The FunctionNode \a fn is assumed to be a member function
+ of this Aggregate. The function's name is looked up in the
+ Aggregate's function map. It should be found because it is
+ assumed that \a fn is in this Aggregate's function map. But
+ in case it is not found, \c false is returned.
+
+ Normally, the name will be found in the function map, and
+ the value of the iterator is used to get the value, which
+ is a pointer to another FunctionNode, which is not itself
+ an overload. If that function has a non-null overload
+ pointer, true is returned. Otherwise false is returned.
+
+ This is a convenience function that you should not need to
+ use.
+ */
+bool Aggregate::hasOverloads(const FunctionNode *fn) const
+{
+ FunctionMap::const_iterator i = functionMap_.find(fn->name());
+ return (i == functionMap_.end() ? false : (i.value()->nextOverload() != nullptr));
+}
+
+/*!
\class NamespaceNode
\brief This class represents a C++ namespace.
@@ -1581,6 +1585,18 @@ QmlPropertyNode* Aggregate::hasQmlProperty(const QString& n, bool attached) cons
*/
/*!
+ If this is the global namespace node, remove all orphans
+ from the child list before deleting anything.
+ */
+NamespaceNode::~NamespaceNode()
+{
+ for (int i = 0; i < children_.size(); ++i) {
+ if (children_[i]->parent() != this)
+ children_[i] = nullptr;
+ }
+}
+
+/*!
Returns true if this namespace is to be documented in the
current module. There can be elements declared in this
namespace spread over multiple modules. Those elements are
@@ -1599,7 +1615,7 @@ bool NamespaceNode::isDocumentedHere() const
*/
bool NamespaceNode::hasDocumentedChildren() const
{
- foreach (Node* n, childNodes()) {
+ foreach (Node *n, children_) {
if (n->hasDoc() && !n->isPrivate() && !n->isInternal())
return true;
}
@@ -1613,7 +1629,7 @@ bool NamespaceNode::hasDocumentedChildren() const
*/
void NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace() const
{
- foreach (Node* n, childNodes()) {
+ foreach (Node *n, children_) {
if (n->hasDoc() && !n->isPrivate() && !n->isInternal()) {
QString msg1 = n->name();
if (n->isFunction())
@@ -1638,6 +1654,31 @@ bool NamespaceNode::docMustBeGenerated() const
}
/*!
+ Returns a const reference to the namespace node's list of
+ included children, which contains pointers to all the child
+ nodes of other namespace nodes that have the same name as
+ this namespace node. The list is built after the prepare
+ phase has been run but just before the generate phase. It
+ is buils by QDocDatabase::resolveNamespaces().
+
+ \sa QDocDatabase::resolveNamespaces()
+ */
+const NodeList &NamespaceNode::includedChildren() const
+{
+ return includedChildren_;
+}
+
+/*!
+ This function is only called from QDocDatabase::resolveNamesapces().
+
+ \sa includedChildren(), QDocDatabase::resolveNamespaces()
+ */
+void NamespaceNode::includeChild(Node *child)
+{
+ includedChildren_.append(child);
+}
+
+/*!
\class ClassNode
\brief This class represents a C++ class.
*/
@@ -1826,6 +1867,9 @@ QmlTypeNode* ClassNode::findQmlBaseNode()
\a fn overrides in this class's children or in one of this
class's base classes. Return a pointer to the overridden
function or return 0.
+
+ This should be revised because clang provides the path to the
+ overridden function. mws 15/12/2018
*/
FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
{
@@ -1837,7 +1881,7 @@ FunctionNode* ClassNode::findOverriddenFunction(const FunctionNode* fn)
bc->node_ = cn;
}
if (cn) {
- FunctionNode* result = cn->findFunctionNode(fn);
+ FunctionNode *result = cn->findFunctionChild(fn);
if (result && !result->isNonvirtual())
return result;
result = cn->findOverriddenFunction(fn);
@@ -1900,44 +1944,9 @@ bool PageNode::setTitle(const QString &title)
Sets the node's \a subtitle. Returns true;
*/
-/*!
- While there are related nodes, remove the first one. If it
- relates to this node (it should), clear that relationship.
- */
-void PageNode::removeFromRelated()
-{
- while (!related_.isEmpty()) {
- Node *p = static_cast<Node *>(related_.takeFirst());
- if (p != 0 && p->relates() == this) p->clearRelated();
- }
-}
-
-/*!
- Removes \a pseudoChild from the list of nodes related to
- this node. If \a pseudoChild is a function node, it is
- also remove from the primary/secondary function maps of
- this node, if this node is a subclass of PageNode
- that has function maps.
+/*! \f void Node::markInternal()
+ Sets the node's access to Private and its status to Internal.
*/
-void PageNode::removeRelated(Node *pseudoChild)
-{
- related_.removeAll(pseudoChild);
- removePseudoChild(pseudoChild);
-}
-
-/*!
- Adds \a pseudoChild to the list of nodes related to this
- node. Also adds \a pseudoChild to the primary/secondary
- function maps, if this PageNode is the base class of
- a subclass that has function maps. In that case, it also
- resolves a correct overload number for a related non-member
- function.
- */
-void PageNode::addRelated(Node *pseudoChild)
-{
- related_.append(pseudoChild);
- addPseudoChild(pseudoChild);
-}
/*!
\class EnumNode
@@ -1977,107 +1986,112 @@ QString EnumNode::itemValue(const QString &name) const
}
/*!
- \class TypedefNode
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-
-/*!
- */
-void TypedefNode::setAssociatedEnum(const EnumNode *enume)
+Node *EnumNode::clone(Aggregate *parent)
{
- associatedEnum_ = enume;
+ EnumNode *en = new EnumNode(*this); // shallow copy
+ en->setParent(nullptr);
+ parent->addChild(en);
+ return en;
}
/*!
- \class TypeAliasNode
- */
-
-/*!
- \class Parameter
- \brief The class Parameter contains one parameter.
-
- A parameter can be a function parameter or a macro
- parameter.
+ \class TypedefNode
*/
/*!
- Constructs this parameter from the \a dataType, the \a name,
- and the \a defaultValue.
*/
-Parameter::Parameter(const QString& dataType, const QString& name, const QString& defaultValue)
- : dataType_(dataType),
- name_(name),
- defaultValue_(defaultValue)
+void TypedefNode::setAssociatedEnum(const EnumNode *enume)
{
- // nothing.
+ associatedEnum_ = enume;
}
/*!
- Standard copy constructor copies \p.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-Parameter::Parameter(const Parameter& p)
- : dataType_(p.dataType_),
- name_(p.name_),
- defaultValue_(p.defaultValue_)
+Node *TypedefNode::clone(Aggregate *parent)
{
- // nothing.
+ TypedefNode *tn = new TypedefNode(*this); // shallow copy
+ tn->setParent(nullptr);
+ parent->addChild(tn);
+ return tn;
}
/*!
- standard assignment operator assigns \p.
+ \class TypeAliasNode
*/
-Parameter& Parameter::operator=(const Parameter& p)
-{
- dataType_ = p.dataType_;
- name_ = p.name_;
- defaultValue_ = p.defaultValue_;
- return *this;
-}
/*!
- Reconstructs the text describing the parameter and
- returns it. If \a value is true, the default value
- will be included, if there is one.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-QString Parameter::reconstruct(bool value) const
+Node *TypeAliasNode::clone(Aggregate *parent)
{
- QString p = dataType_;
- if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
- p += QLatin1Char(' ');
- p += name_;
- if (value && !defaultValue_.isEmpty())
- p += " = " + defaultValue_;
- return p;
+ TypeAliasNode *tan = new TypeAliasNode(*this); // shallow copy
+ tan->setParent(nullptr);
+ parent->addChild(tan);
+ return tan;
}
/*!
\class FunctionNode
+
+ This node is used to represent any kind of function being
+ documented. It can represent a C++ class member function,
+ a C++ global function, a QML method, a javascript method,
+ or a macro, with or without parameters.
+
+ A C++ function can be a signal a slot, a constructor of any
+ kind, a destructor, a copy or move assignment operator, or
+ just a plain old member function or global function.
+
+ A QML or javascript method can be a plain old method, or a
+ signal or signal handler.
+
+ If the function is not an overload, its overload flag is
+ false. If it is an overload, its overload flag is true.
+ If it is not an overload but it has overloads, its next
+ overload pointer will point to an overload function. If it
+ is an overload function, its overload flag is true, and it
+ may or may not have a non-null next overload pointer.
+
+ So all the overloads of a function are in a linked list
+ using the next overload pointer. If a function has no
+ overloads, its overload flag is false and its overload
+ pointer is null.
+
+ The function node also has an overload number. If the
+ node's overload flag is set, this overload number is
+ positive; otherwise, the overload number is 0.
*/
/*!
Construct a function node for a C++ function. It's parent
is \a parent, and it's name is \a name.
- Do not set overloadNumber_ in the initializer list because it
- is set by addChild() in the Node base class.
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
*/
FunctionNode::FunctionNode(Aggregate *parent, const QString& name)
: Node(Function, parent, name),
- metaness_(Plain),
- virtualness_(NonVirtual),
const_(false),
static_(false),
- reimplemented_(false),
+ reimpFlag_(false),
attached_(false),
- privateSignal_(false),
- overload_(false),
- isDeleted_(false),
- isDefaulted_(false),
+ overloadFlag_(false),
isFinal_(false),
isOverride_(false),
- isImplicit_(false),
isRef_(false),
isRefRef_(false),
- isInvokable_(false)
+ isInvokable_(false),
+ metaness_(Plain),
+ virtualness_(NonVirtual),
+ overloadNumber_(0),
+ nextOverload_(nullptr)
{
// nothing
}
@@ -2088,27 +2102,26 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString& name)
it's name is \a name. If \a attached is true, it is an attached
method or signal.
- Do not set overloadNumber_ in the initializer list because it
- is set by addChild() in the Node base class.
+ \note The function node's overload flag is set to false, and
+ its overload number is set to 0. These data members are set
+ in normalizeOverloads(), when all the overloads are known.
*/
FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString& name, bool attached)
: Node(Function, parent, name),
- metaness_(kind),
- virtualness_(NonVirtual),
const_(false),
static_(false),
- reimplemented_(false),
+ reimpFlag_(false),
attached_(attached),
- privateSignal_(false),
- overload_(false),
- isDeleted_(false),
- isDefaulted_(false),
+ overloadFlag_(false),
isFinal_(false),
isOverride_(false),
- isImplicit_(false),
isRef_(false),
isRefRef_(false),
- isInvokable_(false)
+ isInvokable_(false),
+ metaness_(kind),
+ virtualness_(NonVirtual),
+ overloadNumber_(0),
+ nextOverload_(nullptr)
{
setGenus(getGenus(metaness_));
if (!isCppNode() && name.startsWith("__"))
@@ -2116,6 +2129,19 @@ FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString& name
}
/*!
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
+ */
+Node *FunctionNode::clone(Aggregate *parent)
+{
+ FunctionNode *fn = new FunctionNode(*this); // shallow copy
+ fn->setParent(nullptr);
+ fn->setNextOverload(nullptr);
+ parent->addChild(fn);
+ return fn;
+}
+
+/*!
Returns this function's virtualness value as a string
for use as an attribute value in index files.
*/
@@ -2298,29 +2324,71 @@ bool FunctionNode::changeMetaness(Metaness from, Metaness to)
return false;
}
-/*! \fn void FunctionNode::setOverloadFlag(bool b)
- Sets this function node's overload flag to \a b.
- It does not set the overload number.
+/*! \fn void FunctionNode::setOverloadNumber(unsigned char n)
+ Sets the function node's overload number to \a n. If \a n
+ is 0, the function node's overload flag is set to false. If
+ \a n is greater than 0, the overload flag is set to true.
*/
+void FunctionNode::setOverloadNumber(signed short n)
+{
+ overloadNumber_ = n;
+ overloadFlag_ = (n > 0) ? true : false;
+}
-/*! \fn void FunctionNode::setOverloadNumber(unsigned char n)
- Sets this function node's overload number to \a n.
- It does not set the overload flag.
+/*!
+ If this function's next overload pointer is null, set it to
+ \a fn. Otherwise continue down the overload list by calling
+ this function recursively for the next overload.
+
+ Although this function appends an overload function to the list of
+ overloads for this function's name, it does not set the function's
+ overload number or it's overload flag. If the function has the
+ \c{\\overload} in its qdoc comment, that will set the overload
+ flag. But qdoc treats the \c{\\overload} command as a hint that the
+ function should be documented as an overload. The hint is almost
+ always correct, but qdoc reserves the right to decide which function
+ should be the primary function and which functions are the overloads.
+ These decisions are made in Aggregate::normalizeOverloads().
*/
+void FunctionNode::appendOverload(FunctionNode *fn)
+{
+ if (nextOverload_ == nullptr)
+ nextOverload_ = fn;
+ else
+ nextOverload_->appendOverload(fn);
+}
/*!
- Sets the function node's reimplementation flag to \a b.
- When \a b is true, it is supposed to mean that this function
- is a reimplementation of a virtual function in a base class,
- but it really just means the \e {\\reimp} command was seen in
- the qdoc comment.
+ This function assumes that this FunctionNode is marked as an
+ overlaod function. It asks if the next overload is marked as
+ an overload. If not, then remove that FunctionNode from the
+ overload list and return it. Otherwise call this function
+ recursively for the next overload.
*/
-void FunctionNode::setReimplemented(bool b)
+FunctionNode *FunctionNode::findPrimaryFunction()
{
- reimplemented_ = b;
+ if (nextOverload_ != nullptr) {
+ if (!nextOverload_->isOverload()) {
+ FunctionNode *t = nextOverload_;
+ nextOverload_ = t->nextOverload();
+ t->setNextOverload(nullptr);
+ return t;
+ }
+ return nextOverload_->findPrimaryFunction();
+ }
+ return nullptr;
}
/*!
+ \fn void FunctionNode::setReimpFlag()
+
+ Sets the function node's reimp flag to \c true, which means
+ the \e {\\reimp} command was used in the qdoc comment. It is
+ supposed to mean that the function reimplements a virtual
+ function in a base class.
+ */
+
+/*!
Returns a string representing the kind of function this
Function node represents, which depends on the Metaness
value.
@@ -2395,52 +2463,6 @@ QString FunctionNode::metanessString() const
}
/*!
- Append \a parameter to the parameter list.
- */
-void FunctionNode::addParameter(const Parameter& parameter)
-{
- parameters_.append(parameter);
-}
-
-/*!
- Split the parameters \a t and store them in this function's
- Parameter vector.
- */
-void FunctionNode::setParameters(const QString &t)
-{
- clearParams();
- if (!t.isEmpty()) {
- QStringList commaSplit = t.split(',');
- foreach (QString s, commaSplit) {
- QStringList blankSplit = s.split(' ');
- QString pName = blankSplit.last();
- blankSplit.removeLast();
- QString pType = blankSplit.join(' ');
- int i = 0;
- while (i < pName.length() && !pName.at(i).isLetter())
- i++;
- if (i > 0) {
- pType += QChar(' ') + pName.left(i);
- pName = pName.mid(i);
- }
- addParameter(Parameter(pType, pName));
- }
- }
-}
-
-void FunctionNode::borrowParameterNames(const FunctionNode *source)
-{
- QVector<Parameter>::Iterator t = parameters_.begin();
- QVector<Parameter>::ConstIterator s = source->parameters_.constBegin();
- while (s != source->parameters_.constEnd() && t != parameters_.end()) {
- if (!(*s).name().isEmpty())
- (*t).setName((*s).name());
- ++s;
- ++t;
- }
-}
-
-/*!
Adds the "associated" property \a p to this function node.
The function might be the setter or getter for a property,
for example.
@@ -2459,7 +2481,7 @@ bool FunctionNode::hasActiveAssociatedProperty() const
{
if (associatedProperties_.isEmpty())
return false;
- foreach (const PropertyNode* p, associatedProperties_) {
+ foreach (const Node *p, associatedProperties_) {
if (!p->isObsolete())
return true;
}
@@ -2471,87 +2493,28 @@ bool FunctionNode::hasActiveAssociatedProperty() const
*/
/*!
- Returns the list of parameter names.
- */
-QStringList FunctionNode::parameterNames() const
-{
- QStringList names;
- QVector<Parameter>::ConstIterator p = parameters().constBegin();
- while (p != parameters().constEnd()) {
- names << (*p).name();
- ++p;
- }
- return names;
-}
-
-/*!
- Returns a raw list of parameters. If \a names is true, the
- names are included. If \a values is true, the default values
- are included, if any are present.
- */
-QString FunctionNode::rawParameters(bool names, bool values) const
-{
- QString raw;
- foreach (const Parameter &parameter, parameters()) {
- raw += parameter.dataType();
- if (names)
- raw += parameter.name();
- if (values)
- raw += parameter.defaultValue();
- }
- return raw;
-}
-
-/*!
- Returns the list of reconstructed parameters. If \a values
- is true, the default values are included, if any are present.
- */
-QStringList FunctionNode::reconstructParameters(bool values) const
-{
- QStringList reconstructedParameters;
- QVector<Parameter>::ConstIterator p = parameters().constBegin();
- while (p != parameters().constEnd()) {
- reconstructedParameters << (*p).reconstruct(values);
- ++p;
- }
- return reconstructedParameters;
-}
-
-/*!
Reconstructs and returns the function's signature. If \a values
is true, the default values of the parameters are included, if
present.
*/
QString FunctionNode::signature(bool values, bool noReturnType) const
{
- QString s;
+ QString result;
if (!noReturnType && !returnType().isEmpty())
- s = returnType() + QLatin1Char(' ');
- s += name();
+ result = returnType() + QLatin1Char(' ');
+ result += name();
if (!isMacroWithoutParams()) {
- s += QLatin1Char('(');
- QStringList reconstructedParameters = reconstructParameters(values);
- int p = reconstructedParameters.size();
- if (p > 0) {
- for (int i=0; i<p; i++) {
- s += reconstructedParameters[i];
- if (i < (p-1))
- s += ", ";
- }
- }
- s += QLatin1Char(')');
+ result += QLatin1Char('(') + parameters_.signature(values) + QLatin1Char(')');
if (isMacro())
- return s;
+ return result;
}
if (isConst())
- s += " const";
+ result += " const";
if (isRef())
- s += " &";
+ result += " &";
else if (isRefRef())
- s += " &&";
- if (isImplicit())
- s += " = default";
- return s;
+ result += " &&";
+ return result;
}
/*!
@@ -2568,6 +2531,18 @@ PropertyNode::FunctionRole PropertyNode::role(const FunctionNode* fn) const
}
/*!
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
+ */
+Node *VariableNode::clone(Aggregate *parent)
+{
+ VariableNode *vn = new VariableNode(*this); // shallow copy
+ vn->setParent(nullptr);
+ parent->addChild(vn);
+ return vn;
+}
+
+/*!
Print some debugging stuff.
*/
void FunctionNode::debug() const
@@ -2594,12 +2569,12 @@ bool FunctionNode::compare(const FunctionNode *fn) const
return false;
if (isAttached() != fn->isAttached())
return false;
- const QVector<Parameter>& p = fn->parameters();
- if (parameters().size() != p.size())
+ const Parameters &p = fn->parameters();
+ if (parameters_.count() != p.count())
return false;
if (!p.isEmpty()) {
- for (int i = 0; i < p.size(); ++i) {
- if (parameters()[i].dataType() != p[i].dataType())
+ for (int i = 0; i < p.count(); ++i) {
+ if (parameters_.at(i).type() != p.at(i).type())
return false;
}
}
@@ -2638,6 +2613,27 @@ bool FunctionNode::isIgnored() const
}
/*!
+ Returns true if this function has overloads. Otherwise false.
+ First, if this function node's overload pointer is not nullptr,
+ return true. Next, if this function node's overload flag is true
+ return true. Finally, if this function's parent Aggregate has a
+ function by the same name as this one in its function map and
+ that function has overloads, return true. Otherwise return false.
+
+ There is a failsafe way to test it under any circumstances.
+ */
+bool FunctionNode::hasOverloads() const
+{
+ if (nextOverload_ != nullptr)
+ return true;
+ if (overloadFlag_)
+ return true;
+ if (parent())
+ return parent()->hasOverloads(this);
+ return false;
+}
+
+/*!
\class PropertyNode
This class describes one instance of using the Q_PROPERTY macro.
@@ -2876,6 +2872,39 @@ QString QmlPropertyGroupNode::idNumber()
}
/*!
+ Marks each of the properties in the property group
+ Private and Internal.
+ */
+void QmlPropertyGroupNode::markInternal()
+{
+ Node::markInternal();
+ foreach (Node *n, children_)
+ n->markInternal();
+}
+
+/*!
+ Marks each of the properties in the property group
+ as the default. Probably wrong.
+ */
+void QmlPropertyGroupNode::markDefault()
+{
+ Node::markDefault();
+ foreach (Node *n, children_)
+ n->markDefault();
+}
+
+/*!
+ Marks each of the properties in the property group
+ with the read only \a flag.
+ */
+void QmlPropertyGroupNode::markReadOnly(bool flag)
+{
+ Node::markReadOnly(flag);
+ foreach (Node *n, children_)
+ n->markReadOnly(flag);
+}
+
+/*!
Constructor for the QML property node.
*/
QmlPropertyNode::QmlPropertyNode(Aggregate* parent,
@@ -3134,47 +3163,355 @@ void Aggregate::printChildren(const QString& title)
}
/*!
- Removes \a pseudoChild from this node's primary/secondary
- function maps.
+ Removes \a fn from this aggregate's function map. That's
+ all it does. If \a fn is in the function map index and it
+ has an overload, the value pointer in the function map
+ index is set to the the overload pointer. If the function
+ has no overload pointer, the function map entry is erased.
+
+ \note When removing a function node from the function map,
+ it is important to set the removed function node's next
+ overload pointer to null because the function node might
+ be added as a child to some other aggregate.
*/
-void Aggregate::removePseudoChild(Node *pseudoChild)
+void Aggregate::removeFunctionNode(FunctionNode *fn)
{
- if (pseudoChild->isFunction()) {
- QMap<QString, Node *>::Iterator p = primaryFunctionMap_.find(pseudoChild->name());
- while (p != primaryFunctionMap_.end()) {
- if (p.value() == pseudoChild) {
- primaryFunctionMap_.erase(p);
- break;
+ FunctionMap::Iterator i = functionMap_.find(fn->name());
+ if (i != functionMap_.end()) {
+ if (i.value() == fn) {
+ if (fn->nextOverload() != nullptr) {
+ i.value() = fn->nextOverload();
+ fn->setNextOverload(nullptr);
+ fn->setOverloadNumber(0);
+ }
+ else {
+ functionMap_.erase(i);
+ }
+ } else {
+ FunctionNode *current = i.value();
+ while (current != nullptr) {
+ if (current->nextOverload() == fn) {
+ current->setNextOverload(fn->nextOverload());
+ fn->setNextOverload(nullptr);
+ fn->setOverloadNumber(0);
+ break;
+ }
+ current = current->nextOverload();
}
- ++p;
}
- NodeList& overloads = secondaryFunctionMap_[pseudoChild->name()];
- overloads.removeAll(pseudoChild);
}
}
+/*
+ When deciding whether to include a function in the function
+ index, if the function is marked private, don't include it.
+ If the function is marked obsolete, don't include it. If the
+ function is marked internal, don't include it. Or if the
+ function is a destructor or any kind of constructor, don't
+ include it. Otherwise include it.
+ */
+static bool keep(FunctionNode *fn)
+{
+ if (fn->isPrivate() ||
+ fn->isObsolete() ||
+ fn->isInternal() ||
+ fn->isSomeCtor() ||
+ fn->isDtor())
+ return false;
+ return true;
+}
+
/*!
- Adds \a pseudoChild to the list of nodes related to this one. Resolve a correct
- overload number for a related non-member function.
+ Insert all functions declared in this aggregate into the
+ \a functionIndex. Call the function recursively for each
+ child that is an aggregate.
+
+ Only include functions that are in the public API and
+ that are not constructors or destructors.
*/
-void Aggregate::addPseudoChild(Node *pseudoChild)
+void Aggregate::findAllFunctions(NodeMapMap &functionIndex)
{
- 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);
+ FunctionMap::const_iterator i;
+ for (i = functionMap_.constBegin(); i != functionMap_.constEnd(); ++i) {
+ FunctionNode *fn = i.value();
+ if (keep(fn))
+ functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
+ fn = fn->nextOverload();
+ while (fn != nullptr) {
+ if (keep(fn))
+ functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
+ fn = fn->nextOverload();
}
- else {
- primaryFunctionMap_.insert(pseudoChild->name(), pseudoChild);
- fn->setOverloadNumber(0);
- fn->setOverloadFlag(false);
+ }
+ foreach (Node *n, children_) {
+ if (n->isAggregate() && !n->isPrivate())
+ static_cast<Aggregate*>(n)->findAllFunctions(functionIndex);
+ }
+}
+
+/*!
+ For each child of this node, if the child is a namespace node,
+ insert the child into the \a namespaces multimap. If the child
+ is an aggregate, call this function recursively for that child.
+
+ When the function called with the root node of a tree, it finds
+ all the namespace nodes in that tree and inserts them into the
+ \a namespaces multimap.
+
+ The root node of a tree is a namespace, but it has no name, so
+ it is not inserted into the map. So, if this function is called
+ for each tree in the qdoc database, it finds all the namespace
+ nodes in the database.
+ */
+void Aggregate::findAllNamespaces(NodeMultiMap &namespaces)
+{
+ foreach (Node *n, children_) {
+ if (n->isAggregate() && !n->isPrivate()) {
+ if (n->isNamespace() && !n->name().isEmpty())
+ namespaces.insert(n->name(), n);
+ static_cast<Aggregate*>(n)->findAllNamespaces(namespaces);
+ }
+ }
+}
+
+/*!
+ Returns true if this aggregate contains at least one child
+ that is marked obsolete. Otherwise returns false.
+ */
+bool Aggregate::hasObsoleteMembers()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate() && n->isObsolete()) {
+ if (n->isFunction() || n->isProperty() || n->isEnumType() ||
+ n->isTypedef() || n->isTypeAlias() || n->isVariable() ||
+ n->isQmlProperty() || n->isJsProperty())
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
+ Finds all the obsolete C++ classes and QML types in this
+ aggregate and all the C++ classes and QML types with obsolete
+ members, and inserts them into maps used elesewhere for
+ generating documentation.
+ */
+void Aggregate::findAllObsoleteThings()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate()) {
+ QString name = n->name();
+ if (n->isObsolete()) {
+ if (n->isClass())
+ QDocDatabase::obsoleteClasses().insert(n->qualifyCppName(), n);
+ else if (n->isQmlType() || n->isJsType())
+ QDocDatabase::obsoleteQmlTypes().insert(n->qualifyQmlName(), n);
+ } else if (n->isClass()) {
+ Aggregate *a = static_cast<Aggregate *>(n);
+ if (a->hasObsoleteMembers())
+ QDocDatabase::classesWithObsoleteMembers().insert(n->qualifyCppName(), n);
+ }
+ else if (n->isQmlType() || n->isJsType()) {
+ Aggregate *a = static_cast<Aggregate *>(n);
+ if (a->hasObsoleteMembers())
+ QDocDatabase::qmlTypesWithObsoleteMembers().insert(n->qualifyQmlName(), n);
+ }
+ else if (n->isAggregate()) {
+ static_cast<Aggregate*>(n)->findAllObsoleteThings();
+ }
+ }
+ }
+}
+
+/*!
+ Finds all the C++ classes, QML types, JS types, QML and JS
+ basic types, and examples in this aggregate and inserts them
+ into appropriate maps for later use in generating documentation.
+ */
+void Aggregate::findAllClasses()
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate() && !n->isInternal() &&
+ n->tree()->camelCaseModuleName() != QString("QDoc")) {
+ if (n->isClass()) {
+ QDocDatabase::cppClasses().insert(n->qualifyCppName().toLower(), n);
+ } else if (n->isQmlType() || n->isQmlBasicType() || n->isJsType() || n->isJsBasicType()) {
+ QString name = n->unqualifyQmlName();
+ QDocDatabase::qmlTypes().insert(name, n);
+ //also add to the QML basic type map
+ if (n->isQmlBasicType() || n->isJsBasicType())
+ QDocDatabase::qmlBasicTypes().insert(name, n);
+ } else if (n->isExample()) {
+ // use the module index title as key for the example map
+ QString title = n->tree()->indexTitle();
+ if (!QDocDatabase::examples().contains(title, n))
+ QDocDatabase::examples().insert(title, n);
+ } else if (n->isAggregate()) {
+ static_cast<Aggregate*>(n)->findAllClasses();
+ }
}
}
}
/*!
+ Find all the attribution pages in this node and insert them
+ into \a attributions.
+ */
+void Aggregate::findAllAttributions(NodeMultiMap &attributions)
+{
+ foreach (Node *n, children_) {
+ if (!n->isPrivate()) {
+ if (n->pageType() == Node::AttributionPage)
+ attributions.insertMulti(n->tree()->indexTitle(), n);
+ else if (n->isAggregate())
+ static_cast<Aggregate*>(n)->findAllAttributions(attributions);
+ }
+ }
+}
+
+/*!
+ \fn void findAllSince()
+
+ Finds all the nodes in this node where a \e{since} command appeared
+ in the qdoc comment and sorts them into maps according to the kind
+ of 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 Aggregate::findAllSince()
+{
+ foreach (Node *n, children_) {
+ QString sinceString = n->since();
+ // Insert a new entry into each map for each new since string found.
+ if (!n->isPrivate() && !sinceString.isEmpty()) {
+ NodeMultiMapMap::iterator nsmap = QDocDatabase::newSinceMaps().find(sinceString);
+ if (nsmap == QDocDatabase::newSinceMaps().end())
+ nsmap = QDocDatabase::newSinceMaps().insert(sinceString, NodeMultiMap());
+
+ NodeMapMap::iterator ncmap = QDocDatabase::newClassMaps().find(sinceString);
+ if (ncmap == QDocDatabase::newClassMaps().end())
+ ncmap = QDocDatabase::newClassMaps().insert(sinceString, NodeMap());
+
+ NodeMapMap::iterator nqcmap = QDocDatabase::newQmlTypeMaps().find(sinceString);
+ if (nqcmap == QDocDatabase::newQmlTypeMaps().end())
+ nqcmap = QDocDatabase::newQmlTypeMaps().insert(sinceString, NodeMap());
+
+ if (n->isFunction()) {
+ // Insert functions into the general since map.
+ FunctionNode *fn = static_cast<FunctionNode*>(n);
+ if (!fn->isObsolete() && !fn->isSomeCtor() && !fn->isDtor())
+ nsmap.value().insert(fn->name(), fn);
+ }
+ else if (n->isClass()) {
+ // Insert classes into the since and class maps.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ ncmap.value().insert(name, n);
+ } else if (n->isQmlType() || n->isJsType()) {
+ // Insert QML elements into the since and element maps.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ nqcmap.value().insert(name, n);
+ } else if (n->isQmlProperty() || n->isJsProperty()) {
+ // Insert QML properties into the since map.
+ nsmap.value().insert(n->name(), n);
+ } else {
+ // Insert external documents into the general since map.
+ QString name = n->qualifyWithParentName();
+ nsmap.value().insert(name, n);
+ }
+ }
+ // Recursively find child nodes with since commands.
+ if (n->isAggregate())
+ static_cast<Aggregate*>(n)->findAllSince();
+ }
+}
+
+/*!
+ For each QML Type node in this aggregate's children, if the
+ QML type has a QML base type name but its QML base type node
+ pointer is nullptr, use the QML base type name to look up the
+ base type node. If the node is found, set the node's QML base
+ type node pointer to that node.
+ */
+void Aggregate::resolveQmlInheritance()
+{
+ NodeMap previousSearches;
+ // Do we need recursion?
+ foreach (Node *child, children_) {
+ if (!child->isQmlType() && !child->isJsType())
+ continue;
+ QmlTypeNode *type = static_cast<QmlTypeNode *>(child);
+ if (type->qmlBaseNode() != nullptr)
+ continue;
+ if (type->qmlBaseName().isEmpty())
+ continue;
+ QmlTypeNode *base = static_cast<QmlTypeNode *>(previousSearches.value(type->qmlBaseName()));
+ if (base && (base != type)) {
+ type->setQmlBaseNode(base);
+ QmlTypeNode::addInheritedBy(base, type);
+ } else {
+ if (!type->importList().isEmpty()) {
+ const ImportList &imports = type->importList();
+ for (int i=0; i<imports.size(); ++i) {
+ base = QDocDatabase::qdocDB()->findQmlType(imports[i], type->qmlBaseName());
+ if (base && (base != type)) {
+ if (base->logicalModuleVersion()[0] != imports[i].version_[0])
+ base = 0; // Safeguard for QTBUG-53529
+ break;
+ }
+ }
+ }
+ if (base == 0) {
+ base = QDocDatabase::qdocDB()->findQmlType(QString(), type->qmlBaseName());
+ }
+ if (base && (base != type)) {
+ type->setQmlBaseNode(base);
+ QmlTypeNode::addInheritedBy(base, type);
+ previousSearches.insert(type->qmlBaseName(), base);
+ }
+ }
+ }
+}
+
+/*!
+ \class ProxyNode
+ \brief A class for representing an Aggregate that is documented in a different module.
+
+ This class is used to represent an Aggregate (usually a class)
+ that is located and documented in a different module. In the
+ current module, a ProxyNode holds child nodes that are related
+ to the class in the other module.
+
+ For example, class QHash is located and documented in QtCore.
+ There are many global functions named qHash() in QtCore that
+ are all related to class QHash using the \c relates command.
+ There are also a few qHash() function in QtNetwork that are
+ related to QHash. These functions must be documented when the
+ documentation for QtNetwork is generated, but the reference
+ page for QHash must link to that documentation in its related
+ nonmembers list.
+
+ The ProxyNode allows qdoc to construct links to the related
+ functions (or other things?) in QtNetwork from the reference
+ page in QtCore.
+ */
+
+/*!
+ Constructs the ProxyNode, which at this point looks like any
+ other Aggregate, and then finds the Tree this node is in and
+ appends this node to that Tree's proxy list so it will be
+ easy to find later.
+ */
+ProxyNode::ProxyNode(Aggregate *parent, const QString &name)
+ : Aggregate(Node::Proxy, parent, name)
+{
+ tree()->appendProxy(this);
+}
+
+/*!
\class CollectionNode
\brief A class for holding the members of a collection of doc pages.
*/
@@ -3322,34 +3659,39 @@ void CollectionNode::setLogicalModuleInfo(const QStringList& info)
}
/*!
- Sets the overload flag to \b in each node in the collection.
+ Searches the shared comment node's member nodes for function
+ nodes. Each function node's overload flag is set.
*/
-void SharedCommentNode::setOverloadFlag(bool b)
+void SharedCommentNode::setOverloadFlags()
{
- for (Node *n : collective_)
- n->setOverloadFlag(b);
+ for (Node *n : collective_) {
+ if (n->isFunction())
+ static_cast<FunctionNode*>(n)->setOverloadFlag();
+ }
}
/*!
- Sets each node in this node's collective to be related to
- \a pseudoParent.
+ Clone this node on the heap and make the clone a child of
+ \a parent. Return the pointer to the clone.
*/
-void SharedCommentNode::setRelates(PageNode *pseudoParent)
+Node *SharedCommentNode::clone(Aggregate *parent)
{
- Node::setRelates(pseudoParent);
- for (Node *n : collective_)
- n->setRelates(pseudoParent);
+ SharedCommentNode *scn = new SharedCommentNode(*this); // shallow copy
+ scn->setParent(nullptr);
+ parent->addChild(scn);
+ return scn;
}
+
/*!
- Sets the (unresolved) entity \a name that this node relates to
- in each of the nodes in this shared comment node's collective.
+ Sets the related nonmember flag in this node and in each
+ node in the shared comment's collective.
*/
-void SharedCommentNode::setRelates(const QString& name)
+void SharedCommentNode::setRelatedNonmember(bool b)
{
- Node::setRelates(name);
+ Node::setRelatedNonmember(b);
for (Node *n : collective_)
- n->setRelates(name);
+ n->setRelatedNonmember(b);
}
QT_END_NAMESPACE