30#include <QtCore/qxmlstream.h>
51
52
53
54
59
60
68
69
77
78
79
82 if (s_qdocIndexFiles ==
nullptr)
84 return s_qdocIndexFiles;
88
89
92 if (s_qdocIndexFiles !=
nullptr) {
93 delete s_qdocIndexFiles;
94 s_qdocIndexFiles =
nullptr;
99
100
103 for (
const QString &file : indexFiles) {
104 qCDebug(lcQdoc) <<
"Loading index file: " << file;
110
111
117 if (!file.open(QFile::ReadOnly)) {
118 qWarning() <<
"Could not read index file" << path;
122 QXmlStreamReader reader(&file);
123 reader.setNamespaceProcessing(
false);
125 if (!reader.readNextStartElement())
128 if (reader.name() != QLatin1String(
"INDEX"))
131 QXmlStreamAttributes attrs = reader.attributes();
133 QString indexUrl {attrs.value(QLatin1String(
"url")).toString()};
140 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(
CONFIG_URL).asString()) {
143 QDir installDir(path.section(
'/', 0, -3) +
'/' + Generator::outputSubdir());
144 indexUrl = installDir.relativeFilePath(path).section(
'/', 0, -2);
146 m_project = attrs.value(QLatin1String(
"project")).toString();
147 QString indexTitle = attrs.value(QLatin1String(
"indexTitle")).toString();
149 m_relatedNodes.clear();
153 qWarning() <<
"Issue parsing index tree" << path;
157 root
->tree()->setIndexTitle(indexTitle);
161 while (reader.readNextStartElement()) {
162 readIndexSection(reader, root, indexUrl);
171
172
173
175 const QString &indexUrl)
177 QXmlStreamAttributes attributes = reader.attributes();
178 QStringView elementName = reader.name();
180 QString name = attributes.value(QLatin1String(
"name")).toString();
181 QString href = attributes.value(QLatin1String(
"href")).toString();
185 bool hasReadChildren =
false;
187 if (current->isAggregate())
188 parent =
static_cast<Aggregate *>(current);
190 if (attributes.hasAttribute(QLatin1String(
"related"))) {
191 bool isIntTypeRelatedValue =
false;
192 int relatedIndex = attributes.value(QLatin1String(
"related")).toInt(&isIntTypeRelatedValue);
193 if (isIntTypeRelatedValue) {
194 if (adoptRelatedNode(parent, relatedIndex)) {
195 reader.skipCurrentElement();
199 QList<Node *>::iterator nodeIterator =
200 std::find_if(m_relatedNodes.begin(), m_relatedNodes.end(), [&](
const Node *relatedNode) {
201 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char(
'/'), -1));
204 if (nodeIterator != m_relatedNodes.end() && parent) {
206 reader.skipCurrentElement();
214 if (attributes.hasAttribute(QLatin1String(
"filepath"))) {
215 filePath = attributes.value(QLatin1String(
"filepath")).toString();
216 lineNo = attributes.value(
"lineno").toInt();
218 if (elementName == QLatin1String(
"namespace")) {
220 node = namespaceNode;
221 if (!indexUrl.isEmpty())
222 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
223 else if (!indexUrl.isNull())
224 location
= Location(name.toLower() +
".html");
225 }
else if (elementName == QLatin1String(
"class") || elementName == QLatin1String(
"struct")
226 || elementName == QLatin1String(
"union")) {
228 if (elementName == QLatin1String(
"class"))
230 else if (elementName == QLatin1String(
"struct"))
232 else if (elementName == QLatin1String(
"union"))
234 node =
new ClassNode(type, parent, name);
235 if (attributes.hasAttribute(QLatin1String(
"bases"))) {
236 QString bases = attributes.value(QLatin1String(
"bases")).toString();
237 if (!bases.isEmpty())
239 std::pair<ClassNode *, QString>(
static_cast<ClassNode *>(node), bases));
241 if (!indexUrl.isEmpty())
242 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
243 else if (!indexUrl.isNull())
244 location
= Location(name.toLower() +
".html");
245 bool abstract =
false;
246 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
249 }
else if (elementName == QLatin1String(
"header")) {
252 if (attributes.hasAttribute(QLatin1String(
"location")))
253 name = attributes.value(QLatin1String(
"location")).toString();
255 if (!indexUrl.isEmpty())
256 location
= Location(indexUrl + QLatin1Char(
'/') + name);
257 else if (!indexUrl.isNull())
259 }
else if (parent && ((elementName == QLatin1String(
"qmlclass") || elementName == QLatin1String(
"qmlvaluetype")
260 || elementName == QLatin1String(
"qmlbasictype")))) {
263 QString logicalModuleName = attributes.value(QLatin1String(
"qml-module-name")).toString();
264 if (!logicalModuleName.isEmpty())
265 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
266 bool abstract =
false;
267 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
269 qmlTypeNode->setAbstract(abstract);
270 qmlTypeNode->setSingleton(attributes.value(QLatin1String(
"singleton")) == QLatin1String(
"true"));
271 QString qmlFullBaseName = attributes.value(QLatin1String(
"qml-base-type")).toString();
272 if (!qmlFullBaseName.isEmpty()) {
273 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
275 if (attributes.hasAttribute(QLatin1String(
"location")))
276 name = attributes.value(
"location").toString();
277 if (!indexUrl.isEmpty())
278 location
= Location(indexUrl + QLatin1Char(
'/') + name);
279 else if (!indexUrl.isNull())
282 }
else if (parent && elementName == QLatin1String(
"qmlproperty")) {
284 QString propertyGroup = attributes.value(
"inpropertygroup").toString();
286 if (attributes.value(
"propertygroup") ==
"true") {
288 propertyGroup = attributes.value(
"fullname").toString();
290 QString type = attributes.value(QLatin1String(
"type")).toString();
291 bool attached =
false;
292 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
294 bool readonly =
false;
295 if (attributes.value(QLatin1String(
"writable")) == QLatin1String(
"false"))
298 qmlPropertyNode->markReadOnly(readonly);
299 if (attributes.value(QLatin1String(
"required")) == QLatin1String(
"true"))
300 qmlPropertyNode->setRequired();
302 node = qmlPropertyNode;
305 if (!propertyGroup.isEmpty()) {
310 scn =
new SharedCommentNode(
static_cast<QmlTypeNode *>(parent), 0, propertyGroup.split(
".").last());
318 hasReadChildren =
true;
321 }
else if (elementName == QLatin1String(
"group")) {
322 auto *collectionNode = m_qdb->addGroup(name);
323 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
324 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
325 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
326 collectionNode->markSeen();
327 node = collectionNode;
328 }
else if (elementName == QLatin1String(
"module")) {
329 auto *collectionNode = m_qdb->addModule(name);
330 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
331 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
332 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
333 collectionNode->markSeen();
334 node = collectionNode;
335 }
else if (elementName == QLatin1String(
"qmlmodule")) {
336 auto *collectionNode = m_qdb->addQmlModule(name);
337 const QStringList info = QStringList()
339 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
340 collectionNode->setLogicalModuleInfo(info);
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(
"page")) {
348 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
349 if (attr == QLatin1String(
"attribution")) {
351 }
else if (attr == QLatin1String(
"example")) {
353 }
else if (attr == QLatin1String(
"file")) {
355 }
else if (attr == QLatin1String(
"image")) {
357 }
else if (attr == QLatin1String(
"page")) {
359 }
else if (attr == QLatin1String(
"externalpage")) {
365 auto *exampleNode =
static_cast<ExampleNode *>(current);
367 exampleNode->appendFile(name);
370 exampleNode->appendImage(name);
380 pageNode =
new PageNode(parent, name);
384 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
386 if (attributes.hasAttribute(QLatin1String(
"location")))
387 name = attributes.value(QLatin1String(
"location")).toString();
389 if (!indexUrl.isEmpty())
390 location
= Location(indexUrl + QLatin1Char(
'/') + name);
391 else if (!indexUrl.isNull())
396 }
else if (elementName == QLatin1String(
"enum") || elementName == QLatin1String(
"qmlenum")) {
398 if (elementName == QLatin1String(
"enum"))
399 enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
403 if (!indexUrl.isEmpty())
404 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
405 else if (!indexUrl.isNull())
406 location
= Location(parent->name().toLower() +
".html");
408 if (attributes.value(
"anonymous") ==
"true")
411 while (reader.readNextStartElement()) {
412 QXmlStreamAttributes childAttributes = reader.attributes();
413 if (reader.name() == QLatin1String(
"value")) {
414 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
415 childAttributes.value(QLatin1String(
"value")).toString(),
416 childAttributes.value(QLatin1String(
"since")).toString()
419 }
else if (reader.name() == QLatin1String(
"keyword")) {
421 }
else if (reader.name() == QLatin1String(
"target")) {
424 reader.skipCurrentElement();
429 hasReadChildren =
true;
430 }
else if (elementName == QLatin1String(
"typedef")) {
432 if (attributes.hasAttribute(
"aliasedtype"))
433 typedefNode =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
438 if (attributes.hasAttribute(
"enum")) {
439 auto path = attributes.value(QLatin1String(
"enum")).toString();
440 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
442 const EnumNode *n =
static_cast<
const EnumNode *>(enode);
448 if (!indexUrl.isEmpty())
449 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
450 else if (!indexUrl.isNull())
451 location
= Location(parent->name().toLower() +
".html");
452 }
else if (elementName == QLatin1String(
"property")) {
455 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
458 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
459 propNode->setDataType(attributes.value(QLatin1String(
"dataType")).toString());
461 if (attributes.value(QLatin1String(
"constant")) == QLatin1String(
"true"))
462 propNode->setConstant();
464 if (!indexUrl.isEmpty())
465 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
466 else if (!indexUrl.isNull())
467 location
= Location(parent->name().toLower() +
".html");
469 }
else if (elementName == QLatin1String(
"function")) {
470 QString t = attributes.value(QLatin1String(
"meta")).toString();
471 bool attached =
false;
474 metaness = FunctionNode::getMetaness(t);
475 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
477 auto *fn =
new FunctionNode(metaness, parent, name, attached);
479 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
481 const auto &declaredTypeAttr = attributes.value(QLatin1String(
"declaredtype"));
482 if (!declaredTypeAttr.isEmpty())
483 fn->setDeclaredReturnType(declaredTypeAttr.toString());
485 if (fn->isCppNode()) {
486 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
487 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
488 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
489 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
490 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
492 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
495 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
498 if (attributes.value(QLatin1String(
"explicitly-defaulted")) == QLatin1String(
"true"))
499 fn->markExplicitlyDefaulted();
501 if (attributes.value(QLatin1String(
"deleted")) == QLatin1String(
"true"))
502 fn->markDeletedAsWritten();
503 if (attributes.value(QLatin1String(
"hidden-friend")) == QLatin1String(
"true"))
504 fn->setHiddenFriend(
true);
506 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
507 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
510 if (attributes.hasAttribute(QLatin1String(
"trailing_requires")))
511 fn->setTrailingRequiresClause(attributes.value(QLatin1String(
"trailing_requires")).toString());
513 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
516 else if (refness == 2)
519
520
521
522
523
524 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
525 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
527 fn->setOverloadNumber(0);
531
532
533
534
535
536
537 while (reader.readNextStartElement()) {
538 QXmlStreamAttributes childAttributes = reader.attributes();
539 if (reader.name() == QLatin1String(
"parameter")) {
540 QString type = childAttributes.value(QLatin1String(
"type")).toString();
541 QString name = childAttributes.value(QLatin1String(
"name")).toString();
542 QString default_ = childAttributes.value(QLatin1String(
"default")).toString();
543 fn->parameters().append(type, name, default_);
544 }
else if (reader.name() == QLatin1String(
"keyword")) {
546 }
else if (reader.name() == QLatin1String(
"target")) {
549 reader.skipCurrentElement();
553 if (!indexUrl.isEmpty())
554 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
555 else if (!indexUrl.isNull())
556 location
= Location(parent->name().toLower() +
".html");
558 hasReadChildren =
true;
559 }
else if (elementName == QLatin1String(
"variable")) {
561 varNode->setLeftType(attributes.value(
"type").toString());
562 varNode->setStatic((attributes.value(
"static").toString() ==
"true") ?
true :
false);
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");
568 }
else if (elementName == QLatin1String(
"keyword")) {
571 }
else if (elementName == QLatin1String(
"target")) {
574 }
else if (elementName == QLatin1String(
"contents")) {
577 }
else if (elementName == QLatin1String(
"proxy")) {
579 if (!indexUrl.isEmpty())
580 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
581 else if (!indexUrl.isNull())
582 location
= Location(name.toLower() +
".html");
588 if (!href.isEmpty()) {
592 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
595 const QString access = attributes.value(QLatin1String(
"access")).toString();
596 if (access ==
"protected")
598 else if (access ==
"private")
603 if (attributes.hasAttribute(QLatin1String(
"related"))) {
605 m_relatedNodes << node;
608 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
609 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
610 if (threadSafety == QLatin1String(
"non-reentrant"))
612 else if (threadSafety == QLatin1String(
"reentrant"))
614 else if (threadSafety == QLatin1String(
"thread safe"))
621 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
624 QString status = attributes.value(QLatin1String(
"status")).toString();
626 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
628 else if (status == QLatin1String(
"preliminary"))
630 else if (status == QLatin1String(
"internal"))
632 else if (status == QLatin1String(
"ignored"))
637 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
638 if (!physicalModuleName.isEmpty())
639 m_qdb->addToModule(physicalModuleName, node);
641 QString since = attributes.value(QLatin1String(
"since")).toString();
642 if (!since.isEmpty()) {
643 node->setSince(since);
646 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
647 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
651 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
652 if (!groupsAttr.isEmpty()) {
653 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
654 for (
const auto &group : groupNames) {
655 m_qdb->addToGroup(group, node);
660 QSet<QString> emptySet;
662 if (!filePath.isEmpty()) {
667 Doc doc(location, location, QString(), emptySet, emptySet);
668 if (attributes.value(QLatin1String(
"auto-generated")) == QLatin1String(
"true"))
672 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
673 if (!briefAttr.isEmpty()) {
674 node->setReconstitutedBrief(briefAttr);
677 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
680 metaMap->insert(
"sortkey", sortKey);
682 if (!hasReadChildren) {
683 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
684 while (reader.readNextStartElement()) {
686 readIndexSection(reader, parent, indexUrl);
688 readIndexSection(reader, node, indexUrl);
694 while (!reader.isEndElement()) {
695 if (reader.readNext() == QXmlStreamReader::Invalid) {
702 const QXmlStreamAttributes &attributes,
Node *node)
719 QString name = attributes.value(QLatin1String(
"name")).toString();
720 QString title = attributes.value(QLatin1String(
"title")).toString();
721 m_qdb->insertTarget(name, title, type, node, priority);
725
726
727
728
729
730
731
732
733
734
735
736
737
740 for (
const auto &pair : std::as_const(m_basesList)) {
741 const QStringList bases = pair.second.split(QLatin1Char(
','));
742 for (
const auto &base : bases) {
743 QStringList basePath = base.split(QString(
"::"));
744 Node *n = m_qdb->findClassNode(basePath);
746 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
748 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
760 return QLatin1String(
"public");
762 return QLatin1String(
"protected");
764 return QLatin1String(
"private");
768 return QLatin1String(
"public");
775 return QLatin1String(
"deprecated");
777 return QLatin1String(
"preliminary");
779 return QLatin1String(
"active");
781 return QLatin1String(
"internal");
783 return QLatin1String(
"ignored");
787 return QLatin1String(
"active");
794 return QLatin1String(
"non-reentrant");
796 return QLatin1String(
"reentrant");
798 return QLatin1String(
"thread safe");
803 return QLatin1String(
"unspecified");
807
808
811 qsizetype i = m_relatedNodes.indexOf(node);
813 i = m_relatedNodes.size();
814 m_relatedNodes << node;
820
821
822
825 Node *related = m_relatedNodes.value(index);
827 if (adoptiveParent && related) {
836
837
838
839
840
844 for (
const Atom *target : std::as_const(node->doc().targets())) {
845 const QString &title = target->string();
846 const QString &name{Utilities::asAsciiPrintable(title)};
847 writer.writeStartElement(
"target");
848 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
850 writer.writeAttribute(
"title", title);
851 writer.writeEndElement();
855 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
856 const QString &title = keyword->string();
857 const QString &name{Utilities::asAsciiPrintable(title)};
858 writer.writeStartElement(
"keyword");
859 writer.writeAttribute(
"name", name);
861 writer.writeAttribute(
"title", title);
862 writer.writeEndElement();
868
869
870
871
872
873
874
875
884
885
890 QString logicalModuleName;
891 QString logicalModuleVersion;
892 QString qmlFullBaseName;
893 QString baseNameAttr;
894 QString moduleNameAttr;
895 QString moduleVerAttr;
899 nodeName =
"namespace";
914 nodeName =
"qmlenum";
919 logicalModuleName = node->logicalModuleName();
920 baseNameAttr =
"qml-base-type";
921 moduleNameAttr =
"qml-module-name";
922 moduleVerAttr =
"qml-module-version";
923 qmlFullBaseName = node->qmlFullBaseName();
937 nodeName =
"qmlmodule";
938 moduleNameAttr =
"qml-module-name";
939 moduleVerAttr =
"qml-module-version";
940 logicalModuleName = node->logicalModuleName();
941 logicalModuleVersion = node->logicalModuleVersion();
948 nodeName =
"typedef";
951 nodeName =
"property";
954 nodeName =
"variable";
960 nodeName =
"qmlproperty";
963 nodeName =
"qmlproperty";
973 QString objName = node->name();
978 writer.writeStartElement(nodeName);
982 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
985 writer.writeAttribute(
"name", objName);
988 writer.writeAttribute(
"propertygroup",
"true");
993 if (!moduleNameAttr.isEmpty()) {
994 if (!logicalModuleName.isEmpty())
995 writer.writeAttribute(moduleNameAttr, logicalModuleName);
996 if (!logicalModuleVersion.isEmpty())
997 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
999 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
1000 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
1001 else if (!baseNameAttr.isEmpty()) {
1002 const auto &qmlBase =
static_cast<QmlTypeNode *>(node)->qmlBaseName();
1003 if (!qmlBase.isEmpty())
1004 writer.writeAttribute(baseNameAttr, qmlBase);
1009 QString fullName = node->fullDocumentName();
1010 if (fullName != objName)
1011 writer.writeAttribute(
"fullname", fullName);
1012 href = m_gen->fullDocumentLocation(node);
1014 href = node->name();
1020 if (!href.isEmpty())
1021 writer.writeAttribute(
"href", href);
1023 writer.writeAttribute(
"status", getStatusString(node->status()));
1025 writer.writeAttribute(
"access", getAccessString(node->access()));
1027 writer.writeAttribute(
"abstract",
"true");
1030 if (!declLocation.fileName().isEmpty())
1031 writer.writeAttribute(
"location", declLocation.fileName());
1032 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1033 writer.writeAttribute(
"filepath", declLocation.filePath());
1034 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1038 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
1040 if (!node->since().isEmpty())
1041 writer.writeAttribute(
"since", node->since());
1044 writer.writeAttribute(
"documented",
"true");
1046 QStringList groups = m_qdb->groupNamesForNode(node);
1047 if (!groups.isEmpty())
1048 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1051 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
1052 writer.writeAttribute(
"sortkey", sortKey);
1054 QString brief = node
->doc().trimmedBriefText(node->name()).toString();
1060 const auto *classNode =
static_cast<
const ClassNode *>(node);
1061 const QList<RelatedClass> &bases = classNode->baseClasses();
1062 QSet<QString> baseStrings;
1063 for (
const auto &related : bases) {
1064 ClassNode *n = related.m_node;
1066 baseStrings.insert(n->fullName());
1067 else if (!related.m_path.isEmpty())
1068 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
1070 if (!baseStrings.isEmpty()) {
1071 QStringList baseStringsAsList = baseStrings.values();
1072 baseStringsAsList.sort();
1073 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
1075 if (!node->physicalModuleName().isEmpty())
1076 writer.writeAttribute(
"module", node->physicalModuleName());
1077 if (!brief.isEmpty())
1078 writer.writeAttribute(
"brief", brief);
1083 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
1084 if (!headerNode->physicalModuleName().isEmpty())
1085 writer.writeAttribute(
"module", headerNode->physicalModuleName());
1086 if (!brief.isEmpty())
1087 writer.writeAttribute(
"brief", brief);
1088 writer.writeAttribute(
"title", headerNode->title());
1089 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1090 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1093 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1094 if (!namespaceNode->physicalModuleName().isEmpty())
1095 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1096 if (!brief.isEmpty())
1097 writer.writeAttribute(
"brief", brief);
1101 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1102 if (qmlTypeNode->isSingleton())
1103 writer.writeAttribute(
"singleton",
"true");
1104 if (!brief.isEmpty())
1105 writer.writeAttribute(
"brief", brief);
1111 writer.writeAttribute(
"subtype",
"example");
1113 writer.writeAttribute(
"subtype",
"externalpage");
1115 writer.writeAttribute(
"subtype", (
static_cast<PageNode*>(node)->isAttribution() ?
"attribution" :
"page"));
1117 const auto *pageNode =
static_cast<
const PageNode *>(node);
1118 writer.writeAttribute(
"title", pageNode->title());
1119 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1120 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1121 if (!brief.isEmpty())
1122 writer.writeAttribute(
"brief", brief);
1127 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1128 writer.writeAttribute(
"seen", collectionNode->wasSeen() ?
"true" :
"false");
1129 writer.writeAttribute(
"title", collectionNode->title());
1130 if (!collectionNode->subtitle().isEmpty())
1131 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1132 if (!collectionNode->physicalModuleName().isEmpty())
1133 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1134 if (!brief.isEmpty())
1135 writer.writeAttribute(
"brief", brief);
1138 auto *qmlPropertyNode =
static_cast<QmlPropertyNode *>(node);
1139 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1140 writer.writeAttribute(
"attached", qmlPropertyNode->isAttached() ?
"true" :
"false");
1141 writer.writeAttribute(
"writable", qmlPropertyNode->isReadOnly() ?
"false" :
"true");
1142 if (qmlPropertyNode->isRequired())
1143 writer.writeAttribute(
"required",
"true");
1144 if (!brief.isEmpty())
1145 writer.writeAttribute(
"brief", brief);
1148 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1151 writer.writeAttribute(
"bindable",
"true");
1153 if (!propertyNode->isWritable())
1154 writer.writeAttribute(
"writable",
"false");
1156 if (propertyNode->isConstant())
1157 writer.writeAttribute(
"constant",
"true");
1159 writer.writeAttribute(
"dataType", propertyNode->dataType());
1161 if (!brief.isEmpty())
1162 writer.writeAttribute(
"brief", brief);
1164 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1166 for (
const auto *fnNode : propertyNode->functions(role)) {
1167 writer.writeStartElement(PropertyNode::roleName(role));
1168 writer.writeAttribute(
"name", fnNode->name());
1169 writer.writeEndElement();
1174 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1175 writer.writeAttribute(
"type", variableNode->dataType());
1176 writer.writeAttribute(
"static", variableNode->isStatic() ?
"true" :
"false");
1177 if (!brief.isEmpty())
1178 writer.writeAttribute(
"brief", brief);
1182 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1183 if (enumNode->isScoped())
1184 writer.writeAttribute(
"scoped",
"true");
1185 if (enumNode->flagsType())
1186 writer.writeAttribute(
"typedef", enumNode->flagsType()->fullDocumentName());
1187 if (enumNode->isAnonymous())
1188 writer.writeAttribute(
"anonymous",
"true");
1189 const auto &items = enumNode->items();
1190 for (
const auto &item : items) {
1191 writer.writeStartElement(
"value");
1192 writer.writeAttribute(
"name", item.name());
1193 if (node->isEnumType(Genus::CPP))
1194 writer.writeAttribute(
"value", item.value());
1195 if (!item.since().isEmpty())
1196 writer.writeAttribute(
"since", item.since());
1197 writer.writeEndElement();
1201 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1202 if (typedefNode->associatedEnum())
1203 writer.writeAttribute(
"enum", typedefNode->associatedEnum()->fullDocumentName());
1206 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1213 writeTargets(writer, node);
1216
1217
1218
1219
1220
1221
1224 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1226 int level = node
->doc().tableOfContentsLevels()[i];
1228 writer.writeStartElement(
"contents");
1229 writer.writeAttribute(
"name", Tree::refForAtom(item));
1230 writer.writeAttribute(
"title", title);
1231 writer.writeAttribute(
"level", QString::number(level));
1232 writer.writeEndElement();
1238 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1239 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1240 const QString project = Generator::defaultModuleName();
1241 const QString fileExt = m_gen->fileExtension();
1242 const auto &files = exampleNode->files();
1243 const auto &images = exampleNode->images();
1244 for (
const QString &file : files) {
1245 writer.writeStartElement(
"page");
1246 writer.writeAttribute(
"name", file);
1247 writer.writeAttribute(
"href", Utilities::linkForExampleFile(file, project, fileExt));
1248 writer.writeAttribute(
"status",
"active");
1249 writer.writeAttribute(
"subtype",
"file");
1250 writer.writeAttribute(
"title",
"");
1251 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::File));
1252 writer.writeAttribute(
"subtitle", file);
1253 writer.writeEndElement();
1255 for (
const QString &file : images) {
1256 writer.writeStartElement(
"page");
1257 writer.writeAttribute(
"name", file);
1258 writer.writeAttribute(
"href", Utilities::linkForExampleFile(file, project, fileExt));
1259 writer.writeAttribute(
"status",
"active");
1260 writer.writeAttribute(
"subtype",
"image");
1261 writer.writeAttribute(
"title",
"");
1262 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::Image));
1263 writer.writeAttribute(
"subtitle", file);
1264 writer.writeEndElement();
1276
1277
1278
1281 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1286 const QString objName = fn->name();
1287 writer.writeStartElement(
"function");
1288 writer.writeAttribute(
"name", objName);
1290 const QString fullName = fn->fullDocumentName();
1291 if (fullName != objName)
1292 writer.writeAttribute(
"fullname", fullName);
1293 const QString href = m_gen->fullDocumentLocation(fn);
1294 if (!href.isEmpty())
1295 writer.writeAttribute(
"href", href);
1297 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1298 writer.writeAttribute(
"status", getStatusString(fn->status()));
1299 writer.writeAttribute(
"access", getAccessString(fn->access()));
1302 if (!declLocation.fileName().isEmpty())
1303 writer.writeAttribute(
"location", declLocation.fileName());
1304 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1305 writer.writeAttribute(
"filepath", declLocation.filePath());
1306 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1310 writer.writeAttribute(
"documented",
"true");
1312 writer.writeAttribute(
"auto-generated",
"true");
1314 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1315 if (!fn->since().isEmpty())
1316 writer.writeAttribute(
"since", fn->since());
1318 const QString brief = fn
->doc().trimmedBriefText(fn->name()).toString();
1319 writer.writeAttribute(
"meta", fn->metanessString());
1322 writer.writeAttribute(
"virtual", fn->virtualness());
1325 writer.writeAttribute(
"const",
"true");
1327 writer.writeAttribute(
"static",
"true");
1329 writer.writeAttribute(
"final",
"true");
1331 writer.writeAttribute(
"override",
"true");
1333 writer.writeAttribute(
"explicit",
"true");
1335 writer.writeAttribute(
"constexpr",
"true");
1337 writer.writeAttribute(
"explicitly-defaulted",
"true");
1339 writer.writeAttribute(
"deleted",
"true");
1341 writer.writeAttribute(
"hidden-friend",
"true");
1343 if (
auto noexcept_info = fn->getNoexcept()) {
1344 writer.writeAttribute(
"noexcept",
"true");
1345 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1348 if (
const auto &trailing_requires = fn->trailingRequiresClause(); trailing_requires && !trailing_requires->isEmpty())
1349 writer.writeAttribute(
"trailing_requires", *trailing_requires);
1352
1353
1354
1355
1356
1358 writer.writeAttribute(
"overload",
"true");
1359 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1362 writer.writeAttribute(
"refness", QString::number(1));
1364 writer.writeAttribute(
"refness", QString::number(2));
1366 QStringList associatedProperties;
1367 for (
const auto *node : fn->associatedProperties()) {
1368 associatedProperties << node->name();
1370 associatedProperties.sort();
1371 writer.writeAttribute(
"associated-property",
1372 associatedProperties.join(QLatin1Char(
',')));
1376 writer.writeAttribute(
"attached",
"true");
1379 const auto &return_type = fn->returnType();
1380 if (!return_type.isEmpty())
1381 writer.writeAttribute(
"type",
std::move(return_type));
1383 const auto &declared_return_type = fn->declaredReturnType();
1384 if (declared_return_type.has_value())
1385 writer.writeAttribute(
"declaredtype", declared_return_type.value());
1388 if (!brief.isEmpty())
1389 writer.writeAttribute(
"brief", brief);
1392
1393
1394
1395
1396 const QString signature = appendAttributesToSignature(fn);
1397 writer.writeAttribute(
"signature", signature);
1399 QStringList groups = m_qdb->groupNamesForNode(fn);
1400 if (!groups.isEmpty())
1401 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1406 writer.writeStartElement(
"parameter");
1407 writer.writeAttribute(
"type", parameter.type());
1408 writer.writeAttribute(
"name", parameter.name());
1409 writer.writeAttribute(
"default", parameter.defaultValue());
1410 writer.writeEndElement();
1413 writeTargets(writer, fn);
1419 writer.writeEndElement();
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1438 signature +=
" final";
1440 signature +=
" override";
1442 signature +=
" = 0";
1443 if (
const auto &req = fn->trailingRequiresClause(); req && !req->isEmpty())
1444 signature +=
" requires " + *req;
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1462 for (
auto functions : std::as_const(aggregate->functionMap())) {
1463 std::for_each(functions.begin(), functions.end(),
1464 [
this,&writer](FunctionNode *fn) {
1465 generateFunctionSection(writer, fn);
1472
1473
1474
1475
1479 Q_ASSERT(generator);
1482
1483
1484
1489 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1494 if (generateIndexSection(writer, node, generator, post)) {
1496 auto *aggregate =
static_cast<Aggregate *>(node);
1498 generateFunctionSections(writer, aggregate);
1499 const auto &nonFunctionList = aggregate->nonfunctionList();
1500 for (
auto *node : nonFunctionList)
1501 generateIndexSections(writer, node, generator, post);
1504 if (node ==
root_) {
1506
1507
1508
1509
1510
1511
1513 if (!groups.isEmpty()) {
1514 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1515 if (generateIndexSection(writer, it.value(), generator, post))
1516 writer.writeEndElement();
1521 if (!modules.isEmpty()) {
1522 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1523 if (generateIndexSection(writer, it.value(), generator, post))
1524 writer.writeEndElement();
1529 if (!qmlModules.isEmpty()) {
1530 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1531 if (generateIndexSection(writer, it.value(), generator, post))
1532 writer.writeEndElement();
1536 for (
auto *p : m_qdb->primaryTree()->proxies()) {
1537 if (generateIndexSection(writer, p, generator, post)) {
1538 auto aggregate =
static_cast<Aggregate *>(p);
1539 generateFunctionSections(writer, aggregate);
1540 for (
auto *n : aggregate->nonfunctionList())
1541 generateIndexSections(writer, n, generator, post);
1542 writer.writeEndElement();
1547 writer.writeEndElement();
1552
1553
1554
1555
1556
1557
1558void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1559 const QString &title,
const Generator *hrefGenerator)
1561 Q_ASSERT(hrefGenerator);
1562 m_gen = hrefGenerator;
1564 QFile file(fileName);
1565 if (!file.open(QFile::WriteOnly | QFile::Text))
1568 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1569 m_relatedNodes.clear();
1570 QXmlStreamWriter writer(&file);
1571 writer.setAutoFormatting(
true);
1572 writer.writeStartDocument();
1573 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1575 writer.writeStartElement(
"INDEX");
1576 writer.writeAttribute(
"url", url);
1577 writer.writeAttribute(
"title", title);
1578 writer.writeAttribute(
"version", m_qdb->version());
1579 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1583 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1585 generateIndexSections(writer,
root_, m_gen,
nullptr);
1587 writer.writeEndElement();
1588 writer.writeEndElement();
1589 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
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.
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.