diff options
Diffstat (limited to 'src/tools/qdoc')
-rw-r--r-- | src/tools/qdoc/cppcodemarker.cpp | 6 | ||||
-rw-r--r-- | src/tools/qdoc/cppcodeparser.cpp | 45 | ||||
-rw-r--r-- | src/tools/qdoc/ditaxmlgenerator.cpp | 38 | ||||
-rw-r--r-- | src/tools/qdoc/generator.cpp | 39 | ||||
-rw-r--r-- | src/tools/qdoc/helpprojectwriter.cpp | 2 | ||||
-rw-r--r-- | src/tools/qdoc/htmlgenerator.cpp | 37 | ||||
-rw-r--r-- | src/tools/qdoc/htmlgenerator.h | 3 | ||||
-rw-r--r-- | src/tools/qdoc/main.cpp | 4 | ||||
-rw-r--r-- | src/tools/qdoc/node.cpp | 296 | ||||
-rw-r--r-- | src/tools/qdoc/node.h | 63 | ||||
-rw-r--r-- | src/tools/qdoc/qdocdatabase.cpp | 11 | ||||
-rw-r--r-- | src/tools/qdoc/qdocdatabase.h | 53 | ||||
-rw-r--r-- | src/tools/qdoc/qdocindexfiles.cpp | 113 | ||||
-rw-r--r-- | src/tools/qdoc/qdoctagfiles.cpp | 32 | ||||
-rw-r--r-- | src/tools/qdoc/tree.cpp | 566 | ||||
-rw-r--r-- | src/tools/qdoc/tree.h | 73 |
16 files changed, 704 insertions, 677 deletions
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp index 64b11109f7..58fbd45453 100644 --- a/src/tools/qdoc/cppcodemarker.cpp +++ b/src/tools/qdoc/cppcodemarker.cpp @@ -629,7 +629,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, QList<RelatedClass>::ConstIterator r = ancestorClass->baseClasses().constBegin(); while (r != ancestorClass->baseClasses().constEnd()) { - stack.prepend((*r).node); + if ((*r).node_) + stack.prepend((*r).node_); ++r; } } @@ -724,7 +725,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, QList<RelatedClass>::ConstIterator r = ancestorClass->baseClasses().constBegin(); while (r != ancestorClass->baseClasses().constEnd()) { - stack.prepend((*r).node); + if ((*r).node_) + stack.prepend((*r).node_); ++r; } } diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp index bb403bd4d9..c22a5227a6 100644 --- a/src/tools/qdoc/cppcodeparser.cpp +++ b/src/tools/qdoc/cppcodeparser.cpp @@ -225,8 +225,6 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& fil */ void CppCodeParser::doneParsingHeaderFiles() { - qdb_->resolveInheritance(); - QMapIterator<QString, QString> i(sequentialIteratorClasses); while (i.hasNext()) { i.next(); @@ -959,38 +957,12 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, } } else if (command == COMMAND_RELATES) { - /* - Find the node that this node relates to. - */ - Node* n = 0; - if (arg.startsWith(QLatin1Char('<')) || arg.startsWith('"')) { - /* - It should be a header file, I think. - */ - n = qdb_->findNodeByNameAndType(QStringList(arg), Node::Document, Node::NoSubType); - } - else { - /* - If it wasn't a file, it should be either a class or a namespace. - */ - QStringList newPath = arg.split("::"); - n = qdb_->findClassNode(newPath); - if (!n) - n = qdb_->findNamespaceNode(newPath); - } - - if (!n) { - /* - Didn't ind it. Error... - */ + QStringList path = arg.split("::"); + Node* n = qdb_->findRelatesNode(path); + if (!n) doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES)); - } - else { - /* - Found it. This node relates to it. - */ + else node->setRelates(static_cast<InnerNode*>(n)); - } } else if (command == COMMAND_CONTENTSPAGE) { setLink(node, Node::ContentsLink, arg); @@ -1636,11 +1608,7 @@ bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass) if (!matchDataType(&baseClass)) return false; - qdb_->addBaseClass(classe, - access, - baseClass.toPath(), - baseClass.toString(), - classe->parent()); + classe->addUnresolvedBaseClass(access, baseClass.toPath(), baseClass.toString()); return true; } @@ -1735,9 +1703,8 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent) */ QString namespaceName = previousLexeme(); NamespaceNode* ns = 0; - if (parent) { + if (parent) ns = static_cast<NamespaceNode*>(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace)); - } if (!ns) { ns = new NamespaceNode(parent, namespaceName); ns->setAccess(access); diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp index e3b9bdd264..c4f08e45df 100644 --- a/src/tools/qdoc/ditaxmlgenerator.cpp +++ b/src/tools/qdoc/ditaxmlgenerator.cpp @@ -2696,8 +2696,8 @@ void DitaXmlGenerator::generateClassHierarchy(const Node* relative, NodeMap& cla NodeMap newTop; foreach (const RelatedClass &d, child->derivedClasses()) { - if (d.access != Node::Private && !d.node->doc().isEmpty()) - newTop.insert(d.node->name(), d.node); + if (d.node_ && d.access_ != Node::Private && !d.node_->doc().isEmpty()) + newTop.insert(d.node_->name(), d.node_); } if (!newTop.isEmpty()) { stack.push(newTop); @@ -3858,7 +3858,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const *node = relative; } else if (first.endsWith(".html")) { - *node = qdb_->treeRoot()->findChildNodeByNameAndType(first, Node::Document); + *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType); } else { *node = qdb_->resolveTarget(first, relative); @@ -4365,25 +4365,27 @@ void DitaXmlGenerator::writeDerivations(const ClassNode* cn) writeStartTag(DT_cxxClassDerivations); r = cn->baseClasses().constBegin(); while (r != cn->baseClasses().constEnd()) { - writeStartTag(DT_cxxClassDerivation); - writeStartTag(DT_cxxClassDerivationAccessSpecifier); - xmlWriter().writeAttribute("value",(*r).accessString()); - writeEndTag(); // </cxxClassDerivationAccessSpecifier> + ClassNode* bcn = (*r).node_; + if (bcn) { + writeStartTag(DT_cxxClassDerivation); + writeStartTag(DT_cxxClassDerivationAccessSpecifier); + xmlWriter().writeAttribute("value",(*r).accessString()); + writeEndTag(); // </cxxClassDerivationAccessSpecifier> - // not included: <cxxClassDerivationVirtual> + // not included: <cxxClassDerivationVirtual> - writeStartTag(DT_cxxClassBaseClass); - QString attr = fileName((*r).node) + QLatin1Char('#') + (*r).node->guid(); - xmlWriter().writeAttribute("href",attr); - writeCharacters((*r).node->plainFullName()); - writeEndTag(); // </cxxClassBaseClass> + writeStartTag(DT_cxxClassBaseClass); + QString attr = fileName(bcn) + QLatin1Char('#') + bcn->guid(); + xmlWriter().writeAttribute("href",attr); + writeCharacters(bcn->plainFullName()); + writeEndTag(); // </cxxClassBaseClass> - // not included: <ClassBaseStruct> or <cxxClassBaseUnion> + // not included: <ClassBaseStruct> or <cxxClassBaseUnion> - writeEndTag(); // </cxxClassDerivation> - - // not included: <cxxStructDerivation> + writeEndTag(); // </cxxClassDerivation> + // not included: <cxxStructDerivation> + } ++r; } writeEndTag(); // </cxxClassDerivations> @@ -4623,7 +4625,7 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par } i += 2; if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) { - const Node* tn = qdb_->resolveTarget(arg.toString(), parent, n); + const Node* tn = qdb_->resolveTarget(arg.toString(), parent); if (tn) { //Do not generate a link from a C++ function to a QML Basic Type (such as int) if (n->type() == Node::Function && tn->subType() == Node::QmlBasicType) diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp index 9b82e80927..d563546192 100644 --- a/src/tools/qdoc/generator.cpp +++ b/src/tools/qdoc/generator.cpp @@ -189,19 +189,20 @@ void Generator::appendFullNames(Text& text, const NodeList& nodes, const Node* r } } -void Generator::appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes) +void Generator::appendSortedNames(Text& text, const ClassNode* cn, const QList<RelatedClass>& rc) { QList<RelatedClass>::ConstIterator r; QMap<QString,Text> classMap; int index = 0; - r = classes.constBegin(); - while (r != classes.constEnd()) { - if ((*r).node->access() == Node::Public && - (*r).node->status() != Node::Internal - && !(*r).node->doc().isEmpty()) { + r = rc.constBegin(); + while (r != rc.constEnd()) { + ClassNode* rcn = (*r).node_; + if (rcn && rcn->access() == Node::Public && + rcn->status() != Node::Internal && + !rcn->doc().isEmpty()) { Text className; - appendFullName(className, (*r).node, classe); + appendFullName(className, rcn, cn); classMap[className.toString().toLower()] = className; } ++r; @@ -936,18 +937,20 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) r = classe->baseClasses().constBegin(); index = 0; while (r != classe->baseClasses().constEnd()) { - text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, (*r).dataTypeWithTemplateArgs) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - - if ((*r).access == Node::Protected) { - text << " (protected)"; - } - else if ((*r).access == Node::Private) { - text << " (private)"; + if ((*r).node_) { + text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node_)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, (*r).signature_) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + if ((*r).access_ == Node::Protected) { + text << " (protected)"; + } + else if ((*r).access_ == Node::Private) { + text << " (private)"; + } + text << separator(index++, classe->baseClasses().count()); } - text << separator(index++, classe->baseClasses().count()); ++r; } text << Atom::ParaRight; diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp index d46f887518..2057bcd3bc 100644 --- a/src/tools/qdoc/helpprojectwriter.cpp +++ b/src/tools/qdoc/helpprojectwriter.cpp @@ -655,7 +655,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) writer.writeStartElement("section"); const Node* node = qdb_->findDocNodeByTitle(project.indexTitle); if (node == 0) - node = qdb_->findNode(QStringList("index.html")); + node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document, Node::Page); QString indexPath; // Never use a collision node as a landing page if (node && !node->isCollisionNode()) diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 641e59f018..ca52d98596 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -1923,18 +1923,20 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) r = classe->baseClasses().constBegin(); index = 0; while (r != classe->baseClasses().constEnd()) { - text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, (*r).dataTypeWithTemplateArgs) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - - if ((*r).access == Node::Protected) { - text << " (protected)"; - } - else if ((*r).access == Node::Private) { - text << " (private)"; + if ((*r).node_) { + text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node_)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, (*r).signature_) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + if ((*r).access_ == Node::Protected) { + text << " (protected)"; + } + else if ((*r).access_ == Node::Private) { + text << " (private)"; + } + text << separator(index++, classe->baseClasses().count()); } - text << separator(index++, classe->baseClasses().count()); ++r; } text << Atom::ParaRight; @@ -2448,8 +2450,8 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classM NodeMap newTop; foreach (const RelatedClass &d, child->derivedClasses()) { - if (d.access != Node::Private && !d.node->doc().isEmpty()) - newTop.insert(d.node->name(), d.node); + if (d.node_ && (d.access_ != Node::Private && !d.node_->doc().isEmpty())) + newTop.insert(d.node_->name(), d.node_); } if (!newTop.isEmpty()) { stack.push(newTop); @@ -2786,7 +2788,7 @@ void HtmlGenerator::generateQmlItem(const Node *node, marked.remove("<@type>"); marked.remove("</@type>"); } - out() << highlightedCode(marked, relative, false, node); + out() << highlightedCode(marked, relative, false); } void HtmlGenerator::generateOverviewList(const Node *relative) @@ -3099,8 +3101,7 @@ void HtmlGenerator::generateSynopsis(const Node *node, QString HtmlGenerator::highlightedCode(const QString& markedCode, const Node* relative, - bool alignNames, - const Node* self) + bool alignNames) { QString src = markedCode; QString html; @@ -3174,7 +3175,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, bool handled = false; if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) { par1 = QStringRef(); - const Node* n = qdb_->resolveTarget(arg.toString(), relative, self); + const Node* n = qdb_->resolveTarget(arg.toString(), relative); html += QLatin1String("<span class=\"type\">"); if (n && n->subType() == Node::QmlBasicType) { if (relative && relative->subType() == Node::QmlClass) @@ -3751,7 +3752,7 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod node, which must be a direct child of the tree root. */ - *node = qdb_->treeRoot()->findChildNodeByNameAndType(first, Node::Document); + *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType); } else { *node = qdb_->resolveTarget(first, relative); diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index ae16f3c54f..476bd58452 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -200,8 +200,7 @@ private: void generateSectionInheritedList(const Section& section, const Node *relative); QString highlightedCode(const QString& markedCode, const Node* relative, - bool alignNames = false, - const Node* self = 0); + bool alignNames = false); void generateFullName(const Node *apparentNode, const Node *relative, const Node *actualNode = 0); void generateDetailedMember(const Node *node, diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp index 398d188464..a5da6b3edd 100644 --- a/src/tools/qdoc/main.cpp +++ b/src/tools/qdoc/main.cpp @@ -296,7 +296,7 @@ static void processQdocconfFile(const QString &fileName) currentDir = QFileInfo(fileName).path(); Location::initialize(config); config.load(fileName); - + //qDebug() << "\nSTART PROJECT:" << config.getString(CONFIG_PROJECT).toLower(); /* Add the defines to the configuration variables. */ @@ -472,6 +472,8 @@ static void processQdocconfFile(const QString &fileName) codeParser->doneParsingHeaderFiles(); usedParsers.clear(); + qdb->resolveInheritance(); + /* Parse each source text file in the set using the appropriate parser and add it to the big tree. diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index c88ebfc760..6399616725 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -143,6 +143,31 @@ QString Node::fullName(const Node* relative) const } /*! + Try to match this node's type and subtype with one of the + pairs in \a types. If a match is found, return true. If no + match is found, return false. + + \a types is a list of type/subtype pairs, where the first + value in the pair is a Node::Type, and the second value is + a Node::SubType. The second value is used in the match if + this node's type is Node::Document. + */ +bool Node::match(const NodeTypeList& types) const +{ + for (int i=0; i<types.size(); ++i) { + if (type() == types.at(i).first) { + if (type() == Node::Document) { + if (subType() == types.at(i).second) + return true; + } + else + return true; + } + } + return false; +} + +/*! Sets this Node's Doc to \a doc. If \a replace is false and this Node already has a Doc, a warning is reported that the Doc is being overridden, and it reports where the previous @@ -515,7 +540,7 @@ QString Node::extractClassName(const QString &string) const */ QString RelatedClass::accessString() const { - switch (access) { + switch (access_) { case Node::Protected: return "protected"; case Node::Private: @@ -739,15 +764,15 @@ void InnerNode::getMemberClasses(NodeMap& out) sure to also look in the children of its property group nodes. Return the matching node or 0. */ -Node *InnerNode::findChildNodeByName(const QString& name) +Node *InnerNode::findChildNodeByName(const QString& name) const { Node *node = childMap.value(name); - if (node && node->type() != QmlPropertyGroup) + if (node && !node->isQmlPropertyGroup()) return node; - if ((type() == Document) && (subType() == QmlClass)) { + if (isQmlType()) { for (int i=0; i<children_.size(); ++i) { Node* n = children_.at(i); - if (n->type() == QmlPropertyGroup) { + if (n->isQmlPropertyGroup()) { node = static_cast<InnerNode*>(n)->findChildNodeByName(name); if (node) return node; @@ -756,6 +781,9 @@ Node *InnerNode::findChildNodeByName(const QString& name) } return primaryFunctionMap.value(name); } + +/*! + */ void InnerNode::findNodes(const QString& name, QList<Node*>& n) { n.clear(); @@ -763,15 +791,15 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) QList<Node*> nodes = childMap.values(name); /* <sigh> If this node's child map contains no nodes named - name, then if this node is a QML class, seach each of its + name, then if this node is a QML class, search each of its property group nodes for a node named name. If a match is found, append it to the output list and return immediately. */ if (nodes.isEmpty()) { - if ((type() == Document) && (subType() == QmlClass)) { + if (isQmlType()) { for (int i=0; i<children_.size(); ++i) { node = children_.at(i); - if (node->type() == QmlPropertyGroup) { + if (node->isQmlPropertyGroup()) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) { n.append(node); @@ -793,7 +821,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) */ for (int i=0; i<nodes.size(); ++i) { node = nodes.at(i); - if (node->type() != QmlPropertyGroup) + if (!node->isQmlPropertyGroup()) n.append(node); else { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); @@ -819,7 +847,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n) returns \c true. If \a qml is false, only match a node for which node->isQmlNode() returns \c false. */ -Node* InnerNode::findChildNodeByName(const QString& name, bool qml) +Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const { QList<Node*> nodes = childMap.values(name); if (!nodes.isEmpty()) { @@ -829,14 +857,14 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml) if (!node->isQmlNode()) return node; } - else if (node->isQmlNode() && (node->type() != QmlPropertyGroup)) + else if (node->isQmlNode() && !node->isQmlPropertyGroup()) return node; } } - if (qml && (type() == Document) && (subType() == QmlClass)) { + if (qml && isQmlType()) { for (int i=0; i<children_.size(); ++i) { Node* node = children_.at(i); - if (node->type() == QmlPropertyGroup) { + if (node->isQmlPropertyGroup()) { node = static_cast<InnerNode*>(node)->findChildNodeByName(name); if (node) return node; @@ -876,7 +904,7 @@ Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) Find a function node that is a child of this nose, such that the function node has the specified \a name. */ -FunctionNode *InnerNode::findFunctionNode(const QString& name) +FunctionNode *InnerNode::findFunctionNode(const QString& name) const { return static_cast<FunctionNode *>(primaryFunctionMap.value(name)); } @@ -1092,64 +1120,17 @@ bool Node::isWrapper() const } /*! - */ -const Node *InnerNode::findChildNodeByName(const QString& name) const -{ - InnerNode *that = (InnerNode *) this; - return that->findChildNodeByName(name); -} - -/*! - If \a qml is true, only match a node for which node->isQmlNode() - returns \c true. If \a qml is false, only match a node for which - node->isQmlNode() returns \c false. - */ -const Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const -{ - InnerNode*that = (InnerNode*) this; - return that->findChildNodeByName(name, qml); -} - -/*! - Searches this node's children for a child named \a name - with the specified node \a type. - */ -const Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) const -{ - InnerNode *that = (InnerNode *) this; - return that->findChildNodeByNameAndType(name, type); -} - -/*! - Find a function node that is a child of this nose, such - that the function node has the specified \a name. This - function calls the non-const version of itself. - */ -const FunctionNode *InnerNode::findFunctionNode(const QString& name) const -{ - InnerNode *that = (InnerNode *) this; - return that->findFunctionNode(name); -} - -/*! - 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. This function calls the non-const version. - */ -const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const -{ - InnerNode *that = (InnerNode *) this; - return that->findFunctionNode(clone); -} - -/*! + Finds the enum type node that has \a enumValue as one of + its enum values and returns a pointer to it. Returns 0 if + no enum type node is found that has \a enumValue as one + of its values. */ const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const { foreach (const Node *node, enumChildren_) { - const EnumNode *enume = static_cast<const EnumNode *>(node); - if (enume->hasItem(enumValue)) - return enume; + const EnumNode *en = static_cast<const EnumNode *>(node); + if (en->hasItem(enumValue)) + return en; } return 0; } @@ -1381,7 +1362,7 @@ QmlPropertyNode* InnerNode::hasQmlProperty(const QString& n) const if (child->name() == n) return static_cast<QmlPropertyNode*>(child); } - else if (child->type() == Node::QmlPropertyGroup) { + else if (child->isQmlPropertyGroup()) { QmlPropertyNode* t = child->hasQmlProperty(n); if (t) return t; @@ -1480,13 +1461,27 @@ ClassNode::ClassNode(InnerNode *parent, const QString& name) } /*! + Adds the base class \a node to this class's list of base + classes. The base class has the specified \a access. This + is a resolved base class. */ -void ClassNode::addBaseClass(Access access, - ClassNode *node, - const QString &dataTypeWithTemplateArgs) +void ClassNode::addResolvedBaseClass(Access access, ClassNode* node) { - bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs)); - node->derived.append(RelatedClass(access, this)); + bases_.append(RelatedClass(access, node)); + node->derived_.append(RelatedClass(access, this)); +} + +/*! + Add an unresolved base class to this class node's list of + base classes. The unresolved base class will be resolved + before the generate phase of qdoc. In an unresolved base + class, the pointer to the base class node is 0. + */ +void ClassNode::addUnresolvedBaseClass(Access access, + const QStringList& path, + const QString& signature) +{ + bases_.append(RelatedClass(access, path, signature)); } /*! @@ -1498,15 +1493,15 @@ void ClassNode::fixBaseClasses() QSet<ClassNode *> found; // Remove private and duplicate base classes. - while (i < bases.size()) { - ClassNode* bc = bases.at(i).node; - if (bc->access() == Node::Private || found.contains(bc)) { - RelatedClass rc = bases.at(i); - bases.removeAt(i); - ignoredBases.append(rc); + while (i < bases_.size()) { + ClassNode* bc = bases_.at(i).node_; + if (bc && (bc->access() == Node::Private || found.contains(bc))) { + RelatedClass rc = bases_.at(i); + bases_.removeAt(i); + ignoredBases_.append(rc); const QList<RelatedClass> &bb = bc->baseClasses(); for (int j = bb.size() - 1; j >= 0; --j) - bases.insert(i, bb.at(j)); + bases_.insert(i, bb.at(j)); } else { ++i; @@ -1515,13 +1510,13 @@ void ClassNode::fixBaseClasses() } i = 0; - while (i < derived.size()) { - ClassNode* dc = derived.at(i).node; - if (dc->access() == Node::Private) { - derived.removeAt(i); + while (i < derived_.size()) { + ClassNode* dc = derived_.at(i).node_; + if (dc && dc->access() == Node::Private) { + derived_.removeAt(i); const QList<RelatedClass> &dd = dc->derivedClasses(); for (int j = dd.size() - 1; j >= 0; --j) - derived.insert(i, dd.at(j)); + derived_.insert(i, dd.at(j)); } else { ++i; @@ -1530,6 +1525,28 @@ void ClassNode::fixBaseClasses() } /*! + Not sure why this is needed. + */ +void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn) +{ + QList<RelatedClass>::const_iterator bc = baseClasses().constBegin(); + while (bc != baseClasses().constEnd()) { + ClassNode* cn = bc->node_; + if (cn) { + Node* n = cn->findChildNodeByNameAndType(pn->name(), Node::Property); + if (n) { + PropertyNode* baseProperty = static_cast<PropertyNode*>(n); + cn->fixPropertyUsingBaseClasses(baseProperty); + pn->setOverriddenFrom(baseProperty); + } + else + cn->fixPropertyUsingBaseClasses(pn); + } + ++bc; + } +} + +/*! Search the child list to find the property node with the specified \a name. */ @@ -1545,19 +1562,23 @@ PropertyNode* ClassNode::findPropertyNode(const QString& name) const QList<RelatedClass> &bases = baseClasses(); if (!bases.isEmpty()) { for (int i = 0; i < bases.size(); ++i) { - ClassNode* cn = bases[i].node; - pn = cn->findPropertyNode(name); - if (pn) - break; + ClassNode* cn = bases[i].node_; + if (cn) { + pn = cn->findPropertyNode(name); + if (pn) + break; + } } } const QList<RelatedClass>& ignoredBases = ignoredBaseClasses(); if (!ignoredBases.isEmpty()) { for (int i = 0; i < ignoredBases.size(); ++i) { - ClassNode* cn = ignoredBases[i].node; - pn = cn->findPropertyNode(name); - if (pn) - break; + ClassNode* cn = ignoredBases[i].node_; + if (cn) { + pn = cn->findPropertyNode(name); + if (pn) + break; + } } } @@ -1577,13 +1598,13 @@ QmlClassNode* ClassNode::findQmlBaseNode() if (!bases.isEmpty()) { for (int i = 0; i < bases.size(); ++i) { - ClassNode* cn = bases[i].node; + ClassNode* cn = bases[i].node_; if (cn && cn->qmlElement()) { return cn->qmlElement(); } } for (int i = 0; i < bases.size(); ++i) { - ClassNode* cn = bases[i].node; + ClassNode* cn = bases[i].node_; if (cn) { result = cn->findQmlBaseNode(); if (result != 0) { @@ -2354,7 +2375,7 @@ bool QmlPropertyNode::isWritable(QDocDatabase* qdb) if (qcn) { if (qcn->cppClassRequired()) { if (qcn->classNode()) { - PropertyNode* pn = correspondingProperty(qdb); + PropertyNode* pn = findCorrespondingCppProperty(qdb); if (pn) return pn->isWritable(); else @@ -2377,10 +2398,9 @@ bool QmlPropertyNode::isWritable(QDocDatabase* qdb) Returns a pointer this QML property's corresponding C++ property, if it has one. */ -PropertyNode* QmlPropertyNode::correspondingProperty(QDocDatabase* qdb) +PropertyNode* QmlPropertyNode::findCorrespondingCppProperty(QDocDatabase* qdb) { PropertyNode* pn; - Node* n = parent(); while (n && n->subType() != Node::QmlClass) n = n->parent(); @@ -2388,35 +2408,40 @@ PropertyNode* QmlPropertyNode::correspondingProperty(QDocDatabase* qdb) QmlClassNode* qcn = static_cast<QmlClassNode*>(n); ClassNode* cn = qcn->classNode(); if (cn) { + /* + If there is a dot in the property name, first + find the C++ property corresponding to the QML + property group. + */ QStringList dotSplit = name().split(QChar('.')); pn = cn->findPropertyNode(dotSplit[0]); if (pn) { + /* + Now find the C++ property corresponding to + the QML property in the QML property group, + <group>.<property>. + */ if (dotSplit.size() > 1) { - // Find the C++ property corresponding to the QML property in - // the property group, <group>.<property>. - QStringList path(extractClassName(pn->qualifiedDataType())); Node* nn = qdb->findClassNode(path); if (nn) { ClassNode* cn = static_cast<ClassNode*>(nn); PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]); - if (pn2) - return pn2; // Return the property for the QML property. - else - return pn; // Return the property for the QML group. + /* + If found, return the C++ property + corresponding to the QML property. + Otherwise, return the C++ property + corresponding to the QML property + group. + */ + return (pn2 ? pn2 : pn); } } else return pn; } - else { - pn = cn->findPropertyNode(dotSplit[0]); - if (pn) - return pn; - } } } - return 0; } @@ -2520,7 +2545,7 @@ const Node* NameCollisionNode::applyModuleName(const Node* origin) const const NodeList& cn = childNodes(); NodeList::ConstIterator i = cn.constBegin(); while (i != cn.constEnd()) { - if ((*i)->type() == Node::Document && (*i)->subType() == Node::QmlClass) { + if ((*i)->isQmlType()) { if (origin->qmlModuleName() == (*i)->qmlModuleName()) return (*i); } @@ -2531,6 +2556,49 @@ const Node* NameCollisionNode::applyModuleName(const Node* origin) const } /*! + First, find all the colliding nodes that have the correct + type \a t and subtype \a st. If there is only one node + having the correct type and subtype, return that one. + If there is more than one node having the correct type + and subtype, then, in that subset, if there is only one + non-index node, return that one. If there are multiple + non-index nodes, return this collision node because we + can't disambiguate. Otherwise, if there are multiple + nodes having the correct type and subtype, return this + collision node because, again, we can't disambiguate. + But if there are no nodes at all that have the correct + type and subtype, return 0. + */ +Node* NameCollisionNode::disambiguate(Type t, SubType st) +{ + NodeList nl; + const NodeList& cn = childNodes(); + NodeList::ConstIterator i = cn.constBegin(); + while (i != cn.constEnd()) { + if ((*i)->type() == t) { + if ((st == NoSubType) || ((*i)->subType() == st)) + nl.append((*i)); + } + ++i; + } + Node* n = 0; + if (!nl.isEmpty()) { + i = nl.constBegin(); + if (nl.size() == 1) + return (*i); + while (i != nl.constEnd()) { + if (!(*i)->isIndexNode()) { + if (n) + return this; + n = (*i); + } + ++i; + } + } + return n; +} + +/*! Construct the full document name for this node and return it. */ QString Node::fullDocumentName() const @@ -2539,7 +2607,7 @@ QString Node::fullDocumentName() const const Node* n = this; do { - if (!n->name().isEmpty() && n->type() != Node::QmlPropertyGroup) + if (!n->name().isEmpty() && !n->isQmlPropertyGroup()) pieces.insert(0, n->name()); if (n->type() == Node::Document) { diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h index 236b495bd0..ea21e9dcd9 100644 --- a/src/tools/qdoc/node.h +++ b/src/tools/qdoc/node.h @@ -68,6 +68,9 @@ typedef QMap<QString, Node*> NodeMap; typedef QMultiMap<QString, Node*> NodeMultiMap; typedef QMultiMap<QString, const ExampleNode*> ExampleNodeMap; +typedef QPair<int, int> NodeTypePair; +typedef QList<NodeTypePair> NodeTypeList; + class Node { Q_DECLARE_TR_FUNCTIONS(QDoc::Node) @@ -228,10 +231,12 @@ public: virtual bool isInternal() const; virtual void setDataType(const QString& ) { } virtual void setReadOnly(bool ) { } + virtual Node* disambiguate(Type , SubType ) { return this; } bool isIndexNode() const { return indexNodeFlag_; } bool wasSeen() const { return seen_; } Type type() const { return nodeType_; } virtual SubType subType() const { return NoSubType; } + bool match(const NodeTypeList& types) const; InnerNode* parent() const { return parent_; } InnerNode* relates() const { return relatesTo_; } const QString& name() const { return name_; } @@ -334,11 +339,11 @@ class InnerNode : public Node public: virtual ~InnerNode(); - Node* findChildNodeByName(const QString& name); - Node* findChildNodeByName(const QString& name, bool qml); + Node* findChildNodeByName(const QString& name) const; + Node* findChildNodeByName(const QString& name, bool qml) const; Node* findChildNodeByNameAndType(const QString& name, Type type); void findNodes(const QString& name, QList<Node*>& n); - FunctionNode* findFunctionNode(const QString& name); + FunctionNode* findFunctionNode(const QString& name) const; FunctionNode* findFunctionNode(const FunctionNode* clone); void addInclude(const QString &include); void setIncludes(const QStringList &includes); @@ -351,11 +356,6 @@ public: virtual bool isInnerNode() const { return true; } virtual bool isLeaf() const { return false; } - const Node* findChildNodeByName(const QString& name) const; - const Node* findChildNodeByName(const QString& name, bool qml) const; - const Node* findChildNodeByNameAndType(const QString& name, Type type) const; - const FunctionNode* findFunctionNode(const QString& name) const; - const FunctionNode* findFunctionNode(const FunctionNode* clone) const; const EnumNode* findEnumNodeForValue(const QString &enumValue) const; const NodeList & childNodes() const { return children_; } const NodeList & relatedNodes() const { return related_; } @@ -437,17 +437,18 @@ class ClassNode; struct RelatedClass { RelatedClass() { } - RelatedClass(Node::Access access0, - ClassNode* node0, - const QString& dataTypeWithTemplateArgs0 = QString()) - : access(access0), - node(node0), - dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0) { } + // constructor for resolved base class + RelatedClass(Node::Access access, ClassNode* node) + : access_(access), node_(node) { } + // constructor for unresolved base class + RelatedClass(Node::Access access, const QStringList& path, const QString& signature) + : access_(access), node_(0), path_(path), signature_(signature) { } QString accessString() const; - Node::Access access; - ClassNode* node; - QString dataTypeWithTemplateArgs; + Node::Access access_; + ClassNode* node_; + QStringList path_; + QString signature_; }; class PropertyNode; @@ -463,14 +464,18 @@ public: virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; } virtual void setWrapper() { wrapper_ = true; } - void addBaseClass(Access access, - ClassNode* node, - const QString &dataTypeWithTemplateArgs = QString()); + void addResolvedBaseClass(Access access, ClassNode* node); + void addUnresolvedBaseClass(Access access, const QStringList& path, const QString& signature); void fixBaseClasses(); + void fixPropertyUsingBaseClasses(PropertyNode* pn); + + QList<RelatedClass>& baseClasses() { return bases_; } + QList<RelatedClass>& derivedClasses() { return derived_; } + QList<RelatedClass>& ignoredBaseClasses() { return ignoredBases_; } - const QList<RelatedClass> &baseClasses() const { return bases; } - const QList<RelatedClass> &derivedClasses() const { return derived; } - const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases; } + const QList<RelatedClass> &baseClasses() const { return bases_; } + const QList<RelatedClass> &derivedClasses() const { return derived_; } + const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases_; } QString serviceName() const { return sname; } void setServiceName(const QString& value) { sname = value; } @@ -482,9 +487,9 @@ public: QmlClassNode* findQmlBaseNode(); private: - QList<RelatedClass> bases; - QList<RelatedClass> derived; - QList<RelatedClass> ignoredBases; + QList<RelatedClass> bases_; + QList<RelatedClass> derived_; + QList<RelatedClass> ignoredBases_; bool abstract_; bool wrapper_; QString sname; @@ -558,6 +563,7 @@ public: virtual bool isQmlNode() const; virtual bool isCollisionNode() const { return true; } virtual const Node* applyModuleName(const Node* origin) const; + virtual Node* disambiguate(Type t, SubType st); InnerNode* findAny(Node::Type t, Node::SubType st); void addCollision(InnerNode* child); const QMap<QString,QString>& linkTargets() const { return targets; } @@ -723,10 +729,11 @@ public: virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); } virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); } - PropertyNode* correspondingProperty(QDocDatabase* qdb); - const QString& element() const { return static_cast<QmlPropertyGroupNode*>(parent())->element(); } + private: + PropertyNode* findCorrespondingCppProperty(QDocDatabase* qdb); + private: QString type_; FlagValue stored_; diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index 1011a3ac97..bbcb92c30d 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -751,9 +751,7 @@ void QDocDatabase::resolveIssues() { Searches the \a database for a node named \a target and returns a pointer to it if found. */ -const Node* QDocDatabase::resolveTarget(const QString& target, - const Node* relative, - const Node* self) +const Node* QDocDatabase::resolveTarget(const QString& target, const Node* relative) { const Node* node = 0; if (target.endsWith("()")) { @@ -776,7 +774,7 @@ const Node* QDocDatabase::resolveTarget(const QString& target, else { QStringList path = target.split("::"); int flags = SearchBaseClasses | SearchEnumValues | NonFunction; - node = tree_->findNode(path, relative, flags, self); + node = tree_->findNode(path, relative, flags); } return node; } @@ -790,8 +788,9 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r const Node* node = 0; if (target.isEmpty()) node = relative; - else if (target.endsWith(".html")) - node = tree_->root()->findChildNodeByNameAndType(target, Node::Document); + else if (target.endsWith(".html")) { + node = findNodeByNameAndType(QStringList(target), Node::Document, Node::NoSubType); + } else { node = resolveTarget(target, relative); if (!node) diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h index 4decba5f79..4e50396817 100644 --- a/src/tools/qdoc/qdocdatabase.h +++ b/src/tools/qdoc/qdocdatabase.h @@ -134,10 +134,6 @@ class QDocDatabase const NodeMap& getQmlTypeMap(const QString& key) const; const NodeMultiMap& getSinceMap(const QString& key) const; - const Node* resolveTarget(const QString& target, const Node* relative, const Node* self=0); - const Node* findNodeForTarget(const QString& target, const Node* relative); - void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority); - /* convenience functions Many of these will be either eliminated or replaced. */ @@ -150,35 +146,44 @@ class QDocDatabase void fixInheritance() { tree_->fixInheritance(); } void resolveProperties() { tree_->resolveProperties(); } - const Node* findNode(const QStringList& path) { return tree_->findNode(path); } - ClassNode* findClassNode(const QStringList& path) { return tree_->findClassNode(path); } - NamespaceNode* findNamespaceNode(const QStringList& path) { return tree_->findNamespaceNode(path); } - - NameCollisionNode* findCollisionNode(const QString& name) const { - return tree_->findCollisionNode(name); - } - - const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const; - const Node *findUnambiguousTarget(const QString &target, QString& ref, const Node* relative); + /******************************************************************* + The functions declared below don't search in the tree(s). + ********************************************************************/ QString findTarget(const QString &target, const Node *node) const; void resolveTargets(InnerNode* root); + void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority); + /*******************************************************************/ + /******************************************************************* + The functions declared below are called for the current tree only. + ********************************************************************/ FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) { return tree_->findFunctionNode(parentPath, clone); } + FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone); + Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype); + NameCollisionNode* findCollisionNode(const QString& name) const { + return tree_->findCollisionNode(name); + } + /*******************************************************************/ + + /******************************************************************* + The functions declared below are called for all trees. + ********************************************************************/ + ClassNode* findClassNode(const QStringList& path) { return tree_->findClassNode(path); } + InnerNode* findRelatesNode(const QStringList& path) { return tree_->findRelatesNode(path); } + const Node* resolveTarget(const QString& target, const Node* relative); + const Node* findNodeForTarget(const QString& target, const Node* relative); + const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const; + const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative); Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){ return tree_->findNodeByNameAndType(path, type, subtype, 0); } NameCollisionNode* checkForCollision(const QString& name) const { return tree_->checkForCollision(name); } - void addBaseClass(ClassNode* subclass, - Node::Access access, - const QStringList& basePath, - const QString& dataTypeWithTemplateArgs, - InnerNode* parent) { - tree_->addBaseClass(subclass, access, basePath, dataTypeWithTemplateArgs, parent); - } + /*******************************************************************/ + void addPropertyFunction(PropertyNode* property, const QString& funcName, PropertyNode::FunctionRole funcRole) { @@ -198,8 +203,6 @@ class QDocDatabase void clearOpenNamespaces() { openNamespaces_.clear(); } void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); } - FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone); - Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype); void setShowInternal(bool value) { showInternal_ = value; } /* debugging functions */ @@ -210,10 +213,6 @@ class QDocDatabase friend class QDocIndexFiles; friend class QDocTagFiles; - const Node* findNode(const QStringList& path, const Node* relative, int findFlags) { - return tree_->findNode(path, relative, findFlags); - } - private: QDocDatabase(); QDocDatabase(QDocDatabase const& ) { }; // copy constructor is private diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 47e302dad6..55e580427f 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -109,8 +109,10 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles) foreach (const QString& indexFile, indexFiles) { QString msg = "Loading index file: " + indexFile; Location::logToStdErr(msg); + //qDebug() << "READING INDEX:" << indexFile; readIndexFile(indexFile); } + //qDebug() << "DONE READING INDEX FILES"; } /*! @@ -189,9 +191,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, } else if (element.nodeName() == "class") { node = new ClassNode(parent, name); - basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node), - element.attribute("bases"))); - + if (element.hasAttribute("bases")) { + QString bases = element.attribute("bases"); + if (!bases.isEmpty()) + basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node), bases)); + } if (!indexUrl.isEmpty()) location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html"); else if (!indexUrl.isNull()) @@ -383,31 +387,33 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, } else if (element.nodeName() == "function") { FunctionNode::Virtualness virt; - if (element.attribute("virtual") == "non") + QString t = element.attribute("virtual"); + if (t == "non") virt = FunctionNode::NonVirtual; - else if (element.attribute("virtual") == "impure") + else if (t == "impure") virt = FunctionNode::ImpureVirtual; - else if (element.attribute("virtual") == "pure") + else if (t == "pure") virt = FunctionNode::PureVirtual; else return; + t = element.attribute("meta"); FunctionNode::Metaness meta; - if (element.attribute("meta") == "plain") + if (t == "plain") meta = FunctionNode::Plain; - else if (element.attribute("meta") == "signal") + else if (t == "signal") meta = FunctionNode::Signal; - else if (element.attribute("meta") == "slot") + else if (t == "slot") meta = FunctionNode::Slot; - else if (element.attribute("meta") == "constructor") + else if (t == "constructor") meta = FunctionNode::Ctor; - else if (element.attribute("meta") == "destructor") + else if (t == "destructor") meta = FunctionNode::Dtor; - else if (element.attribute("meta") == "macro") + else if (t == "macro") meta = FunctionNode::MacroWithParams; - else if (element.attribute("meta") == "macrowithparams") + else if (t == "macrowithparams") meta = FunctionNode::MacroWithParams; - else if (element.attribute("meta") == "macrowithoutparams") + else if (t == "macrowithoutparams") meta = FunctionNode::MacroWithoutParams; else return; @@ -426,6 +432,10 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QPair<FunctionNode*,QString>(functionNode, element.attribute("relates"))); } + /* + Note: The "signature" attribute was written to the + index file, but it is not read back in. Is that ok? + */ QDomElement child = element.firstChildElement("parameter"); while (!child.isNull()) { @@ -534,10 +544,12 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, if (dn) { dn->addMember(node); } +#if 0 else { qDebug() << "NODE:" << node->name() << "GROUPS:" << groupNames; qDebug() << "DID NOT FIND GROUP:" << dn->name() << "for:" << node->name(); } +#endif } } @@ -584,22 +596,37 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, } /*! + This function tries to resolve class inheritance immediately + after the index file is read. It is not always possible to + resolve a class inheritance at this point, because the base + class might be in an index file that hasn't been read yet, or + it might be in one of the header files that will be read for + the current module. These cases will be resolved after all + the index files and header and source files have been read, + just prior to beginning the generate phase for the current + module. + + I don't think this is completely correct because it always + sets the access to public. */ void QDocIndexFiles::resolveIndex() { QPair<ClassNode*,QString> pair; foreach (pair, basesList_) { foreach (const QString& base, pair.second.split(QLatin1Char(','))) { - Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(base, Node::Class); - if (n) { - pair.first->addBaseClass(Node::Public, static_cast<ClassNode*>(n)); - } + QStringList basePath = base.split(QString("::")); + Node* n = qdb_->findNodeByNameAndType(basePath, Node::Class, Node::NoSubType); + if (n) + pair.first->addResolvedBaseClass(Node::Public, static_cast<ClassNode*>(n)); + else + pair.first->addUnresolvedBaseClass(Node::Public, basePath, QString()); } } QPair<FunctionNode*,QString> relatedPair; foreach (relatedPair, relatedList_) { - Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(relatedPair.second, Node::Class); + QStringList path = relatedPair.second.split("::"); + Node* n = qdb_->findRelatesNode(path); if (n) relatedPair.first->setRelates(static_cast<ClassNode*>(n)); } @@ -856,10 +883,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QList<RelatedClass> bases = classNode->baseClasses(); QSet<QString> baseStrings; foreach (const RelatedClass& related, bases) { - ClassNode* baseClassNode = related.node; - baseStrings.insert(baseClassNode->name()); + ClassNode* n = related.node_; + if (n) + baseStrings.insert(n->fullName()); } - writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(",")); + if (!baseStrings.isEmpty()) + writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(",")); if (!node->moduleName().isEmpty()) writer.writeAttribute("module", node->moduleName()); writeMembersAttribute(writer, classNode, Node::Document, Node::Group, "groups"); @@ -995,8 +1024,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("overload", functionNode->isOverload()?"true":"false"); if (functionNode->isOverload()) writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber())); - if (functionNode->relates()) + if (functionNode->relates()) { writer.writeAttribute("relates", functionNode->relates()->name()); + } const PropertyNode* propertyNode = functionNode->associatedProperty(); if (propertyNode) writer.writeAttribute("associated-property", propertyNode->name()); @@ -1127,36 +1157,11 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, } else if (node->type() == Node::Function) { const FunctionNode* functionNode = static_cast<const FunctionNode*>(node); - // Write a signature attribute for convenience. - QStringList signatureList; - QStringList resolvedParameters; - foreach (const Parameter& parameter, functionNode->parameters()) { - QString leftType = parameter.leftType(); - const Node* leftNode = qdb_->findNode(parameter.leftType().split("::"), - 0, - SearchBaseClasses|NonFunction); - if (!leftNode || leftNode->type() != Node::Typedef) { - leftNode = qdb_->findNode(parameter.leftType().split("::"), - node->parent(), - SearchBaseClasses|NonFunction); - } - if (leftNode && leftNode->type() == Node::Typedef) { - if (leftNode->type() == Node::Typedef) { - const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode); - if (typedefNode->associatedEnum()) { - leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() + - QLatin1Char('>'); - } - } - else - leftType = leftNode->fullDocumentName(); - } - resolvedParameters.append(leftType); - signatureList.append(leftType + QLatin1Char(' ') + parameter.name()); - } - - QString signature = functionNode->name() + QLatin1Char('(') + signatureList.join(", ") + - QLatin1Char(')'); + /* + Note: The "signature" attribute is written to the + index file, but it is not read back in. Is that ok? + */ + QString signature = functionNode->signature(); if (functionNode->isConst()) signature += " const"; writer.writeAttribute("signature", signature); @@ -1164,7 +1169,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, for (int i = 0; i < functionNode->parameters().size(); ++i) { Parameter parameter = functionNode->parameters()[i]; writer.writeStartElement("parameter"); - writer.writeAttribute("left", resolvedParameters[i]); + writer.writeAttribute("left", parameter.leftType()); writer.writeAttribute("right", parameter.rightType()); writer.writeAttribute("name", parameter.name()); writer.writeAttribute("default", parameter.defaultValue()); diff --git a/src/tools/qdoc/qdoctagfiles.cpp b/src/tools/qdoc/qdoctagfiles.cpp index a0054ea229..23c10c01b5 100644 --- a/src/tools/qdoc/qdoctagfiles.cpp +++ b/src/tools/qdoc/qdoctagfiles.cpp @@ -162,8 +162,9 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne const ClassNode* classNode = static_cast<const ClassNode*>(node); QList<RelatedClass> bases = classNode->baseClasses(); foreach (const RelatedClass& related, bases) { - ClassNode* baseClassNode = related.node; - writer.writeTextElement("base", baseClassNode->name()); + ClassNode* n = related.node_; + if (n) + writer.writeTextElement("base", n->name()); } // Recurse to write all members. @@ -294,31 +295,8 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#')); writer.writeTextElement("anchorfile", pieces[0]); writer.writeTextElement("anchor", pieces[1]); - - // Write a signature attribute for convenience. - QStringList signatureList; - - foreach (const Parameter& parameter, functionNode->parameters()) { - QString leftType = parameter.leftType(); - const Node* leftNode = qdb_->findNode(parameter.leftType().split("::"), - 0, - SearchBaseClasses|NonFunction); - if (!leftNode || leftNode->type() != Node::Typedef) { - leftNode = qdb_->findNode(parameter.leftType().split("::"), - node->parent(), - SearchBaseClasses|NonFunction); - } - if (leftNode && leftNode->type() == Node::Typedef) { - const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode); - if (typedefNode->associatedEnum()) { - leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() + - QLatin1Char('>'); - } - } - signatureList.append(leftType + QLatin1Char(' ') + parameter.name()); - } - - QString signature = QLatin1Char('(')+signatureList.join(", ")+QLatin1Char(')'); + QString signature = functionNode->signature(); + signature = signature.mid(signature.indexOf(QChar('('))).trimmed(); if (functionNode->isConst()) signature += " const"; if (functionNode->virtualness() == FunctionNode::PureVirtual) diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index 113220059c..98ac64246e 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 diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h index 26dd982abd..e1a08dd471 100644 --- a/src/tools/qdoc/tree.h +++ b/src/tools/qdoc/tree.h @@ -61,73 +61,54 @@ class Tree typedef QMap<PropertyNode::FunctionRole, QString> RoleMap; typedef QMap<PropertyNode*, RoleMap> PropertyMap; - struct InheritanceBound - { - Node::Access access; - QStringList basePath; - QString dataTypeWithTemplateArgs; - InnerNode* parent; - - InheritanceBound() : access(Node::Public) { } - InheritanceBound(Node::Access access0, - const QStringList& basePath0, - const QString& dataTypeWithTemplateArgs0, - InnerNode* parent) - : access(access0), basePath(basePath0), - dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0), - parent(parent) { } - }; - Tree(QDocDatabase* qdb); ~Tree(); - EnumNode* findEnumNode(const QStringList& path, Node* start = 0); + /* API members */ ClassNode* findClassNode(const QStringList& path, Node* start = 0) const; - QmlClassNode* findQmlTypeNode(const QStringList& path); NamespaceNode* findNamespaceNode(const QStringList& path) const; + FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone); - Node* findNodeByNameAndType(const QStringList& path, - Node::Type type, - Node::SubType subtype, - Node* start, - bool acceptCollision = false); - + /* internal members */ Node* findNodeRecursive(const QStringList& path, int pathIndex, Node* start, Node::Type type, Node::SubType subtype, bool acceptCollision = false) const; + Node* findNodeRecursive(const QStringList& path, + int pathIndex, + Node* start, + const NodeTypeList& types) const; const Node* findNode(const QStringList &path, const Node* relative = 0, - int findFlags = 0, - const Node* self=0) const; + int findFlags = 0) const; const Node* findNode(const QStringList& path, const Node* start, int findFlags, - const Node* self, bool qml) const; +// --------------------------------------------------------------------- + QmlClassNode* findQmlTypeNode(const QStringList& path); + + Node* findNodeByNameAndType(const QStringList& path, + Node::Type type, + Node::SubType subtype, + Node* start, + bool acceptCollision = false); + + + InnerNode* findRelatesNode(const QStringList& path); NameCollisionNode* checkForCollision(const QString& name) const; NameCollisionNode* findCollisionNode(const QString& name) const; - FunctionNode *findFunctionNode(const QStringList &path, - Node *relative = 0, - int findFlags = 0); - FunctionNode *findFunctionNode(const QStringList &parentPath, - const FunctionNode *clone, - Node *relative = 0, - int findFlags = 0); - void addBaseClass(ClassNode *subclass, - Node::Access access, - const QStringList &basePath, - const QString &dataTypeWithTemplateArgs, - InnerNode *parent); + void addPropertyFunction(PropertyNode *property, const QString &funcName, PropertyNode::FunctionRole funcRole); - void resolveInheritance(NamespaceNode *rootNode = 0); + void resolveInheritance(InnerNode* n = 0); + void resolveInheritanceHelper(int pass, ClassNode* cn); void resolveProperties(); void resolveCppToQmlLinks(); void fixInheritance(NamespaceNode *rootNode = 0); @@ -136,22 +117,18 @@ class Tree const FunctionNode *findFunctionNode(const QStringList &path, const Node *relative = 0, int findFlags = 0) const; - const FunctionNode *findFunctionNode(const QStringList &parentPath, - const FunctionNode *clone, - const Node *relative = 0, - int findFlags = 0) const; const NamespaceNode *root() const { return &root_; } - void resolveInheritance(int pass, ClassNode *classe); FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe, FunctionNode *clone); - void fixPropertyUsingBaseClasses(ClassNode *classe, PropertyNode *property); NodeList allBaseClasses(const ClassNode *classe) const; + public: + static bool debug_; + private: QDocDatabase* qdb_; NamespaceNode root_; - QMap<ClassNode* , QList<InheritanceBound> > unresolvedInheritanceMap; PropertyMap unresolvedPropertyMap; }; |