29#include <QtCore/qxmlstream.h>
49
50
51
52
57
58
66
67
75
76
77
80 if (s_qdocIndexFiles ==
nullptr)
82 return s_qdocIndexFiles;
86
87
90 if (s_qdocIndexFiles !=
nullptr) {
91 delete s_qdocIndexFiles;
92 s_qdocIndexFiles =
nullptr;
97
98
101 for (
const QString &file : indexFiles) {
102 qCDebug(lcQdoc) <<
"Loading index file: " << file;
108
109
113 if (!file.open(QFile::ReadOnly)) {
114 qWarning() <<
"Could not read index file" << path;
118 QXmlStreamReader reader(&file);
119 reader.setNamespaceProcessing(
false);
121 if (!reader.readNextStartElement())
124 if (reader.name() != QLatin1String(
"INDEX"))
127 QXmlStreamAttributes attrs = reader.attributes();
129 QString indexUrl {attrs.value(QLatin1String(
"url")).toString()};
136 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(
CONFIG_URL).asString()) {
139 QDir installDir(path.section(
'/', 0, -3) +
'/' + Generator::outputSubdir());
140 indexUrl = installDir.relativeFilePath(path).section(
'/', 0, -2);
142 m_project = attrs.value(QLatin1String(
"project")).toString();
143 QString indexTitle = attrs.value(QLatin1String(
"indexTitle")).toString();
145 m_relatedNodes.clear();
149 qWarning() <<
"Issue parsing index tree" << path;
153 root
->tree()->setIndexTitle(indexTitle);
157 while (reader.readNextStartElement()) {
158 readIndexSection(reader, root, indexUrl);
167
168
169
171 const QString &indexUrl)
173 QXmlStreamAttributes attributes = reader.attributes();
174 QStringView elementName = reader.name();
176 QString name = attributes.value(QLatin1String(
"name")).toString();
177 QString href = attributes.value(QLatin1String(
"href")).toString();
181 bool hasReadChildren =
false;
184 parent =
static_cast<
Aggregate *>(current);
186 if (attributes.hasAttribute(QLatin1String(
"related"))) {
187 bool isIntTypeRelatedValue =
false;
188 int relatedIndex = attributes.value(QLatin1String(
"related")).toInt(&isIntTypeRelatedValue);
189 if (isIntTypeRelatedValue) {
190 if (adoptRelatedNode(parent, relatedIndex)) {
191 reader.skipCurrentElement();
195 QList<Node *>::iterator nodeIterator =
196 std::find_if(m_relatedNodes.begin(), m_relatedNodes.end(), [&](
const Node *relatedNode) {
197 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char(
'/'), -1));
200 if (nodeIterator != m_relatedNodes.end() && parent) {
202 reader.skipCurrentElement();
210 if (attributes.hasAttribute(QLatin1String(
"filepath"))) {
211 filePath = attributes.value(QLatin1String(
"filepath")).toString();
212 lineNo = attributes.value(
"lineno").toInt();
214 if (elementName == QLatin1String(
"namespace")) {
216 node = namespaceNode;
217 if (!indexUrl.isEmpty())
218 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
219 else if (!indexUrl.isNull())
220 location
= Location(name.toLower() +
".html");
221 }
else if (elementName == QLatin1String(
"class") || elementName == QLatin1String(
"struct")
222 || elementName == QLatin1String(
"union")) {
224 if (elementName == QLatin1String(
"class"))
226 else if (elementName == QLatin1String(
"struct"))
228 else if (elementName == QLatin1String(
"union"))
230 node =
new ClassNode(type, parent, name);
231 if (attributes.hasAttribute(QLatin1String(
"bases"))) {
232 QString bases = attributes.value(QLatin1String(
"bases")).toString();
233 if (!bases.isEmpty())
235 std::pair<ClassNode *, QString>(
static_cast<ClassNode *>(node), bases));
237 if (!indexUrl.isEmpty())
238 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
239 else if (!indexUrl.isNull())
240 location
= Location(name.toLower() +
".html");
241 bool abstract =
false;
242 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
245 }
else if (elementName == QLatin1String(
"header")) {
248 if (attributes.hasAttribute(QLatin1String(
"location")))
249 name = attributes.value(QLatin1String(
"location")).toString();
251 if (!indexUrl.isEmpty())
252 location
= Location(indexUrl + QLatin1Char(
'/') + name);
253 else if (!indexUrl.isNull())
255 }
else if (parent && ((elementName == QLatin1String(
"qmlclass") || elementName == QLatin1String(
"qmlvaluetype")
256 || elementName == QLatin1String(
"qmlbasictype")))) {
259 qmlTypeNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
260 QString logicalModuleName = attributes.value(QLatin1String(
"qml-module-name")).toString();
261 if (!logicalModuleName.isEmpty())
262 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
263 bool abstract =
false;
264 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
266 qmlTypeNode->setAbstract(abstract);
267 qmlTypeNode->setSingleton(attributes.value(QLatin1String(
"singleton")) == QLatin1String(
"true"));
268 QString qmlFullBaseName = attributes.value(QLatin1String(
"qml-base-type")).toString();
269 if (!qmlFullBaseName.isEmpty()) {
270 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
272 if (attributes.hasAttribute(QLatin1String(
"location")))
273 name = attributes.value(
"location").toString();
274 if (!indexUrl.isEmpty())
275 location
= Location(indexUrl + QLatin1Char(
'/') + name);
276 else if (!indexUrl.isNull())
279 }
else if (parent && elementName == QLatin1String(
"qmlproperty")) {
280 QString type = attributes.value(QLatin1String(
"type")).toString();
281 bool attached =
false;
282 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
284 bool readonly =
false;
285 if (attributes.value(QLatin1String(
"writable")) == QLatin1String(
"false"))
288 qmlPropertyNode->markReadOnly(readonly);
289 if (attributes.value(QLatin1String(
"required")) == QLatin1String(
"true"))
290 qmlPropertyNode->setRequired();
291 node = qmlPropertyNode;
292 }
else if (elementName == QLatin1String(
"group")) {
293 auto *collectionNode = m_qdb->addGroup(name);
294 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
295 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
296 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
297 collectionNode->markSeen();
298 node = collectionNode;
299 }
else if (elementName == QLatin1String(
"module")) {
300 auto *collectionNode = m_qdb->addModule(name);
301 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
302 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
303 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
304 collectionNode->markSeen();
305 node = collectionNode;
306 }
else if (elementName == QLatin1String(
"qmlmodule")) {
307 auto *collectionNode = m_qdb->addQmlModule(name);
308 const QStringList info = QStringList()
310 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
311 collectionNode->setLogicalModuleInfo(info);
312 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
313 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
314 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
315 collectionNode->markSeen();
316 node = collectionNode;
317 }
else if (elementName == QLatin1String(
"page")) {
319 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
320 if (attr == QLatin1String(
"attribution")) {
322 }
else if (attr == QLatin1String(
"example")) {
324 }
else if (attr == QLatin1String(
"file")) {
326 }
else if (attr == QLatin1String(
"image")) {
328 }
else if (attr == QLatin1String(
"page")) {
330 }
else if (attr == QLatin1String(
"externalpage")) {
336 auto *exampleNode =
static_cast<
ExampleNode *>(current);
338 exampleNode->appendFile(name);
341 exampleNode->appendImage(name);
351 pageNode =
new PageNode(parent, name);
355 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
357 if (attributes.hasAttribute(QLatin1String(
"location")))
358 name = attributes.value(QLatin1String(
"location")).toString();
360 if (!indexUrl.isEmpty())
361 location
= Location(indexUrl + QLatin1Char(
'/') + name);
362 else if (!indexUrl.isNull())
367 }
else if (elementName == QLatin1String(
"enum") || elementName == QLatin1String(
"qmlenum")) {
369 if (elementName == QLatin1String(
"enum"))
370 enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
374 if (!indexUrl.isEmpty())
375 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
376 else if (!indexUrl.isNull())
377 location
= Location(parent->name().toLower() +
".html");
379 while (reader.readNextStartElement()) {
380 QXmlStreamAttributes childAttributes = reader.attributes();
381 if (reader.name() == QLatin1String(
"value")) {
382 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
383 childAttributes.value(QLatin1String(
"value")).toString(),
384 childAttributes.value(QLatin1String(
"since")).toString()
387 }
else if (reader.name() == QLatin1String(
"keyword")) {
389 }
else if (reader.name() == QLatin1String(
"target")) {
392 reader.skipCurrentElement();
397 hasReadChildren =
true;
398 }
else if (elementName == QLatin1String(
"typedef")) {
400 if (attributes.hasAttribute(
"aliasedtype"))
401 typedefNode =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
406 if (attributes.hasAttribute(
"enum")) {
407 auto path = attributes.value(QLatin1String(
"enum")).toString();
408 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
416 if (!indexUrl.isEmpty())
417 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
418 else if (!indexUrl.isNull())
419 location
= Location(parent->name().toLower() +
".html");
420 }
else if (elementName == QLatin1String(
"property")) {
423 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
426 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
427 propNode->setDataType(attributes.value(QLatin1String(
"dataType")).toString());
429 if (attributes.value(QLatin1String(
"constant")) == QLatin1String(
"true"))
430 propNode->setConstant();
432 if (!indexUrl.isEmpty())
433 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
434 else if (!indexUrl.isNull())
435 location
= Location(parent->name().toLower() +
".html");
437 }
else if (elementName == QLatin1String(
"function")) {
438 QString t = attributes.value(QLatin1String(
"meta")).toString();
439 bool attached =
false;
442 metaness = FunctionNode::getMetaness(t);
443 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
445 auto *fn =
new FunctionNode(metaness, parent, name, attached);
447 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
449 const auto &declaredTypeAttr = attributes.value(QLatin1String(
"declaredtype"));
450 if (!declaredTypeAttr.isEmpty())
451 fn->setDeclaredReturnType(declaredTypeAttr.toString());
453 if (fn->isCppNode()) {
454 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
455 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
456 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
457 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
458 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
460 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
463 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
466 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
467 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
470 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
473 else if (refness == 2)
476
477
478
479
480
481 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
482 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
484 fn->setOverloadNumber(0);
488
489
490
491
492
493
494 while (reader.readNextStartElement()) {
495 QXmlStreamAttributes childAttributes = reader.attributes();
496 if (reader.name() == QLatin1String(
"parameter")) {
497 QString type = childAttributes.value(QLatin1String(
"type")).toString();
498 QString name = childAttributes.value(QLatin1String(
"name")).toString();
499 QString default_ = childAttributes.value(QLatin1String(
"default")).toString();
500 fn->parameters().append(type, name, default_);
501 }
else if (reader.name() == QLatin1String(
"keyword")) {
503 }
else if (reader.name() == QLatin1String(
"target")) {
506 reader.skipCurrentElement();
510 if (!indexUrl.isEmpty())
511 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
512 else if (!indexUrl.isNull())
513 location
= Location(parent->name().toLower() +
".html");
515 hasReadChildren =
true;
516 }
else if (elementName == QLatin1String(
"variable")) {
518 varNode->setLeftType(attributes.value(
"type").toString());
519 varNode->setStatic((attributes.value(
"static").toString() ==
"true") ?
true :
false);
521 if (!indexUrl.isEmpty())
522 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
523 else if (!indexUrl.isNull())
524 location
= Location(parent->name().toLower() +
".html");
525 }
else if (elementName == QLatin1String(
"keyword")) {
528 }
else if (elementName == QLatin1String(
"target")) {
531 }
else if (elementName == QLatin1String(
"contents")) {
534 }
else if (elementName == QLatin1String(
"proxy")) {
536 if (!indexUrl.isEmpty())
537 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
538 else if (!indexUrl.isNull())
539 location
= Location(name.toLower() +
".html");
545 if (!href.isEmpty()) {
549 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
552 const QString access = attributes.value(QLatin1String(
"access")).toString();
553 if (access ==
"protected")
555 else if (access ==
"private")
560 if (attributes.hasAttribute(QLatin1String(
"related"))) {
562 m_relatedNodes << node;
565 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
566 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
567 if (threadSafety == QLatin1String(
"non-reentrant"))
569 else if (threadSafety == QLatin1String(
"reentrant"))
571 else if (threadSafety == QLatin1String(
"thread safe"))
578 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
581 QString status = attributes.value(QLatin1String(
"status")).toString();
583 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
585 else if (status == QLatin1String(
"preliminary"))
587 else if (status == QLatin1String(
"internal"))
589 else if (status == QLatin1String(
"ignored"))
594 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
595 if (!physicalModuleName.isEmpty())
596 m_qdb->addToModule(physicalModuleName, node);
598 QString since = attributes.value(QLatin1String(
"since")).toString();
599 if (!since.isEmpty()) {
600 node->setSince(since);
603 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
604 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
608 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
609 if (!groupsAttr.isEmpty()) {
610 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
611 for (
const auto &group : groupNames) {
612 m_qdb->addToGroup(group, node);
617 QSet<QString> emptySet;
619 if (!filePath.isEmpty()) {
624 Doc doc(location, location, QString(), emptySet, emptySet);
627 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
628 if (!briefAttr.isEmpty()) {
629 node->setReconstitutedBrief(briefAttr);
632 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
635 metaMap->insert(
"sortkey", sortKey);
637 if (!hasReadChildren) {
638 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
639 while (reader.readNextStartElement()) {
641 readIndexSection(reader, parent, indexUrl);
643 readIndexSection(reader, node, indexUrl);
649 while (!reader.isEndElement()) {
650 if (reader.readNext() == QXmlStreamReader::Invalid) {
657 const QXmlStreamAttributes &attributes,
Node *node)
674 QString name = attributes.value(QLatin1String(
"name")).toString();
675 QString title = attributes.value(QLatin1String(
"title")).toString();
676 m_qdb->insertTarget(name, title, type, node, priority);
680
681
682
683
684
685
686
687
688
689
690
691
692
695 for (
const auto &pair : std::as_const(m_basesList)) {
696 const QStringList bases = pair.second.split(QLatin1Char(
','));
697 for (
const auto &base : bases) {
698 QStringList basePath = base.split(QString(
"::"));
699 Node *n = m_qdb->findClassNode(basePath);
701 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
703 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
715 return QLatin1String(
"public");
717 return QLatin1String(
"protected");
719 return QLatin1String(
"private");
723 return QLatin1String(
"public");
730 return QLatin1String(
"deprecated");
732 return QLatin1String(
"preliminary");
734 return QLatin1String(
"active");
736 return QLatin1String(
"internal");
738 return QLatin1String(
"ignored");
742 return QLatin1String(
"active");
749 return QLatin1String(
"non-reentrant");
751 return QLatin1String(
"reentrant");
753 return QLatin1String(
"thread safe");
758 return QLatin1String(
"unspecified");
762
763
766 qsizetype i = m_relatedNodes.indexOf(node);
768 i = m_relatedNodes.size();
769 m_relatedNodes << node;
775
776
777
780 Node *related = m_relatedNodes.value(index);
782 if (adoptiveParent && related) {
791
792
793
794
795
799 for (
const Atom *target : std::as_const(node->doc().targets())) {
800 const QString &title = target->string();
801 const QString &name{Utilities::asAsciiPrintable(title)};
802 writer.writeStartElement(
"target");
803 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
805 writer.writeAttribute(
"title", title);
806 writer.writeEndElement();
810 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
811 const QString &title = keyword->string();
812 const QString &name{Utilities::asAsciiPrintable(title)};
813 writer.writeStartElement(
"keyword");
814 writer.writeAttribute(
"name", name);
816 writer.writeAttribute(
"title", title);
817 writer.writeEndElement();
823
824
825
826
827
828
832 if (m_gen ==
nullptr)
839
840
845 QString logicalModuleName;
846 QString logicalModuleVersion;
847 QString qmlFullBaseName;
848 QString baseNameAttr;
849 QString moduleNameAttr;
850 QString moduleVerAttr;
854 nodeName =
"namespace";
869 nodeName =
"qmlenum";
874 logicalModuleName = node->logicalModuleName();
875 baseNameAttr =
"qml-base-type";
876 moduleNameAttr =
"qml-module-name";
877 moduleVerAttr =
"qml-module-version";
878 qmlFullBaseName = node->qmlFullBaseName();
892 nodeName =
"qmlmodule";
893 moduleNameAttr =
"qml-module-name";
894 moduleVerAttr =
"qml-module-version";
895 logicalModuleName = node->logicalModuleName();
896 logicalModuleVersion = node->logicalModuleVersion();
903 nodeName =
"typedef";
906 nodeName =
"property";
909 nodeName =
"variable";
915 nodeName =
"qmlproperty";
918 nodeName =
"qmlproperty";
928 QString objName = node->name();
933 writer.writeStartElement(nodeName);
936 if (node->threadSafeness() != Node::UnspecifiedSafeness)
937 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
940 writer.writeAttribute(
"name", objName);
943 if (!moduleNameAttr.isEmpty()) {
944 if (!logicalModuleName.isEmpty())
945 writer.writeAttribute(moduleNameAttr, logicalModuleName);
946 if (!logicalModuleVersion.isEmpty())
947 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
949 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
950 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
954 QString fullName = node->fullDocumentName();
955 if (fullName != objName)
956 writer.writeAttribute(
"fullname", fullName);
957 href = m_gen->fullDocumentLocation(node);
966 writer.writeAttribute(
"href", href);
968 writer.writeAttribute(
"status", getStatusString(node->status()));
970 writer.writeAttribute(
"access", getAccessString(node->access()));
972 writer.writeAttribute(
"abstract",
"true");
975 if (!declLocation.fileName().isEmpty())
976 writer.writeAttribute(
"location", declLocation.fileName());
977 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
978 writer.writeAttribute(
"filepath", declLocation.filePath());
979 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
982 if (node->isRelatedNonmember())
983 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
985 if (!node->since().isEmpty())
986 writer.writeAttribute(
"since", node->since());
989 writer.writeAttribute(
"documented",
"true");
991 QStringList groups = m_qdb->groupNamesForNode(node);
992 if (!groups.isEmpty())
993 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
996 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
997 writer.writeAttribute(
"sortkey", sortKey);
999 QString brief = node
->doc().trimmedBriefText(node->name()).toString();
1005 const auto *classNode =
static_cast<
const ClassNode *>(node);
1006 const QList<RelatedClass> &bases = classNode->baseClasses();
1007 QSet<QString> baseStrings;
1008 for (
const auto &related : bases) {
1009 ClassNode *n = related.m_node;
1011 baseStrings.insert(n->fullName());
1012 else if (!related.m_path.isEmpty())
1013 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
1015 if (!baseStrings.isEmpty()) {
1016 QStringList baseStringsAsList = baseStrings.values();
1017 baseStringsAsList.sort();
1018 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
1020 if (!node->physicalModuleName().isEmpty())
1021 writer.writeAttribute(
"module", node->physicalModuleName());
1022 if (!brief.isEmpty())
1023 writer.writeAttribute(
"brief", brief);
1028 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
1029 if (!headerNode->physicalModuleName().isEmpty())
1030 writer.writeAttribute(
"module", headerNode->physicalModuleName());
1031 if (!brief.isEmpty())
1032 writer.writeAttribute(
"brief", brief);
1033 writer.writeAttribute(
"title", headerNode->title());
1034 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1035 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1038 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1039 if (!namespaceNode->physicalModuleName().isEmpty())
1040 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1041 if (!brief.isEmpty())
1042 writer.writeAttribute(
"brief", brief);
1046 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1047 writer.writeAttribute(
"title", qmlTypeNode->title());
1048 writer.writeAttribute(
"fulltitle", qmlTypeNode->fullTitle());
1049 writer.writeAttribute(
"subtitle", qmlTypeNode->subtitle());
1051 writer.writeAttribute(
"singleton",
"true");
1052 if (!brief.isEmpty())
1053 writer.writeAttribute(
"brief", brief);
1059 writer.writeAttribute(
"subtype",
"example");
1061 writer.writeAttribute(
"subtype",
"externalpage");
1065 const auto *pageNode =
static_cast<
const PageNode *>(node);
1066 writer.writeAttribute(
"title", pageNode->title());
1067 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1068 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1069 if (!brief.isEmpty())
1070 writer.writeAttribute(
"brief", brief);
1075 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1076 writer.writeAttribute(
"seen", collectionNode
->wasSeen() ?
"true" :
"false");
1077 writer.writeAttribute(
"title", collectionNode->title());
1078 if (!collectionNode->subtitle().isEmpty())
1079 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1080 if (!collectionNode->physicalModuleName().isEmpty())
1081 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1082 if (!brief.isEmpty())
1083 writer.writeAttribute(
"brief", brief);
1087 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1088 writer.writeAttribute(
"attached", qmlPropertyNode
->isAttached() ?
"true" :
"false");
1089 writer.writeAttribute(
"writable", qmlPropertyNode
->isReadOnly() ?
"false" :
"true");
1091 writer.writeAttribute(
"required",
"true");
1092 if (!brief.isEmpty())
1093 writer.writeAttribute(
"brief", brief);
1096 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1099 writer.writeAttribute(
"bindable",
"true");
1102 writer.writeAttribute(
"writable",
"false");
1105 writer.writeAttribute(
"constant",
"true");
1107 writer.writeAttribute(
"dataType", propertyNode->dataType());
1109 if (!brief.isEmpty())
1110 writer.writeAttribute(
"brief", brief);
1112 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1114 for (
const auto *fnNode : propertyNode->functions(role)) {
1115 writer.writeStartElement(PropertyNode::roleName(role));
1116 writer.writeAttribute(
"name", fnNode->name());
1117 writer.writeEndElement();
1122 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1123 writer.writeAttribute(
"type", variableNode->dataType());
1124 writer.writeAttribute(
"static", variableNode
->isStatic() ?
"true" :
"false");
1125 if (!brief.isEmpty())
1126 writer.writeAttribute(
"brief", brief);
1130 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1132 writer.writeAttribute(
"scoped",
"true");
1134 writer.writeAttribute(
"typedef", enumNode
->flagsType()->fullDocumentName());
1135 const auto &items = enumNode->items();
1136 for (
const auto &item : items) {
1137 writer.writeStartElement(
"value");
1138 writer.writeAttribute(
"name", item.name());
1139 if (node->isEnumType(Genus::CPP))
1140 writer.writeAttribute(
"value", item.value());
1141 if (!item.since().isEmpty())
1142 writer.writeAttribute(
"since", item.since());
1143 writer.writeEndElement();
1147 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1152 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1159 writeTargets(writer, node);
1162
1163
1164
1165
1166
1167
1170 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1172 int level = node
->doc().tableOfContentsLevels()[i];
1174 writer.writeStartElement(
"contents");
1175 writer.writeAttribute(
"name", Tree::refForAtom(item));
1176 writer.writeAttribute(
"title", title);
1177 writer.writeAttribute(
"level", QString::number(level));
1178 writer.writeEndElement();
1184 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1185 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1186 const auto &files = exampleNode->files();
1187 for (
const QString &file : files) {
1188 writer.writeStartElement(
"page");
1189 writer.writeAttribute(
"name", file);
1190 QString href = m_gen->linkForExampleFile(file);
1191 writer.writeAttribute(
"href", href);
1192 writer.writeAttribute(
"status",
"active");
1193 writer.writeAttribute(
"subtype",
"file");
1194 writer.writeAttribute(
"title",
"");
1195 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1196 writer.writeAttribute(
"subtitle", file);
1197 writer.writeEndElement();
1199 const auto &images = exampleNode->images();
1200 for (
const QString &file : images) {
1201 writer.writeStartElement(
"page");
1202 writer.writeAttribute(
"name", file);
1203 QString href = m_gen->linkForExampleFile(file);
1204 writer.writeAttribute(
"href", href);
1205 writer.writeAttribute(
"status",
"active");
1206 writer.writeAttribute(
"subtype",
"image");
1207 writer.writeAttribute(
"title",
"");
1208 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1209 writer.writeAttribute(
"subtitle", file);
1210 writer.writeEndElement();
1222
1223
1224
1227 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1232 const QString objName = fn->name();
1233 writer.writeStartElement(
"function");
1234 writer.writeAttribute(
"name", objName);
1236 const QString fullName = fn->fullDocumentName();
1237 if (fullName != objName)
1238 writer.writeAttribute(
"fullname", fullName);
1239 const QString href = m_gen->fullDocumentLocation(fn);
1240 if (!href.isEmpty())
1241 writer.writeAttribute(
"href", href);
1242 if (fn->threadSafeness() != Node::UnspecifiedSafeness)
1243 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1244 writer.writeAttribute(
"status", getStatusString(fn->status()));
1245 writer.writeAttribute(
"access", getAccessString(fn->access()));
1248 if (!declLocation.fileName().isEmpty())
1249 writer.writeAttribute(
"location", declLocation.fileName());
1250 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1251 writer.writeAttribute(
"filepath", declLocation.filePath());
1252 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1256 writer.writeAttribute(
"documented",
"true");
1257 if (fn->isRelatedNonmember())
1258 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1259 if (!fn->since().isEmpty())
1260 writer.writeAttribute(
"since", fn->since());
1262 const QString brief = fn
->doc().trimmedBriefText(fn->name()).toString();
1263 writer.writeAttribute(
"meta", fn->metanessString());
1266 writer.writeAttribute(
"virtual", fn->virtualness());
1269 writer.writeAttribute(
"const",
"true");
1271 writer.writeAttribute(
"static",
"true");
1273 writer.writeAttribute(
"final",
"true");
1275 writer.writeAttribute(
"override",
"true");
1277 writer.writeAttribute(
"explicit",
"true");
1279 writer.writeAttribute(
"constexpr",
"true");
1281 if (
auto noexcept_info = fn->getNoexcept()) {
1282 writer.writeAttribute(
"noexcept",
"true");
1283 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1287
1288
1289
1290
1291
1293 writer.writeAttribute(
"overload",
"true");
1294 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1297 writer.writeAttribute(
"refness", QString::number(1));
1298 else if (fn->isRefRef())
1299 writer.writeAttribute(
"refness", QString::number(2));
1301 QStringList associatedProperties;
1302 for (
const auto *node : fn->associatedProperties()) {
1303 associatedProperties << node->name();
1305 associatedProperties.sort();
1306 writer.writeAttribute(
"associated-property",
1307 associatedProperties.join(QLatin1Char(
',')));
1311 const auto &return_type = fn->returnType();
1312 if (!return_type.isEmpty())
1313 writer.writeAttribute(
"type",
std::move(return_type));
1315 const auto &declared_return_type = fn->declaredReturnType();
1316 if (declared_return_type.has_value())
1317 writer.writeAttribute(
"declaredtype", declared_return_type.value());
1320 if (!brief.isEmpty())
1321 writer.writeAttribute(
"brief", brief);
1324
1325
1326
1327
1328 const QString signature = appendAttributesToSignature(fn);
1329 writer.writeAttribute(
"signature", signature);
1331 QStringList groups = m_qdb->groupNamesForNode(fn);
1332 if (!groups.isEmpty())
1333 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1338 writer.writeStartElement(
"parameter");
1339 writer.writeAttribute(
"type", parameter.type());
1340 writer.writeAttribute(
"name", parameter.name());
1341 writer.writeAttribute(
"default", parameter.defaultValue());
1342 writer.writeEndElement();
1345 writeTargets(writer, fn);
1351 writer.writeEndElement();
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1370 signature +=
" final";
1372 signature +=
" override";
1374 signature +=
" = 0";
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1392 for (
auto functions : std::as_const(aggregate->functionMap())) {
1393 std::for_each(functions.begin(), functions.end(),
1394 [
this,&writer](FunctionNode *fn) {
1395 generateFunctionSection(writer, fn);
1402
1403
1404
1409
1410
1411
1416 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1421 if (generateIndexSection(writer, node, post)) {
1423 auto *aggregate =
static_cast<
Aggregate *>(node);
1425 generateFunctionSections(writer, aggregate);
1427 for (
auto *node : nonFunctionList)
1428 generateIndexSections(writer, node, post);
1431 if (node ==
root_) {
1433
1434
1435
1436
1437
1438
1440 if (!groups.isEmpty()) {
1441 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1442 if (generateIndexSection(writer, it.value(), post))
1443 writer.writeEndElement();
1448 if (!modules.isEmpty()) {
1449 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1450 if (generateIndexSection(writer, it.value(), post))
1451 writer.writeEndElement();
1456 if (!qmlModules.isEmpty()) {
1457 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1458 if (generateIndexSection(writer, it.value(), post))
1459 writer.writeEndElement();
1463 for (
auto *p : m_qdb->primaryTree()->proxies()) {
1464 if (generateIndexSection(writer, p, post)) {
1465 auto aggregate =
static_cast<Aggregate *>(p);
1466 generateFunctionSections(writer, aggregate);
1467 for (
auto *n : aggregate->nonfunctionList())
1468 generateIndexSections(writer, n, post);
1469 writer.writeEndElement();
1474 writer.writeEndElement();
1479
1480
1481
1482
1483
1484void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1485 const QString &title)
1487 QFile file(fileName);
1488 if (!file.open(QFile::WriteOnly | QFile::Text))
1491 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1494 m_relatedNodes.clear();
1495 QXmlStreamWriter writer(&file);
1496 writer.setAutoFormatting(
true);
1497 writer.writeStartDocument();
1498 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1500 writer.writeStartElement(
"INDEX");
1501 writer.writeAttribute(
"url", url);
1502 writer.writeAttribute(
"title", title);
1503 writer.writeAttribute(
"version", m_qdb->version());
1504 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1508 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1510 generateIndexSections(writer,
root_,
nullptr);
1512 writer.writeEndElement();
1513 writer.writeEndElement();
1514 writer.writeEndDocument();
void adoptChild(Node *child)
This Aggregate becomes the adoptive parent of child.
const NodeList & nonfunctionList()
Returns a const reference to the list of child nodes of this aggregate that are not function nodes.
The Atom class is the fundamental unit for representing documents internally.
The ClassNode represents a C++ class.
A class for holding the members of a collection of doc pages.
bool wasSeen() const override
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
bool hasTableOfContents() const
QStringMultiMap * metaTagMap() const
void constructExtra() const
void setFlagsType(TypedefNode *typedefNode)
void addItem(const EnumItem &item)
Add item to the enum type's item list.
const TypedefNode * flagsType() const
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 isStatic() const override
Returns true if the FunctionNode represents a static function.
Parameters & parameters()
bool hasAssociatedProperties() const
static Generator * currentGenerator()
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.
bool isAttribution() const
The Parameter class describes one function parameter.
This class describes one instance of using the Q_PROPERTY macro.
PropertyType propertyType() const
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.
bool isRequired()
Returns true if this QML property is marked with \required or the corresponding C++ property uses the...
bool isReadOnly()
Returns true if this QML property or attached property is read-only.
bool isAttached() const override
Returns true if the QML property or QML method node is marked as attached.
static Text sectionHeading(const Atom *sectionBegin)
const EnumNode * associatedEnum() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
static std::string comparisonCategoryAsString(ComparisonCategory category)
#define CONFIG_LOCATIONINFO
QMap< QString, CollectionNode * > CNMap
static QString getStatusString(Node::Status t)
static QString getAccessString(Access t)
static IndexSectionWriter * post_
static QString getThreadSafenessString(Node::ThreadSafeness 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.
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.
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.
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 isCppNode() const
Returns true if this node's Genus value is CPP.
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.
Status
An unsigned char that specifies the status of the documentation element in the documentation set.
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.