18#include <QtCore/qregularexpression.h>
23using namespace Qt::StringLiterals;
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
61
64
65
66
67
68
69
72 for (
auto *entry : m_searchOrder)
75 m_searchOrder.clear();
76 m_indexSearchOrder.clear();
77 m_moduleNames.clear();
78 m_primaryTree =
nullptr;
82
83
84
85
89 return (!searchOrder().isEmpty() ? searchOrder()[0] :
nullptr);
93
94
95
96
100 return (m_currentIndex < searchOrder().size() ? searchOrder()[m_currentIndex] :
nullptr);
104
105
106
107
110
111
112
113
114
115
116
117
118void QDocForest::setPrimaryTree(
const QString &t)
120 QString T = t.toLower();
121 m_primaryTree = findTree(T);
123 if (m_primaryTree ==
nullptr)
124 qCCritical(lcQdoc) <<
"Error: Could not set primary tree to" << t;
128
129
130
131void QDocForest::setSearchOrder(
const QStringList &t)
133 if (!m_searchOrder.isEmpty())
137 m_searchOrder.reserve(m_forest.size() + 1);
138 m_searchOrder.clear();
139 m_moduleNames.reserve(m_forest.size() + 1);
140 m_moduleNames.clear();
143 QString primaryName = primaryTree()->physicalModuleName();
144 m_searchOrder.append(m_primaryTree);
145 m_moduleNames.append(primaryName);
146 m_forest.remove(primaryName);
148 for (
const QString &m : t) {
149 if (primaryName != m) {
150 auto it = m_forest.find(m);
151 if (it != m_forest.end()) {
152 m_searchOrder.append(it.value());
153 m_moduleNames.append(m);
159
160
161
162
163 if (!m_forest.isEmpty()) {
164 for (
auto it = m_forest.begin(); it != m_forest.end(); ++it) {
165 m_searchOrder.append(it.value());
166 m_moduleNames.append(it.key());
172
173
174
175
176
177
178
179 for (
int i = 0; i < m_searchOrder.size(); ++i) {
180 if (!m_forest.contains(m_moduleNames.at(i))) {
181 m_forest.insert(m_moduleNames.at(i), m_searchOrder.at(i));
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
213 if (m_searchOrder.isEmpty())
214 return indexSearchOrder();
215 return m_searchOrder;
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233const QList<Tree *> &
QDocForest::indexSearchOrder()
235 if (m_forest.size() > m_indexSearchOrder.size())
236 m_indexSearchOrder.prepend(m_primaryTree);
237 return m_indexSearchOrder;
241
242
243
244
247 m_primaryTree =
new Tree(module, m_qdb);
248 m_forest.insert(module.toLower(), m_primaryTree);
249 return m_primaryTree->root();
253
254
255
256void QDocForest::newPrimaryTree(
const QString &module)
258 m_primaryTree =
new Tree(module, m_qdb);
262
263
264
265
266
267
268
269
270
271
272
273
274
275const Node *
QDocForest::findNodeForTarget(QStringList &targetPath,
const Node *relative,
276 Genus genus, QString &ref,
int findFlags)
280 QString entity = targetPath.takeFirst();
281 QStringList entityPath = entity.split(
"::");
284 if (!targetPath.isEmpty())
285 target = targetPath.takeFirst();
288 const Node *tocNode =
nullptr;
289 for (
const auto *tree : searchOrder()) {
290 const Node *n = tree->findNodeForTarget(entityPath, target, relative, flags, genus, ref, &type);
293 if (type != TargetRec::Contents)
304
305
306
307
308
309
310
311
312
317 for (
const auto *tree : searchOrder()) {
318 const FunctionNode *fn = tree->findFunctionNode(path, parameters, relative, genus);
327
328
329
330
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
369
370
371
374 if (s_qdocDB ==
nullptr) {
382
383
386 if (s_qdocDB !=
nullptr) {
393
394
395
396
397
398
399
400
401
402
403
404
405
408 s_typeNodeMap.insert(
"accepted",
nullptr);
409 s_typeNodeMap.insert(
"actionPerformed",
nullptr);
410 s_typeNodeMap.insert(
"activated",
nullptr);
411 s_typeNodeMap.insert(
"alias",
nullptr);
412 s_typeNodeMap.insert(
"anchors",
nullptr);
413 s_typeNodeMap.insert(
"any",
nullptr);
414 s_typeNodeMap.insert(
"array",
nullptr);
415 s_typeNodeMap.insert(
"autoSearch",
nullptr);
416 s_typeNodeMap.insert(
"axis",
nullptr);
417 s_typeNodeMap.insert(
"backClicked",
nullptr);
418 s_typeNodeMap.insert(
"boomTime",
nullptr);
419 s_typeNodeMap.insert(
"border",
nullptr);
420 s_typeNodeMap.insert(
"buttonClicked",
nullptr);
421 s_typeNodeMap.insert(
"callback",
nullptr);
422 s_typeNodeMap.insert(
"char",
nullptr);
423 s_typeNodeMap.insert(
"clicked",
nullptr);
424 s_typeNodeMap.insert(
"close",
nullptr);
425 s_typeNodeMap.insert(
"closed",
nullptr);
426 s_typeNodeMap.insert(
"cond",
nullptr);
427 s_typeNodeMap.insert(
"data",
nullptr);
428 s_typeNodeMap.insert(
"dataReady",
nullptr);
429 s_typeNodeMap.insert(
"dateString",
nullptr);
430 s_typeNodeMap.insert(
"dateTimeString",
nullptr);
431 s_typeNodeMap.insert(
"datetime",
nullptr);
432 s_typeNodeMap.insert(
"day",
nullptr);
433 s_typeNodeMap.insert(
"deactivated",
nullptr);
434 s_typeNodeMap.insert(
"drag",
nullptr);
435 s_typeNodeMap.insert(
"easing",
nullptr);
436 s_typeNodeMap.insert(
"error",
nullptr);
437 s_typeNodeMap.insert(
"exposure",
nullptr);
438 s_typeNodeMap.insert(
"fatalError",
nullptr);
439 s_typeNodeMap.insert(
"fileSelected",
nullptr);
440 s_typeNodeMap.insert(
"flags",
nullptr);
441 s_typeNodeMap.insert(
"float",
nullptr);
442 s_typeNodeMap.insert(
"focus",
nullptr);
443 s_typeNodeMap.insert(
"focusZone",
nullptr);
444 s_typeNodeMap.insert(
"format",
nullptr);
445 s_typeNodeMap.insert(
"framePainted",
nullptr);
446 s_typeNodeMap.insert(
"from",
nullptr);
447 s_typeNodeMap.insert(
"frontClicked",
nullptr);
448 s_typeNodeMap.insert(
"function",
nullptr);
449 s_typeNodeMap.insert(
"hasOpened",
nullptr);
450 s_typeNodeMap.insert(
"hovered",
nullptr);
451 s_typeNodeMap.insert(
"hoveredTitle",
nullptr);
452 s_typeNodeMap.insert(
"hoveredUrl",
nullptr);
453 s_typeNodeMap.insert(
"imageCapture",
nullptr);
454 s_typeNodeMap.insert(
"imageProcessing",
nullptr);
455 s_typeNodeMap.insert(
"index",
nullptr);
456 s_typeNodeMap.insert(
"initialized",
nullptr);
457 s_typeNodeMap.insert(
"isLoaded",
nullptr);
458 s_typeNodeMap.insert(
"item",
nullptr);
459 s_typeNodeMap.insert(
"key",
nullptr);
460 s_typeNodeMap.insert(
"keysequence",
nullptr);
461 s_typeNodeMap.insert(
"listViewClicked",
nullptr);
462 s_typeNodeMap.insert(
"loadRequest",
nullptr);
463 s_typeNodeMap.insert(
"locale",
nullptr);
464 s_typeNodeMap.insert(
"location",
nullptr);
465 s_typeNodeMap.insert(
"long",
nullptr);
466 s_typeNodeMap.insert(
"message",
nullptr);
467 s_typeNodeMap.insert(
"messageReceived",
nullptr);
468 s_typeNodeMap.insert(
"mode",
nullptr);
469 s_typeNodeMap.insert(
"month",
nullptr);
470 s_typeNodeMap.insert(
"name",
nullptr);
471 s_typeNodeMap.insert(
"number",
nullptr);
472 s_typeNodeMap.insert(
"object",
nullptr);
473 s_typeNodeMap.insert(
"offset",
nullptr);
474 s_typeNodeMap.insert(
"ok",
nullptr);
475 s_typeNodeMap.insert(
"openCamera",
nullptr);
476 s_typeNodeMap.insert(
"openImage",
nullptr);
477 s_typeNodeMap.insert(
"openVideo",
nullptr);
478 s_typeNodeMap.insert(
"padding",
nullptr);
479 s_typeNodeMap.insert(
"parent",
nullptr);
480 s_typeNodeMap.insert(
"path",
nullptr);
481 s_typeNodeMap.insert(
"photoModeSelected",
nullptr);
482 s_typeNodeMap.insert(
"position",
nullptr);
483 s_typeNodeMap.insert(
"precision",
nullptr);
484 s_typeNodeMap.insert(
"presetClicked",
nullptr);
485 s_typeNodeMap.insert(
"preview",
nullptr);
486 s_typeNodeMap.insert(
"previewSelected",
nullptr);
487 s_typeNodeMap.insert(
"progress",
nullptr);
488 s_typeNodeMap.insert(
"puzzleLost",
nullptr);
489 s_typeNodeMap.insert(
"qmlSignal",
nullptr);
490 s_typeNodeMap.insert(
"rectangle",
nullptr);
491 s_typeNodeMap.insert(
"request",
nullptr);
492 s_typeNodeMap.insert(
"requestId",
nullptr);
493 s_typeNodeMap.insert(
"section",
nullptr);
494 s_typeNodeMap.insert(
"selected",
nullptr);
495 s_typeNodeMap.insert(
"send",
nullptr);
496 s_typeNodeMap.insert(
"settingsClicked",
nullptr);
497 s_typeNodeMap.insert(
"shoe",
nullptr);
498 s_typeNodeMap.insert(
"short",
nullptr);
499 s_typeNodeMap.insert(
"signed",
nullptr);
500 s_typeNodeMap.insert(
"sizeChanged",
nullptr);
501 s_typeNodeMap.insert(
"size_t",
nullptr);
502 s_typeNodeMap.insert(
"sockaddr",
nullptr);
503 s_typeNodeMap.insert(
"someOtherSignal",
nullptr);
504 s_typeNodeMap.insert(
"sourceSize",
nullptr);
505 s_typeNodeMap.insert(
"startButtonClicked",
nullptr);
506 s_typeNodeMap.insert(
"state",
nullptr);
507 s_typeNodeMap.insert(
"std::initializer_list",
nullptr);
508 s_typeNodeMap.insert(
"std::list",
nullptr);
509 s_typeNodeMap.insert(
"std::map",
nullptr);
510 s_typeNodeMap.insert(
"std::pair",
nullptr);
511 s_typeNodeMap.insert(
"std::string",
nullptr);
512 s_typeNodeMap.insert(
"std::vector",
nullptr);
513 s_typeNodeMap.insert(
"stringlist",
nullptr);
514 s_typeNodeMap.insert(
"swapPlayers",
nullptr);
515 s_typeNodeMap.insert(
"symbol",
nullptr);
516 s_typeNodeMap.insert(
"t",
nullptr);
517 s_typeNodeMap.insert(
"T",
nullptr);
518 s_typeNodeMap.insert(
"tagChanged",
nullptr);
519 s_typeNodeMap.insert(
"timeString",
nullptr);
520 s_typeNodeMap.insert(
"timeout",
nullptr);
521 s_typeNodeMap.insert(
"to",
nullptr);
522 s_typeNodeMap.insert(
"toggled",
nullptr);
523 s_typeNodeMap.insert(
"type",
nullptr);
524 s_typeNodeMap.insert(
"unsigned",
nullptr);
525 s_typeNodeMap.insert(
"urllist",
nullptr);
526 s_typeNodeMap.insert(
"va_list",
nullptr);
527 s_typeNodeMap.insert(
"value",
nullptr);
528 s_typeNodeMap.insert(
"valueEmitted",
nullptr);
529 s_typeNodeMap.insert(
"videoFramePainted",
nullptr);
530 s_typeNodeMap.insert(
"videoModeSelected",
nullptr);
531 s_typeNodeMap.insert(
"videoRecorder",
nullptr);
532 s_typeNodeMap.insert(
"void",
nullptr);
533 s_typeNodeMap.insert(
"volatile",
nullptr);
534 s_typeNodeMap.insert(
"wchar_t",
nullptr);
535 s_typeNodeMap.insert(
"x",
nullptr);
536 s_typeNodeMap.insert(
"y",
nullptr);
537 s_typeNodeMap.insert(
"zoom",
nullptr);
538 s_typeNodeMap.insert(
"zoomTo",
nullptr);
542
543
546
547
548
549
552
553
554
555
558
559
560
561
564
565
566
567
568
569
570
573
574
575
576
577
578
579
582
583
584
585
586
587
590
591
592
593
594
595
598
599
600
601
602
603
606
607
608
609
610
611
612
613
616
617
618
619
620
621
624
625
626
627
630
631
632
635
636
637
638
639
640
641
644 if (!qmid.isEmpty()) {
645 if (
auto *qcn = m_forest.lookupQmlType(qmid + u"::"_s + name, relative); qcn)
650 if (
auto *qcn = m_forest.lookupQmlType(name, relative); qcn)
654 QStringList path(name);
655 return static_cast<QmlTypeNode *>(m_forest.findNodeByNameAndType(path, &Node::isQmlType));
659
660
661
662
672 if (!record.m_importId.isEmpty()) {
673 const QString namespacePrefix{
"%1."_L1.arg(record.m_importId)};
674 if (!type.startsWith(namespacePrefix))
676 type.remove(0, namespacePrefix.size());
679 const QString qmName = record.m_importUri.isEmpty() ? record.m_moduleName : record.m_importUri;
680 return m_forest.lookupQmlType(qmName + u"::"_s + type, relative);
684
685
686
687
688
689
698
699
700
701
702
703
716
717
718
719
720
723 Tree *t = m_forest.firstTree();
725 if (!m_completedFindFunctions.values(t).contains(func)) {
726 (
this->*(func))(t->root());
727 m_completedFindFunctions.insert(t, func);
729 t = m_forest.nextTree();
734
735
739 return m_legaleseTexts;
743
744
748 return s_classesWithObsoleteMembers;
752
753
757 return s_obsoleteQmlTypes;
761
762
766 return s_qmlTypesWithObsoleteMembers;
770
771
775 return s_qmlBasicTypes;
779
780
788
789
797
798
802 return m_attributions;
806
807
811 return s_obsoleteClasses;
815
816
824
825
826
830 return m_functionIndex;
834
835
836
839 for (
const auto &childNode : node->childNodes()) {
840 if (childNode->isPrivate())
842 if (!childNode->doc().legaleseText().isEmpty())
843 m_legaleseTexts.insert(childNode->doc().legaleseText(), childNode);
844 if (childNode->isAggregate())
845 findAllLegaleseTexts(
static_cast<Aggregate *>(childNode));
850
851
852
853
854
855
858
859
860
861
862
863
864
865
866
869
870
871
872
873
874
875
878
879
880
881
885 auto it = s_newClassMaps.constFind(key);
890
891
892
893
897 auto it = s_newQmlTypeMaps.constFind(key);
902
903
904
905
909 auto it = s_newSinceMaps.constFind(key);
914
915
916
917
920 const auto &config = Config::instance();
921 if (config.dualExec() || config.preparing()) {
938 if (config.singleExec() && config.generating()) {
946 if (!config.preparing()) {
952 if (config.dualExec())
958 Tree *t = m_forest.firstTree();
960 t->resolveBaseClasses(t->root());
963 t = m_forest.nextTree();
968
969
970
971
972
976 for (
const auto &name : td->referenced_concepts)
977 refs.append(QString::fromStdString(name));
980 const auto *fn =
static_cast<
const FunctionNode *>(node);
981 refs += fn->referencedConcepts();
986
987
988
989
990
991
994 for (
auto *child : std::as_const(parent->childNodes())) {
1000 const bool registerChild =
1001 !child->isPrivate() && !child->isInternal() && !child->isDontDocument();
1003 if (registerChild) {
1005 collectConceptReferences(child, refs);
1007 refs.removeDuplicates();
1009 for (
const QString &conceptName : std::as_const(refs)) {
1022 if (
auto *cn = db.findMutableCollectionNode(conceptName, NodeType::Concept))
1023 cn->addMember(child);
1027 if (child->isAggregate())
1028 registerConceptUsersUnder(
static_cast<Aggregate *>(child), db);
1033
1034
1035
1036
1037
1038
1039
1040
1047
1048
1049
1050
1051
1055 return m_namespaceIndex;
1059
1060
1061
1062
1063
1064
1065
1068 if (!m_namespaceIndex.isEmpty())
1073 Tree *t = m_forest.firstTree();
1076 t = m_forest.nextTree();
1078 const QList<QString> keys = namespaceMultimap.uniqueKeys();
1079 for (
const QString &key : keys) {
1080 NamespaceNode *ns =
nullptr;
1081 NamespaceNode *indexNamespace =
nullptr;
1082 const NodeList namespaces = namespaceMultimap.values(key);
1083 qsizetype count = namespaceMultimap.remove(key);
1085 for (
auto *node : namespaces) {
1086 ns =
static_cast<NamespaceNode *>(node);
1087 if (ns->isDocumentedHere())
1089 else if (ns->hadDoc())
1090 indexNamespace = ns;
1094 for (
auto *node : namespaces) {
1095 auto *nsNode =
static_cast<NamespaceNode *>(node);
1096 if (nsNode->hadDoc() && nsNode != ns) {
1097 ns->doc().location().warning(
1098 QStringLiteral(
"Namespace %1 documented more than once")
1099 .arg(nsNode->name()), QStringLiteral(
"also seen here: %1")
1100 .arg(nsNode->doc().location().toString()));
1103 }
else if (!indexNamespace) {
1108 for (
auto *node : namespaces) {
1109 if (!node->isIndexNode())
1110 static_cast<NamespaceNode *>(node)->reportDocumentedChildrenInUndocumentedNamespace();
1114 for (
auto *node : namespaces) {
1115 auto *nsNode =
static_cast<NamespaceNode *>(node);
1116 if (nsNode != indexNamespace)
1117 nsNode->setDocNode(indexNamespace);
1122
1123
1124
1125
1126
1127 if (ns && count > 1) {
1128 for (
auto *node : namespaces) {
1129 auto *nameSpaceNode =
static_cast<NamespaceNode *>(node);
1130 if (nameSpaceNode != ns) {
1131 for (
auto it = nameSpaceNode->constBegin(); it != nameSpaceNode->constEnd();
1133 Node *anotherNs = *it;
1134 if (anotherNs && anotherNs->isPublic() && !anotherNs->isInternal())
1135 ns->includeChild(anotherNs);
1141
1142
1143
1145 ns = indexNamespace ? indexNamespace :
static_cast<NamespaceNode *>(namespaces.last());
1146 m_namespaceIndex.insert(ns->name(), ns);
1151
1152
1153
1154
1155
1156
1157
1158
1159
1164 Tree *t = m_forest.firstTree();
1165 t = m_forest.nextTree();
1168 if (!proxies.isEmpty()) {
1169 for (
auto *node : proxies) {
1170 const auto *pn =
static_cast<ProxyNode *>(node);
1171 if (pn->count() > 0) {
1172 Aggregate *aggregate = primaryTree()->findAggregate(pn->name());
1173 if (aggregate !=
nullptr)
1174 aggregate->appendToRelatedByProxy(pn->childNodes());
1178 t = m_forest.nextTree();
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1199 QString function = target;
1200 qsizetype length = target.size();
1201 if (function.endsWith(
"()"))
1203 if (function.endsWith(QChar(
')'))) {
1204 qsizetype position = function.lastIndexOf(QChar(
'('));
1205 signature = function.mid(position + 1, length - position - 2);
1206 function = function.left(position);
1208 QStringList path = function.split(
"::");
1209 return m_forest.findFunctionNode(path, Parameters(signature), relative, genus);
1213
1214
1215
1216
1217
1218
1219
1220
1221
1225 if ((genus == Genus::QML || (relative && relative
->genus() == Genus::QML)) &&
1226 type.contains(
'.') && !type.contains(
"::")) {
1228 const QmlTypeNode *qmlType =
static_cast<
const QmlTypeNode*>(relative);
1231 for (
const auto &import : imports) {
1232 if (QmlTypeNode *found = findQmlType(import, type)) {
1239 QStringList path = type.split(
".");
1240 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1241 auto it = s_typeNodeMap.find(path.at(0));
1242 if (it != s_typeNodeMap.end())
1247 const Node *node = m_forest.findTypeNode(path, relative, genus);
1254 if (path.size() > 1) {
1255 const Node *lastSegmentNode = m_forest.findTypeNode(QStringList{path.last()}, relative, genus);
1257 return lastSegmentNode;
1264 QStringList path = type.split(
"::");
1265 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1266 auto it = s_typeNodeMap.find(path.at(0));
1267 if (it != s_typeNodeMap.end())
1270 return m_forest.findTypeNode(path, relative, genus);
1274
1275
1276
1277
1278
1281 const Node *node =
nullptr;
1282 if (target.isEmpty())
1284 else if (target.endsWith(
".html"))
1285 node = findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1287 QStringList path = target.split(
"::");
1289 for (
const auto *tree : searchOrder()) {
1290 const Node *n = tree->findNode(path, relative, flags, Genus::DontCare);
1295 node = findPageNodeByTitle(target);
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1315 Genus genus,
const QString &moduleName,
1318 if (target.isEmpty())
1321 Tree *domain = moduleName.isEmpty() ?
nullptr : findTree(moduleName);
1324 const Node *node =
nullptr;
1325 if (target.endsWith(
".html"_L1)) {
1326 node = domain->findNodeByNameAndType(QStringList(target), &
Node::isPageNode);
1327 }
else if (target.endsWith(
')'_L1)) {
1328 QString function = target;
1330 if (function.endsWith(
"()"_L1))
1332 if (function.endsWith(
')'_L1)) {
1333 qsizetype position = function.lastIndexOf(
'('_L1);
1334 signature = function.mid(position + 1, function.size() - position - 2);
1335 function = function.left(position);
1337 QStringList path = function.split(
"::"_L1);
1338 node = domain->findFunctionNode(path,
Parameters(signature),
nullptr, genus);
1343 if (genus == Genus::QML && target.contains(
'.'_L1) && !target.contains(
"::"_L1)) {
1345 QStringList path = target.split(
'.'_L1);
1346 node = domain->findNode(path, relative, typeFlags, genus);
1349 if (path.size() > 1) {
1350 node = domain->findNode(QStringList{path.last()}, relative, typeFlags, genus);
1357 QStringList nodePath = target.split(
"::"_L1);
1358 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1361 const Node *result =
1362 domain->findNodeForTarget(nodePath, {}, relative, flags, genus, localRef);
1369 if (target.endsWith(
".html"_L1))
1370 return findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1372 if (target.endsWith(
')'_L1)) {
1373 const Node *node = findFunctionNode(target, relative, genus);
1378 if (genus == Genus::QML && target.contains(
'.'_L1) && !target.contains(
"::"_L1)) {
1379 const Node *node = findTypeNode(target, relative, genus);
1384 QStringList targetPath = Utilities::pathAndFragment(target);
1387 const Node *node = findNodeForTarget(targetPath, relative, genus, localRef, flags);
1394 return findPageNodeByTitle(target);
1405 for (
auto it = m->cbegin(); it != m->cend(); ++it)
1406 if (it.value()->members().contains(node))
1413
1414
1417 QStringList filesToRead;
1418 for (
const QString &file : indexFiles) {
1419 QString fn = file.mid(file.lastIndexOf(QChar(
'/')) + 1);
1421 filesToRead << file;
1423 qCCritical(lcQdoc) <<
"Index file" << file <<
"is already in memory.";
1429
1430
1431
1432
1433
1434
1435
1436
1437
1442 const Generator *generator = hrefGenerator;
1444 generator = Generator::generatorForFormat(u"HTML"_s);
1446 qCWarning(lcQdoc) <<
"Cannot generate index file: no href generator available"
1447 " (HTML generator missing)";
1451 QString t = fileName.mid(fileName.lastIndexOf(QChar(
'/')) + 1);
1453 QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, generator);
1458
1459
1460
1461
1470 moduleName = relative->physicalModuleName();
1474 moduleName = relative->logicalModuleName();
1479 if (moduleName.isEmpty())
1482 return primaryTree()->getCollection(moduleName, moduleType);
1486
1487
1488
1489
1494 for (
auto *tree : searchOrder()) {
1495 CNMap *m = tree->getCollectionMap(type);
1496 if (m && !m->isEmpty()) {
1497 for (
auto it = m->cbegin(); it != m->cend(); ++it) {
1498 if (!it.value()->isInternal())
1499 cnmm.insert(it.key(), it.value());
1505 static const QRegularExpression singleDigit(
"\\b([0-9])\\b");
1506 const QStringList keys = cnmm.uniqueKeys();
1507 for (
const auto &key : keys) {
1508 const QList<CollectionNode *> values = cnmm.values(key);
1509 CollectionNode *n =
nullptr;
1510 for (
auto *value : values) {
1511 if (value && value->wasSeen() && value != relative) {
1517 if (values.size() > 1) {
1518 for (CollectionNode *value : values) {
1521 if ((n->isQmlModule())
1522 && n->logicalModuleIdentifier() != value->logicalModuleIdentifier()) {
1523 if (value->wasSeen() && value != relative)
1524 cnm.insert(value->fullTitle().toLower(), value);
1527 for (Node *t : value->members())
1532 QString sortKey = n->fullTitle().toLower();
1533 if (sortKey.startsWith(
"the "))
1534 sortKey.remove(0, 4);
1535 sortKey.replace(singleDigit,
"0\\1");
1536 cnm.insert(sortKey, n);
1542
1543
1544
1545
1546
1547
1548
1549
1594 for (
auto *tree : searchOrder()) {
1595 CollectionNode *cn = tree->getCollection(c->name(), c->nodeType());
1596 if (cn && cn != c) {
1597 if ((cn->isQmlModule())
1598 && cn->logicalModuleIdentifier() != c->logicalModuleIdentifier())
1601 for (
auto *node : cn->members())
1661 if (!c->wasSeen() && cn->wasSeen()) {
1663 c->setTitle(cn->title());
1664 c->setUrl(cn->url());
1665 c->setResolvedPhysicalModuleName(cn->tree()->physicalModuleName());
1674
1675
1676
1677
1678
1679
1680
1687 for (
auto piece : path.split(
"."_L1)) {
1688 for (
auto inner : piece.split(
"::"_L1)) {
1689 pieces.append(inner);
1694 QString modName{
""};
1695 QString tryName{
""};
1696 const Node *modNode{
nullptr};
1699 for (i = 0; i < pieces.count(); i++) {
1700 tryName += pieces.at(i);
1701 const Node *node = findNodeByNameAndType(QStringList(tryName), &Node::isQmlModule);
1713 if (i == pieces.count())
1719 pieces = pieces.mid(i);
1720 qtn = findQmlType(modName, pieces.takeFirst(), relative);
1722 qtn = findQmlType(pieces.takeFirst(), relative);
1725 if (!qtn || pieces.isEmpty())
1728 auto propertyName = pieces.join(
"."_L1);
1737 return qtn->findChildNode(propertyName, Genus::QML);
1741
1742
1743
1744
1745
1746
1747
1748
1752 const Node *node =
nullptr;
1754 Atom *atom =
const_cast<
Atom *>(a);
1755 QStringList targetPath = Utilities::pathAndFragment(atom->string());
1756 QString first = targetPath.first().trimmed();
1758 Tree *domain =
nullptr;
1762 domain = atomDomain;
1766 if (!first.contains(
"://"_L1) && !first.contains(
" "_L1) && !first.endsWith(
".html"_L1) && first.contains(
"."_L1)) {
1767 const Node *found = findQmlNode(first, relative);
1768 if (found)
return found;
1772 if (first.isEmpty())
1775 if (first.endsWith(
".html"))
1776 node = domain->findNodeByNameAndType(QStringList(first), &
Node::isPageNode);
1777 else if (first.endsWith(QChar(
')'))) {
1779 QString function = first;
1780 qsizetype length = first.size();
1781 if (function.endsWith(
"()"))
1783 if (function.endsWith(QChar(
')'))) {
1784 qsizetype position = function.lastIndexOf(QChar(
'('));
1785 signature = function.mid(position + 1, length - position - 2);
1786 function = function.left(position);
1788 QStringList path = function.split(
"::");
1789 node = domain->findFunctionNode(path,
Parameters(signature),
nullptr, genus);
1791 if (node ==
nullptr) {
1793 QStringList nodePath = first.split(
"::");
1795 targetPath.removeFirst();
1796 if (!targetPath.isEmpty())
1797 target = targetPath.takeFirst();
1798 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1800 return domain->findNodeForTarget(nodePath, target, relative, flags, genus, ref);
1803 if (first.endsWith(
".html"))
1804 node = findNodeByNameAndType(QStringList(first), &Node::isPageNode);
1805 else if (first.endsWith(QChar(
')')))
1806 node = findFunctionNode(first, relative, genus);
1807 if (node ==
nullptr) {
1809 if (genus == Genus::QML && first.contains(
'.') && !first.contains(
"::")) {
1811 node = findTypeNode(first, relative, genus);
1814 targetPath.removeFirst();
1815 if (!targetPath.isEmpty()) {
1823 return findNodeForTarget(targetPath, relative, genus, ref, atom->flags());
1827 if (node !=
nullptr && ref.isEmpty()) {
1828 if (!node->url().isEmpty())
1830 targetPath.removeFirst();
1831 if (!targetPath.isEmpty()) {
1841
1842
1843
1844
1845
1846
1847
1848
1852 QList<Tree *> searchOrder =
this->searchOrder();
1871 bool inclusive{Config::instance().get(
1875 const auto tocTitles{Config::instance().get(configVar).asStringList()};
1877 for (
const auto &tocTitle : tocTitles) {
1878 if (
const auto candidateTarget = findNodeForTarget(tocTitle,
nullptr); candidateTarget && candidateTarget->isPageNode()) {
1879 auto tocPage{
static_cast<
const PageNode*>(candidateTarget)};
1881 Text body = tocPage->doc().body();
1883 auto *atom = body.firstAtom();
1885 std::pair<PageNode *, QString> prev {
nullptr, QString() };
1887 std::stack<
const PageNode *> tocStack;
1888 tocStack.push(inclusive ? tocPage :
nullptr);
1890 bool inItem =
false;
1897 switch (atom->type()) {
1898 case Atom::ListItemLeft:
1900 tocStack.push(
nullptr);
1903 case Atom::ListItemRight:
1943 auto candidatePage =
const_cast<Node *>(findNodeForAtom(atom,
nullptr, unused));
1944 if (!candidatePage || !candidatePage->isPageNode())
break;
1946 auto page{
static_cast<PageNode*>(candidatePage)};
1949 if (page == prev.first)
break;
1952 prev.first->setLink(
1993 prev.first->title(),
1998 if (page == tocPage)
2003 qsizetype popped = 0;
2004 while (tocStack.size() > 1 && !tocStack.top()) {
2009 page->setNavigationParent(tocStack.empty() ?
nullptr : tocStack.top());
2011 while (--popped > 0)
2012 tocStack.push(
nullptr);
2014 tocStack.push(page);
2016 prev = { page, atom->linkText() };
2020 case Atom::AnnotatedList:
2021 case Atom::GeneratedList: {
2022 if (
const auto *cn = getCollectionNode(atom->string(), NodeType::Group)) {
2023 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
2024 NodeList members{cn->members()};
2027 members.erase(std::remove_if(members.begin(), members.end(),
2029 return n->isIndexNode() || !n->isPageNode() || n->isExternalPage();
2031 if (members.isEmpty())
2034 if (sortOrder == Qt::DescendingOrder)
2035 std::sort(members.rbegin(), members.rend(), Node::nodeSortKeyOrNameLessThan);
2037 std::sort(members.begin(), members.end(), Node::nodeSortKeyOrNameLessThan);
2042 for (
auto *m : members) {
2043 auto *page =
static_cast<PageNode *>(m);
2045 prev.first->setLink(Node::NextLink, page->title(), page->fullName());
2046 page->setLink(Node::PreviousLink, prev.first->title(), prev.second);
2048 prev = { page, page->fullName() };
2058 atom = atom->next();
2061 Config::instance().get(configVar).location()
2062 .warning(QStringLiteral(
"Failed to find table of contents with title '%1'")
2068 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 ...
const Node * findQmlNode(const QString &path, const Node *relative)
Returns the node to a piece of QML API documentation that corresponds to the given path,...
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.