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(
"qmlmodule")) {
340 auto *collectionNode = m_qdb->addQmlModule(name);
341 const QStringList info = QStringList()
343 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
344 collectionNode->setLogicalModuleInfo(info);
345 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
346 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
347 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
348 collectionNode->markSeen();
349 node = collectionNode;
350 }
else if (elementName == QLatin1String(
"page")) {
352 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
353 if (attr == QLatin1String(
"attribution")) {
355 }
else if (attr == QLatin1String(
"example")) {
357 }
else if (attr == QLatin1String(
"file")) {
359 }
else if (attr == QLatin1String(
"image")) {
361 }
else if (attr == QLatin1String(
"page")) {
363 }
else if (attr == QLatin1String(
"externalpage")) {
369 auto *exampleNode =
static_cast<ExampleNode *>(current);
371 exampleNode->appendFile(name);
374 exampleNode->appendImage(name);
384 pageNode =
new PageNode(parent, name);
388 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
390 if (attributes.hasAttribute(QLatin1String(
"location")))
391 name = attributes.value(QLatin1String(
"location")).toString();
393 if (!indexUrl.isEmpty())
394 location
= Location(indexUrl + QLatin1Char(
'/') + name);
395 else if (!indexUrl.isNull())
400 }
else if (parent && (elementName == QLatin1String(
"enum") || elementName == QLatin1String(
"qmlenum"))) {
402 if (elementName == QLatin1String(
"enum"))
403 enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
407 if (!indexUrl.isEmpty())
408 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
409 else if (!indexUrl.isNull())
410 location
= Location(parent->name().toLower() +
".html");
412 if (attributes.value(
"anonymous") ==
"true")
415 while (reader.readNextStartElement()) {
416 QXmlStreamAttributes childAttributes = reader.attributes();
417 if (reader.name() == QLatin1String(
"value")) {
418 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
419 childAttributes.value(QLatin1String(
"value")).toString(),
420 childAttributes.value(QLatin1String(
"since")).toString()
423 }
else if (reader.name() == QLatin1String(
"keyword")) {
425 }
else if (reader.name() == QLatin1String(
"target")) {
428 reader.skipCurrentElement();
433 hasReadChildren =
true;
434 }
else if (parent && elementName == QLatin1String(
"typedef")) {
436 if (attributes.hasAttribute(
"aliasedtype"))
437 typedefNode =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
442 if (attributes.hasAttribute(
"enum")) {
443 auto path = attributes.value(QLatin1String(
"enum")).toString();
444 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
446 const EnumNode *n =
static_cast<
const EnumNode *>(enode);
452 if (!indexUrl.isEmpty())
453 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
454 else if (!indexUrl.isNull())
455 location
= Location(parent->name().toLower() +
".html");
456 }
else if (parent && elementName == QLatin1String(
"property")) {
459 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
462 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
463 propNode->setDataType(attributes.value(QLatin1String(
"dataType")).toString());
465 if (attributes.value(QLatin1String(
"constant")) == QLatin1String(
"true"))
466 propNode->setConstant();
468 if (!indexUrl.isEmpty())
469 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
470 else if (!indexUrl.isNull())
471 location
= Location(parent->name().toLower() +
".html");
473 }
else if (parent && elementName == QLatin1String(
"function")) {
474 QString t = attributes.value(QLatin1String(
"meta")).toString();
475 bool attached =
false;
478 metaness = FunctionNode::getMetaness(t);
479 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
481 auto *fn =
new FunctionNode(metaness, parent, name, attached);
483 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
485 const auto &declaredTypeAttr = attributes.value(QLatin1String(
"declaredtype"));
486 if (!declaredTypeAttr.isEmpty())
487 fn->setDeclaredReturnType(declaredTypeAttr.toString());
489 if (fn->isCppNode()) {
490 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
491 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
492 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
493 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
494 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
496 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
499 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
502 if (attributes.value(QLatin1String(
"explicitly-defaulted")) == QLatin1String(
"true"))
503 fn->markExplicitlyDefaulted();
505 if (attributes.value(QLatin1String(
"deleted")) == QLatin1String(
"true"))
506 fn->markDeletedAsWritten();
507 if (attributes.value(QLatin1String(
"hidden-friend")) == QLatin1String(
"true"))
508 fn->setHiddenFriend(
true);
510 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
511 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
514 if (attributes.hasAttribute(QLatin1String(
"trailing_requires")))
515 fn->setTrailingRequiresClause(attributes.value(QLatin1String(
"trailing_requires")).toString());
517 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
520 else if (refness == 2)
523
524
525
526
527
528 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
529 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
531 fn->setOverloadNumber(0);
535
536
537
538
539
540
541 while (reader.readNextStartElement()) {
542 QXmlStreamAttributes childAttributes = reader.attributes();
543 if (reader.name() == QLatin1String(
"parameter")) {
544 QString type = childAttributes.value(QLatin1String(
"type")).toString();
545 QString name = childAttributes.value(QLatin1String(
"name")).toString();
546 QString default_ = childAttributes.value(QLatin1String(
"default")).toString();
547 fn->parameters().append(type, name, default_);
548 }
else if (reader.name() == QLatin1String(
"keyword")) {
550 }
else if (reader.name() == QLatin1String(
"target")) {
553 reader.skipCurrentElement();
557 if (!indexUrl.isEmpty())
558 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
559 else if (!indexUrl.isNull())
560 location
= Location(parent->name().toLower() +
".html");
562 hasReadChildren =
true;
563 }
else if (parent && elementName == QLatin1String(
"variable")) {
565 varNode->setLeftType(attributes.value(
"type").toString());
566 varNode->setStatic((attributes.value(
"static").toString() ==
"true") ?
true :
false);
568 if (!indexUrl.isEmpty())
569 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
570 else if (!indexUrl.isNull())
571 location
= Location(parent->name().toLower() +
".html");
572 }
else if (elementName == QLatin1String(
"keyword")) {
575 }
else if (elementName == QLatin1String(
"target")) {
578 }
else if (elementName == QLatin1String(
"contents")) {
581 }
else if (parent && elementName == QLatin1String(
"proxy")) {
583 if (!indexUrl.isEmpty())
584 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
585 else if (!indexUrl.isNull())
586 location
= Location(name.toLower() +
".html");
592 if (!href.isEmpty()) {
596 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
599 const QString access = attributes.value(QLatin1String(
"access")).toString();
600 if (access ==
"protected")
602 else if (access ==
"private")
607 if (attributes.hasAttribute(QLatin1String(
"related"))) {
609 m_relatedNodes << node;
612 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
613 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
614 if (threadSafety == QLatin1String(
"non-reentrant"))
616 else if (threadSafety == QLatin1String(
"reentrant"))
618 else if (threadSafety == QLatin1String(
"thread safe"))
625 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
628 QString status = attributes.value(QLatin1String(
"status")).toString();
630 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
632 else if (status == QLatin1String(
"preliminary"))
634 else if (status == QLatin1String(
"internal"))
636 else if (status == QLatin1String(
"internal-auto"))
638 else if (status == QLatin1String(
"ignored"))
643 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
644 if (!physicalModuleName.isEmpty())
645 m_qdb->addToModule(physicalModuleName, node);
647 QString since = attributes.value(QLatin1String(
"since")).toString();
648 if (!since.isEmpty()) {
649 node->setSince(since);
652 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
653 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
657 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
658 if (!groupsAttr.isEmpty()) {
659 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
660 for (
const auto &group : groupNames) {
661 m_qdb->addToGroup(group, node);
666 QSet<QString> emptySet;
668 if (!filePath.isEmpty()) {
673 Doc doc(location, location, QString(), emptySet, emptySet);
674 if (attributes.value(QLatin1String(
"auto-generated")) == QLatin1String(
"true"))
678 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
679 if (!briefAttr.isEmpty()) {
680 node->setReconstitutedBrief(briefAttr);
683 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
686 metaMap->insert(
"sortkey", sortKey);
688 if (!hasReadChildren) {
689 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
690 while (reader.readNextStartElement()) {
692 readIndexSection(reader, parent, indexUrl);
694 readIndexSection(reader, node, indexUrl);
700 while (!reader.isEndElement()) {
701 if (reader.readNext() == QXmlStreamReader::Invalid) {
708 const QXmlStreamAttributes &attributes,
Node *node)
725 QString name = attributes.value(QLatin1String(
"name")).toString();
726 QString title = attributes.value(QLatin1String(
"title")).toString();
727 m_qdb->insertTarget(name, title, type, node, priority);
731
732
733
734
735
736
737
738
739
740
741
742
743
746 for (
const auto &pair : std::as_const(m_basesList)) {
747 const QStringList bases = pair.second.split(QLatin1Char(
','));
748 for (
const auto &base : bases) {
749 QStringList basePath = base.split(QString(
"::"));
750 Node *n = m_qdb->findClassNode(basePath);
752 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
754 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
766 return QLatin1String(
"public");
767 case Access::Protected:
768 return QLatin1String(
"protected");
769 case Access::Private:
770 return QLatin1String(
"private");
774 return QLatin1String(
"public");
781 return QLatin1String(
"deprecated");
783 return QLatin1String(
"preliminary");
785 return QLatin1String(
"active");
787 return QLatin1String(
"internal");
789 return QLatin1String(
"internal-auto");
791 return QLatin1String(
"ignored");
795 return QLatin1String(
"active");
802 return QLatin1String(
"non-reentrant");
804 return QLatin1String(
"reentrant");
806 return QLatin1String(
"thread safe");
811 return QLatin1String(
"unspecified");
815
816
819 qsizetype i = m_relatedNodes.indexOf(node);
821 i = m_relatedNodes.size();
822 m_relatedNodes << node;
828
829
830
833 Node *related = m_relatedNodes.value(index);
835 if (adoptiveParent && related) {
844
845
846
847
848
852 for (
const Atom *target : std::as_const(node->doc().targets())) {
853 const QString &title = target->string();
854 const QString &name{TextUtils::asAsciiPrintable(title)};
855 writer.writeStartElement(
"target");
856 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
858 writer.writeAttribute(
"title", title);
859 writer.writeEndElement();
863 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
864 const QString &title = keyword->string();
865 const QString &name{TextUtils::asAsciiPrintable(title)};
866 writer.writeStartElement(
"keyword");
867 writer.writeAttribute(
"name", name);
869 writer.writeAttribute(
"title", title);
870 writer.writeEndElement();
876
877
878
879
880
881
882
883
892
893
898 QString logicalModuleName;
899 QString logicalModuleVersion;
900 QString qmlFullBaseName;
901 QString baseNameAttr;
902 QString moduleNameAttr;
903 QString moduleVerAttr;
907 nodeName =
"namespace";
922 nodeName =
"qmlenum";
927 logicalModuleName = node->logicalModuleName();
928 baseNameAttr =
"qml-base-type";
929 moduleNameAttr =
"qml-module-name";
930 moduleVerAttr =
"qml-module-version";
931 qmlFullBaseName = node->qmlFullBaseName();
945 nodeName =
"qmlmodule";
946 moduleNameAttr =
"qml-module-name";
947 moduleVerAttr =
"qml-module-version";
948 logicalModuleName = node->logicalModuleName();
949 logicalModuleVersion = node->logicalModuleVersion();
956 nodeName =
"typedef";
959 nodeName =
"property";
962 nodeName =
"variable";
968 nodeName =
"qmlproperty";
971 nodeName =
"qmlproperty";
981 QString objName = node->name();
986 writer.writeStartElement(nodeName);
990 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
993 writer.writeAttribute(
"name", objName);
996 writer.writeAttribute(
"propertygroup",
"true");
1001 if (!moduleNameAttr.isEmpty()) {
1002 if (!logicalModuleName.isEmpty())
1003 writer.writeAttribute(moduleNameAttr, logicalModuleName);
1004 if (!logicalModuleVersion.isEmpty())
1005 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
1007 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
1008 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
1009 else if (!baseNameAttr.isEmpty()) {
1010 const auto &qmlBase =
static_cast<QmlTypeNode *>(node)->qmlBaseName();
1011 if (!qmlBase.isEmpty())
1012 writer.writeAttribute(baseNameAttr, qmlBase);
1017 QString fullName = node->fullDocumentName();
1018 if (fullName != objName)
1019 writer.writeAttribute(
"fullname", fullName);
1020 href = m_gen->fullDocumentLocation(node);
1022 href = node->name();
1028 if (!href.isEmpty())
1029 writer.writeAttribute(
"href", href);
1031 writer.writeAttribute(
"status", getStatusString(node->status()));
1033 writer.writeAttribute(
"access", getAccessString(node->access()));
1035 writer.writeAttribute(
"abstract",
"true");
1038 if (!declLocation.fileName().isEmpty())
1039 writer.writeAttribute(
"location", declLocation.fileName());
1040 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1041 writer.writeAttribute(
"filepath", declLocation.filePath());
1042 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1046 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
1048 if (!node->since().isEmpty())
1049 writer.writeAttribute(
"since", node->since());
1052 writer.writeAttribute(
"documented",
"true");
1054 QStringList groups = m_qdb->groupNamesForNode(node);
1055 if (!groups.isEmpty())
1056 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1059 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
1060 writer.writeAttribute(
"sortkey", sortKey);
1062 QString brief = node
->doc().trimmedBriefText(node->name()).toString();
1068 const auto *classNode =
static_cast<
const ClassNode *>(node);
1069 const QList<RelatedClass> &bases = classNode->baseClasses();
1070 QSet<QString> baseStrings;
1071 for (
const auto &related : bases) {
1072 ClassNode *n = related.m_node;
1074 baseStrings.insert(n->fullName());
1075 else if (!related.m_path.isEmpty())
1076 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
1078 if (!baseStrings.isEmpty()) {
1079 QStringList baseStringsAsList = baseStrings.values();
1080 baseStringsAsList.sort();
1081 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
1083 if (!node->physicalModuleName().isEmpty())
1084 writer.writeAttribute(
"module", node->physicalModuleName());
1085 if (!brief.isEmpty())
1086 writer.writeAttribute(
"brief", brief);
1091 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
1092 if (!headerNode->physicalModuleName().isEmpty())
1093 writer.writeAttribute(
"module", headerNode->physicalModuleName());
1094 if (!brief.isEmpty())
1095 writer.writeAttribute(
"brief", brief);
1096 writer.writeAttribute(
"title", headerNode->title());
1097 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1098 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1101 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1102 if (!namespaceNode->physicalModuleName().isEmpty())
1103 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1104 if (!brief.isEmpty())
1105 writer.writeAttribute(
"brief", brief);
1109 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1110 if (qmlTypeNode->isSingleton())
1111 writer.writeAttribute(
"singleton",
"true");
1112 if (qmlTypeNode->isUncreatable())
1113 writer.writeAttribute(
"uncreatable",
"true");
1114 if (!brief.isEmpty())
1115 writer.writeAttribute(
"brief", brief);
1121 writer.writeAttribute(
"subtype",
"example");
1123 writer.writeAttribute(
"subtype",
"externalpage");
1125 writer.writeAttribute(
"subtype", (
static_cast<PageNode*>(node)->isAttribution() ?
"attribution" :
"page"));
1127 const auto *pageNode =
static_cast<
const PageNode *>(node);
1128 writer.writeAttribute(
"title", pageNode->title());
1129 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1130 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1131 if (!brief.isEmpty())
1132 writer.writeAttribute(
"brief", brief);
1137 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1138 writer.writeAttribute(
"seen", collectionNode->wasSeen() ?
"true" :
"false");
1139 writer.writeAttribute(
"title", collectionNode->title());
1140 if (!collectionNode->subtitle().isEmpty())
1141 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1142 if (!collectionNode->physicalModuleName().isEmpty())
1143 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1144 if (!brief.isEmpty())
1145 writer.writeAttribute(
"brief", brief);
1148 auto *qmlPropertyNode =
static_cast<QmlPropertyNode *>(node);
1149 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1150 writer.writeAttribute(
"attached", qmlPropertyNode->isAttached() ?
"true" :
"false");
1151 writer.writeAttribute(
"writable", qmlPropertyNode->isReadOnly() ?
"false" :
"true");
1152 if (qmlPropertyNode->isRequired())
1153 writer.writeAttribute(
"required",
"true");
1154 if (!brief.isEmpty())
1155 writer.writeAttribute(
"brief", brief);
1158 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1161 writer.writeAttribute(
"bindable",
"true");
1163 if (!propertyNode->isWritable())
1164 writer.writeAttribute(
"writable",
"false");
1166 if (propertyNode->isConstant())
1167 writer.writeAttribute(
"constant",
"true");
1169 writer.writeAttribute(
"dataType", propertyNode->dataType());
1171 if (!brief.isEmpty())
1172 writer.writeAttribute(
"brief", brief);
1174 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1176 for (
const auto *fnNode : propertyNode->functions(role)) {
1177 writer.writeStartElement(PropertyNode::roleName(role));
1178 writer.writeAttribute(
"name", fnNode->name());
1179 writer.writeEndElement();
1184 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1185 writer.writeAttribute(
"type", variableNode->dataType());
1186 writer.writeAttribute(
"static", variableNode->isStatic() ?
"true" :
"false");
1187 if (!brief.isEmpty())
1188 writer.writeAttribute(
"brief", brief);
1192 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1193 if (enumNode->isScoped())
1194 writer.writeAttribute(
"scoped",
"true");
1195 if (enumNode->flagsType())
1196 writer.writeAttribute(
"typedef", enumNode->flagsType()->fullDocumentName());
1197 if (enumNode->isAnonymous())
1198 writer.writeAttribute(
"anonymous",
"true");
1199 const auto &items = enumNode->items();
1200 for (
const auto &item : items) {
1201 writer.writeStartElement(
"value");
1202 writer.writeAttribute(
"name", item.name());
1203 if (node->isEnumType(Genus::CPP))
1204 writer.writeAttribute(
"value", item.value());
1205 if (!item.since().isEmpty())
1206 writer.writeAttribute(
"since", item.since());
1207 writer.writeEndElement();
1211 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1212 if (typedefNode->associatedEnum())
1213 writer.writeAttribute(
"enum", typedefNode->associatedEnum()->fullDocumentName());
1216 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1223 writeTargets(writer, node);
1226
1227
1228
1229
1230
1231
1234 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1236 int level = node
->doc().tableOfContentsLevels()[i];
1238 writer.writeStartElement(
"contents");
1239 writer.writeAttribute(
"name", Tree::refForAtom(item));
1240 writer.writeAttribute(
"title", title);
1241 writer.writeAttribute(
"level", QString::number(level));
1242 writer.writeEndElement();
1248 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1249 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1250 const QString project = Generator::defaultModuleName();
1251 const QString fileExt = m_gen->fileExtension();
1252 const auto &files = exampleNode->files();
1253 const auto &images = exampleNode->images();
1254 for (
const QString &file : files) {
1255 writer.writeStartElement(
"page");
1256 writer.writeAttribute(
"name", file);
1257 writer.writeAttribute(
"href", Utilities::linkForExampleFile(file, project, fileExt));
1258 writer.writeAttribute(
"status",
"active");
1259 writer.writeAttribute(
"subtype",
"file");
1260 writer.writeAttribute(
"title",
"");
1261 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::File));
1262 writer.writeAttribute(
"subtitle", file);
1263 writer.writeEndElement();
1265 for (
const QString &file : images) {
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",
"image");
1271 writer.writeAttribute(
"title",
"");
1272 writer.writeAttribute(
"fulltitle", Utilities::exampleFileTitle(file, Utilities::ExampleFileKind::Image));
1273 writer.writeAttribute(
"subtitle", file);
1274 writer.writeEndElement();
1286
1287
1288
1291 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1296 const QString objName = fn->name();
1297 writer.writeStartElement(
"function");
1298 writer.writeAttribute(
"name", objName);
1300 const QString fullName = fn->fullDocumentName();
1301 if (fullName != objName)
1302 writer.writeAttribute(
"fullname", fullName);
1303 const QString href = m_gen->fullDocumentLocation(fn);
1304 if (!href.isEmpty())
1305 writer.writeAttribute(
"href", href);
1307 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1308 writer.writeAttribute(
"status", getStatusString(fn->status()));
1309 writer.writeAttribute(
"access", getAccessString(fn->access()));
1312 if (!declLocation.fileName().isEmpty())
1313 writer.writeAttribute(
"location", declLocation.fileName());
1314 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1315 writer.writeAttribute(
"filepath", declLocation.filePath());
1316 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1320 writer.writeAttribute(
"documented",
"true");
1322 writer.writeAttribute(
"auto-generated",
"true");
1324 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1325 if (!fn->since().isEmpty())
1326 writer.writeAttribute(
"since", fn->since());
1328 const QString brief = fn
->doc().trimmedBriefText(fn->name()).toString();
1329 writer.writeAttribute(
"meta", fn->metanessString());
1332 writer.writeAttribute(
"virtual", fn->virtualness());
1335 writer.writeAttribute(
"const",
"true");
1337 writer.writeAttribute(
"static",
"true");
1339 writer.writeAttribute(
"final",
"true");
1341 writer.writeAttribute(
"override",
"true");
1343 writer.writeAttribute(
"explicit",
"true");
1345 writer.writeAttribute(
"constexpr",
"true");
1347 writer.writeAttribute(
"explicitly-defaulted",
"true");
1349 writer.writeAttribute(
"deleted",
"true");
1351 writer.writeAttribute(
"hidden-friend",
"true");
1353 if (
auto noexcept_info = fn->getNoexcept()) {
1354 writer.writeAttribute(
"noexcept",
"true");
1355 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1358 if (
const auto &trailing_requires = fn->trailingRequiresClause(); trailing_requires && !trailing_requires->isEmpty())
1359 writer.writeAttribute(
"trailing_requires", *trailing_requires);
1362
1363
1364
1365
1366
1368 writer.writeAttribute(
"overload",
"true");
1369 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1372 writer.writeAttribute(
"refness", QString::number(1));
1374 writer.writeAttribute(
"refness", QString::number(2));
1376 QStringList associatedProperties;
1377 for (
const auto *node : fn->associatedProperties()) {
1378 associatedProperties << node->name();
1380 associatedProperties.sort();
1381 writer.writeAttribute(
"associated-property",
1382 associatedProperties.join(QLatin1Char(
',')));
1386 writer.writeAttribute(
"attached",
"true");
1389 const auto &return_type = fn->returnType();
1390 if (!return_type.isEmpty())
1391 writer.writeAttribute(
"type",
std::move(return_type));
1393 const auto &declared_return_type = fn->declaredReturnType();
1394 if (declared_return_type.has_value())
1395 writer.writeAttribute(
"declaredtype", declared_return_type.value());
1398 if (!brief.isEmpty())
1399 writer.writeAttribute(
"brief", brief);
1402
1403
1404
1405
1406 const QString signature = appendAttributesToSignature(fn);
1407 writer.writeAttribute(
"signature", signature);
1409 QStringList groups = m_qdb->groupNamesForNode(fn);
1410 if (!groups.isEmpty())
1411 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1416 writer.writeStartElement(
"parameter");
1417 writer.writeAttribute(
"type", parameter.type());
1418 writer.writeAttribute(
"name", parameter.name());
1419 writer.writeAttribute(
"default", parameter.defaultValue());
1420 writer.writeEndElement();
1423 writeTargets(writer, fn);
1429 writer.writeEndElement();
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1448 signature +=
" final";
1450 signature +=
" override";
1452 signature +=
" = 0";
1453 if (
const auto &req = fn->trailingRequiresClause(); req && !req->isEmpty())
1454 signature +=
" requires " + *req;
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1472 for (
auto functions : std::as_const(aggregate->functionMap())) {
1473 std::for_each(functions.begin(), functions.end(),
1474 [
this,&writer](FunctionNode *fn) {
1475 generateFunctionSection(writer, fn);
1482
1483
1484
1485
1489 Q_ASSERT(generator);
1492
1493
1494
1499 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1504 if (generateIndexSection(writer, node, generator, post)) {
1506 auto *aggregate =
static_cast<Aggregate *>(node);
1508 generateFunctionSections(writer, aggregate);
1509 const auto &nonFunctionList = aggregate->nonfunctionList();
1510 for (
auto *node : nonFunctionList)
1511 generateIndexSections(writer, node, generator, post);
1514 if (node ==
root_) {
1516
1517
1518
1519
1520
1521
1523 if (!groups.isEmpty()) {
1524 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1525 if (generateIndexSection(writer, it.value(), generator, post))
1526 writer.writeEndElement();
1531 if (!modules.isEmpty()) {
1532 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1533 if (generateIndexSection(writer, it.value(), generator, post))
1534 writer.writeEndElement();
1539 if (!qmlModules.isEmpty()) {
1540 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1541 if (generateIndexSection(writer, it.value(), generator, post))
1542 writer.writeEndElement();
1546 for (
auto *p : m_qdb->primaryTree()->proxies()) {
1547 if (generateIndexSection(writer, p, generator, post)) {
1548 auto aggregate =
static_cast<Aggregate *>(p);
1549 generateFunctionSections(writer, aggregate);
1550 for (
auto *n : aggregate->nonfunctionList())
1551 generateIndexSections(writer, n, generator, post);
1552 writer.writeEndElement();
1557 writer.writeEndElement();
1562
1563
1564
1565
1566
1567
1568void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1569 const QString &title,
const Generator *hrefGenerator)
1571 Q_ASSERT(hrefGenerator);
1572 m_gen = hrefGenerator;
1574 QFile file(fileName);
1575 if (!file.open(QFile::WriteOnly | QFile::Text))
1578 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1579 m_relatedNodes.clear();
1580 QXmlStreamWriter writer(&file);
1581 writer.setAutoFormatting(
true);
1582 writer.writeStartDocument();
1583 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1585 writer.writeStartElement(
"INDEX");
1586 writer.writeAttribute(
"url", url);
1587 writer.writeAttribute(
"title", title);
1588 writer.writeAttribute(
"version", m_qdb->version());
1589 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1593 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1595 generateIndexSections(writer,
root_, m_gen,
nullptr);
1597 writer.writeEndElement();
1598 writer.writeEndElement();
1599 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.