diff options
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 |
