diff options
Diffstat (limited to 'src/tools/qdoc/qdocindexfiles.cpp')
-rw-r--r-- | src/tools/qdoc/qdocindexfiles.cpp | 394 |
1 files changed, 235 insertions, 159 deletions
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 47e302dad6..be8184b596 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -77,6 +77,7 @@ QDocIndexFiles::QDocIndexFiles() QDocIndexFiles::~QDocIndexFiles() { qdb_ = 0; + gen_ = 0; } /*! @@ -109,6 +110,7 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles) foreach (const QString& indexFile, indexFiles) { QString msg = "Loading index file: " + indexFile; Location::logToStdErr(msg); + //qDebug() << " LOAD INDEX FILE:" << indexFile; readIndexFile(indexFile); } } @@ -144,12 +146,13 @@ void QDocIndexFiles::readIndexFile(const QString& path) basesList_.clear(); relatedList_.clear(); + NamespaceNode* root = qdb_->newIndexTree(project_); + // Scan all elements in the XML file, constructing a map that contains // base classes for each class found. - QDomElement child = indexElement.firstChildElement(); while (!child.isNull()) { - readIndexSection(child, qdb_->treeRoot(), indexUrl); + readIndexSection(child, root, indexUrl); child = child.nextSiblingElement(); } @@ -189,9 +192,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()) @@ -213,8 +218,9 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, abstract = true; qcn->setAbstract(abstract); QString qmlFullBaseName = element.attribute("qml-base-type"); - if (!qmlFullBaseName.isEmpty()) + if (!qmlFullBaseName.isEmpty()) { qcn->setQmlBaseName(qmlFullBaseName); + } if (element.hasAttribute("location")) name = element.attribute("location", QString()); if (!indexUrl.isEmpty()) @@ -277,6 +283,31 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, FunctionNode* fn = new FunctionNode(t, parent, name, attached); node = fn; } + else if (element.nodeName() == "group") { + GroupNode* gn = qdb_->addGroup(name); + gn->setTitle(element.attribute("title")); + gn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + gn->markSeen(); + node = gn; + } + else if (element.nodeName() == "module") { + ModuleNode* mn = qdb_->addModule(name); + mn->setTitle(element.attribute("title")); + mn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + mn->markSeen(); + node = mn; + } + else if (element.nodeName() == "qmlmodule") { + QString t = element.attribute("qml-module-name") + " " + element.attribute("qml-module-version"); + QmlModuleNode* qmn = qdb_->addQmlModule(t); + qmn->setTitle(element.attribute("title")); + qmn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + qmn->markSeen(); + node = qmn; + } else if (element.nodeName() == "page") { Node::SubType subtype; Node::PageType ptype = Node::NoPageType; @@ -293,18 +324,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, subtype = Node::File; ptype = Node::NoPageType; } - else if (attr == "group") { - subtype = Node::Group; - ptype = Node::OverviewPage; - } - else if (attr == "module") { - subtype = Node::Module; - ptype = Node::OverviewPage; - } - else if (attr == "qmlmodule") { - subtype = Node::QmlModule; - ptype = Node::OverviewPage; - } else if (attr == "page") { subtype = Node::Page; ptype = Node::ArticlePage; @@ -324,14 +343,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, else return; - DocNode* docNode = 0; - if (subtype == Node::QmlModule) { - QString t = element.attribute("qml-module-name") + " " + - element.attribute("qml-module-version"); - docNode = qdb_->addQmlModule(t); - } - else - docNode = new DocNode(parent, name, subtype, ptype); + DocNode* docNode = new DocNode(parent, name, subtype, ptype); docNode->setTitle(element.attribute("title")); if (element.hasAttribute("location")) @@ -383,31 +395,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 +440,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()) { @@ -513,7 +531,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QString moduleName = element.attribute("module"); if (!moduleName.isEmpty()) - node->setModuleName(moduleName); + qdb_->addToModule(moduleName, node); if (!href.isEmpty()) { if (node->isExternalPage()) node->setUrl(href); @@ -529,15 +547,8 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QString groupsAttr = element.attribute("groups"); if (!groupsAttr.isEmpty()) { QStringList groupNames = groupsAttr.split(","); - for (int i=0; i<groupNames.size(); ++i) { - DocNode* dn = qdb_->findGroup(groupNames[i]); - if (dn) { - dn->addMember(node); - } - else { - qDebug() << "NODE:" << node->name() << "GROUPS:" << groupNames; - qDebug() << "DID NOT FIND GROUP:" << dn->name() << "for:" << node->name(); - } + foreach (QString name, groupNames) { + qdb_->addToGroup(name, node); } } @@ -584,57 +595,44 @@ 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)); } -} - -/*! - Normally this is used for writing the \e groups attribute, - but it can be used for writing any attribute with a list - value that comes from some subset of the members of \a n. - - \note The members of \a n are \e not the children of \a n. - The names we want to include are the names of the members - of \a n that have node type \a t and node subtype \a st. - The attribute name is \a attr. The names are joined with - the space character and written with \a writer. - */ -void QDocIndexFiles::writeMembersAttribute(QXmlStreamWriter& writer, - const InnerNode* n, - Node::Type t, - Node::SubType st, - const QString& attr) -{ - const NodeList& members = n->members(); - if (!members.isEmpty()) { - QStringList names; - NodeList::ConstIterator i = members.constBegin(); - while (i != members.constEnd()) { - if ((*i)->type() == t && (*i)->subType() == st) - names.append((*i)->name()); - ++i; - } - if (!names.isEmpty()) - writer.writeAttribute(attr, names.join(",")); - } + // No longer needed. + basesList_.clear(); + relatedList_.clear(); } /*! @@ -675,6 +673,15 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, else if (node->subType() == Node::QmlBasicType) nodeName = "qmlbasictype"; break; + case Node::Group: + nodeName = "group"; + break; + case Node::Module: + nodeName = "module"; + break; + case Node::QmlModule: + nodeName = "qmlmodule"; + break; case Node::Enum: nodeName = "enum"; break; @@ -741,14 +748,17 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QString objName = node->name(); // Special case: only the root node should have an empty name. - if (objName.isEmpty() && node != qdb_->treeRoot()) + if (objName.isEmpty() && node != qdb_->primaryTreeRoot()) return false; writer.writeStartElement(nodeName); QXmlStreamAttributes attributes; - if (node->type() != Node::Document) { + if ((node->type() != Node::Document) && + (node->type() != Node::Group) && + (node->type() != Node::Module) && + (node->type() != Node::QmlModule)) { QString threadSafety; switch (node->threadSafeness()) { case Node::NonReentrant: @@ -832,10 +842,15 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (!href.isEmpty()) writer.writeAttribute("href", href); - writer.writeAttribute("access", access); writer.writeAttribute("status", status); - if (node->isAbstract()) - writer.writeAttribute("abstract", "true"); + if ((node->type() != Node::Document) && + (node->type() != Node::Group) && + (node->type() != Node::Module) && + (node->type() != Node::QmlModule)) { + writer.writeAttribute("access", access); + if (node->isAbstract()) + writer.writeAttribute("abstract", "true"); + } if (!node->location().fileName().isEmpty()) writer.writeAttribute("location", node->location().fileName()); if (!node->location().filePath().isEmpty()) { @@ -847,7 +862,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("since", node->since()); } - QString brief = node->doc().briefText().toString(); + QString brief = node->doc().trimmedBriefText(node->name()).toString(); switch (node->type()) { case Node::Class: { @@ -856,13 +871,16 @@ 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"); + if (!classNode->groupNames().isEmpty()) + writer.writeAttribute("groups", classNode->groupNames().join(",")); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -872,7 +890,8 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, const NamespaceNode* namespaceNode = static_cast<const NamespaceNode*>(node); if (!namespaceNode->moduleName().isEmpty()) writer.writeAttribute("module", namespaceNode->moduleName()); - writeMembersAttribute(writer, namespaceNode, Node::Document, Node::Group, "groups"); + if (!namespaceNode->groupNames().isEmpty()) + writer.writeAttribute("groups", namespaceNode->groupNames().join(",")); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -880,8 +899,8 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::Document: { /* - Document nodes (such as manual pages) contain subtypes, - titles and other attributes. + Document nodes (such as manual pages) have a subtype, + a title, and other attributes. */ bool writeModuleName = false; const DocNode* docNode = static_cast<const DocNode*>(node); @@ -897,26 +916,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::File: writer.writeAttribute("subtype", "file"); break; - case Node::Group: - { - writer.writeAttribute("subtype", "group"); - writer.writeAttribute("seen", docNode->wasSeen() ? "true" : "false"); - // Groups contain information about their group members. - const NodeList& members = docNode->members(); - QStringList names; - foreach (const Node* member, members) { - names.append(member->name()); - } - writer.writeAttribute("members", names.join(",")); - writeModuleName = true; - } - break; - case Node::Module: - writer.writeAttribute("subtype", "module"); - break; - case Node::QmlModule: - writer.writeAttribute("subtype", "qmlmodule"); - break; case Node::Page: writer.writeAttribute("subtype", "page"); writeModuleName = true; @@ -939,7 +938,82 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (!node->moduleName().isEmpty() && writeModuleName) { writer.writeAttribute("module", node->moduleName()); } - writeMembersAttribute(writer, docNode, Node::Document, Node::Group, "groups"); + if (!docNode->groupNames().isEmpty()) + writer.writeAttribute("groups", docNode->groupNames().join(",")); + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; + case Node::Group: + { + const GroupNode* gn = static_cast<const GroupNode*>(node); + writer.writeAttribute("seen", gn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", gn->title()); + if (!gn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", gn->subTitle()); + if (!gn->moduleName().isEmpty()) + writer.writeAttribute("module", gn->moduleName()); + if (!gn->groupNames().isEmpty()) + writer.writeAttribute("groups", gn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!gn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, gn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; + case Node::Module: + { + const ModuleNode* mn = static_cast<const ModuleNode*>(node); + writer.writeAttribute("seen", mn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", mn->title()); + if (!mn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", mn->subTitle()); + if (!mn->moduleName().isEmpty()) + writer.writeAttribute("module", mn->moduleName()); + if (!mn->groupNames().isEmpty()) + writer.writeAttribute("groups", mn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!mn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, mn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + case Node::QmlModule: + { + const QmlModuleNode* qmn = static_cast<const QmlModuleNode*>(node); + writer.writeAttribute("seen", qmn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", qmn->title()); + if (!qmn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", qmn->subTitle()); + if (!qmn->moduleName().isEmpty()) + writer.writeAttribute("module", qmn->moduleName()); + if (!qmn->groupNames().isEmpty()) + writer.writeAttribute("groups", qmn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!qmn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, qmn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -995,8 +1069,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()); @@ -1010,7 +1085,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); writer.writeAttribute("type", qpn->dataType()); writer.writeAttribute("attached", qpn->isAttached() ? "true" : "false"); - writer.writeAttribute("writable", qpn->isWritable(qdb_) ? "true" : "false"); + writer.writeAttribute("writable", qpn->isWritable() ? "true" : "false"); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -1127,36 +1202,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 +1214,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()); @@ -1262,9 +1312,13 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer, bool generateInternalNodes) { /* - Note that the groups are written after all the other nodes. + Note that groups, modules, and QML modules are written + after all the other nodes. */ - if (!node->isGroup() && generateIndexSection(writer, node, generateInternalNodes)) { + if (node->isGroup() || node->isModule() || node->isQmlModule()) + return; + + if (generateIndexSection(writer, node, generateInternalNodes)) { if (node->isInnerNode()) { const InnerNode* inner = static_cast<const InnerNode*>(node); @@ -1320,17 +1374,19 @@ void QDocIndexFiles::generateIndex(const QString& fileName, writer.writeAttribute("version", qdb_->version()); writer.writeAttribute("project", g->config()->getString(CONFIG_PROJECT)); - generateIndexSections(writer, qdb_->treeRoot(), generateInternalNodes); + generateIndexSections(writer, qdb_->primaryTreeRoot(), generateInternalNodes); /* - We wait until the end of the index file to output the group elements. - By waiting until the end, when we read each group element, its members - will have already been created. It is then only necessary to create - the group page and add each member to its member list. + We wait until the end of the index file to output the group, module, + and QML module elements. By outputting them at the end, when we read + the index file back in, all the group, module, and QML module member + elements will have already been created. It is then only necessary to + create the group, module, or QML module element and add each member to + its member list. */ - const DocNodeMap& groups = qdb_->groups(); + const CNMap& groups = qdb_->groups(); if (!groups.isEmpty()) { - DocNodeMap::ConstIterator g = groups.constBegin(); + CNMap::ConstIterator g = groups.constBegin(); while (g != groups.constEnd()) { if (generateIndexSection(writer, g.value(), generateInternalNodes)) writer.writeEndElement(); @@ -1338,6 +1394,26 @@ void QDocIndexFiles::generateIndex(const QString& fileName, } } + const CNMap& modules = qdb_->modules(); + if (!modules.isEmpty()) { + CNMap::ConstIterator g = modules.constBegin(); + while (g != modules.constEnd()) { + if (generateIndexSection(writer, g.value(), generateInternalNodes)) + writer.writeEndElement(); + ++g; + } + } + + const CNMap& qmlModules = qdb_->qmlModules(); + if (!qmlModules.isEmpty()) { + CNMap::ConstIterator g = qmlModules.constBegin(); + while (g != qmlModules.constEnd()) { + if (generateIndexSection(writer, g.value(), generateInternalNodes)) + writer.writeEndElement(); + ++g; + } + } + writer.writeEndElement(); // INDEX writer.writeEndElement(); // QDOCINDEX writer.writeEndDocument(); |