diff options
| author | Martin Smith <martin.smith@digia.com> | 2014-01-06 12:57:17 +0100 |
|---|---|---|
| committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-31 21:04:43 +0200 |
| commit | e9954e31624c77d986077ec5431c7ec4a9b058e0 (patch) | |
| tree | ce07acd32f8a03c07fa0f16cfc9ab186459c13fa /src/tools/qdoc/tree.cpp | |
| parent | 4f50be8d1885e685ec8df3796e4156eb015affa7 (diff) | |
qdoc: Teach qdoc to use multiple trees
qdoc now builds a separate Node Tree for each index
file it parsed. The main Node Tree now contains only
the Nodes of things being documented in the current
module. This should make qdoc run a little faster.
qdoc now uses these separate trees to make intra-module
and inter-module linking more robust by searching the
trees in an order that depends on the type of link it
is searching for. The tree for the current module is
always searched first. Then qdoc searches the trees
for either the C++ modules or the QML modules, depending
on whether it is looking for a C++ link or a QML link.
In preparation for this update, qdoc was also simplified
a lot. Many functions became obsolete and were removed.
Others were combined.
Task-number: QTBUG-35377
Change-Id: Iea4e49869ff6a6ff0f4d53090728770d40d892f3
Reviewed-by: Topi Reiniƶ <topi.reinio@digia.com>
Diffstat (limited to 'src/tools/qdoc/tree.cpp')
| -rw-r--r-- | src/tools/qdoc/tree.cpp | 566 |
1 files changed, 292 insertions, 274 deletions
diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index 113220059c8..98ac64246e9 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -49,6 +49,8 @@ #include <limits.h> #include <qdebug.h> +bool Tree::debug_ = false; + QT_BEGIN_NAMESPACE /*! @@ -79,113 +81,59 @@ Tree::~Tree() { } -// 1 calls 2 +/* API members */ + /*! - 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. + 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. */ -const Node* Tree::findNode(const QStringList& path, - const Node* start, - int findFlags, - const Node* self) const +ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const { - const Node* current = start; - if (!current) - current = root(); - - /* - First, search for a node assuming we don't want a QML node. - If that search fails, search again assuming we do want a - QML node. - */ - const Node* n = findNode(path,current,findFlags,self,false); - if (!n) { - n = findNode(path,current,findFlags,self,true); - } - return n; + if (!start) + start = const_cast<NamespaceNode*>(root()); + return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType)); } -// 2 is private; it is only called by 1. /*! - This overload function was extracted from the one above that has the - same signature without the last bool parameter, \a qml. This version - is called only by that other one. It is therefore private. It can - be called a second time by that other version, if the first call - returns null. If \a qml is false, the search will only match a node - that is not a QML node. If \a qml is true, the search will only - match a node that is a QML node. -*/ -const Node* Tree::findNode(const QStringList& path, - const Node* start, - int findFlags, - const Node* self, - bool qml) const + 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 { - const Node* current = start; - 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 anser is yes, the reference identifies a QML - class node. - */ - if (qml && path.size() >= 2 && !path[0].isEmpty()) { - QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]); - if (qcn) { - node = qcn; - if (path.size() == 2) - return node; - start_idx = 2; - } - } - - for (i = start_idx; i < path.size(); ++i) { - if (node == 0 || !node->isInnerNode()) - break; - - const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml); - if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) - next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i)); + Node* start = const_cast<NamespaceNode*>(root()); + return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType)); +} - if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) { - NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node)); - foreach (const Node* baseClass, baseClasses) { - next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i)); - if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1) - next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i)); - if (next) - break; - } - } - node = next; - } - if (node && i == path.size() - && (!(findFlags & NonFunction) || node->type() != Node::Function - || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) { - if ((node != self) && (node->type() != Node::QmlPropertyGroup)) { - if (node->subType() == Node::Collision) { - node = node->applyModuleName(start); - } - return node; - } - } - current = current->parent(); - } while (current); +/*! + This function first ignores the \a clone node and searches + for the parent node with \a parentPath. If that search is + successful, it searches for a child node of the parent that + matches the \a clone node. If it finds a node that is just + like the \a clone, it returns a pointer to the found node. - return 0; + There should be a way to avoid creating the clone in the + first place. Investigate when time allows. + */ +FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) +{ + const Node* parent = findNamespaceNode(parentPath); + if (parent == 0) + parent = findClassNode(parentPath, 0); + if (parent == 0) + parent = findNode(parentPath); + if (parent == 0 || !parent->isInnerNode()) + return 0; + return ((InnerNode*)parent)->findFunctionNode(clone); } + /*! Find the Qml type 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 Qml type node named \a path is + at the root of the tree. Only a Qml type node named <\a path is acceptible. If one is not found, 0 is returned. */ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path) @@ -248,18 +196,6 @@ NameCollisionNode* Tree::findCollisionNode(const QString& name) const } /*! - This function just calls the const version of the same function - and returns the function node. - */ -FunctionNode* Tree::findFunctionNode(const QStringList& path, - Node* relative, - int findFlags) -{ - return const_cast<FunctionNode*> - (const_cast<const Tree*>(this)->findFunctionNode(path,relative,findFlags)); -} - -/*! This function begins searching the tree at \a relative for the \l {FunctionNode} {function node} identified by \a path. The \a findFlags are used to restrict the search. If a node @@ -339,57 +275,34 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path, return 0; } -/*! - This function just calls the const version of itself and - returns the result. - */ -FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, - const FunctionNode* clone, - Node* relative, - int findFlags) +static NodeTypeList t; +static const NodeTypeList& relatesTypes() { - return const_cast<FunctionNode*>( - const_cast<const Tree*>(this)->findFunctionNode(parentPath, - clone, - relative, - findFlags)); + if (t.isEmpty()) { + t.reserve(3); + t.append(NodeTypePair(Node::Class, Node::NoSubType)); + t.append(NodeTypePair(Node::Namespace, Node::NoSubType)); + t.append(NodeTypePair(Node::Document, Node::HeaderFile)); + } + return t; } /*! - This function first ignores the \a clone node and searches - for the node having the \a parentPath by calling the main - findFunction(\a {parentPath}, \a {relative}, \a {findFlags}). - If that search is successful, then it searches for the \a clone - in the found parent node. - */ -const FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, - const FunctionNode* clone, - const Node* relative, - int findFlags) const -{ - const Node* parent = findNamespaceNode(parentPath); - if (parent == 0) - parent = findClassNode(parentPath, 0); - if (parent == 0) - parent = findNode(parentPath, relative, findFlags); - if (parent == 0 || !parent->isInnerNode()) - return 0; - return ((InnerNode*)parent)->findFunctionNode(clone); -} + 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. */ -void Tree::addBaseClass(ClassNode* subclass, Node::Access access, - const QStringList& basePath, - const QString& dataTypeWithTemplateArgs, - InnerNode* parent) +InnerNode* Tree::findRelatesNode(const QStringList& path) { - unresolvedInheritanceMap[subclass].append( - InheritanceBound(access, - basePath, - dataTypeWithTemplateArgs, - parent) - ); + Node* n = findNodeRecursive(path, 0, root(), relatesTypes()); + return ((n && n->isInnerNode()) ? static_cast<InnerNode*>(n) : 0); } /*! @@ -402,24 +315,25 @@ void Tree::addPropertyFunction(PropertyNode* property, } /*! - This function resolves inheritance and reimplementation settings - for each C++ class node found in the namspace beginning at \a rootNode. - If it finds another namespace node in the child list of \a rootNode, - it calls itself recursively. For each child of \a rootNode that is a - class node, it calls the other resolveInheritance() function. + 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. For each child of \a n + that is a class node, it calls resolveInheritanceHelper(). This function does not resolve QML inheritance. */ -void Tree::resolveInheritance(NamespaceNode* rootNode) +void Tree::resolveInheritance(InnerNode* n) { - if (!rootNode) - rootNode = root(); + if (!n) + n = root(); for (int pass = 0; pass < 2; pass++) { - NodeList::ConstIterator c = rootNode->childNodes().constBegin(); - while (c != rootNode->childNodes().constEnd()) { + NodeList::ConstIterator c = n->childNodes().constBegin(); + while (c != n->childNodes().constEnd()) { if ((*c)->type() == Node::Class) { - resolveInheritance(pass, (ClassNode*)* c); + resolveInheritanceHelper(pass, (ClassNode*)*c); + resolveInheritance((ClassNode*)*c); } else if ((*c)->type() == Node::Namespace) { NamespaceNode* ns = static_cast<NamespaceNode*>(*c); @@ -427,8 +341,67 @@ void Tree::resolveInheritance(NamespaceNode* rootNode) } ++c; } - if (rootNode == root()) - unresolvedInheritanceMap.clear(); + } +} + +/*! + This function is run twice for eachclass node \a cn in the + tree. First it is run with \a pass set to 0 for each + class node \a cn. Then it is run with \a pass set to 1 for + eachclass node \a cn. + + In \a pass 0, all the base classes ofclass node \a cn are + found and added to the base class list forclass node \a cn. + + In \a pass 1, each child ofclass node \a cn that is a function + that is reimplemented from one of the base classes is marked + as being reimplemented from that class. + + Some property node fixing up is also done in \a pass 1. + */ +void Tree::resolveInheritanceHelper(int pass, ClassNode* cn) +{ + if (pass == 0) { + QList<RelatedClass>& bases = cn->baseClasses(); + QList<RelatedClass>::iterator b = bases.begin(); + while (b != bases.end()) { + if (!(*b).node_) { + InnerNode* parent = cn->parent(); + Node* n = findClassNode((*b).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) + n = findClassNode((*b).path_, parent); + if (n) + (*b).node_ = static_cast<ClassNode*>(n); + } + ++b; + } + } + else { + NodeList::ConstIterator c = cn->childNodes().constBegin(); + while (c != cn->childNodes().constEnd()) { + if ((*c)->type() == Node::Function) { + FunctionNode* func = (FunctionNode*)* c; + FunctionNode* from = findVirtualFunctionInBaseClasses(cn, func); + if (from != 0) { + if (func->virtualness() == FunctionNode::NonVirtual) + func->setVirtualness(FunctionNode::ImpureVirtual); + func->setReimplementedFrom(from); + } + } + else if ((*c)->type() == Node::Property) + cn->fixPropertyUsingBaseClasses(static_cast<PropertyNode*>(*c)); + ++c; + } } } @@ -486,57 +459,6 @@ void Tree::resolveProperties() } /*! - This function is run twice for each \a classNode in the - tree. First it is run with \a pass set to 0 for each - \a classNode. Then it is run with \a pass set to 1 for - each \a classNode. - - In \a pass 0, all the base classes of \a classNode are - found and added to the base class list for \a classNode. - - In \a pass 1, each child of \a classNode that is a function - that is reimplemented from one of the base classes is marked - as being reimplemented from that class. - - Some property node fixing up is also done in \a pass 1. - */ -void Tree::resolveInheritance(int pass, ClassNode* classNode) -{ - if (pass == 0) { - QList<InheritanceBound> bounds = unresolvedInheritanceMap[classNode]; - QList<InheritanceBound>::ConstIterator b = bounds.constBegin(); - while (b != bounds.constEnd()) { - Node* n = findClassNode((*b).basePath); - if (!n && (*b).parent) { - n = findClassNode((*b).basePath, (*b).parent); - } - if (n) { - classNode->addBaseClass((*b).access, static_cast<ClassNode*>(n), (*b).dataTypeWithTemplateArgs); - } - ++b; - } - } - else { - NodeList::ConstIterator c = classNode->childNodes().constBegin(); - while (c != classNode->childNodes().constEnd()) { - if ((*c)->type() == Node::Function) { - FunctionNode* func = (FunctionNode*)* c; - FunctionNode* from = findVirtualFunctionInBaseClasses(classNode, func); - if (from != 0) { - if (func->virtualness() == FunctionNode::NonVirtual) - func->setVirtualness(FunctionNode::ImpureVirtual); - func->setReimplementedFrom(from); - } - } - else if ((*c)->type() == Node::Property) { - fixPropertyUsingBaseClasses(classNode, static_cast<PropertyNode*>(*c)); - } - ++c; - } - } -} - -/*! 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. @@ -575,16 +497,18 @@ void Tree::fixInheritance(NamespaceNode* rootNode) /*! */ -FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classNode, - FunctionNode* clone) +FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* cn, FunctionNode* clone) { - QList<RelatedClass>::ConstIterator r = classNode->baseClasses().constBegin(); - while (r != classNode->baseClasses().constEnd()) { + const QList<RelatedClass>& rc = cn->baseClasses(); + QList<RelatedClass>::ConstIterator r = rc.constBegin(); + while (r != rc.constEnd()) { FunctionNode* func; - if (((func = findVirtualFunctionInBaseClasses((*r).node, clone)) != 0 || - (func = (*r).node->findFunctionNode(clone)) != 0)) { - if (func->virtualness() != FunctionNode::NonVirtual) - return func; + if ((*r).node_) { + if (((func = findVirtualFunctionInBaseClasses((*r).node_, clone)) != 0 || + (func = (*r).node_->findFunctionNode(clone)) != 0)) { + if (func->virtualness() != FunctionNode::NonVirtual) + return func; + } } ++r; } @@ -593,31 +517,14 @@ FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classNode, /*! */ -void Tree::fixPropertyUsingBaseClasses(ClassNode* classNode, PropertyNode* property) -{ - QList<RelatedClass>::const_iterator r = classNode->baseClasses().constBegin(); - while (r != classNode->baseClasses().constEnd()) { - Node* n = r->node->findChildNodeByNameAndType(property->name(), Node::Property); - if (n) { - PropertyNode* baseProperty = static_cast<PropertyNode*>(n); - fixPropertyUsingBaseClasses(r->node, baseProperty); - property->setOverriddenFrom(baseProperty); - } - else { - fixPropertyUsingBaseClasses(r->node, property); - } - ++r; - } -} - -/*! - */ NodeList Tree::allBaseClasses(const ClassNode* classNode) const { NodeList result; foreach (const RelatedClass& r, classNode->baseClasses()) { - result += r.node; - result += allBaseClasses(r.node); + if (r.node_) { + result += r.node_; + result += allBaseClasses(r.node_); + } } return result; } @@ -641,6 +548,8 @@ Node* Tree::findNodeByNameAndType(const QStringList& path, return result; } +/* internal members */ + /*! Recursive search for a node identified by \a path. Each path element is a name. \a pathIndex specifies the index @@ -694,24 +603,27 @@ Node* Tree::findNodeRecursive(const QStringList& path, if (type == Node::Document) { if (n->subType() == subtype) return n; - else if (n->subType() == Node::Collision && acceptCollision) - return n; + else if (n->subType() == Node::Collision) { + if (acceptCollision) + return n; + return n->disambiguate(type, subtype); + } else if (subtype == Node::NoSubType) - return n; // don't care what subtype is. - return 0; + return n; + continue; } - else - return n; + return n; } else if (n->isCollisionNode()) { if (acceptCollision) return n; return findNodeRecursive(path, pathIndex, n, type, subtype); } - else - return 0; + else { + continue; + } } - else { // Not at the end of the path. + else { // Search the children of n for the next name in the path. n = findNodeRecursive(path, pathIndex+1, n, type, subtype); if (n) return n; @@ -722,40 +634,146 @@ Node* Tree::findNodeRecursive(const QStringList& path, } /*! - Find the Enum type 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 an Enum type node named \a path is - acceptible. If one is not found, 0 is returned. + 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 name 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), test the + matching node's type and subtype values against the ones + listed in \a types. If a match is found there, return the + pointer to the final node. Otherwise return 0. */ -EnumNode* Tree::findEnumNode(const QStringList& path, Node* start) +Node* Tree::findNodeRecursive(const QStringList& path, + int pathIndex, + Node* start, + const NodeTypeList& types) const { - if (!start) - start = const_cast<NamespaceNode*>(root()); - return static_cast<EnumNode*>(findNodeRecursive(path, 0, start, Node::Enum, Node::NoSubType)); + /* + Safety checks + */ + if (!start || path.isEmpty()) + return 0; + if (start->isLeaf()) + return ((pathIndex >= path.size()) ? start : 0); + if (pathIndex >= path.size()) + return 0; + + InnerNode* current = static_cast<InnerNode*>(start); + const NodeList& children = current->childNodes(); + for (int i=0; i<children.size(); ++i) { + Node* n = children.at(i); + if (n && n->name() == path.at(pathIndex)) { + if (pathIndex+1 >= path.size()) { + if (n->match(types)) + return n; + } + else if (!n->isLeaf()) { + n = findNodeRecursive(path, pathIndex+1, n, types); + if (n) + return n; + } + } + } + return 0; } /*! - 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. + 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. + + This findNode() callse the other findNode(), which is not + called anywhere else. */ -ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const +const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags) const { - if (!start) - start = const_cast<NamespaceNode*>(root()); - return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType)); + const Node* current = start; + if (!current) + current = root(); + + /* + First, search for a node assuming we don't want a QML node. + If that search fails, search again assuming we do want a + QML node. + */ + const Node* n = findNode(path, current, findFlags, false); + return (n ? n : findNode(path, current, findFlags, true)); } /*! - 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 + This overload function was extracted from the one above that has the + same signature without the last bool parameter, \a qml. This version + is called only by that other one. It is therefore private. It can + be called a second time by that other version, if the first call + returns null. If \a qml is false, the search will only match a node + that is not a QML node. If \a qml is true, the search will only + match a node that is a QML node. + + This findNode() is only called by the other findNode(). +*/ +const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags, bool qml) const { - Node* start = const_cast<NamespaceNode*>(root()); - return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType)); + const Node* current = start; + 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 anser is yes, the reference identifies a QML + class node. + */ + if (qml && path.size() >= 2 && !path[0].isEmpty()) { + QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]); + if (qcn) { + node = qcn; + if (path.size() == 2) + return node; + start_idx = 2; + } + } + + for (i = start_idx; i < path.size(); ++i) { + if (node == 0 || !node->isInnerNode()) + break; + + const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml); + if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) + next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i)); + + if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) { + NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node)); + foreach (const Node* baseClass, baseClasses) { + next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i)); + if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1) + next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i)); + if (next) + break; + } + } + node = next; + } + if (node && i == path.size() + && (!(findFlags & NonFunction) || node->type() != Node::Function + || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) { + if (!node->isQmlPropertyGroup()) { + if (node->isCollisionNode()) + node = node->applyModuleName(start); + return node; + } + } + current = current->parent(); + } while (current); + + return 0; } QT_END_NAMESPACE |
