31#include <QtCore/qxmlstream.h>
52
53
54
55
60
61
69
70
78
79
80
83 if (s_qdocIndexFiles ==
nullptr)
85 return s_qdocIndexFiles;
89
90
93 if (s_qdocIndexFiles !=
nullptr) {
94 delete s_qdocIndexFiles;
95 s_qdocIndexFiles =
nullptr;
100
101
104 for (
const QString &file : indexFiles) {
105 qCDebug(lcQdoc) <<
"Loading index file: " << file;
111
112
118 if (!file.open(QFile::ReadOnly)) {
119 qWarning() <<
"Could not read index file" << path;
123 QXmlStreamReader reader(&file);
124 reader.setNamespaceProcessing(
false);
126 if (!reader.readNextStartElement())
129 if (reader.name() != QLatin1String(
"INDEX"))
132 QXmlStreamAttributes attrs = reader.attributes();
134 QString indexUrl {attrs.value(QLatin1String(
"url")).toString()};
141 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(
CONFIG_URL).asString()) {
144 QDir installDir(path.section(
'/', 0, -3) +
'/' + Generator::outputSubdir());
145 indexUrl = installDir.relativeFilePath(path).section(
'/', 0, -2);
147 m_project = attrs.value(QLatin1String(
"project")).toString();
148 QString indexTitle = attrs.value(QLatin1String(
"indexTitle")).toString();
150 m_relatedNodes.clear();
154 qWarning() <<
"Issue parsing index tree" << path;
158 root
->tree()->setIndexTitle(indexTitle);
162 while (reader.readNextStartElement()) {
163 readIndexSection(reader, root, indexUrl);
172
173
174
176 const QString &indexUrl)
178 QXmlStreamAttributes attributes = reader.attributes();
179 QStringView elementName = reader.name();
181 QString name = attributes.value(QLatin1String(
"name")).toString();
182 QString href = attributes.value(QLatin1String(
"href")).toString();
186 bool hasReadChildren =
false;
188 if (current->isAggregate())
189 parent =
static_cast<Aggregate *>(current);
191 if (attributes.hasAttribute(QLatin1String(
"related"))) {
192 bool isIntTypeRelatedValue =
false;
193 int relatedIndex = attributes.value(QLatin1String(
"related")).toInt(&isIntTypeRelatedValue);
194 if (isIntTypeRelatedValue) {
195 if (adoptRelatedNode(parent, relatedIndex)) {
196 reader.skipCurrentElement();
200 QList<Node *>::iterator nodeIterator =
201 std::find_if(m_relatedNodes.begin(), m_relatedNodes.end(), [&](
const Node *relatedNode) {
202 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char(
'/'), -1));
205 if (nodeIterator != m_relatedNodes.end() && parent) {
207 reader.skipCurrentElement();
215 if (attributes.hasAttribute(QLatin1String(
"filepath"))) {
216 filePath = attributes.value(QLatin1String(
"filepath")).toString();
217 lineNo = attributes.value(
"lineno").toInt();
219 if (parent && elementName == QLatin1String(
"namespace")) {
221 node = namespaceNode;
222 if (!indexUrl.isEmpty())
223 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
224 else if (!indexUrl.isNull())
225 location
= Location(name.toLower() +
".html");
226 }
else if (parent && (elementName == QLatin1String(
"class") || elementName == QLatin1String(
"struct")
227 || elementName == QLatin1String(
"union"))) {
229 if (elementName == QLatin1String(
"class"))
231 else if (elementName == QLatin1String(
"struct"))
233 else if (elementName == QLatin1String(
"union"))
235 node =
new ClassNode(type, parent, name);
236 if (attributes.hasAttribute(QLatin1String(
"bases"))) {
237 QString bases = attributes.value(QLatin1String(
"bases")).toString();
238 if (!bases.isEmpty())
240 std::pair<ClassNode *, QString>(
static_cast<ClassNode *>(node), bases));
242 if (!indexUrl.isEmpty())
243 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
244 else if (!indexUrl.isNull())
245 location
= Location(name.toLower() +
".html");
246 bool abstract =
false;
247 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
250 }
else if (parent && elementName == QLatin1String(
"header")) {
253 if (attributes.hasAttribute(QLatin1String(
"location")))
254 name = attributes.value(QLatin1String(
"location")).toString();
256 if (!indexUrl.isEmpty())
257 location
= Location(indexUrl + QLatin1Char(
'/') + name);
258 else if (!indexUrl.isNull())
260 }
else if (parent && ((elementName == QLatin1String(
"qmlclass") || elementName == QLatin1String(
"qmlvaluetype")
261 || elementName == QLatin1String(
"qmlbasictype")))) {
264 QString logicalModuleName = attributes.value(QLatin1String(
"qml-module-name")).toString();
265 if (!logicalModuleName.isEmpty())
266 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
267 bool abstract =
false;
268 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
270 qmlTypeNode->setAbstract(abstract);
271 if (attributes.value(QLatin1String(
"singleton")) == QLatin1String(
"true"))
272 qmlTypeNode->setSingleton();
273 else if (attributes.value(QLatin1String(
"uncreatable")) == QLatin1String(
"true"))
274 qmlTypeNode->setUncreatable();
275 QString qmlFullBaseName = attributes.value(QLatin1String(
"qml-base-type")).toString();
276 if (!qmlFullBaseName.isEmpty()) {
277 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
279 if (attributes.hasAttribute(QLatin1String(
"location")))
280 name = attributes.value(
"location").toString();
281 if (!indexUrl.isEmpty())
282 location
= Location(indexUrl + QLatin1Char(
'/') + name);
283 else if (!indexUrl.isNull())
286 }
else if (parent && elementName == QLatin1String(
"qmlproperty")) {
288 QString propertyGroup = attributes.value(
"inpropertygroup").toString();
290 if (attributes.value(
"propertygroup") ==
"true") {
292 propertyGroup = attributes.value(
"fullname").toString();
294 QString type = attributes.value(QLatin1String(
"type")).toString();
295 bool attached =
false;
296 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
298 bool readonly =
false;
299 if (attributes.value(QLatin1String(
"writable")) == QLatin1String(
"false"))
302 qmlPropertyNode->markReadOnly(readonly);
303 if (attributes.value(QLatin1String(
"required")) == QLatin1String(
"true"))
304 qmlPropertyNode->setRequired();
306 node = qmlPropertyNode;
309 if (!propertyGroup.isEmpty()) {
314 scn =
new SharedCommentNode(
static_cast<QmlTypeNode *>(parent), 0, propertyGroup.split(
".").last());
322 hasReadChildren =
true;
325 }
else if (elementName == QLatin1String(
"group")) {
326 auto *collectionNode = m_qdb->addGroup(name);
327 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
328 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
329 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
330 collectionNode->markSeen();
331 node = collectionNode;
332 }
else if (elementName == QLatin1String(
"module")) {
333 auto *collectionNode = m_qdb->addModule(name);
334 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
335 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
336 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
337 collectionNode->markSeen();
338 node = collectionNode;
339 }
else if (elementName == QLatin1String(
"concept")) {
340 auto *collectionNode = m_qdb->addConcept(name);
341 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
342 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
343 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
344 collectionNode->markSeen();
345 node = collectionNode;
346 }
else if (elementName == QLatin1String(
"qmlmodule")) {
347 auto *collectionNode = m_qdb->addQmlModule(name);
348 const QStringList info = QStringList()
350 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
351 collectionNode->setLogicalModuleInfo(info);
352 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
353 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
354 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
355 collectionNode->markSeen();
356 node = collectionNode;
357 }
else if (elementName == QLatin1String(
"page")) {
359 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
360 if (attr == QLatin1String(
"attribution")) {
362 }
else if (attr == QLatin1String(
"example")) {
364 }
else if (attr == QLatin1String(
"file")) {
366 }
else if (attr == QLatin1String(
"image")) {
368 }
else if (attr == QLatin1String(
"page")) {
370 }
else if (attr == QLatin1String(
"externalpage")) {
376 auto *exampleNode =
static_cast<ExampleNode *>(current);
378 exampleNode->appendFile(name);
381 exampleNode->appendImage(name);
391 pageNode =
new PageNode(parent, name);
395 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
397 if (attributes.hasAttribute(QLatin1String(
"location")))
398 name = attributes.value(QLatin1String(
"location")).toString();
400 if (!indexUrl.isEmpty())
401 location
= Location(indexUrl + QLatin1Char(
'/') + name);
402 else if (!indexUrl.isNull())
407 }
else if (parent && (elementName == QLatin1String(
"enum") || elementName == QLatin1String(
"qmlenum"))) {
409 if (elementName == QLatin1String(
"enum"))
410 enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
414 if (!indexUrl.isEmpty())
415 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
416 else if (!indexUrl.isNull())
417 location
= Location(parent->name().toLower() +
".html");
419 if (attributes.value(
"anonymous") ==
"true")
422 while (reader.readNextStartElement()) {
423 QXmlStreamAttributes childAttributes = reader.attributes();
424 if (reader.name() == QLatin1String(
"value")) {
425 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
426 childAttributes.value(QLatin1String(
"value")).toString(),
427 childAttributes.value(QLatin1String(
"since")).toString()
430 }
else if (reader.name() == QLatin1String(
"keyword")) {
432 }
else if (reader.name() == QLatin1String(
"target")) {
435 reader.skipCurrentElement();
440 hasReadChildren =
true;
441 }
else if (parent && elementName == QLatin1String(
"typedef")) {
443 if (attributes.hasAttribute(
"aliasedtype"))
444 typedefNode =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
449 if (attributes.hasAttribute(
"enum")) {
450 auto path = attributes.value(QLatin1String(
"enum")).toString();
451 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
453 const EnumNode *n =
static_cast<
const EnumNode *>(enode);
459 if (!indexUrl.isEmpty())
460 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
461 else if (!indexUrl.isNull())
462 location
= Location(parent->name().toLower() +
".html");
463 }
else if (parent && elementName == QLatin1String(
"property")) {
466 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
469 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
470 propNode->setDataType(attributes.value(QLatin1String(
"dataType")).toString());
472 if (attributes.value(QLatin1String(
"constant")) == QLatin1String(
"true"))
473 propNode->setConstant();
475 if (!indexUrl.isEmpty())
476 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
477 else if (!indexUrl.isNull())
478 location
= Location(parent->name().toLower() +
".html");
480 }
else if (parent && elementName == QLatin1String(
"function")) {
481 QString t = attributes.value(QLatin1String(
"meta")).toString();
482 bool attached =
false;
485 metaness = FunctionNode::getMetaness(t);
486 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
488 auto *fn =
new FunctionNode(metaness, parent, name, attached);
490 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
492 const auto &declaredTypeAttr = attributes.value(QLatin1String(
"declaredtype"));
493 if (!declaredTypeAttr.isEmpty())
494 fn->setDeclaredReturnType(declaredTypeAttr.toString());
496 if (fn->isCppNode()) {
497 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
498 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
499 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
500 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
501 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
503 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
506 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
509 if (attributes.value(QLatin1String(
"explicitly-defaulted")) == QLatin1String(
"true"))
510 fn->markExplicitlyDefaulted();
512 if (attributes.value(QLatin1String(
"deleted")) == QLatin1String(
"true"))
513 fn->markDeletedAsWritten();
514 if (attributes.value(QLatin1String(
"hidden-friend")) == QLatin1String(
"true"))
515 fn->setHiddenFriend(
true);
517 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
518 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
521 if (attributes.hasAttribute(QLatin1String(
"trailing_requires")))
522 fn->setTrailingRequiresClause(attributes.value(QLatin1String(
"trailing_requires")).toString());
524 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
527 else if (refness == 2)
530
531
532
533
534
535 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
536 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
538 fn->setOverloadNumber(0);
542
543
544
545
546
547
548 while (reader.readNextStartElement()) {
549 QXmlStreamAttributes childAttributes = reader.attributes();
550 if (reader.name() == QLatin1String(
"parameter")) {
551 QString type = childAttributes.value(QLatin1String(
"type")).toString();
552 QString name = childAttributes.value(QLatin1String(
"name")).toString();
553 QString default_ = childAttributes.value(QLatin1String(
"default")).toString();
554 fn->parameters().append(type, name, default_);
555 }
else if (reader.name() == QLatin1String(
"keyword")) {
557 }
else if (reader.name() == QLatin1String(
"target")) {
560 reader.skipCurrentElement();
564 if (!indexUrl.isEmpty())
565 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
566 else if (!indexUrl.isNull())
567 location
= Location(parent->name().toLower() +
".html");
569 hasReadChildren =
true;
570 }
else if (parent && elementName == QLatin1String(
"variable")) {
572 varNode->setLeftType(attributes.value(
"type").toString());
573 varNode->setStatic((attributes.value(
"static").toString() ==
"true") ?
true :
false);
575 if (!indexUrl.isEmpty())
576 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
577 else if (!indexUrl.isNull())
578 location
= Location(parent->name().toLower() +
".html");
579 }
else if (elementName == QLatin1String(
"keyword")) {
582 }
else if (elementName == QLatin1String(
"target")) {
585 }
else if (elementName == QLatin1String(
"contents")) {
588 }
else if (parent && elementName == QLatin1String(
"proxy")) {
590 if (!indexUrl.isEmpty())
591 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
592 else if (!indexUrl.isNull())
593 location
= Location(name.toLower() +
".html");
599 if (!href.isEmpty()) {
603 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
606 const QString access = attributes.value(QLatin1String(
"access")).toString();
607 if (access ==
"protected")
609 else if (access ==
"private")
614 if (attributes.hasAttribute(QLatin1String(
"related"))) {
616 m_relatedNodes << node;
619 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
620 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
621 if (threadSafety == QLatin1String(
"non-reentrant"))
623 else if (threadSafety == QLatin1String(
"reentrant"))
625 else if (threadSafety == QLatin1String(
"thread safe"))
632 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
635 QString status = attributes.value(QLatin1String(
"status")).toString();
637 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
639 else if (status == QLatin1String(
"preliminary"))
641 else if (status == QLatin1String(
"internal"))
643 else if (status == QLatin1String(
"internal-auto"))
645 else if (status == QLatin1String(
"ignored"))
650 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
651 if (!physicalModuleName.isEmpty())
652 m_qdb->addToModule(physicalModuleName, node);
654 QString since = attributes.value(QLatin1String(
"since")).toString();
655 if (!since.isEmpty()) {
656 node->setSince(since);
659 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
660 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
664 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
665 if (!groupsAttr.isEmpty()) {
666 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
667 for (
const auto &group : groupNames) {
668 m_qdb->addToGroup(group, node);
673 QSet<QString> emptySet;
675 if (!filePath.isEmpty()) {
680 Doc doc(location, location, QString(), emptySet, emptySet);
681 if (attributes.value(QLatin1String(
"auto-generated")) == QLatin1String(
"true"))
685 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
686 if (!briefAttr.isEmpty()) {
687 node->setReconstitutedBrief(briefAttr);
690 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
693 metaMap->insert(
"sortkey", sortKey);
695 if (!hasReadChildren) {
696 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
697 while (reader.readNextStartElement()) {
699 readIndexSection(reader, parent, indexUrl);
701 readIndexSection(reader, node, indexUrl);
707 while (!reader.isEndElement()) {
708 if (reader.readNext() == QXmlStreamReader::Invalid) {
715 const QXmlStreamAttributes &attributes,
Node *node)
732 QString name = attributes.value(QLatin1String(
"name")).toString();
733 QString title = attributes.value(QLatin1String(
"title")).toString();
734 m_qdb->insertTarget(name, title, type, node, priority);
738
739
740
741
742
743
744
745
746
747
748
749
750
753 for (
const auto &pair : std::as_const(m_basesList)) {
754 const QStringList bases = pair.second.split(QLatin1Char(
','));
755 for (
const auto &base : bases) {
756 QStringList basePath = base.split(QString(
"::"));
757 Node *n = m_qdb->findClassNode(basePath);
759 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
761 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
773 return QLatin1String(
"public");
774 case Access::Protected:
775 return QLatin1String(
"protected");
776 case Access::Private:
777 return QLatin1String(
"private");
781 return QLatin1String(
"public");
788 return QLatin1String(
"deprecated");
790 return QLatin1String(
"preliminary");
792 return QLatin1String(
"active");
794 return QLatin1String(
"internal");
796 return QLatin1String(
"internal-auto");
798 return QLatin1String(
"ignored");
802 return QLatin1String(
"active");
809 return QLatin1String(
"non-reentrant");
811 return QLatin1String(
"reentrant");
813 return QLatin1String(
"thread safe");
818 return QLatin1String(
"unspecified");
822
823
826 qsizetype i = m_relatedNodes.indexOf(node);
828 i = m_relatedNodes.size();
829 m_relatedNodes << node;
835
836
837
840 Node *related = m_relatedNodes.value(index);
842 if (adoptiveParent && related) {
851
852
853
854
855
859 for (
const Atom *target : std::as_const(node->doc().targets())) {
860 const QString &title = target->string();
861 const QString &name{TextUtils::asAsciiPrintable(title)};
862 writer.writeStartElement(
"target");
863 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
865 writer.writeAttribute(
"title", title);
866 writer.writeEndElement();
870 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
871 const QString &title = keyword->string();
872 const QString &name{TextUtils::asAsciiPrintable(title)};
873 writer.writeStartElement(
"keyword");
874 writer.writeAttribute(
"name", name);
876 writer.writeAttribute(
"title", title);
877 writer.writeEndElement();
883
884
885
886
887
888
889
890
899
900
905 QString logicalModuleName;
906 QString logicalModuleVersion;
907 QString qmlFullBaseName;
908 QString baseNameAttr;
909 QString moduleNameAttr;
910 QString moduleVerAttr;
914 nodeName =
"namespace";
929 nodeName =
"qmlenum";
934 logicalModuleName = node->logicalModuleName();
935 baseNameAttr =
"qml-base-type";
936 moduleNameAttr =
"qml-module-name";
937 moduleVerAttr =
"qml-module-version";
938 qmlFullBaseName = node->qmlFullBaseName();
952 nodeName =
"concept";
955 nodeName =
"qmlmodule";
956 moduleNameAttr =
"qml-module-name";
957 moduleVerAttr =
"qml-module-version";
958 logicalModuleName = node->logicalModuleName();
959 logicalModuleVersion = node->logicalModuleVersion();
966 nodeName =
"typedef";
969 nodeName =
"property";
972 nodeName =
"variable";
978 nodeName =
"qmlproperty";
981 nodeName =
"qmlproperty";
991 QString objName = node->name();
996 writer.writeStartElement(nodeName);
1000 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
1003 writer.writeAttribute(
"name", objName);
1006 writer.writeAttribute(
"propertygroup",
"true");
1011 if (!moduleNameAttr.isEmpty()) {
1012 if (!logicalModuleName.isEmpty())
1013 writer.writeAttribute(moduleNameAttr, logicalModuleName);
1014 if (!logicalModuleVersion.isEmpty())
1015 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
1017 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
1018 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
1019 else if (!baseNameAttr.isEmpty()) {
1020 const auto &qmlBase =
static_cast<QmlTypeNode *>(node)->qmlBaseName();
1021 if (!qmlBase.isEmpty())
1022 writer.writeAttribute(baseNameAttr, qmlBase);
1027 QString fullName = node->fullDocumentName();
1028 if (fullName != objName)
1029 writer.writeAttribute(
"fullname", fullName);
1030 href = m_gen->fullDocumentLocation(node);
1032 href = node->name();
1038 if (!href.isEmpty())
1039 writer.writeAttribute(
"href", href);
1041 writer.writeAttribute(
"status", getStatusString(node->status()));
1043 writer.writeAttribute(
"access", getAccessString(node->access()));
1045 writer.writeAttribute(
"abstract",
"true");
1048 if (!declLocation.fileName().isEmpty())
1049 writer.writeAttribute(
"location", declLocation.fileName());
1050 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1051 writer.writeAttribute(
"filepath", declLocation.filePath());
1052 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1056 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
1058 if (!node->since().isEmpty())
1059 writer.writeAttribute(
"since", node->since());
1062 writer.writeAttribute(
"documented",
"true");
1064 QStringList groups = m_qdb->groupNamesForNode(node);
1065 if (!groups.isEmpty())
1066 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1069 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
1070 writer.writeAttribute(
"sortkey", sortKey);
1072 QString brief = node
->doc().trimmedBriefText(node->name()).toString();
1078 const auto *classNode =
static_cast<
const ClassNode *>(node);
1079 const QList<RelatedClass> &bases = classNode->baseClasses();
1080 QSet<QString> baseStrings;
1081 for (
const auto &related : bases) {
1082 ClassNode *n = related.m_node;
1084 baseStrings.insert(n->fullName());
1085 else if (!related.m_path.isEmpty())
1086 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
1088 if (!baseStrings.isEmpty()) {
1089 QStringList baseStringsAsList = baseStrings.values();
1090 baseStringsAsList.sort();
1091 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
1093 if (!node->physicalModuleName().isEmpty())
1094 writer.writeAttribute(
"module", node->physicalModuleName());
1095 if (!brief.isEmpty())
1096 writer.writeAttribute(
"brief", brief);
1101 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
1102 if (!headerNode->physicalModuleName().isEmpty())
1103 writer.writeAttribute(
"module", headerNode->physicalModuleName());
1104 if (!brief.isEmpty())
1105 writer.writeAttribute(
"brief", brief);
1106 writer.writeAttribute(
"title", headerNode->title());
1107 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1108 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1111 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1112 if (!namespaceNode->physicalModuleName().isEmpty())
1113 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1114 if (!brief.isEmpty())
1115 writer.writeAttribute(
"brief", brief);
1119 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1120 if (qmlTypeNode->isSingleton())
1121 writer.writeAttribute(
"singleton",
"true");
1122 if (qmlTypeNode->isUncreatable())
1123 writer.writeAttribute(
"uncreatable",
"true");
1124 if (!brief.isEmpty())
1125 writer.writeAttribute(
"brief", brief);
1131 writer.writeAttribute(
"subtype",
"example");
1133 writer.writeAttribute(
"subtype",
"externalpage");
1135 writer.writeAttribute(
"subtype", (
static_cast<PageNode*>(node)->isAttribution() ?
"attribution" :
"page"));
1137 const auto *pageNode =
static_cast<
const PageNode *>(node);
1138 writer.writeAttribute(
"title", pageNode->title());
1139 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1140 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1141 if (!brief.isEmpty())
1142 writer.writeAttribute(
"brief", brief);
1148 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1149 writer.writeAttribute(
"seen", collectionNode->wasSeen() ?
"true" :
"false");
1150 writer.writeAttribute(
"title", collectionNode->title());
1151 if (!collectionNode->subtitle().isEmpty())
1152 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1153 if (!collectionNode->physicalModuleName().isEmpty())
1154 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1155 if (!brief.isEmpty())
1156 writer.writeAttribute(
"brief", brief);
1159 auto *qmlPropertyNode =
static_cast<QmlPropertyNode *>(node);
1160 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1161 writer.writeAttribute(
"attached", qmlPropertyNode->isAttached() ?
"true" :
"false");
1162 writer.writeAttribute(
"writable", qmlPropertyNode->isReadOnly() ?
"false" :
"true");
1163 if (qmlPropertyNode->isRequired())
1164 writer.writeAttribute(
"required",
"true");
1165 if (!brief.isEmpty())
1166 writer.writeAttribute(
"brief", brief);
1169 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1172 writer.writeAttribute(
"bindable",
"true");
1174 if (!propertyNode->isWritable())
1175 writer.writeAttribute(
"writable",
"false");
1177 if (propertyNode->isConstant())
1178 writer.writeAttribute(
"constant",
"true");
1180 writer.writeAttribute(
"dataType", propertyNode->dataType());
1182 if (!brief.isEmpty())
1183 writer.writeAttribute(
"brief", brief);
1185 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1187 for (
const auto *fnNode : propertyNode->functions(role)) {
1188 writer.writeStartElement(PropertyNode::roleName(role));
1189 writer.writeAttribute(
"name", fnNode->name());
1190 writer.writeEndElement();
1195 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1196 writer.writeAttribute(
"type", variableNode->dataType());
1197 writer.writeAttribute(
"static", variableNode->isStatic() ?
"true" :
"false");
1198 if (!brief.isEmpty())
1199 writer.writeAttribute(
"brief", brief);
1203 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1204 if (enumNode->isScoped())
1205 writer.writeAttribute(
"scoped",
"true");
1206 if (enumNode->flagsType())
1207 writer.writeAttribute(
"typedef", enumNode->flagsType()->fullDocumentName());
1208 if (enumNode->isAnonymous())
1209 writer.writeAttribute(
"anonymous",
"true");
1210 const auto &items = enumNode->items();
1211 for (
const auto &item : items) {
1212 writer.writeStartElement(
"value");
1213 writer.writeAttribute(
"name", item.name());
1214 if (node->isEnumType(Genus::CPP))
1215 writer.writeAttribute(
"value", item.value());
1216 if (!item.since().isEmpty())
1217 writer.writeAttribute(
"since", item.since());
1218 writer.writeEndElement();
1222 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1223 if (typedefNode->associatedEnum())
1224 writer.writeAttribute(
"enum", typedefNode->associatedEnum()->fullDocumentName());
1227 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1234 writeTargets(writer, node);
1237
1238
1239
1240
1241
1242
1245 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1247 int level = node
->doc().tableOfContentsLevels()[i];
1249 writer.writeStartElement(
"contents");
1250 writer.writeAttribute(
"name", Tree::refForAtom(item));
1251 writer.writeAttribute(
"title", title);
1252 writer.writeAttribute(
"level", QString::number(level));
1253 writer.writeEndElement();
1259 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1260 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1261 const QString project = Generator::defaultModuleName();
1262 const QString fileExt = m_gen->fileExtension();
1263 const auto &files = exampleNode->files();
1264 const auto &images = exampleNode->images();
1265 for (
const QString &file : files) {
1266 writer.writeStartElement(
"page");
1267 writer.writeAttribute(
"name", file);
1268 writer.writeAttribute(
"href", Utilities::linkForExampleFile(file, project, fileExt));
1269 writer.writeAttribute(
"status",
"active");
1270 writer.writeAttribute(
"subtype",
"file");
1271 writer.writeAttribute(
"title",
"");
1272 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::File));
1273 writer.writeAttribute(
"subtitle", file);
1274 writer.writeEndElement();
1276 for (
const QString &file : images) {
1277 writer.writeStartElement(
"page");
1278 writer.writeAttribute(
"name", file);
1279 writer.writeAttribute(
"href", Utilities::linkForExampleFile(file, project, fileExt));
1280 writer.writeAttribute(
"status",
"active");
1281 writer.writeAttribute(
"subtype",
"image");
1282 writer.writeAttribute(
"title",
"");
1283 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::Image));
1284 writer.writeAttribute(
"subtitle", file);
1285 writer.writeEndElement();
1297
1298
1299
1302 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1307 const QString objName = fn->name();
1308 writer.writeStartElement(
"function");
1309 writer.writeAttribute(
"name", objName);
1311 const QString fullName = fn->fullDocumentName();
1312 if (fullName != objName)
1313 writer.writeAttribute(
"fullname", fullName);
1314 const QString href = m_gen->fullDocumentLocation(fn);
1315 if (!href.isEmpty())
1316 writer.writeAttribute(
"href", href);
1318 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1319 writer.writeAttribute(
"status", getStatusString(fn->status()));
1320 writer.writeAttribute(
"access", getAccessString(fn->access()));
1323 if (!declLocation.fileName().isEmpty())
1324 writer.writeAttribute(
"location", declLocation.fileName());
1325 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1326 writer.writeAttribute(
"filepath", declLocation.filePath());
1327 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1331 writer.writeAttribute(
"documented",
"true");
1333 writer.writeAttribute(
"auto-generated",
"true");
1335 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1336 if (!fn->since().isEmpty())
1337 writer.writeAttribute(
"since", fn->since());
1339 const QString brief = fn
->doc().trimmedBriefText(fn->name()).toString();
1340 writer.writeAttribute(
"meta", fn->metanessString());
1343 writer.writeAttribute(
"virtual", fn->virtualness());
1346 writer.writeAttribute(
"const",
"true");
1348 writer.writeAttribute(
"static",
"true");
1350 writer.writeAttribute(
"final",
"true");
1352 writer.writeAttribute(
"override",
"true");
1354 writer.writeAttribute(
"explicit",
"true");
1356 writer.writeAttribute(
"constexpr",
"true");
1358 writer.writeAttribute(
"explicitly-defaulted",
"true");
1360 writer.writeAttribute(
"deleted",
"true");
1362 writer.writeAttribute(
"hidden-friend",
"true");
1364 if (
auto noexcept_info = fn->getNoexcept()) {
1365 writer.writeAttribute(
"noexcept",
"true");
1366 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1369 if (
const auto &trailing_requires = fn->trailingRequiresClause(); trailing_requires && !trailing_requires->isEmpty())
1370 writer.writeAttribute(
"trailing_requires", *trailing_requires);
1373
1374
1375
1376
1377
1379 writer.writeAttribute(
"overload",
"true");
1380 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1383 writer.writeAttribute(
"refness", QString::number(1));
1385 writer.writeAttribute(
"refness", QString::number(2));
1387 QStringList associatedProperties;
1388 for (
const auto *node : fn->associatedProperties()) {
1389 associatedProperties << node->name();
1391 associatedProperties.sort();
1392 writer.writeAttribute(
"associated-property",
1393 associatedProperties.join(QLatin1Char(
',')));
1397 writer.writeAttribute(
"attached",
"true");
1400 const auto &return_type = fn->returnType();
1401 if (!return_type.isEmpty())
1402 writer.writeAttribute(
"type",
std::move(return_type));
1404 const auto &declared_return_type = fn->declaredReturnType();
1405 if (declared_return_type.has_value())
1406 writer.writeAttribute(
"declaredtype", declared_return_type.value());
1409 if (!brief.isEmpty())
1410 writer.writeAttribute(
"brief", brief);
1413
1414
1415
1416
1417 const QString signature = appendAttributesToSignature(fn);
1418 writer.writeAttribute(
"signature", signature);
1420 QStringList groups = m_qdb->groupNamesForNode(fn);
1421 if (!groups.isEmpty())
1422 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1427 writer.writeStartElement(
"parameter");
1428 writer.writeAttribute(
"type", parameter.type());
1429 writer.writeAttribute(
"name", parameter.name());
1430 writer.writeAttribute(
"default", parameter.defaultValue());
1431 writer.writeEndElement();
1434 writeTargets(writer, fn);
1440 writer.writeEndElement();
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1459 signature +=
" final";
1461 signature +=
" override";
1463 signature +=
" = 0";
1464 if (
const auto &req = fn->trailingRequiresClause(); req && !req->isEmpty())
1465 signature +=
" requires " + *req;
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1483 for (
auto functions : std::as_const(aggregate->functionMap())) {
1484 std::for_each(functions.begin(), functions.end(),
1485 [
this,&writer](FunctionNode *fn) {
1486 generateFunctionSection(writer, fn);
1493
1494
1495
1496
1500 Q_ASSERT(generator);
1503
1504
1505
1510 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1515 if (generateIndexSection(writer, node, generator, post)) {
1517 auto *aggregate =
static_cast<Aggregate *>(node);
1519 generateFunctionSections(writer, aggregate);
1520 const auto &nonFunctionList = aggregate->nonfunctionList();
1521 for (
auto *node : nonFunctionList)
1522 generateIndexSections(writer, node, generator, post);
1525 if (node ==
root_) {
1527
1528
1529
1530
1531
1532
1534 if (!groups.isEmpty()) {
1535 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1536 if (generateIndexSection(writer, it.value(), generator, post))
1537 writer.writeEndElement();
1542 if (!modules.isEmpty()) {
1543 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1544 if (generateIndexSection(writer, it.value(), generator, post))
1545 writer.writeEndElement();
1550 if (!qmlModules.isEmpty()) {
1551 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1552 if (generateIndexSection(writer, it.value(), generator, post))
1553 writer.writeEndElement();
1558 if (!concepts.isEmpty()) {
1559 for (
auto it = concepts.constBegin(); it != concepts.constEnd(); ++it) {
1560 if (generateIndexSection(writer, it.value(), generator, post))
1561 writer.writeEndElement();
1565 for (
auto *p : m_qdb->primaryTree()->proxies()) {
1566 if (generateIndexSection(writer, p, generator, post)) {
1567 auto aggregate =
static_cast<Aggregate *>(p);
1568 generateFunctionSections(writer, aggregate);
1569 for (
auto *n : aggregate->nonfunctionList())
1570 generateIndexSections(writer, n, generator, post);
1571 writer.writeEndElement();
1576 writer.writeEndElement();
1581
1582
1583
1584
1585
1586
1587void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1588 const QString &title,
const Generator *hrefGenerator)
1590 Q_ASSERT(hrefGenerator);
1591 m_gen = hrefGenerator;
1593 QFile file(fileName);
1594 if (!file.open(QFile::WriteOnly | QFile::Text))
1597 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1598 m_relatedNodes.clear();
1599 QXmlStreamWriter writer(&file);
1600 writer.setAutoFormatting(
true);
1601 writer.writeStartDocument();
1602 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1604 writer.writeStartElement(
"INDEX");
1605 writer.writeAttribute(
"url", url);
1606 writer.writeAttribute(
"title", title);
1607 writer.writeAttribute(
"version", m_qdb->version());
1608 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1612 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1614 generateIndexSections(writer,
root_, m_gen,
nullptr);
1616 writer.writeEndElement();
1617 writer.writeEndElement();
1618 writer.writeEndDocument();
void adoptChild(Node *child)
This Aggregate becomes the adoptive parent of child.
The Atom class is the fundamental unit for representing documents internally.
The ClassNode represents a C++ class.
bool hasTableOfContents() const
void markAutoGenerated()
Marks this documentation as auto-generated by QDoc.
QStringMultiMap * metaTagMap() const
void constructExtra() const
void setFlagsType(TypedefNode *typedefNode)
void addItem(const EnumItem &item)
Add item to the enum type's item list.
void setAnonymous(bool anonymous)
The ExternalPageNode represents an external documentation page.
This node is used to represent any kind of function being documented.
signed short overloadNumber() const
Returns the overload number for this function.
bool isPureVirtual() const override
bool isNonvirtual() const
bool isHiddenFriend() const
bool isAttached() const override
Returns true if the QML property or QML method node is marked as attached.
bool isDeletedAsWritten() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
bool isExplicitlyDefaulted() const
Parameters & parameters()
bool hasAssociatedProperties() const
static bool isPubliclyVisible(const InclusionPolicy &policy, const NodeContext &context)
virtual void append(QXmlStreamWriter &writer, Node *node)=0
The Location class provides a way to mark a location in a file.
int lineNo() const
Returns the current line number.
Location & operator=(const Location &other)
The assignment operator does a deep copy of the entire state of other into this Location.
This class represents a C++ namespace.
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
A PageNode is a Node that generates a documentation page.
The Parameter class describes one function parameter.
This class describes one instance of using the Q_PROPERTY macro.
A class for representing an Aggregate that is documented in a different module.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
const CNMap & qmlModules()
Returns a const reference to the collection of all QML module nodes in the primary tree.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
const CNMap & modules()
Returns a const reference to the collection of all module nodes in the primary tree.
const CNMap & groups()
Returns a const reference to the collection of all group nodes in the primary tree.
This class handles qdoc index files.
Status
Specifies the status of the QQmlIncubator.
static Text sectionHeading(const Atom *sectionBegin)
static std::string comparisonCategoryAsString(ComparisonCategory category)
#define CONFIG_LOCATIONINFO
Metaness
Specifies the kind of function a FunctionNode represents.
Combined button and popup list for selecting options.
QMap< QString, CollectionNode * > CNMap
static QHash< QString, SharedCommentNode * > sharedDocNodes_
static QString getAccessString(Access t)
static IndexSectionWriter * post_
static QString getThreadSafenessString(Node::ThreadSafeness t)
static QString getStatusString(Status t)
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isExternalPage() const
Returns true if the node type is ExternalPage.
const Doc & doc() const
Returns a reference to the node's Doc data member.
bool isQmlNode() const
Returns true if this node's Genus value is QML.
bool isGroup() const
Returns true if the node type is Group.
void setAccess(Access t)
Sets the node's access type to t.
void setIndexNodeFlag(bool isIndexNode=true)
Sets a flag in this Node that indicates the node was created for something in an index file.
virtual bool isAbstract() const
Returns true if the ClassNode or QmlTypeNode is marked abstract.
SharedCommentNode * sharedCommentNode()
ComparisonCategory comparisonCategory() const
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
bool isEnumType() const
Returns true if the node type is Enum.
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Aggregate * parent() const
Returns the node's parent pointer.
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
virtual void setRelatedNonmember(bool b)
Sets a flag in the node indicating whether this node is a related nonmember of something.
void setComparisonCategory(const ComparisonCategory &category)
bool isProxyNode() const
Returns true if the node type is Proxy.
ThreadSafeness threadSafeness() const
Returns the thread safeness value for whatever this node represents.
virtual Tree * tree() const
Returns a pointer to the Tree this node is in.
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
NodeContext createContext() const
void setDoc(const Doc &doc, bool replace=false)
Sets this Node's Doc to doc.
bool isModule() const
Returns true if the node type is Module.
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
virtual void setAbstract(bool)
If this node is a ClassNode or a QmlTypeNode, the node's abstract flag data member is set to b.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
bool isCppNode() const
Returns true if this node's Genus value is CPP.
virtual void setStatus(Status t)
Sets the node's status to t.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
void setThreadSafeness(ThreadSafeness t)
Sets the node's thread safeness to t.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isExample() const
Returns true if the node type is Example.
bool isIndexNode() const
Returns true if this node was created from something in an index file.
const Parameter & at(int i) const
A record of a linkable target within the documentation.
TargetType
A type of a linkable target record.