summaryrefslogtreecommitdiffstats
path: root/src/qdoc/tree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/tree.cpp')
-rw-r--r--src/qdoc/tree.cpp1361
1 files changed, 0 insertions, 1361 deletions
diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp
deleted file mode 100644
index 5b73bd717..000000000
--- a/src/qdoc/tree.cpp
+++ /dev/null
@@ -1,1361 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "tree.h"
-
-#include "classnode.h"
-#include "collectionnode.h"
-#include "doc.h"
-#include "enumnode.h"
-#include "functionnode.h"
-#include "htmlgenerator.h"
-#include "location.h"
-#include "node.h"
-#include "qdocdatabase.h"
-#include "text.h"
-#include "typedefnode.h"
-#include "usingclause.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class Tree
-
- This class constructs and maintains a tree of instances of
- the subclasses of Node.
-
- This class is now private. Only class QDocDatabase has access.
- Please don't change this. If you must access class Tree, do it
- though the pointer to the singleton QDocDatabase.
-
- Tree is being converted to a forest. A static member provides a
- map of Tree *values with the module names as the keys. There is
- one Tree in the map for each index file read, and there is one
- tree that is not in the map for the module whose documentation
- is being generated.
- */
-
-/*!
- Constructs a Tree. \a qdb is the pointer to the singleton
- qdoc database that is constructing the tree. This might not
- be necessary, and it might be removed later.
-
- \a camelCaseModuleName is the project name for this tree
- as it appears in the qdocconf file.
- */
-Tree::Tree(const QString &camelCaseModuleName, QDocDatabase *qdb)
- : m_treeHasBeenAnalyzed(false),
- m_camelCaseModuleName(camelCaseModuleName),
- m_physicalModuleName(camelCaseModuleName.toLower()),
- m_qdb(qdb),
- m_root(nullptr, QString())
-{
- m_root.setPhysicalModuleName(m_physicalModuleName);
- m_root.setTree(this);
-}
-
-/*!
- Destroys the Tree. The root node is a data member
- of this object, so its destructor is called. The
- destructor of each child node is called, and these
- destructors are recursive. Thus the entire tree is
- destroyed.
-
- There are two maps of targets, keywords, and contents.
- One map is indexed by ref, the other by title. The ref
- is just the canonical form of the title. Both maps
- use the same set of TargetRec objects as the values,
- so the destructor only deletes the values from one of
- the maps. Then it clears both maps.
- */
-Tree::~Tree()
-{
- for (auto i = m_nodesByTargetRef.begin(); i != m_nodesByTargetRef.end(); ++i) {
- delete i.value();
- }
- m_nodesByTargetRef.clear();
- m_nodesByTargetTitle.clear();
-}
-
-/* API members */
-
-/*!
- Calls findClassNode() first with \a path and \a start. If
- it finds a node, the node is returned. If not, it calls
- findNamespaceNode() with the same parameters. The result
- is returned.
- */
-Node *Tree::findNodeForInclude(const QStringList &path) const
-{
- Node *n = findClassNode(path);
- if (n == nullptr)
- n = findNamespaceNode(path);
- return n;
-}
-
-/*!
- This function searches this tree for an Aggregate node with
- the specified \a name. It returns the pointer to that node
- or nullptr.
-
- We might need to split the name on '::' but we assume the
- name is a single word at the moment.
- */
-Aggregate *Tree::findAggregate(const QString &name)
-{
- QStringList path = name.split(QLatin1String("::"));
- return static_cast<Aggregate *>(findNodeRecursive(path, 0, const_cast<NamespaceNode *>(root()),
- &Node::isFirstClassAggregate));
-}
-
-/*!
- Find the C++ class node named \a path. Begin the search at the
- \a start node. If the \a start node is 0, begin the search
- at the root of the tree. Only a C++ class node named \a path is
- acceptible. If one is not found, 0 is returned.
- */
-ClassNode *Tree::findClassNode(const QStringList &path, const Node *start) const
-{
- if (start == nullptr)
- start = const_cast<NamespaceNode *>(root());
- return static_cast<ClassNode *>(findNodeRecursive(path, 0, start, &Node::isClassNode));
-}
-
-/*!
- Find the Namespace node named \a path. Begin the search at
- the root of the tree. Only a Namespace node named \a path
- is acceptible. If one is not found, 0 is returned.
- */
-NamespaceNode *Tree::findNamespaceNode(const QStringList &path) const
-{
- Node *start = const_cast<NamespaceNode *>(root());
- return static_cast<NamespaceNode *>(findNodeRecursive(path, 0, start, &Node::isNamespace));
-}
-
-/*!
- This function searches for the node specified by \a path.
- The matching node can be one of several different types
- including a C++ class, a C++ namespace, or a C++ header
- file.
-
- I'm not sure if it can be a QML type, but if that is a
- possibility, the code can easily accommodate it.
-
- If a matching node is found, a pointer to it is returned.
- Otherwise 0 is returned.
- */
-Aggregate *Tree::findRelatesNode(const QStringList &path)
-{
- Node *n = findNodeRecursive(path, 0, root(), &Node::isRelatableType);
- return (((n != nullptr) && n->isAggregate()) ? static_cast<Aggregate *>(n) : nullptr);
-}
-
-/*!
- Inserts function name \a funcName and function role \a funcRole into
- the property function map for the specified \a property.
- */
-void Tree::addPropertyFunction(PropertyNode *property, const QString &funcName,
- PropertyNode::FunctionRole funcRole)
-{
- m_unresolvedPropertyMap[property].insert(funcRole, funcName);
-}
-
-/*!
- This function resolves C++ inheritance and reimplementation
- settings for each C++ class node found in the tree beginning
- at \a n. It also calls itself recursively for each C++ class
- node or namespace node it encounters.
-
- This function does not resolve QML inheritance.
- */
-void Tree::resolveBaseClasses(Aggregate *n)
-{
- for (auto it = n->constBegin(); it != n->constEnd(); ++it) {
- if ((*it)->isClassNode()) {
- auto *cn = static_cast<ClassNode *>(*it);
- QList<RelatedClass> &bases = cn->baseClasses();
- for (auto &base : bases) {
- if (base.m_node == nullptr) {
- Node *n = m_qdb->findClassNode(base.m_path);
- /*
- If the node for the base class was not found,
- the reason might be that the subclass is in a
- namespace and the base class is in the same
- namespace, but the base class name was not
- qualified with the namespace name. That is the
- case most of the time. Then restart the search
- at the parent of the subclass node (the namespace
- node) using the unqualified base class name.
- */
- if (n == nullptr) {
- Aggregate *parent = cn->parent();
- if (parent != nullptr)
- // Exclude the root namespace
- if (parent->isNamespace() && !parent->name().isEmpty())
- n = findClassNode(base.m_path, parent);
- }
- if (n != nullptr) {
- auto *bcn = static_cast<ClassNode *>(n);
- base.m_node = bcn;
- bcn->addDerivedClass(base.m_access, cn);
- }
- }
- }
- resolveBaseClasses(cn);
- } else if ((*it)->isNamespace()) {
- resolveBaseClasses(static_cast<NamespaceNode *>(*it));
- }
- }
-}
-
-/*!
- */
-void Tree::resolvePropertyOverriddenFromPtrs(Aggregate *n)
-{
- for (auto node = n->constBegin(); node != n->constEnd(); ++node) {
- if ((*node)->isClassNode()) {
- auto *cn = static_cast<ClassNode *>(*node);
- for (auto property = cn->constBegin(); property != cn->constEnd(); ++property) {
- if ((*property)->isProperty())
- cn->resolvePropertyOverriddenFromPtrs(static_cast<PropertyNode *>(*property));
- }
- resolvePropertyOverriddenFromPtrs(cn);
- } else if ((*node)->isNamespace()) {
- resolvePropertyOverriddenFromPtrs(static_cast<NamespaceNode *>(*node));
- }
- }
-}
-
-/*!
- */
-void Tree::resolveProperties()
-{
- for (auto propEntry = m_unresolvedPropertyMap.constBegin();
- propEntry != m_unresolvedPropertyMap.constEnd(); ++propEntry) {
- PropertyNode *property = propEntry.key();
- Aggregate *parent = property->parent();
- QString getterName = (*propEntry)[PropertyNode::Getter];
- QString setterName = (*propEntry)[PropertyNode::Setter];
- QString resetterName = (*propEntry)[PropertyNode::Resetter];
- QString notifierName = (*propEntry)[PropertyNode::Notifier];
-
- for (auto it = parent->constBegin(); it != parent->constEnd(); ++it) {
- if ((*it)->isFunction()) {
- auto *function = static_cast<FunctionNode *>(*it);
- if (function->access() == property->access()
- && (function->status() == property->status() || function->doc().isEmpty())) {
- if (function->name() == getterName) {
- property->addFunction(function, PropertyNode::Getter);
- } else if (function->name() == setterName) {
- property->addFunction(function, PropertyNode::Setter);
- } else if (function->name() == resetterName) {
- property->addFunction(function, PropertyNode::Resetter);
- } else if (function->name() == notifierName) {
- property->addSignal(function, PropertyNode::Notifier);
- }
- }
- }
- }
- }
-
- for (auto propEntry = m_unresolvedPropertyMap.constBegin();
- propEntry != m_unresolvedPropertyMap.constEnd(); ++propEntry) {
- PropertyNode *property = propEntry.key();
- // redo it to set the property functions
- if (property->overriddenFrom())
- property->setOverriddenFrom(property->overriddenFrom());
- }
-
- m_unresolvedPropertyMap.clear();
-}
-
-/*!
- For each QML class node that points to a C++ class node,
- follow its C++ class node pointer and set the C++ class
- node's QML class node pointer back to the QML class node.
- */
-void Tree::resolveCppToQmlLinks()
-{
-
- const NodeList &children = m_root.childNodes();
- for (auto *child : children) {
- if (child->isQmlType() || child->isJsType()) {
- auto *qcn = static_cast<QmlTypeNode *>(child);
- auto *cn = const_cast<ClassNode *>(qcn->classNode());
- if (cn)
- cn->setQmlElement(qcn);
- }
- }
-}
-
-/*!
- For each C++ class node, resolve any \c using clauses
- that appeared in the class declaration.
-
- For type aliases, resolve the aliased node.
- */
-void Tree::resolveUsingClauses(Aggregate *parent)
-{
- if (!parent)
- parent = &m_root;
- for (auto *child : parent->childNodes()) {
- if (child->isClassNode()) {
- auto *cn = static_cast<ClassNode *>(child);
- QList<UsingClause> &usingClauses = cn->usingClauses();
- for (auto &usingClause : usingClauses) {
- if (usingClause.node() == nullptr) {
- const Node *n = m_qdb->findFunctionNode(usingClause.signature(), cn, Node::CPP);
- if (n != nullptr)
- usingClause.setNode(n);
- }
- }
- }
- if (child->genus() == Node::CPP && child->isAggregate())
- resolveUsingClauses(static_cast<Aggregate *>(child));
- }
-}
-
-/*!
- Traverse this Tree and for each ClassNode found, remove
- from its list of base classes any that are marked private
- or internal. When a class is removed from a base class
- list, promote its public pase classes to be base classes
- of the class where the base class was removed. This is
- done for documentation purposes. The function is recursive
- on namespace nodes.
- */
-void Tree::removePrivateAndInternalBases(NamespaceNode *rootNode)
-{
- if (rootNode == nullptr)
- rootNode = root();
-
- for (auto node = rootNode->constBegin(); node != rootNode->constEnd(); ++node) {
- if ((*node)->isClassNode())
- static_cast<ClassNode *>(*node)->removePrivateAndInternalBases();
- else if ((*node)->isNamespace())
- removePrivateAndInternalBases(static_cast<NamespaceNode *>(*node));
- }
-}
-
-/*!
- */
-ClassList Tree::allBaseClasses(const ClassNode *classNode) const
-{
- ClassList result;
- const auto &baseClasses = classNode->baseClasses();
- for (const auto &relatedClass : baseClasses) {
- if (relatedClass.m_node != nullptr) {
- result += relatedClass.m_node;
- result += allBaseClasses(relatedClass.m_node);
- }
- }
- return result;
-}
-
-/*!
- Find the node with the specified \a path name that is of
- the specified \a type and \a subtype. Begin the search at
- the \a start node. If the \a start node is 0, begin the
- search at the tree root. \a subtype is not used unless
- \a type is \c{Page}.
- */
-Node *Tree::findNodeByNameAndType(const QStringList &path, bool (Node::*isMatch)() const) const
-{
- return findNodeRecursive(path, 0, root(), isMatch);
-}
-
-/*!
- Recursive search for a node identified by \a path. Each
- path element is a name. \a pathIndex specifies the index
- of the name in \a path to try to match. \a start is the
- node whose children shoulod be searched for one that has
- that name. Each time a match is found, increment the
- \a pathIndex and call this function recursively.
-
- If the end of the path is reached (i.e. if a matching
- node is found for each name in the \a path), the \a type
- must match the type of the last matching node, and if the
- type is \e{Page}, the \a subtype must match as well.
-
- If the algorithm is successful, the pointer to the final
- node is returned. Otherwise 0 is returned.
- */
-Node *Tree::findNodeRecursive(const QStringList &path, int pathIndex, const Node *start,
- bool (Node::*isMatch)() const) const
-{
- if (start == nullptr || path.isEmpty())
- return nullptr;
- Node *node = const_cast<Node *>(start);
- if (!node->isAggregate())
- return ((pathIndex >= path.size()) ? node : nullptr);
- auto *current = static_cast<Aggregate *>(node);
- const NodeList &children = current->childNodes();
- const QString &name = path.at(pathIndex);
- for (auto *node : children) {
- if (node == nullptr)
- continue;
- if (node->name() == name) {
- if (pathIndex + 1 >= path.size()) {
- if ((node->*(isMatch))())
- return node;
- continue;
- } else { // Search the children of n for the next name in the path.
- node = findNodeRecursive(path, pathIndex + 1, node, isMatch);
- if (node != nullptr)
- return node;
- }
- }
- }
- return nullptr;
-}
-
-/*!
- Searches the tree for a node that matches the \a path plus
- the \a target. The search begins at \a start and moves up
- the parent chain from there, or, if \a start is 0, the search
- begins at the root.
-
- The \a flags can indicate whether to search base classes and/or
- the enum values in enum types. \a genus can be a further restriction
- on what kind of node is an acceptible match, i.e. CPP or QML.
-
- If a matching node is found, \a ref is an output parameter that
- is set to the HTML reference to use for the link.
- */
-const Node *Tree::findNodeForTarget(const QStringList &path, const QString &target,
- const Node *start, int flags, Node::Genus genus,
- QString &ref) const
-{
- const Node *node = nullptr;
- if ((genus == Node::DontCare) || (genus == Node::DOC)) {
- node = findPageNodeByTitle(path.at(0));
- if (node) {
- if (!target.isEmpty()) {
- ref = getRef(target, node);
- if (ref.isEmpty())
- node = nullptr;
- }
- if (node)
- return node;
- }
- }
-
- node = findUnambiguousTarget(path.join(QLatin1String("::")), genus, ref);
- if (node) {
- if (!target.isEmpty()) {
- ref = getRef(target, node);
- if (ref.isEmpty())
- node = nullptr;
- }
- if (node)
- return node;
- }
-
- const Node *current = start;
- if (current == nullptr)
- current = root();
-
- /*
- If the path contains one or two double colons ("::"),
- check first to see if the first two path strings refer
- to a QML element. If they do, path[0] will be the QML
- module identifier, and path[1] will be the QML type.
- If the answer is yes, the reference identifies a QML
- type node.
- */
- int path_idx = 0;
- if (((genus == Node::QML) || (genus == Node::DontCare)) && (path.size() >= 2)
- && !path[0].isEmpty()) {
- QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
- if (qcn) {
- current = qcn;
- if (path.size() == 2) {
- if (!target.isEmpty()) {
- ref = getRef(target, current);
- if (!ref.isEmpty())
- return current;
- return nullptr;
- } else
- return current;
- }
- path_idx = 2;
- }
- }
-
- while (current != nullptr) {
- if (current->isAggregate()) { // Should this be isPageNode() ???
- const Node *node =
- matchPathAndTarget(path, path_idx, target, current, flags, genus, ref);
- if (node)
- return node;
- }
- current = current->parent();
- path_idx = 0;
- }
- return nullptr;
-}
-
-/*!
- First, the \a path is used to find a node. The \a path
- matches some part of the node's fully quallified name.
- If the \a target is not empty, it must match a target
- in the matching node. If the matching of the \a path
- and the \a target (if present) is successful, \a ref
- is set from the \a target, and the pointer to the
- matching node is returned. \a idx is the index into the
- \a path where to begin the matching. The function is
- recursive with idx being incremented for each recursive
- call.
-
- The matching node must be of the correct \a genus, i.e.
- either QML or C++, but \a genus can be set to \c DontCare.
- \a flags indicates whether to search base classes and
- whether to search for an enum value. \a node points to
- the node where the search should begin, assuming the
- \a path is a not a fully-qualified name. \a node is
- most often the root of this Tree.
- */
-const Node *Tree::matchPathAndTarget(const QStringList &path, int idx, const QString &target,
- const Node *node, int flags, Node::Genus genus,
- QString &ref) const
-{
- /*
- If the path has been matched, then if there is a target,
- try to match the target. If there is a target, but you
- can't match it at the end of the path, give up; return 0.
- */
- if (idx == path.size()) {
- if (!target.isEmpty()) {
- ref = getRef(target, node);
- if (ref.isEmpty())
- return nullptr;
- }
- if (node->isFunction() && node->name() == node->parent()->name())
- node = node->parent();
- return node;
- }
-
- QString name = path.at(idx);
- if (node->isAggregate()) {
- NodeVector nodes;
- static_cast<const Aggregate *>(node)->findChildren(name, nodes);
- for (const auto *child : qAsConst(nodes)) {
- if (genus != Node::DontCare && !(genus & child->genus()))
- continue;
- const Node *t = matchPathAndTarget(path, idx + 1, target, child, flags, genus, ref);
- if (t && !t->isPrivate())
- return t;
- }
- }
- if (target.isEmpty() && (flags & SearchEnumValues)) {
- const auto *enumNode = node->isAggregate() ?
- findEnumNode(nullptr, node, path, idx) :
- findEnumNode(node, nullptr, path, idx);
- if (enumNode)
- return enumNode;
- }
- if (((genus == Node::CPP) || (genus == Node::DontCare)) && node->isClassNode()
- && (flags & SearchBaseClasses)) {
- const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(node));
- for (const auto *base : bases) {
- const Node *t = matchPathAndTarget(path, idx, target, base, flags, genus, ref);
- if (t && !t->isPrivate())
- return t;
- if (target.isEmpty() && (flags & SearchEnumValues)) {
- if ((t = findEnumNode(base->findChildNode(path.at(idx), genus, flags), base, path, idx)))
- return t;
- }
- }
- }
- return nullptr;
-}
-
-/*!
- Searches the tree for a node that matches the \a path. The
- search begins at \a start but can move up the parent chain
- recursively if no match is found. The \a flags are used to
- restrict the search.
- */
-const Node *Tree::findNode(const QStringList &path, const Node *start, int flags,
- Node::Genus genus) const
-{
- const Node *current = start;
- if (current == nullptr)
- current = root();
-
- do {
- const Node *node = current;
- int i;
- int start_idx = 0;
-
- /*
- If the path contains one or two double colons ("::"),
- check first to see if the first two path strings refer
- to a QML element. If they do, path[0] will be the QML
- module identifier, and path[1] will be the QML type.
- If the answer is yes, the reference identifies a QML
- type node.
- */
- if (((genus == Node::QML) || (genus == Node::DontCare)) && (path.size() >= 2)
- && !path[0].isEmpty()) {
- QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
- if (qcn != nullptr) {
- node = qcn;
- if (path.size() == 2)
- return node;
- start_idx = 2;
- }
- }
-
- for (i = start_idx; i < path.size(); ++i) {
- if (node == nullptr || !node->isAggregate())
- break;
-
- // Clear the TypesOnly flag until the last path segment, as e.g. namespaces are not
- // types. We also ignore module nodes as they are not aggregates and thus have no
- // children.
- int tmpFlags = (i < path.size() - 1) ? (flags & ~TypesOnly) | IgnoreModules : flags;
-
- const Node *next = static_cast<const Aggregate *>(node)->findChildNode(path.at(i),
- genus, tmpFlags);
- const Node *enumNode = (flags & SearchEnumValues) ?
- findEnumNode(next, node, path, i) : nullptr;
-
- if (enumNode)
- return enumNode;
-
-
- if (!next && ((genus == Node::CPP) || (genus == Node::DontCare))
- && node->isClassNode() && (flags & SearchBaseClasses)) {
- const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(node));
- for (const auto *base : bases) {
- next = base->findChildNode(path.at(i), genus, tmpFlags);
- if (flags & SearchEnumValues)
- if ((enumNode = findEnumNode(next, base, path, i)))
- return enumNode;
- if (next)
- break;
- }
- }
- node = next;
- }
- if ((node != nullptr) && i == path.size())
- return node;
- current = current->parent();
- } while (current != nullptr);
-
- return nullptr;
-}
-
-
-/*!
- \internal
-
- Helper function to return an enum that matches the \a path at a specified \a offset.
- If \a node is a valid enum node, the enum name is assumed to be included in the path
- (i.e, a scoped enum). Otherwise, query the \a aggregate (typically, the class node)
- for enum node that includes the value at the last position in \a path.
- */
-const Node *Tree::findEnumNode(const Node *node, const Node *aggregate, const QStringList &path, int offset) const
-{
- // Scoped enum (path ends in enum_name :: enum_value)
- if (node && node->isEnumType() && offset == path.size() - 1) {
- const auto *en = static_cast<const EnumNode*>(node);
- if (en->isScoped() && en->hasItem(path.last()))
- return en;
- }
-
- // Standard enum (path ends in class_name :: enum_value)
- return (!node && aggregate && offset == path.size() - 1) ?
- static_cast<const Aggregate *>(aggregate)->findEnumNodeForValue(path.last()) :
- nullptr;
-}
-
-/*!
- This function searches for a node with a canonical title
- constructed from \a target. If the node it finds is \a node,
- it returns the ref from that node. Otherwise it returns an
- empty string.
- */
-QString Tree::getRef(const QString &target, const Node *node) const
-{
- auto it = m_nodesByTargetTitle.constFind(target);
- if (it != m_nodesByTargetTitle.constEnd()) {
- do {
- if (it.value()->m_node == node)
- return it.value()->m_ref;
- ++it;
- } while (it != m_nodesByTargetTitle.constEnd() && it.key() == target);
- }
- QString key = Doc::canonicalTitle(target);
- it = m_nodesByTargetRef.constFind(key);
- if (it != m_nodesByTargetRef.constEnd()) {
- do {
- if (it.value()->m_node == node)
- return it.value()->m_ref;
- ++it;
- } while (it != m_nodesByTargetRef.constEnd() && it.key() == key);
- }
- return QString();
-}
-
-/*!
- Inserts a new target into the target table. \a name is the
- key. The target record contains the \a type, a pointer to
- the \a node, the \a priority. and a canonicalized form of
- the \a name, which is later used.
- */
-void Tree::insertTarget(const QString &name, const QString &title, TargetRec::TargetType type,
- Node *node, int priority)
-{
- auto *target = new TargetRec(name, type, node, priority);
- m_nodesByTargetRef.insert(name, target);
- m_nodesByTargetTitle.insert(title, target);
-}
-
-/*!
- */
-void Tree::resolveTargets(Aggregate *root)
-{
- for (auto *child : root->childNodes()) {
- if (child->isTextPageNode()) {
- auto *node = static_cast<PageNode *>(child);
- QString key = node->title();
- if (!key.isEmpty()) {
- if (key.contains(QChar(' ')))
- key = Doc::canonicalTitle(key);
- QList<PageNode *> nodes = m_pageNodesByTitle.values(key);
- bool alreadyThere = false;
- if (!nodes.empty()) {
- for (const auto &node_ : nodes) {
- if (node_->isExternalPage()) {
- if (node->name() == node_->name()) {
- alreadyThere = true;
- break;
- }
- }
- }
- }
- if (!alreadyThere)
- m_pageNodesByTitle.insert(key, node);
- }
- }
-
- if (child->doc().hasTableOfContents()) {
- const QList<Atom *> &toc = child->doc().tableOfContents();
- for (Atom *i : toc) {
- QString ref = refForAtom(i);
- QString title = Text::sectionHeading(i).toString();
- if (!ref.isEmpty() && !title.isEmpty()) {
- QString key = Doc::canonicalTitle(title);
- auto *target = new TargetRec(ref, TargetRec::Contents, child, 3);
- m_nodesByTargetRef.insert(key, target);
- m_nodesByTargetTitle.insert(title, target);
- }
- }
- }
- if (child->doc().hasKeywords()) {
- const QList<Atom *> &keywords = child->doc().keywords();
- for (Atom *i : keywords) {
- QString ref = refForAtom(i);
- QString title = i->string();
- if (!ref.isEmpty() && !title.isEmpty()) {
- auto *target = new TargetRec(ref, TargetRec::Keyword, child, 1);
- m_nodesByTargetRef.insert(Doc::canonicalTitle(title), target);
- m_nodesByTargetTitle.insert(title, target);
- }
- }
- }
- if (child->doc().hasTargets()) {
- const QList<Atom *> &targets = child->doc().targets();
- for (Atom *i : targets) {
- QString ref = refForAtom(i);
- QString title = i->string();
- if (!ref.isEmpty() && !title.isEmpty()) {
- QString key = Doc::canonicalTitle(title);
- auto *target = new TargetRec(ref, TargetRec::Target, child, 2);
- m_nodesByTargetRef.insert(key, target);
- m_nodesByTargetTitle.insert(title, target);
- }
- }
- }
- if (child->isAggregate())
- resolveTargets(static_cast<Aggregate *>(child));
- }
-}
-
-/*!
- This function searches for a \a target anchor node. If it
- finds one, it sets \a ref and returns the found node.
- */
-const Node *Tree::findUnambiguousTarget(const QString &target, Node::Genus genus,
- QString &ref) const
-{
- int numBestTargets = 0;
- TargetRec *bestTarget = nullptr;
- QList<TargetRec *> bestTargetList;
-
- QString key = target;
- for (auto it = m_nodesByTargetTitle.find(key); it != m_nodesByTargetTitle.constEnd(); ++it) {
- if (it.key() != key)
- break;
- TargetRec *candidate = it.value();
- if ((genus == Node::DontCare) || (genus & candidate->genus())) {
- if (!bestTarget || (candidate->m_priority < bestTarget->m_priority)) {
- bestTarget = candidate;
- bestTargetList.clear();
- bestTargetList.append(candidate);
- numBestTargets = 1;
- } else if (candidate->m_priority == bestTarget->m_priority) {
- bestTargetList.append(candidate);
- ++numBestTargets;
- }
- }
- }
- if (bestTarget) {
- ref = bestTarget->m_ref;
- return bestTarget->m_node;
- }
-
- numBestTargets = 0;
- bestTarget = nullptr;
- key = Doc::canonicalTitle(target);
- for (auto it = m_nodesByTargetRef.find(key); it != m_nodesByTargetRef.constEnd(); ++it) {
- if (it.key() != key)
- break;
- TargetRec *candidate = it.value();
- if ((genus == Node::DontCare) || (genus & candidate->genus())) {
- if (!bestTarget || (candidate->m_priority < bestTarget->m_priority)) {
- bestTarget = candidate;
- bestTargetList.clear();
- bestTargetList.append(candidate);
- numBestTargets = 1;
- } else if (candidate->m_priority == bestTarget->m_priority) {
- bestTargetList.append(candidate);
- ++numBestTargets;
- }
- }
- }
- if (bestTarget) {
- ref = bestTarget->m_ref;
- return bestTarget->m_node;
- }
-
- ref.clear();
- return nullptr;
-}
-
-/*!
- This function searches for a node with the specified \a title.
- */
-const PageNode *Tree::findPageNodeByTitle(const QString &title) const
-{
- PageNodeMultiMap::const_iterator it;
- if (title.contains(QChar(' ')))
- it = m_pageNodesByTitle.constFind(Doc::canonicalTitle(title));
- else
- it = m_pageNodesByTitle.constFind(title);
- if (it != m_pageNodesByTitle.constEnd()) {
- /*
- Reporting all these duplicate section titles is probably
- overkill. We should report the duplicate file and let
- that suffice.
- */
- PageNodeMultiMap::const_iterator j = it;
- ++j;
- if (j != m_pageNodesByTitle.constEnd() && j.key() == it.key()) {
- while (j != m_pageNodesByTitle.constEnd()) {
- if (j.key() == it.key() && j.value()->url().isEmpty()) {
- break; // Just report one duplicate for now.
- }
- ++j;
- }
- if (j != m_pageNodesByTitle.cend()) {
- it.value()->location().warning("This page title exists in more than one file: "
- + title);
- j.value()->location().warning("[It also exists here]");
- }
- }
- return it.value();
- }
- return nullptr;
-}
-
-/*!
- Returns a canonical title for the \a atom, if the \a atom
- is a SectionLeft or a Target.
- */
-QString Tree::refForAtom(const Atom *atom)
-{
- if (atom) {
- if (atom->type() == Atom::SectionLeft)
- return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
- if ((atom->type() == Atom::Target) || (atom->type() == Atom::Keyword))
- return Doc::canonicalTitle(atom->string());
- }
- return QString();
-}
-
-/*!
- \fn const CNMap &Tree::groups() const
- Returns a const reference to the collection of all
- group nodes.
-*/
-
-/*!
- \fn const ModuleMap &Tree::modules() const
- Returns a const reference to the collection of all
- module nodes.
-*/
-
-/*!
- \fn const QmlModuleMap &Tree::qmlModules() const
- Returns a const reference to the collection of all
- QML module nodes.
-*/
-
-/*!
- Returns a pointer to the collection map specified by \a type.
- Returns null if \a type is not specified.
- */
-CNMap *Tree::getCollectionMap(Node::NodeType type)
-{
- switch (type) {
- case Node::Group:
- return &m_groups;
- case Node::Module:
- return &m_modules;
- case Node::QmlModule:
- return &m_qmlModules;
- case Node::JsModule:
- return &m_jsModules;
- default:
- break;
- }
- return nullptr;
-}
-
-/*!
- Searches this tree for a collection named \a name with the
- specified \a type. If the collection is found, a pointer
- to it is returned. If a collection is not found, null is
- returned.
- */
-CollectionNode *Tree::getCollection(const QString &name, Node::NodeType type)
-{
- CNMap *map = getCollectionMap(type);
- if (map) {
- auto it = map->constFind(name);
- if (it != map->cend())
- return it.value();
- }
- return nullptr;
-}
-
-/*!
- Find the group, module, QML module, or JavaScript module
- named \a name and return a pointer to that collection node.
- \a type specifies which kind of collection node you want.
- If a collection node with the specified \a name and \a type
- is not found, a new one is created, and the pointer to the
- new one is returned.
-
- If a new collection node is created, its parent is the tree
- root, and the new collection node is marked \e{not seen}.
-
- \a genus must be specified, i.e. it must not be \c{DontCare}.
- If it is \c{DontCare}, 0 is returned, which is a programming
- error.
- */
-CollectionNode *Tree::findCollection(const QString &name, Node::NodeType type)
-{
- CNMap *m = getCollectionMap(type);
- if (!m) // error
- return nullptr;
- auto it = m->constFind(name);
- if (it != m->cend())
- return it.value();
- CollectionNode *cn = new CollectionNode(type, root(), name);
- cn->markNotSeen();
- m->insert(name, cn);
- return cn;
-}
-
-/*! \fn CollectionNode *Tree::findGroup(const QString &name)
- Find the group node named \a name and return a pointer
- to it. If the group node is not found, add a new group
- node named \a name and return a pointer to the new one.
-
- If a new group node is added, its parent is the tree root,
- and the new group node is marked \e{not seen}.
- */
-
-/*! \fn CollectionNode *Tree::findModule(const QString &name)
- Find the module node named \a name and return a pointer
- to it. If a matching node is not found, add a new module
- node named \a name and return a pointer to that one.
-
- If a new module node is added, its parent is the tree root,
- and the new module node is marked \e{not seen}.
- */
-
-/*! \fn CollectionNode *Tree::findQmlModule(const QString &name)
- Find the QML module node named \a name and return a pointer
- to it. If a matching node is not found, add a new QML module
- node named \a name and return a pointer to that one.
-
- If a new QML module node is added, its parent is the tree root,
- and the new node is marked \e{not seen}.
- */
-
-/*! \fn CollectionNode *Tree::findJsModule(const QString &name)
- Find the JavaScript module named \a name and return a pointer
- to it. If a matching node is not found, add a new JavaScript
- module node named \a name and return a pointer to that one.
-
- If a new JavaScript module node is added, its parent is the
- tree root, and the new node is marked \e{not seen}.
- */
-
-/*! \fn CollectionNode *Tree::addGroup(const QString &name)
- Looks up the group node named \a name in the collection
- of all group nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new group node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned.
- */
-
-/*! \fn CollectionNode *Tree::addModule(const QString &name)
- Looks up the module node named \a name in the collection
- of all module nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new module node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned.
- */
-
-/*! \fn CollectionNode *Tree::addQmlModule(const QString &name)
- Looks up the QML module node named \a name in the collection
- of all QML module nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new QML module node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned.
- */
-
-/*! \fn CollectionNode *Tree::addJsModule(const QString &name)
- Looks up the JavaScript module node named \a name in the collection
- of all JavaScript module nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new JavaScrpt module node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned.
- */
-
-/*!
- Looks up the group node named \a name in the collection
- of all group nodes. If a match is not found, a new group
- node named \a name is created and inserted into the collection.
- Then append \a node to the group's members list, and append the
- group name to the list of group names in \a node. The parent of
- \a node is not changed by this function. Returns a pointer to
- the group node.
- */
-CollectionNode *Tree::addToGroup(const QString &name, Node *node)
-{
- CollectionNode *cn = findGroup(name);
- if (!node->isInternal()) {
- cn->addMember(node);
- node->appendGroupName(name);
- }
- return cn;
-}
-
-/*!
- Looks up the module node named \a name in the collection
- of all module nodes. If a match is not found, a new module
- node named \a name is created and inserted into the collection.
- Then append \a node to the module's members list. The parent of
- \a node is not changed by this function. Returns the module node.
- */
-CollectionNode *Tree::addToModule(const QString &name, Node *node)
-{
- CollectionNode *cn = findModule(name);
- cn->addMember(node);
- node->setPhysicalModuleName(name);
- return cn;
-}
-
-/*!
- Looks up the QML module named \a name. If it isn't there,
- create it. Then append \a node to the QML module's member
- list. The parent of \a node is not changed by this function.
- Returns the pointer to the QML module node.
- */
-CollectionNode *Tree::addToQmlModule(const QString &name, Node *node)
-{
- QStringList qmid;
- QStringList dotSplit;
- QStringList blankSplit = name.split(QLatin1Char(' '));
- qmid.append(blankSplit[0]);
- if (blankSplit.size() > 1) {
- qmid.append(blankSplit[0] + blankSplit[1]);
- dotSplit = blankSplit[1].split(QLatin1Char('.'));
- qmid.append(blankSplit[0] + dotSplit[0]);
- }
-
- CollectionNode *cn = findQmlModule(blankSplit[0]);
- cn->addMember(node);
- node->setQmlModule(cn);
- if (node->isQmlType()) {
- QmlTypeNode *n = static_cast<QmlTypeNode *>(node);
- for (int i = 0; i < qmid.size(); ++i) {
- QString key = qmid[i] + "::" + node->name();
- insertQmlType(key, n);
- }
- }
- return cn;
-}
-
-/*!
- Looks up the QML module named \a name. If it isn't there,
- create it. Then append \a node to the QML module's member
- list. The parent of \a node is not changed by this function.
- Returns the pointer to the QML module node.
- */
-CollectionNode *Tree::addToJsModule(const QString &name, Node *node)
-{
- QStringList qmid;
- QStringList dotSplit;
- QStringList blankSplit = name.split(QLatin1Char(' '));
- qmid.append(blankSplit[0]);
- if (blankSplit.size() > 1) {
- qmid.append(blankSplit[0] + blankSplit[1]);
- dotSplit = blankSplit[1].split(QLatin1Char('.'));
- qmid.append(blankSplit[0] + dotSplit[0]);
- }
-
- CollectionNode *cn = findJsModule(blankSplit[0]);
- cn->addMember(node);
- node->setQmlModule(cn);
- if (node->isJsType()) {
- QmlTypeNode *n = static_cast<QmlTypeNode *>(node);
- for (int i = 0; i < qmid.size(); ++i) {
- QString key = qmid[i] + "::" + node->name();
- insertQmlType(key, n);
- }
- }
- return cn;
-}
-
-/*!
- If the QML type map does not contain \a key, insert node
- \a n with the specified \a key.
- */
-void Tree::insertQmlType(const QString &key, QmlTypeNode *n)
-{
- if (!m_qmlTypeMap.contains(key))
- m_qmlTypeMap.insert(key, n);
-}
-
-/*!
- Finds the function node with the specifried name \a path that
- also has the specified \a parameters and returns a pointer to
- the the first matching function node if one is found.
-
- This function begins searching the tree at \a relative for
- the \l {FunctionNode} {function node} identified by \a path
- that has the specified \a parameters. The \a flags are
- used to restrict the search. If a matching node is found, a
- pointer to it is returned. Otherwise, nullis returned. If
- \a relative is ull, the search begins at the tree root.
- */
-const FunctionNode *Tree::findFunctionNode(const QStringList &path, const Parameters &parameters,
- const Node *relative, Node::Genus genus) const
-{
- if (path.size() == 3 && !path[0].isEmpty()
- && ((genus == Node::QML) || (genus == Node::DontCare))) {
- QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
- if (qcn == nullptr) {
- QStringList p(path[1]);
- Node *n = findNodeByNameAndType(p, &Node::isQmlType);
- if ((n != nullptr) && (n->isQmlType() || n->isJsType()))
- qcn = static_cast<QmlTypeNode *>(n);
- }
- if (qcn != nullptr)
- return static_cast<const FunctionNode *>(qcn->findFunctionChild(path[2], parameters));
- }
-
- if (relative == nullptr)
- relative = root();
- else if (genus != Node::DontCare) {
- if (!(genus & relative->genus()))
- relative = root();
- }
-
- do {
- Node *node = const_cast<Node *>(relative);
- int i;
-
- for (i = 0; i < path.size(); ++i) {
- if (node == nullptr || !node->isAggregate())
- break;
-
- Aggregate *aggregate = static_cast<Aggregate *>(node);
- Node *next = nullptr;
- if (i == path.size() - 1)
- next = aggregate->findFunctionChild(path.at(i), parameters);
- else
- next = aggregate->findChildNode(path.at(i), genus);
-
- if ((next == nullptr) && aggregate->isClassNode()) {
- const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(aggregate));
- for (auto *base : bases) {
- if (i == path.size() - 1)
- next = base->findFunctionChild(path.at(i), parameters);
- else
- next = base->findChildNode(path.at(i), genus);
-
- if (next != nullptr)
- break;
- }
- }
-
- node = next;
- } // for (i = 0; i < path.size(); ++i)
-
- if (node && i == path.size() && node->isFunction()) {
- // A function node was found at the end of the path.
- // If it is not marked private, return it. If it is
- // marked private, then if it overrides a function,
- // find that function instead because it might not
- // be marked private. If all the overloads are
- // marked private, return the original function node.
- // This should be replace with findOverriddenFunctionNode().
- const FunctionNode *fn = static_cast<const FunctionNode *>(node);
- const FunctionNode *FN = fn;
- while (FN->isPrivate() && !FN->overridesThis().isEmpty()) {
- QStringList path = FN->overridesThis().split("::");
- FN = m_qdb->findFunctionNode(path, parameters, relative, genus);
- if (FN == nullptr)
- break;
- if (!FN->isPrivate())
- return FN;
- }
- return fn;
- }
- relative = relative->parent();
- } while (relative);
- return nullptr;
-}
-
-/*!
- Search this tree recursively from \a parent to find a function
- node with the specified \a tag. If no function node is found
- with the required \a tag, return 0.
- */
-FunctionNode *Tree::findFunctionNodeForTag(const QString &tag, Aggregate *parent)
-{
- if (parent == nullptr)
- parent = root();
- const NodeList &children = parent->childNodes();
- for (Node *n : children) {
- if (n != nullptr && n->isFunction() && n->hasTag(tag))
- return static_cast<FunctionNode *>(n);
- }
- for (Node *n : children) {
- if (n != nullptr && n->isAggregate()) {
- n = findFunctionNodeForTag(tag, static_cast<Aggregate *>(n));
- if (n != nullptr)
- return static_cast<FunctionNode *>(n);
- }
- }
- return nullptr;
-}
-
-/*!
- There should only be one macro node for macro name \a t.
- The macro node is not built until the \macro command is seen.
- */
-FunctionNode *Tree::findMacroNode(const QString &t, const Aggregate *parent)
-{
- if (parent == nullptr)
- parent = root();
- const NodeList &children = parent->childNodes();
- for (Node *n : children) {
- if (n != nullptr && (n->isMacro() || n->isFunction()) && n->name() == t)
- return static_cast<FunctionNode *>(n);
- }
- for (Node *n : children) {
- if (n != nullptr && n->isAggregate()) {
- FunctionNode *fn = findMacroNode(t, static_cast<Aggregate *>(n));
- if (fn != nullptr)
- return fn;
- }
- }
- return nullptr;
-}
-
-/*!
- Add the class and struct names in \a arg to the \e {don't document}
- map.
- */
-void Tree::addToDontDocumentMap(QString &arg)
-{
- arg.remove(QChar('('));
- arg.remove(QChar(')'));
- QString t = arg.simplified();
- QStringList sl = t.split(QChar(' '));
- if (sl.isEmpty())
- return;
- for (const QString &s : sl) {
- if (!m_dontDocumentMap.contains(s))
- m_dontDocumentMap.insert(s, nullptr);
- }
-}
-
-/*!
- The \e {don't document} map has been loaded with the names
- of classes and structs in the current module that are not
- documented and should not be documented. Now traverse the
- map, and for each class or struct name, find the class node
- that represents that class or struct and mark it with the
- \C DontDocument status.
-
- This results in a map of the class and struct nodes in the
- module that are in the public API but are not meant to be
- used by anyone. They are only used internally, but for one
- reason or another, they must have public visibility.
- */
-void Tree::markDontDocumentNodes()
-{
- for (auto it = m_dontDocumentMap.begin(); it != m_dontDocumentMap.end(); ++it) {
- Aggregate *node = findAggregate(it.key());
- if (node != nullptr)
- node->setStatus(Node::DontDocument);
- }
-}
-
-QT_END_NAMESPACE