17#include <QtCore/qregularexpression.h>
22using namespace Qt::StringLiterals;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
63
64
65
66
67
68
71 for (
auto *entry : m_searchOrder)
74 m_searchOrder.clear();
75 m_indexSearchOrder.clear();
76 m_moduleNames.clear();
77 m_primaryTree =
nullptr;
81
82
83
84
88 return (!searchOrder().isEmpty() ? searchOrder()[0] :
nullptr);
92
93
94
95
99 return (m_currentIndex < searchOrder().size() ? searchOrder()[m_currentIndex] :
nullptr);
103
104
105
106
109
110
111
112
113
114
115
116
117void QDocForest::setPrimaryTree(
const QString &t)
119 QString T = t.toLower();
120 m_primaryTree = findTree(T);
122 if (m_primaryTree ==
nullptr)
123 qCCritical(lcQdoc) <<
"Error: Could not set primary tree to" << t;
127
128
129
130void QDocForest::setSearchOrder(
const QStringList &t)
132 if (!m_searchOrder.isEmpty())
136 m_searchOrder.reserve(m_forest.size() + 1);
137 m_searchOrder.clear();
138 m_moduleNames.reserve(m_forest.size() + 1);
139 m_moduleNames.clear();
142 QString primaryName = primaryTree()->physicalModuleName();
143 m_searchOrder.append(m_primaryTree);
144 m_moduleNames.append(primaryName);
145 m_forest.remove(primaryName);
147 for (
const QString &m : t) {
148 if (primaryName != m) {
149 auto it = m_forest.find(m);
150 if (it != m_forest.end()) {
151 m_searchOrder.append(it.value());
152 m_moduleNames.append(m);
158
159
160
161
162 if (!m_forest.isEmpty()) {
163 for (
auto it = m_forest.begin(); it != m_forest.end(); ++it) {
164 m_searchOrder.append(it.value());
165 m_moduleNames.append(it.key());
171
172
173
174
175
176
177
178 for (
int i = 0; i < m_searchOrder.size(); ++i) {
179 if (!m_forest.contains(m_moduleNames.at(i))) {
180 m_forest.insert(m_moduleNames.at(i), m_searchOrder.at(i));
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
212 if (m_searchOrder.isEmpty())
213 return indexSearchOrder();
214 return m_searchOrder;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232const QList<Tree *> &
QDocForest::indexSearchOrder()
234 if (m_forest.size() > m_indexSearchOrder.size())
235 m_indexSearchOrder.prepend(m_primaryTree);
236 return m_indexSearchOrder;
240
241
242
243
246 m_primaryTree =
new Tree(module, m_qdb);
247 m_forest.insert(module.toLower(), m_primaryTree);
248 return m_primaryTree->root();
252
253
254
255void QDocForest::newPrimaryTree(
const QString &module)
257 m_primaryTree =
new Tree(module, m_qdb);
261
262
263
264
265
266
267
268
269
270
271
272
273
274const Node *
QDocForest::findNodeForTarget(QStringList &targetPath,
const Node *relative,
275 Genus genus, QString &ref,
int findFlags)
279 QString entity = targetPath.takeFirst();
280 QStringList entityPath = entity.split(
"::");
283 if (!targetPath.isEmpty())
284 target = targetPath.takeFirst();
287 const Node *tocNode =
nullptr;
288 for (
const auto *tree : searchOrder()) {
289 const Node *n = tree->findNodeForTarget(entityPath, target, relative, flags, genus, ref, &type);
292 if (type != TargetRec::Contents)
303
304
305
306
307
308
309
310
311
316 for (
const auto *tree : searchOrder()) {
317 const FunctionNode *fn = tree->findFunctionNode(path, parameters, relative, genus);
326
327
328
329
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
368
369
370
373 if (s_qdocDB ==
nullptr) {
381
382
385 if (s_qdocDB !=
nullptr) {
392
393
394
395
396
397
398
399
400
401
402
403
404
407 s_typeNodeMap.insert(
"accepted",
nullptr);
408 s_typeNodeMap.insert(
"actionPerformed",
nullptr);
409 s_typeNodeMap.insert(
"activated",
nullptr);
410 s_typeNodeMap.insert(
"alias",
nullptr);
411 s_typeNodeMap.insert(
"anchors",
nullptr);
412 s_typeNodeMap.insert(
"any",
nullptr);
413 s_typeNodeMap.insert(
"array",
nullptr);
414 s_typeNodeMap.insert(
"autoSearch",
nullptr);
415 s_typeNodeMap.insert(
"axis",
nullptr);
416 s_typeNodeMap.insert(
"backClicked",
nullptr);
417 s_typeNodeMap.insert(
"boomTime",
nullptr);
418 s_typeNodeMap.insert(
"border",
nullptr);
419 s_typeNodeMap.insert(
"buttonClicked",
nullptr);
420 s_typeNodeMap.insert(
"callback",
nullptr);
421 s_typeNodeMap.insert(
"char",
nullptr);
422 s_typeNodeMap.insert(
"clicked",
nullptr);
423 s_typeNodeMap.insert(
"close",
nullptr);
424 s_typeNodeMap.insert(
"closed",
nullptr);
425 s_typeNodeMap.insert(
"cond",
nullptr);
426 s_typeNodeMap.insert(
"data",
nullptr);
427 s_typeNodeMap.insert(
"dataReady",
nullptr);
428 s_typeNodeMap.insert(
"dateString",
nullptr);
429 s_typeNodeMap.insert(
"dateTimeString",
nullptr);
430 s_typeNodeMap.insert(
"datetime",
nullptr);
431 s_typeNodeMap.insert(
"day",
nullptr);
432 s_typeNodeMap.insert(
"deactivated",
nullptr);
433 s_typeNodeMap.insert(
"drag",
nullptr);
434 s_typeNodeMap.insert(
"easing",
nullptr);
435 s_typeNodeMap.insert(
"error",
nullptr);
436 s_typeNodeMap.insert(
"exposure",
nullptr);
437 s_typeNodeMap.insert(
"fatalError",
nullptr);
438 s_typeNodeMap.insert(
"fileSelected",
nullptr);
439 s_typeNodeMap.insert(
"flags",
nullptr);
440 s_typeNodeMap.insert(
"float",
nullptr);
441 s_typeNodeMap.insert(
"focus",
nullptr);
442 s_typeNodeMap.insert(
"focusZone",
nullptr);
443 s_typeNodeMap.insert(
"format",
nullptr);
444 s_typeNodeMap.insert(
"framePainted",
nullptr);
445 s_typeNodeMap.insert(
"from",
nullptr);
446 s_typeNodeMap.insert(
"frontClicked",
nullptr);
447 s_typeNodeMap.insert(
"function",
nullptr);
448 s_typeNodeMap.insert(
"hasOpened",
nullptr);
449 s_typeNodeMap.insert(
"hovered",
nullptr);
450 s_typeNodeMap.insert(
"hoveredTitle",
nullptr);
451 s_typeNodeMap.insert(
"hoveredUrl",
nullptr);
452 s_typeNodeMap.insert(
"imageCapture",
nullptr);
453 s_typeNodeMap.insert(
"imageProcessing",
nullptr);
454 s_typeNodeMap.insert(
"index",
nullptr);
455 s_typeNodeMap.insert(
"initialized",
nullptr);
456 s_typeNodeMap.insert(
"isLoaded",
nullptr);
457 s_typeNodeMap.insert(
"item",
nullptr);
458 s_typeNodeMap.insert(
"key",
nullptr);
459 s_typeNodeMap.insert(
"keysequence",
nullptr);
460 s_typeNodeMap.insert(
"listViewClicked",
nullptr);
461 s_typeNodeMap.insert(
"loadRequest",
nullptr);
462 s_typeNodeMap.insert(
"locale",
nullptr);
463 s_typeNodeMap.insert(
"location",
nullptr);
464 s_typeNodeMap.insert(
"long",
nullptr);
465 s_typeNodeMap.insert(
"message",
nullptr);
466 s_typeNodeMap.insert(
"messageReceived",
nullptr);
467 s_typeNodeMap.insert(
"mode",
nullptr);
468 s_typeNodeMap.insert(
"month",
nullptr);
469 s_typeNodeMap.insert(
"name",
nullptr);
470 s_typeNodeMap.insert(
"number",
nullptr);
471 s_typeNodeMap.insert(
"object",
nullptr);
472 s_typeNodeMap.insert(
"offset",
nullptr);
473 s_typeNodeMap.insert(
"ok",
nullptr);
474 s_typeNodeMap.insert(
"openCamera",
nullptr);
475 s_typeNodeMap.insert(
"openImage",
nullptr);
476 s_typeNodeMap.insert(
"openVideo",
nullptr);
477 s_typeNodeMap.insert(
"padding",
nullptr);
478 s_typeNodeMap.insert(
"parent",
nullptr);
479 s_typeNodeMap.insert(
"path",
nullptr);
480 s_typeNodeMap.insert(
"photoModeSelected",
nullptr);
481 s_typeNodeMap.insert(
"position",
nullptr);
482 s_typeNodeMap.insert(
"precision",
nullptr);
483 s_typeNodeMap.insert(
"presetClicked",
nullptr);
484 s_typeNodeMap.insert(
"preview",
nullptr);
485 s_typeNodeMap.insert(
"previewSelected",
nullptr);
486 s_typeNodeMap.insert(
"progress",
nullptr);
487 s_typeNodeMap.insert(
"puzzleLost",
nullptr);
488 s_typeNodeMap.insert(
"qmlSignal",
nullptr);
489 s_typeNodeMap.insert(
"rectangle",
nullptr);
490 s_typeNodeMap.insert(
"request",
nullptr);
491 s_typeNodeMap.insert(
"requestId",
nullptr);
492 s_typeNodeMap.insert(
"section",
nullptr);
493 s_typeNodeMap.insert(
"selected",
nullptr);
494 s_typeNodeMap.insert(
"send",
nullptr);
495 s_typeNodeMap.insert(
"settingsClicked",
nullptr);
496 s_typeNodeMap.insert(
"shoe",
nullptr);
497 s_typeNodeMap.insert(
"short",
nullptr);
498 s_typeNodeMap.insert(
"signed",
nullptr);
499 s_typeNodeMap.insert(
"sizeChanged",
nullptr);
500 s_typeNodeMap.insert(
"size_t",
nullptr);
501 s_typeNodeMap.insert(
"sockaddr",
nullptr);
502 s_typeNodeMap.insert(
"someOtherSignal",
nullptr);
503 s_typeNodeMap.insert(
"sourceSize",
nullptr);
504 s_typeNodeMap.insert(
"startButtonClicked",
nullptr);
505 s_typeNodeMap.insert(
"state",
nullptr);
506 s_typeNodeMap.insert(
"std::initializer_list",
nullptr);
507 s_typeNodeMap.insert(
"std::list",
nullptr);
508 s_typeNodeMap.insert(
"std::map",
nullptr);
509 s_typeNodeMap.insert(
"std::pair",
nullptr);
510 s_typeNodeMap.insert(
"std::string",
nullptr);
511 s_typeNodeMap.insert(
"std::vector",
nullptr);
512 s_typeNodeMap.insert(
"stringlist",
nullptr);
513 s_typeNodeMap.insert(
"swapPlayers",
nullptr);
514 s_typeNodeMap.insert(
"symbol",
nullptr);
515 s_typeNodeMap.insert(
"t",
nullptr);
516 s_typeNodeMap.insert(
"T",
nullptr);
517 s_typeNodeMap.insert(
"tagChanged",
nullptr);
518 s_typeNodeMap.insert(
"timeString",
nullptr);
519 s_typeNodeMap.insert(
"timeout",
nullptr);
520 s_typeNodeMap.insert(
"to",
nullptr);
521 s_typeNodeMap.insert(
"toggled",
nullptr);
522 s_typeNodeMap.insert(
"type",
nullptr);
523 s_typeNodeMap.insert(
"unsigned",
nullptr);
524 s_typeNodeMap.insert(
"urllist",
nullptr);
525 s_typeNodeMap.insert(
"va_list",
nullptr);
526 s_typeNodeMap.insert(
"value",
nullptr);
527 s_typeNodeMap.insert(
"valueEmitted",
nullptr);
528 s_typeNodeMap.insert(
"videoFramePainted",
nullptr);
529 s_typeNodeMap.insert(
"videoModeSelected",
nullptr);
530 s_typeNodeMap.insert(
"videoRecorder",
nullptr);
531 s_typeNodeMap.insert(
"void",
nullptr);
532 s_typeNodeMap.insert(
"volatile",
nullptr);
533 s_typeNodeMap.insert(
"wchar_t",
nullptr);
534 s_typeNodeMap.insert(
"x",
nullptr);
535 s_typeNodeMap.insert(
"y",
nullptr);
536 s_typeNodeMap.insert(
"zoom",
nullptr);
537 s_typeNodeMap.insert(
"zoomTo",
nullptr);
541
542
545
546
547
548
551
552
553
554
557
558
559
560
563
564
565
566
567
568
569
572
573
574
575
576
577
578
581
582
583
584
585
586
589
590
591
592
593
594
597
598
599
600
601
602
605
606
607
608
609
610
611
612
615
616
617
618
619
620
623
624
625
626
629
630
631
634
635
636
637
638
639
640
643 if (!qmid.isEmpty()) {
644 if (
auto *qcn = m_forest.lookupQmlType(qmid + u"::"_s + name, relative); qcn)
649 if (
auto *qcn = m_forest.lookupQmlType(name, relative); qcn)
653 QStringList path(name);
654 return static_cast<QmlTypeNode *>(m_forest.findNodeByNameAndType(path, &Node::isQmlType));
658
659
660
661
671 if (!record.m_importId.isEmpty()) {
672 const QString namespacePrefix{
"%1."_L1.arg(record.m_importId)};
673 if (!type.startsWith(namespacePrefix))
675 type.remove(0, namespacePrefix.size());
678 const QString qmName = record.m_importUri.isEmpty() ? record.m_moduleName : record.m_importUri;
679 return m_forest.lookupQmlType(qmName + u"::"_s + type, relative);
683
684
685
686
687
688
697
698
699
700
701
702
715
716
717
718
719
722 Tree *t = m_forest.firstTree();
724 if (!m_completedFindFunctions.values(t).contains(func)) {
725 (
this->*(func))(t->root());
726 m_completedFindFunctions.insert(t, func);
728 t = m_forest.nextTree();
733
734
738 return m_legaleseTexts;
742
743
747 return s_classesWithObsoleteMembers;
751
752
756 return s_obsoleteQmlTypes;
760
761
765 return s_qmlTypesWithObsoleteMembers;
769
770
774 return s_qmlBasicTypes;
778
779
787
788
796
797
801 return m_attributions;
805
806
810 return s_obsoleteClasses;
814
815
823
824
825
829 return m_functionIndex;
833
834
835
838 for (
const auto &childNode : node->childNodes()) {
839 if (childNode->isPrivate())
841 if (!childNode->doc().legaleseText().isEmpty())
842 m_legaleseTexts.insert(childNode->doc().legaleseText(), childNode);
843 if (childNode->isAggregate())
844 findAllLegaleseTexts(
static_cast<Aggregate *>(childNode));
849
850
851
852
853
854
857
858
859
860
861
862
863
864
865
868
869
870
871
872
873
874
877
878
879
880
884 auto it = s_newClassMaps.constFind(key);
889
890
891
892
896 auto it = s_newQmlTypeMaps.constFind(key);
901
902
903
904
908 auto it = s_newSinceMaps.constFind(key);
913
914
915
916
919 const auto &config = Config::instance();
920 if (config.dualExec() || config.preparing()) {
937 if (config.singleExec() && config.generating()) {
945 if (!config.preparing()) {
951 if (config.dualExec())
957 Tree *t = m_forest.firstTree();
959 t->resolveBaseClasses(t->root());
962 t = m_forest.nextTree();
967
968
969
970
971
975 for (
const auto &name : td->referenced_concepts)
976 refs.append(QString::fromStdString(name));
979 const auto *fn =
static_cast<
const FunctionNode *>(node);
980 refs += fn->referencedConcepts();
985
986
987
988
989
990
993 for (
auto *child : std::as_const(parent->childNodes())) {
999 const bool registerChild =
1000 !child->isPrivate() && !child->isInternal() && !child->isDontDocument();
1002 if (registerChild) {
1004 collectConceptReferences(child, refs);
1006 refs.removeDuplicates();
1008 for (
const QString &conceptName : std::as_const(refs)) {
1021 if (
auto *cn = db.findMutableCollectionNode(conceptName, NodeType::Concept))
1022 cn->addMember(child);
1026 if (child->isAggregate())
1027 registerConceptUsersUnder(
static_cast<Aggregate *>(child), db);
1032
1033
1034
1035
1036
1037
1038
1039
1046
1047
1048
1049
1050
1054 return m_namespaceIndex;
1058
1059
1060
1061
1062
1063
1064
1067 if (!m_namespaceIndex.isEmpty())
1072 Tree *t = m_forest.firstTree();
1075 t = m_forest.nextTree();
1077 const QList<QString> keys = namespaceMultimap.uniqueKeys();
1078 for (
const QString &key : keys) {
1079 NamespaceNode *ns =
nullptr;
1080 NamespaceNode *indexNamespace =
nullptr;
1081 const NodeList namespaces = namespaceMultimap.values(key);
1082 qsizetype count = namespaceMultimap.remove(key);
1084 for (
auto *node : namespaces) {
1085 ns =
static_cast<NamespaceNode *>(node);
1086 if (ns->isDocumentedHere())
1088 else if (ns->hadDoc())
1089 indexNamespace = ns;
1093 for (
auto *node : namespaces) {
1094 auto *nsNode =
static_cast<NamespaceNode *>(node);
1095 if (nsNode->hadDoc() && nsNode != ns) {
1096 ns->doc().location().warning(
1097 QStringLiteral(
"Namespace %1 documented more than once")
1098 .arg(nsNode->name()), QStringLiteral(
"also seen here: %1")
1099 .arg(nsNode->doc().location().toString()));
1102 }
else if (!indexNamespace) {
1107 for (
auto *node : namespaces) {
1108 if (!node->isIndexNode())
1109 static_cast<NamespaceNode *>(node)->reportDocumentedChildrenInUndocumentedNamespace();
1113 for (
auto *node : namespaces) {
1114 auto *nsNode =
static_cast<NamespaceNode *>(node);
1115 if (nsNode != indexNamespace)
1116 nsNode->setDocNode(indexNamespace);
1121
1122
1123
1124
1125
1126 if (ns && count > 1) {
1127 for (
auto *node : namespaces) {
1128 auto *nameSpaceNode =
static_cast<NamespaceNode *>(node);
1129 if (nameSpaceNode != ns) {
1130 for (
auto it = nameSpaceNode->constBegin(); it != nameSpaceNode->constEnd();
1132 Node *anotherNs = *it;
1133 if (anotherNs && anotherNs->isPublic() && !anotherNs->isInternal())
1134 ns->includeChild(anotherNs);
1140
1141
1142
1144 ns = indexNamespace ? indexNamespace :
static_cast<NamespaceNode *>(namespaces.last());
1145 m_namespaceIndex.insert(ns->name(), ns);
1150
1151
1152
1153
1154
1155
1156
1157
1158
1163 Tree *t = m_forest.firstTree();
1164 t = m_forest.nextTree();
1167 if (!proxies.isEmpty()) {
1168 for (
auto *node : proxies) {
1169 const auto *pn =
static_cast<ProxyNode *>(node);
1170 if (pn->count() > 0) {
1171 Aggregate *aggregate = primaryTree()->findAggregate(pn->name());
1172 if (aggregate !=
nullptr)
1173 aggregate->appendToRelatedByProxy(pn->childNodes());
1177 t = m_forest.nextTree();
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1198 QString function = target;
1199 qsizetype length = target.size();
1200 if (function.endsWith(
"()"))
1202 if (function.endsWith(QChar(
')'))) {
1203 qsizetype position = function.lastIndexOf(QChar(
'('));
1204 signature = function.mid(position + 1, length - position - 2);
1205 function = function.left(position);
1207 QStringList path = function.split(
"::");
1208 return m_forest.findFunctionNode(path, Parameters(signature), relative, genus);
1212
1213
1214
1215
1216
1217
1218
1219
1220
1224 if ((genus == Genus::QML || (relative && relative
->genus() == Genus::QML)) &&
1225 type.contains(
'.') && !type.contains(
"::")) {
1227 const QmlTypeNode *qmlType =
static_cast<
const QmlTypeNode*>(relative);
1230 for (
const auto &import : imports) {
1231 if (QmlTypeNode *found = findQmlType(import, type)) {
1238 QStringList path = type.split(
".");
1239 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1240 auto it = s_typeNodeMap.find(path.at(0));
1241 if (it != s_typeNodeMap.end())
1246 const Node *node = m_forest.findTypeNode(path, relative, genus);
1253 if (path.size() > 1) {
1254 const Node *lastSegmentNode = m_forest.findTypeNode(QStringList{path.last()}, relative, genus);
1256 return lastSegmentNode;
1263 QStringList path = type.split(
"::");
1264 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1265 auto it = s_typeNodeMap.find(path.at(0));
1266 if (it != s_typeNodeMap.end())
1269 return m_forest.findTypeNode(path, relative, genus);
1273
1274
1275
1276
1277
1280 const Node *node =
nullptr;
1281 if (target.isEmpty())
1283 else if (target.endsWith(
".html"))
1284 node = findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1286 QStringList path = target.split(
"::");
1288 for (
const auto *tree : searchOrder()) {
1289 const Node *n = tree->findNode(path, relative, flags, Genus::DontCare);
1294 node = findPageNodeByTitle(target);
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1314 Genus genus,
const QString &moduleName,
1317 if (target.isEmpty())
1320 Tree *domain = moduleName.isEmpty() ?
nullptr : findTree(moduleName);
1323 const Node *node =
nullptr;
1324 if (target.endsWith(
".html"_L1)) {
1325 node = domain->findNodeByNameAndType(QStringList(target), &
Node::isPageNode);
1326 }
else if (target.endsWith(
')'_L1)) {
1327 QString function = target;
1329 if (function.endsWith(
"()"_L1))
1331 if (function.endsWith(
')'_L1)) {
1332 qsizetype position = function.lastIndexOf(
'('_L1);
1333 signature = function.mid(position + 1, function.size() - position - 2);
1334 function = function.left(position);
1336 QStringList path = function.split(
"::"_L1);
1337 node = domain->findFunctionNode(path,
Parameters(signature),
nullptr, genus);
1342 if (genus == Genus::QML && target.contains(
'.'_L1) && !target.contains(
"::"_L1)) {
1344 QStringList path = target.split(
'.'_L1);
1345 node = domain->findNode(path, relative, typeFlags, genus);
1348 if (path.size() > 1) {
1349 node = domain->findNode(QStringList{path.last()}, relative, typeFlags, genus);
1356 QStringList nodePath = target.split(
"::"_L1);
1357 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1360 const Node *result =
1361 domain->findNodeForTarget(nodePath, {}, relative, flags, genus, localRef);
1368 if (target.endsWith(
".html"_L1))
1369 return findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1371 if (target.endsWith(
')'_L1)) {
1372 const Node *node = findFunctionNode(target, relative, genus);
1377 if (genus == Genus::QML && target.contains(
'.'_L1) && !target.contains(
"::"_L1)) {
1378 const Node *node = findTypeNode(target, relative, genus);
1383 QStringList targetPath = Utilities::pathAndFragment(target);
1386 const Node *node = findNodeForTarget(targetPath, relative, genus, localRef, flags);
1393 return findPageNodeByTitle(target);
1404 for (
auto it = m->cbegin(); it != m->cend(); ++it)
1405 if (it.value()->members().contains(node))
1412
1413
1416 QStringList filesToRead;
1417 for (
const QString &file : indexFiles) {
1418 QString fn = file.mid(file.lastIndexOf(QChar(
'/')) + 1);
1420 filesToRead << file;
1422 qCCritical(lcQdoc) <<
"Index file" << file <<
"is already in memory.";
1428
1429
1430
1431
1432
1433
1434
1435
1436
1441 const Generator *generator = hrefGenerator;
1443 generator = Generator::generatorForFormat(u"HTML"_s);
1445 qCWarning(lcQdoc) <<
"Cannot generate index file: no href generator available"
1446 " (HTML generator missing)";
1450 QString t = fileName.mid(fileName.lastIndexOf(QChar(
'/')) + 1);
1452 QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, generator);
1457
1458
1459
1460
1469 moduleName = relative->physicalModuleName();
1473 moduleName = relative->logicalModuleName();
1478 if (moduleName.isEmpty())
1481 return primaryTree()->getCollection(moduleName, moduleType);
1485
1486
1487
1488
1493 for (
auto *tree : searchOrder()) {
1494 CNMap *m = tree->getCollectionMap(type);
1495 if (m && !m->isEmpty()) {
1496 for (
auto it = m->cbegin(); it != m->cend(); ++it) {
1497 if (!it.value()->isInternal())
1498 cnmm.insert(it.key(), it.value());
1504 static const QRegularExpression singleDigit(
"\\b([0-9])\\b");
1505 const QStringList keys = cnmm.uniqueKeys();
1506 for (
const auto &key : keys) {
1507 const QList<CollectionNode *> values = cnmm.values(key);
1508 CollectionNode *n =
nullptr;
1509 for (
auto *value : values) {
1510 if (value && value->wasSeen() && value != relative) {
1516 if (values.size() > 1) {
1517 for (CollectionNode *value : values) {
1520 if ((n->isQmlModule())
1521 && n->logicalModuleIdentifier() != value->logicalModuleIdentifier()) {
1522 if (value->wasSeen() && value != relative)
1523 cnm.insert(value->fullTitle().toLower(), value);
1526 for (Node *t : value->members())
1531 QString sortKey = n->fullTitle().toLower();
1532 if (sortKey.startsWith(
"the "))
1533 sortKey.remove(0, 4);
1534 sortKey.replace(singleDigit,
"0\\1");
1535 cnm.insert(sortKey, n);
1541
1542
1543
1544
1545
1546
1547
1548
1593 for (
auto *tree : searchOrder()) {
1594 CollectionNode *cn = tree->getCollection(c->name(), c->nodeType());
1595 if (cn && cn != c) {
1596 if ((cn->isQmlModule())
1597 && cn->logicalModuleIdentifier() != c->logicalModuleIdentifier())
1600 for (
auto *node : cn->members())
1660 if (!c->wasSeen() && cn->wasSeen()) {
1662 c->setTitle(cn->title());
1663 c->setUrl(cn->url());
1664 c->setResolvedPhysicalModuleName(cn->tree()->physicalModuleName());
1673
1674
1675
1676
1677
1678
1679
1680
1684 const Node *node =
nullptr;
1686 Atom *atom =
const_cast<
Atom *>(a);
1687 QStringList targetPath = Utilities::pathAndFragment(atom->string());
1688 QString first = targetPath.first().trimmed();
1690 Tree *domain =
nullptr;
1694 domain = atomDomain;
1699 if (first.isEmpty())
1702 if (first.endsWith(
".html"))
1703 node = domain->findNodeByNameAndType(QStringList(first), &
Node::isPageNode);
1704 else if (first.endsWith(QChar(
')'))) {
1706 QString function = first;
1707 qsizetype length = first.size();
1708 if (function.endsWith(
"()"))
1710 if (function.endsWith(QChar(
')'))) {
1711 qsizetype position = function.lastIndexOf(QChar(
'('));
1712 signature = function.mid(position + 1, length - position - 2);
1713 function = function.left(position);
1715 QStringList path = function.split(
"::");
1716 node = domain->findFunctionNode(path,
Parameters(signature),
nullptr, genus);
1718 if (node ==
nullptr) {
1720 QStringList nodePath = first.split(
"::");
1722 targetPath.removeFirst();
1723 if (!targetPath.isEmpty())
1724 target = targetPath.takeFirst();
1725 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1727 return domain->findNodeForTarget(nodePath, target, relative, flags, genus, ref);
1730 if (first.endsWith(
".html"))
1731 node = findNodeByNameAndType(QStringList(first), &Node::isPageNode);
1732 else if (first.endsWith(QChar(
')')))
1733 node = findFunctionNode(first, relative, genus);
1734 if (node ==
nullptr) {
1736 if (genus == Genus::QML && first.contains(
'.') && !first.contains(
"::")) {
1738 node = findTypeNode(first, relative, genus);
1741 targetPath.removeFirst();
1742 if (!targetPath.isEmpty()) {
1750 return findNodeForTarget(targetPath, relative, genus, ref, atom->flags());
1754 if (node !=
nullptr && ref.isEmpty()) {
1755 if (!node->url().isEmpty())
1757 targetPath.removeFirst();
1758 if (!targetPath.isEmpty()) {
1768
1769
1770
1771
1772
1773
1774
1775
1779 QList<Tree *> searchOrder =
this->searchOrder();
1798 bool inclusive{Config::instance().get(
1802 const auto tocTitles{Config::instance().get(configVar).asStringList()};
1804 for (
const auto &tocTitle : tocTitles) {
1805 if (
const auto candidateTarget = findNodeForTarget(tocTitle,
nullptr); candidateTarget && candidateTarget->isPageNode()) {
1806 auto tocPage{
static_cast<
const PageNode*>(candidateTarget)};
1808 Text body = tocPage->doc().body();
1810 auto *atom = body.firstAtom();
1812 std::pair<PageNode *, QString> prev {
nullptr, QString() };
1814 std::stack<
const PageNode *> tocStack;
1815 tocStack.push(inclusive ? tocPage :
nullptr);
1817 bool inItem =
false;
1824 switch (atom->type()) {
1825 case Atom::ListItemLeft:
1827 tocStack.push(
nullptr);
1830 case Atom::ListItemRight:
1870 auto candidatePage =
const_cast<Node *>(findNodeForAtom(atom,
nullptr, unused));
1871 if (!candidatePage || !candidatePage->isPageNode())
break;
1873 auto page{
static_cast<PageNode*>(candidatePage)};
1876 if (page == prev.first)
break;
1879 prev.first->setLink(
1920 prev.first->title(),
1925 if (page == tocPage)
1930 qsizetype popped = 0;
1931 while (tocStack.size() > 1 && !tocStack.top()) {
1936 page->setNavigationParent(tocStack.empty() ?
nullptr : tocStack.top());
1938 while (--popped > 0)
1939 tocStack.push(
nullptr);
1941 tocStack.push(page);
1943 prev = { page, atom->linkText() };
1947 case Atom::AnnotatedList:
1948 case Atom::GeneratedList: {
1949 if (
const auto *cn = getCollectionNode(atom->string(), NodeType::Group)) {
1950 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
1951 NodeList members{cn->members()};
1954 members.erase(std::remove_if(members.begin(), members.end(),
1956 return n->isIndexNode() || !n->isPageNode() || n->isExternalPage();
1958 if (members.isEmpty())
1961 if (sortOrder == Qt::DescendingOrder)
1962 std::sort(members.rbegin(), members.rend(), Node::nodeSortKeyOrNameLessThan);
1964 std::sort(members.begin(), members.end(), Node::nodeSortKeyOrNameLessThan);
1969 for (
auto *m : members) {
1970 auto *page =
static_cast<PageNode *>(m);
1972 prev.first->setLink(Node::NextLink, page->title(), page->fullName());
1973 page->setLink(Node::PreviousLink, prev.first->title(), prev.second);
1975 prev = { page, page->fullName() };
1985 atom = atom->next();
1988 Config::instance().get(configVar).location()
1989 .warning(QStringLiteral(
"Failed to find table of contents with title '%1'")
1995 setSearchOrder(searchOrder);
void resolveRelates()
Adopts each non-aggregate C++ node (function/macro, typedef, enum, variable, or a shared comment node...
void resolveQmlInheritance()
Resolves the inheritance information for all QML type children of this aggregate.
void normalizeOverloads()
Sorts the lists of overloads in the function map and assigns overload numbers.
void findAllNamespaces(NodeMultiMap &namespaces)
For each child of this node, if the child is a namespace node, insert the child into the namespaces m...
void markUndocumentedChildrenInternal()
Mark all child nodes that have no documentation as having internal status.
The Atom class is the fundamental unit for representing documents internally.
virtual bool isLinkAtom() const
A class for holding the members of a collection of doc pages.
This node is used to represent any kind of function being documented.
This class represents a C++ namespace.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
const Node * findTypeNode(const QString &type, const Node *relative, Genus genus)
This function is called for autolinking to a type, which could be a function return type or a paramet...
NodeMapMap & getFunctionIndex()
Returns the function index.
const NodeMultiMap & getClassMap(const QString &key)
Find the key in the map of new class maps, and return a reference to the value, which is a NodeMap.
const NodeMultiMap & getQmlTypeMap(const QString &key)
Find the key in the map of new QML type maps, and return a reference to the value,...
void resolveNamespaces()
Multiple namespace nodes for namespace X can exist in the qdoc database in different trees.
TextToNodeMap & getLegaleseTexts()
Returns a reference to the collection of legalese texts.
NodeMultiMap & getAttributions()
Returns a reference to the multimap of attribution nodes.
static void destroyQdocDB()
Destroys the singleton.
NodeMultiMap & getQmlTypesWithObsoleteMembers()
Returns a reference to the map of QML types with obsolete members.
NodeMultiMap & getObsoleteQmlTypes()
Returns a reference to the map of obsolete QML types.
QmlTypeNode * findQmlType(const QString &qmid, const QString &name, const Node *relative=nullptr)
Returns the QML type node identified by the QML module id qmid and QML type name, or nullptr if no ty...
QmlTypeNode * findQmlType(const ImportRec &import, const QString &name, const Node *relative=nullptr)
const FunctionNode * findFunctionNode(const QString &target, const Node *relative, Genus genus)
Finds the function node for the qualified function path in target and returns a pointer to it.
static QDocDatabase * qdocDB()
Creates the singleton.
void resolveBaseClasses()
NodeMultiMap & getQmlTypes()
Returns a reference to the multimap of QML types.
NodeMultiMap & getClassesWithObsoleteMembers()
Returns a reference to the map of C++ classes with obsolete members.
NodeMultiMap & getQmlValueTypes()
Returns a reference to the map of QML basic types.
NodeMultiMap & getCppClasses()
Returns a reference to the map of all C++ classes.
QStringList groupNamesForNode(Node *node)
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
void readIndexes(const QStringList &indexFiles)
Reads and parses the qdoc index files listed in indexFiles.
void resolveConceptUsers()
Builds the concept-to-users reverse index after parsing finishes and before any generator runs.
const Node * findNodeForTarget(const QString &target, const Node *relative)
Finds the node that will generate the documentation that contains the target and returns a pointer to...
const Node * findNodeForAtom(const Atom *atom, const Node *relative, QString &ref, Genus genus=Genus::DontCare)
Searches for the node that matches the path in atom and the specified genus.
void mergeCollections(NodeType type, CNMap &cnm, const Node *relative)
Finds all the collection nodes of the specified type and merges them into the collection node map cnm...
NodeMultiMap & getNamespaces()
Returns a reference to the namespace map.
QmlTypeNode * findQmlTypeInPrimaryTree(const QString &qmid, const QString &name)
Returns the QML node identified by the QML module id qmid and name, searching in the primary tree onl...
const NodeMultiMap & getSinceMap(const QString &key)
Find the key in the map of new {since} maps, and return a reference to the value, which is a NodeMult...
NodeMultiMap & getExamples()
Returns a reference to the multimap of example nodes.
void processForest()
This function calls a set of functions for each tree in the forest that has not already been analyzed...
const Node * findNodeForTarget(const QString &target, const Node *relative, Genus genus, const QString &moduleName, QString *ref=nullptr)
Finds the node for target with genus and module scoping.
void(QDocDatabase::*)(Aggregate *) FindFunctionPtr
void updateNavigation()
Updates navigation (previous/next page links and the navigation parent) for pages listed in the TOC,...
void resolveStuff()
Performs several housekeeping tasks prior to generating the documentation.
NodeMultiMap & getObsoleteClasses()
Returns a reference to the map of obsolete C++ clases.
const CollectionNode * getModuleNode(const Node *relative)
Returns the collection node representing the module that relative node belongs to,...
void resolveProxies()
Each instance of class Tree that represents an index file must be traversed to find all instances of ...
void mergeCollections(CollectionNode *c)
Finds all the collection nodes with the same name and type as c and merges their members into the mem...
void generateIndex(const QString &fileName, const QString &url, const QString &title, const Generator *hrefGenerator)
Generates a qdoc index file and writes it to fileName.
A class representing a forest of Tree objects.
This class handles qdoc index files.
const ImportList & importList() const
This class constructs and maintains a tree of instances of the subclasses of Node.
void markDontDocumentNodes()
The {don't document} map has been loaded with the names of classes and structs in the current module ...
void resolveProperties()
Resolves access functions associated with each PropertyNode stored in m_unresolvedPropertyMap,...
#define CONFIG_NOLINKERRORS
#define CONFIG_NAVIGATION
QMultiMap< QString, CollectionNode * > CNMultiMap
QMap< QString, NodeMultiMap > NodeMultiMapMap
QMap< QString, Node * > NodeMap
QMap< QString, NodeMap > NodeMapMap
QMap< QString, CollectionNode * > CNMap
static void collectConceptReferences(const Node *node, QStringList &refs)
Gathers the fully-qualified concept names referenced by node.
static void registerConceptUsersUnder(Aggregate *parent, QDocDatabase &db)
Walks every documented node under parent and registers each constrained item as a member of the conce...
static NodeMultiMap emptyNodeMultiMap_
QT_BEGIN_NAMESPACE typedef QMultiMap< Text, const Node * > TextToNodeMap
QList< ImportRec > ImportList
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Genus genus() const override
Returns this node's Genus.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
const std::optional< RelaxedTemplateDeclaration > & templateDecl() const
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
virtual Tree * tree() const
Returns a pointer to the Tree this node is in.
A class for parsing and managing a function parameter list.
A record of a linkable target within the documentation.
TargetType
A type of a linkable target record.