19#include <QtCore/qregularexpression.h>
24using namespace Qt::StringLiterals;
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
62
65
66
67
68
69
70
73 for (
auto *entry : m_searchOrder)
76 m_searchOrder.clear();
77 m_indexSearchOrder.clear();
78 m_moduleNames.clear();
79 m_primaryTree =
nullptr;
83
84
85
86
90 return (!searchOrder().isEmpty() ? searchOrder()[0] :
nullptr);
94
95
96
97
101 return (m_currentIndex < searchOrder().size() ? searchOrder()[m_currentIndex] :
nullptr);
105
106
107
108
111
112
113
114
115
116
117
118
119void QDocForest::setPrimaryTree(
const QString &t)
121 QString T = t.toLower();
122 m_primaryTree = findTree(T);
124 if (m_primaryTree ==
nullptr)
125 qCCritical(lcQdoc) <<
"Error: Could not set primary tree to" << t;
129
130
131
132void QDocForest::setSearchOrder(
const QStringList &t)
134 if (!m_searchOrder.isEmpty())
138 m_searchOrder.reserve(m_forest.size() + 1);
139 m_searchOrder.clear();
140 m_moduleNames.reserve(m_forest.size() + 1);
141 m_moduleNames.clear();
144 QString primaryName = primaryTree()->physicalModuleName();
145 m_searchOrder.append(m_primaryTree);
146 m_moduleNames.append(primaryName);
147 m_forest.remove(primaryName);
149 for (
const QString &m : t) {
150 if (primaryName != m) {
151 auto it = m_forest.find(m);
152 if (it != m_forest.end()) {
153 m_searchOrder.append(it.value());
154 m_moduleNames.append(m);
160
161
162
163
164 if (!m_forest.isEmpty()) {
165 for (
auto it = m_forest.begin(); it != m_forest.end(); ++it) {
166 m_searchOrder.append(it.value());
167 m_moduleNames.append(it.key());
173
174
175
176
177
178
179
180 for (
int i = 0; i < m_searchOrder.size(); ++i) {
181 if (!m_forest.contains(m_moduleNames.at(i))) {
182 m_forest.insert(m_moduleNames.at(i), m_searchOrder.at(i));
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
214 if (m_searchOrder.isEmpty())
215 return indexSearchOrder();
216 return m_searchOrder;
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234const QList<Tree *> &
QDocForest::indexSearchOrder()
236 if (m_forest.size() > m_indexSearchOrder.size())
237 m_indexSearchOrder.prepend(m_primaryTree);
238 return m_indexSearchOrder;
242
243
244
245
248 m_primaryTree =
new Tree(module, m_qdb);
249 m_forest.insert(module.toLower(), m_primaryTree);
250 return m_primaryTree->root();
254
255
256
257void QDocForest::newPrimaryTree(
const QString &module)
259 m_primaryTree =
new Tree(module, m_qdb);
263
264
265
266
267
268
269
270
271
272
273
274
275
276const Node *
QDocForest::findNodeForTarget(QStringList &targetPath,
const Node *relative,
277 Genus genus, QString &ref,
int findFlags)
281 QString entity = targetPath.takeFirst();
282 QStringList entityPath = entity.split(
"::");
285 if (!targetPath.isEmpty())
286 target = targetPath.takeFirst();
289 const Node *tocNode =
nullptr;
290 for (
const auto *tree : searchOrder()) {
291 const Node *n = tree->findNodeForTarget(entityPath, target, relative, flags, genus, ref, &type);
294 if (type != TargetRec::Contents)
305
306
307
308
309
310
311
312
313
318 for (
const auto *tree : searchOrder()) {
319 const FunctionNode *fn = tree->findFunctionNode(path, parameters, relative, genus);
328
329
330
331
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
370
371
372
375 if (s_qdocDB ==
nullptr) {
383
384
387 if (s_qdocDB !=
nullptr) {
394
395
396
397
398
399
400
401
402
403
404
405
406
409 s_typeNodeMap.insert(
"accepted",
nullptr);
410 s_typeNodeMap.insert(
"actionPerformed",
nullptr);
411 s_typeNodeMap.insert(
"activated",
nullptr);
412 s_typeNodeMap.insert(
"alias",
nullptr);
413 s_typeNodeMap.insert(
"anchors",
nullptr);
414 s_typeNodeMap.insert(
"any",
nullptr);
415 s_typeNodeMap.insert(
"array",
nullptr);
416 s_typeNodeMap.insert(
"autoSearch",
nullptr);
417 s_typeNodeMap.insert(
"axis",
nullptr);
418 s_typeNodeMap.insert(
"backClicked",
nullptr);
419 s_typeNodeMap.insert(
"boomTime",
nullptr);
420 s_typeNodeMap.insert(
"border",
nullptr);
421 s_typeNodeMap.insert(
"buttonClicked",
nullptr);
422 s_typeNodeMap.insert(
"callback",
nullptr);
423 s_typeNodeMap.insert(
"char",
nullptr);
424 s_typeNodeMap.insert(
"clicked",
nullptr);
425 s_typeNodeMap.insert(
"close",
nullptr);
426 s_typeNodeMap.insert(
"closed",
nullptr);
427 s_typeNodeMap.insert(
"cond",
nullptr);
428 s_typeNodeMap.insert(
"data",
nullptr);
429 s_typeNodeMap.insert(
"dataReady",
nullptr);
430 s_typeNodeMap.insert(
"dateString",
nullptr);
431 s_typeNodeMap.insert(
"dateTimeString",
nullptr);
432 s_typeNodeMap.insert(
"datetime",
nullptr);
433 s_typeNodeMap.insert(
"day",
nullptr);
434 s_typeNodeMap.insert(
"deactivated",
nullptr);
435 s_typeNodeMap.insert(
"drag",
nullptr);
436 s_typeNodeMap.insert(
"easing",
nullptr);
437 s_typeNodeMap.insert(
"error",
nullptr);
438 s_typeNodeMap.insert(
"exposure",
nullptr);
439 s_typeNodeMap.insert(
"fatalError",
nullptr);
440 s_typeNodeMap.insert(
"fileSelected",
nullptr);
441 s_typeNodeMap.insert(
"flags",
nullptr);
442 s_typeNodeMap.insert(
"float",
nullptr);
443 s_typeNodeMap.insert(
"focus",
nullptr);
444 s_typeNodeMap.insert(
"focusZone",
nullptr);
445 s_typeNodeMap.insert(
"format",
nullptr);
446 s_typeNodeMap.insert(
"framePainted",
nullptr);
447 s_typeNodeMap.insert(
"from",
nullptr);
448 s_typeNodeMap.insert(
"frontClicked",
nullptr);
449 s_typeNodeMap.insert(
"function",
nullptr);
450 s_typeNodeMap.insert(
"hasOpened",
nullptr);
451 s_typeNodeMap.insert(
"hovered",
nullptr);
452 s_typeNodeMap.insert(
"hoveredTitle",
nullptr);
453 s_typeNodeMap.insert(
"hoveredUrl",
nullptr);
454 s_typeNodeMap.insert(
"imageCapture",
nullptr);
455 s_typeNodeMap.insert(
"imageProcessing",
nullptr);
456 s_typeNodeMap.insert(
"index",
nullptr);
457 s_typeNodeMap.insert(
"initialized",
nullptr);
458 s_typeNodeMap.insert(
"isLoaded",
nullptr);
459 s_typeNodeMap.insert(
"item",
nullptr);
460 s_typeNodeMap.insert(
"key",
nullptr);
461 s_typeNodeMap.insert(
"keysequence",
nullptr);
462 s_typeNodeMap.insert(
"listViewClicked",
nullptr);
463 s_typeNodeMap.insert(
"loadRequest",
nullptr);
464 s_typeNodeMap.insert(
"locale",
nullptr);
465 s_typeNodeMap.insert(
"location",
nullptr);
466 s_typeNodeMap.insert(
"long",
nullptr);
467 s_typeNodeMap.insert(
"message",
nullptr);
468 s_typeNodeMap.insert(
"messageReceived",
nullptr);
469 s_typeNodeMap.insert(
"mode",
nullptr);
470 s_typeNodeMap.insert(
"month",
nullptr);
471 s_typeNodeMap.insert(
"name",
nullptr);
472 s_typeNodeMap.insert(
"number",
nullptr);
473 s_typeNodeMap.insert(
"object",
nullptr);
474 s_typeNodeMap.insert(
"offset",
nullptr);
475 s_typeNodeMap.insert(
"ok",
nullptr);
476 s_typeNodeMap.insert(
"openCamera",
nullptr);
477 s_typeNodeMap.insert(
"openImage",
nullptr);
478 s_typeNodeMap.insert(
"openVideo",
nullptr);
479 s_typeNodeMap.insert(
"padding",
nullptr);
480 s_typeNodeMap.insert(
"parent",
nullptr);
481 s_typeNodeMap.insert(
"path",
nullptr);
482 s_typeNodeMap.insert(
"photoModeSelected",
nullptr);
483 s_typeNodeMap.insert(
"position",
nullptr);
484 s_typeNodeMap.insert(
"precision",
nullptr);
485 s_typeNodeMap.insert(
"presetClicked",
nullptr);
486 s_typeNodeMap.insert(
"preview",
nullptr);
487 s_typeNodeMap.insert(
"previewSelected",
nullptr);
488 s_typeNodeMap.insert(
"progress",
nullptr);
489 s_typeNodeMap.insert(
"puzzleLost",
nullptr);
490 s_typeNodeMap.insert(
"qmlSignal",
nullptr);
491 s_typeNodeMap.insert(
"rectangle",
nullptr);
492 s_typeNodeMap.insert(
"request",
nullptr);
493 s_typeNodeMap.insert(
"requestId",
nullptr);
494 s_typeNodeMap.insert(
"section",
nullptr);
495 s_typeNodeMap.insert(
"selected",
nullptr);
496 s_typeNodeMap.insert(
"send",
nullptr);
497 s_typeNodeMap.insert(
"settingsClicked",
nullptr);
498 s_typeNodeMap.insert(
"shoe",
nullptr);
499 s_typeNodeMap.insert(
"short",
nullptr);
500 s_typeNodeMap.insert(
"signed",
nullptr);
501 s_typeNodeMap.insert(
"sizeChanged",
nullptr);
502 s_typeNodeMap.insert(
"size_t",
nullptr);
503 s_typeNodeMap.insert(
"sockaddr",
nullptr);
504 s_typeNodeMap.insert(
"someOtherSignal",
nullptr);
505 s_typeNodeMap.insert(
"sourceSize",
nullptr);
506 s_typeNodeMap.insert(
"startButtonClicked",
nullptr);
507 s_typeNodeMap.insert(
"state",
nullptr);
508 s_typeNodeMap.insert(
"std::initializer_list",
nullptr);
509 s_typeNodeMap.insert(
"std::list",
nullptr);
510 s_typeNodeMap.insert(
"std::map",
nullptr);
511 s_typeNodeMap.insert(
"std::pair",
nullptr);
512 s_typeNodeMap.insert(
"std::string",
nullptr);
513 s_typeNodeMap.insert(
"std::vector",
nullptr);
514 s_typeNodeMap.insert(
"stringlist",
nullptr);
515 s_typeNodeMap.insert(
"swapPlayers",
nullptr);
516 s_typeNodeMap.insert(
"symbol",
nullptr);
517 s_typeNodeMap.insert(
"t",
nullptr);
518 s_typeNodeMap.insert(
"T",
nullptr);
519 s_typeNodeMap.insert(
"tagChanged",
nullptr);
520 s_typeNodeMap.insert(
"timeString",
nullptr);
521 s_typeNodeMap.insert(
"timeout",
nullptr);
522 s_typeNodeMap.insert(
"to",
nullptr);
523 s_typeNodeMap.insert(
"toggled",
nullptr);
524 s_typeNodeMap.insert(
"type",
nullptr);
525 s_typeNodeMap.insert(
"unsigned",
nullptr);
526 s_typeNodeMap.insert(
"urllist",
nullptr);
527 s_typeNodeMap.insert(
"va_list",
nullptr);
528 s_typeNodeMap.insert(
"value",
nullptr);
529 s_typeNodeMap.insert(
"valueEmitted",
nullptr);
530 s_typeNodeMap.insert(
"videoFramePainted",
nullptr);
531 s_typeNodeMap.insert(
"videoModeSelected",
nullptr);
532 s_typeNodeMap.insert(
"videoRecorder",
nullptr);
533 s_typeNodeMap.insert(
"void",
nullptr);
534 s_typeNodeMap.insert(
"volatile",
nullptr);
535 s_typeNodeMap.insert(
"wchar_t",
nullptr);
536 s_typeNodeMap.insert(
"x",
nullptr);
537 s_typeNodeMap.insert(
"y",
nullptr);
538 s_typeNodeMap.insert(
"zoom",
nullptr);
539 s_typeNodeMap.insert(
"zoomTo",
nullptr);
543
544
547
548
549
550
553
554
555
556
559
560
561
562
565
566
567
568
569
570
571
574
575
576
577
578
579
580
583
584
585
586
587
588
591
592
593
594
595
596
599
600
601
602
603
604
607
608
609
610
611
612
613
614
617
618
619
620
621
622
625
626
627
628
631
632
633
636
637
638
639
640
641
642
643
644
645
649 if (!qmid.isEmpty()) {
651 ? tree->lookupQmlType(qmid + u"::"_s + name, relative)
652 : m_forest.lookupQmlType(qmid + u"::"_s + name, relative);
659 ? tree->lookupQmlType(name, relative)
660 : m_forest.lookupQmlType(name, relative);
665 QStringList path(name);
667 ? tree->findNodeByNameAndType(path, &Node::isQmlType)
668 : findNodeByNameAndType(path, &Node::isQmlType);
669 return static_cast<QmlTypeNode *>(node);
673
674
675
676
686 if (!record.m_importId.isEmpty()) {
687 const QString namespacePrefix{
"%1."_L1.arg(record.m_importId)};
688 if (!type.startsWith(namespacePrefix))
690 type.remove(0, namespacePrefix.size());
693 const QString qmName = record.m_importUri.isEmpty() ? record.m_moduleName : record.m_importUri;
694 return m_forest.lookupQmlType(qmName + u"::"_s + type, relative);
698
699
700
701
702
703
712
713
714
715
716
717
730
731
732
733
734
737 Tree *t = m_forest.firstTree();
739 if (!m_completedFindFunctions.values(t).contains(func)) {
740 (
this->*(func))(t->root());
741 m_completedFindFunctions.insert(t, func);
743 t = m_forest.nextTree();
748
749
753 return m_legaleseTexts;
757
758
762 return s_classesWithObsoleteMembers;
766
767
771 return s_obsoleteQmlTypes;
775
776
780 return s_qmlTypesWithObsoleteMembers;
784
785
789 return s_qmlBasicTypes;
793
794
802
803
811
812
816 return m_attributions;
820
821
825 return s_obsoleteClasses;
829
830
838
839
840
844 return m_functionIndex;
848
849
850
853 for (
const auto &childNode : node->childNodes()) {
854 if (childNode->isPrivate())
856 if (!childNode->doc().legaleseText().isEmpty())
857 m_legaleseTexts.insert(childNode->doc().legaleseText(), childNode);
858 if (childNode->isAggregate())
859 findAllLegaleseTexts(
static_cast<Aggregate *>(childNode));
864
865
866
867
868
869
872
873
874
875
876
877
878
879
880
883
884
885
886
887
888
889
892
893
894
895
899 auto it = s_newClassMaps.constFind(key);
904
905
906
907
911 auto it = s_newQmlTypeMaps.constFind(key);
916
917
918
919
923 auto it = s_newSinceMaps.constFind(key);
928
929
930
931
932
933
934
935
938 const auto &config = Config::instance();
939 if (config.dualExec() || config.preparing()) {
956 if (config.singleExec() && config.generating()) {
964 if (!config.preparing()) {
970 if (config.dualExec())
976 Tree *t = m_forest.firstTree();
978 t->resolveBaseClasses(t->root());
981 t = m_forest.nextTree();
986
987
988
989
990
994 for (
const auto &name : td->referenced_concepts)
995 refs.append(QString::fromStdString(name));
998 const auto *fn =
static_cast<
const FunctionNode *>(node);
999 refs += fn->referencedConcepts();
1004
1005
1006
1007
1008
1009
1012 for (
auto *child : std::as_const(parent->childNodes())) {
1018 const bool registerChild =
1019 !child->isPrivate() && !child->isInternal() && !child->isDontDocument();
1021 if (registerChild) {
1023 collectConceptReferences(child, refs);
1025 refs.removeDuplicates();
1027 for (
const QString &conceptName : std::as_const(refs)) {
1040 if (
auto *cn = db.findMutableCollectionNode(conceptName, NodeType::Concept))
1041 cn->addMember(child);
1045 if (child->isAggregate())
1046 registerConceptUsersUnder(
static_cast<Aggregate *>(child), db);
1051
1052
1053
1054
1055
1056
1057
1058
1065
1066
1067
1068
1069
1073 return m_namespaceIndex;
1077
1078
1079
1080
1081
1082
1083
1086 if (!m_namespaceIndex.isEmpty())
1091 Tree *t = m_forest.firstTree();
1094 t = m_forest.nextTree();
1096 const QList<QString> keys = namespaceMultimap.uniqueKeys();
1097 for (
const QString &key : keys) {
1098 NamespaceNode *ns =
nullptr;
1099 NamespaceNode *indexNamespace =
nullptr;
1100 const NodeList namespaces = namespaceMultimap.values(key);
1101 qsizetype count = namespaceMultimap.remove(key);
1103 for (
auto *node : namespaces) {
1104 ns =
static_cast<NamespaceNode *>(node);
1105 if (ns->isDocumentedHere())
1107 else if (ns->hadDoc())
1108 indexNamespace = ns;
1112 for (
auto *node : namespaces) {
1113 auto *nsNode =
static_cast<NamespaceNode *>(node);
1114 if (nsNode->hadDoc() && nsNode != ns) {
1115 ns->doc().location().warning(
1116 QStringLiteral(
"Namespace %1 documented more than once")
1117 .arg(nsNode->name()), QStringLiteral(
"also seen here: %1")
1118 .arg(nsNode->doc().location().toString()));
1121 }
else if (!indexNamespace) {
1126 for (
auto *node : namespaces) {
1127 if (!node->isIndexNode())
1128 static_cast<NamespaceNode *>(node)->reportDocumentedChildrenInUndocumentedNamespace();
1132 for (
auto *node : namespaces) {
1133 auto *nsNode =
static_cast<NamespaceNode *>(node);
1134 if (nsNode != indexNamespace)
1135 nsNode->setDocNode(indexNamespace);
1140
1141
1142
1143
1144
1145 if (ns && count > 1) {
1146 for (
auto *node : namespaces) {
1147 auto *nameSpaceNode =
static_cast<NamespaceNode *>(node);
1148 if (nameSpaceNode != ns) {
1149 for (
auto it = nameSpaceNode->constBegin(); it != nameSpaceNode->constEnd();
1151 Node *anotherNs = *it;
1152 if (anotherNs && anotherNs->isPublic() && !anotherNs->isInternal())
1153 ns->includeChild(anotherNs);
1159
1160
1161
1163 ns = indexNamespace ? indexNamespace :
static_cast<NamespaceNode *>(namespaces.last());
1164 m_namespaceIndex.insert(ns->name(), ns);
1169
1170
1171
1172
1173
1174
1175
1176
1177
1182 Tree *t = m_forest.firstTree();
1183 t = m_forest.nextTree();
1186 if (!proxies.isEmpty()) {
1187 for (
auto *node : proxies) {
1188 const auto *pn =
static_cast<ProxyNode *>(node);
1189 if (pn->count() > 0) {
1190 Aggregate *aggregate = primaryTree()->findAggregate(pn->name());
1191 if (aggregate !=
nullptr)
1192 aggregate->appendToRelatedByProxy(pn->childNodes());
1196 t = m_forest.nextTree();
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1216 QString function = target;
1217 const QString signature = Parameters::extractParameters(function);
1218 const Parameters parameters(signature.trimmed());
1222 const QStringList path = function.split(
"::"_L1);
1223 return m_forest.findFunctionNode(path, parameters, relative, genus);
1227
1228
1229
1230
1231
1232
1233
1234
1235
1239 if ((genus == Genus::QML || (relative && relative
->genus() == Genus::QML)) &&
1240 type.contains(
'.') && !type.contains(
"::")) {
1242 const QmlTypeNode *qmlType =
static_cast<
const QmlTypeNode*>(relative);
1245 for (
const auto &import : imports) {
1246 if (QmlTypeNode *found = findQmlType(import, type)) {
1253 QStringList path = type.split(
".");
1254 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1255 auto it = s_typeNodeMap.find(path.at(0));
1256 if (it != s_typeNodeMap.end())
1261 const Node *node = m_forest.findTypeNode(path, relative, genus);
1268 if (path.size() > 1) {
1269 const Node *lastSegmentNode = m_forest.findTypeNode(QStringList{path.last()}, relative, genus);
1271 return lastSegmentNode;
1278 QStringList path = type.split(
"::");
1279 if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString(
"T"))) {
1280 auto it = s_typeNodeMap.find(path.at(0));
1281 if (it != s_typeNodeMap.end())
1284 return m_forest.findTypeNode(path, relative, genus);
1288
1289
1290
1291
1292
1295 const Node *node =
nullptr;
1296 if (target.isEmpty())
1298 else if (target.endsWith(
".html"))
1299 node = findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1301 QStringList path = target.split(
"::");
1303 for (
const auto *tree : searchOrder()) {
1304 const Node *n = tree->findNode(path, relative, flags, Genus::DontCare);
1309 node = findPageNodeByTitle(target);
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1346 Genus genus,
const QString &moduleName,
1347 QString *ref, LinkReferenceOrigin origin,
1350 if (target.isEmpty())
1353 Tree *domain = moduleName.isEmpty() ?
nullptr : findTree(moduleName);
1356 const Node *qmlContext = relative;
1359 if (!parent || parent
->genus() != Genus::QML)
1361 qmlContext = parent;
1364 QStringList targetPath = Utilities::pathAndFragment(target);
1365 const QString first = targetPath.first().trimmed();
1366 QString qmlName = first;
1367 Parameters::extractParameters(qmlName);
1369 const bool qmlDotPath =
1370 origin == LinkReferenceOrigin::Explicit
1371 && (genus == Genus::DontCare || genus == Genus::QML)
1372 && qmlName.contains(
'.'_L1)
1373 && !qmlName.contains(
"::"_L1)
1374 && !qmlName.contains(
"://"_L1)
1375 && !qmlName.contains(
' '_L1)
1376 && !qmlName.endsWith(
".html"_L1);
1378 auto withFragment = [targetPath, ref](
const Node *node) ->
const Node * {
1380 node = setReferenceFromFragment(targetPath.value(1), node, localRef);
1386 auto findQmlDotPathNode = [
this, qmlContext, domain, &withFragment, genus, flags](
const QString &path)
1389 const Node *node = findQmlNode(path, qmlContext, FindFlags::fromInt(flags), domain);
1392 const QmlTypeNode *qmlRelative =
static_cast<
const QmlTypeNode *>(qmlContext);
1393 const QStringList pieces = path.split(
'.'_L1);
1394 if (pieces.size() >= 2) {
1395 for (
const ImportRec &import : qmlRelative->importList()) {
1396 if (import.m_importId.isEmpty() || import.m_importId != pieces.first())
1398 const QString qmid = import.m_importUri.isEmpty()
1399 ? import.m_moduleName
1400 : import.m_importUri;
1401 const QString qualifiedPath = qmid + path.mid(pieces.first().size());
1402 node = findQmlNode(qualifiedPath, qmlContext, FindFlags::fromInt(flags),
1410 if (!node && genus == Genus::QML)
1411 node = findTypeNode(path, qmlContext, genus);
1414 if (node && domain && node
->tree() != domain)
1416 return withFragment(node);
1420 const Node *node =
nullptr;
1421 if (target.endsWith(
".html"_L1)) {
1422 node = domain->findNodeByNameAndType(QStringList(target), &
Node::isPageNode);
1423 }
else if (target.endsWith(
')'_L1)) {
1424 QString function = target;
1425 const QString signature = Parameters::extractParameters(function);
1426 const Parameters parameters(signature.trimmed());
1428 const QStringList path = function.split(
"::"_L1);
1430 node = domain->findFunctionNode(path, parameters,
nullptr, genus);
1436 if (
const Node *qmlNode = findQmlDotPathNode(first))
1440 QStringList nodePath = target.split(
"::"_L1);
1441 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1444 const Node *result =
1445 domain->findNodeForTarget(nodePath, {}, relative, flags, genus, localRef);
1451 if (target.endsWith(
".html"_L1))
1452 return findNodeByNameAndType(QStringList(target), &Node::isPageNode);
1454 if (target.endsWith(
')'_L1)) {
1455 const Node *node = findFunctionNode(target, relative, genus);
1461 if (
const Node *qmlNode = findQmlDotPathNode(first))
1466 const Node *node = findNodeForTarget(targetPath, relative, genus, localRef, flags);
1473 return findPageNodeByTitle(target);
1484 for (
auto it = m->cbegin(); it != m->cend(); ++it)
1485 if (it.value()->members().contains(node))
1492
1493
1496 QStringList filesToRead;
1497 for (
const QString &file : indexFiles) {
1498 QString fn = file.mid(file.lastIndexOf(QChar(
'/')) + 1);
1500 filesToRead << file;
1502 qCCritical(lcQdoc) <<
"Index file" << file <<
"is already in memory.";
1508
1509
1510
1511
1512
1516 QString t = fileName.mid(fileName.lastIndexOf(QChar(
'/')) + 1);
1518 QDocIndexFiles::qdocIndexFiles()->generateIndex(fileName, url, title, context);
1523
1524
1525
1526
1535 moduleName = relative->physicalModuleName();
1539 moduleName = relative->logicalModuleName();
1544 if (moduleName.isEmpty())
1547 return primaryTree()->getCollection(moduleName, moduleType);
1551
1552
1553
1554
1559 for (
auto *tree : searchOrder()) {
1560 CNMap *m = tree->getCollectionMap(type);
1561 if (m && !m->isEmpty()) {
1562 for (
auto it = m->cbegin(); it != m->cend(); ++it) {
1563 if (!it.value()->isInternal())
1564 cnmm.insert(it.key(), it.value());
1570 static const QRegularExpression singleDigit(
"\\b([0-9])\\b");
1571 const QStringList keys = cnmm.uniqueKeys();
1572 for (
const auto &key : keys) {
1573 const QList<CollectionNode *> values = cnmm.values(key);
1574 CollectionNode *n =
nullptr;
1575 for (
auto *value : values) {
1576 if (value && value->wasSeen() && value != relative) {
1582 if (values.size() > 1) {
1583 for (CollectionNode *value : values) {
1586 if ((n->isQmlModule())
1587 && n->logicalModuleIdentifier() != value->logicalModuleIdentifier()) {
1588 if (value->wasSeen() && value != relative)
1589 cnm.insert(value->fullTitle().toLower(), value);
1592 for (Node *t : value->members())
1597 QString sortKey = n->fullTitle().toLower();
1598 if (sortKey.startsWith(
"the "))
1599 sortKey.remove(0, 4);
1600 sortKey.replace(singleDigit,
"0\\1");
1601 cnm.insert(sortKey, n);
1607
1608
1609
1610
1611
1612
1613
1614
1659 for (
auto *tree : searchOrder()) {
1660 CollectionNode *cn = tree->getCollection(c->name(), c->nodeType());
1661 if (cn && cn != c) {
1662 if ((cn->isQmlModule())
1663 && cn->logicalModuleIdentifier() != c->logicalModuleIdentifier())
1666 for (
auto *node : cn->members())
1726 if (!c->wasSeen() && cn->wasSeen()) {
1728 c->setTitle(cn->title());
1729 c->setUrl(cn->url());
1730 c->setResolvedPhysicalModuleName(cn->tree()->physicalModuleName());
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1754 QString qmlPath = path;
1755 const QString signature = Parameters::extractParameters(qmlPath);
1756 const bool findFunction = !signature.isNull();
1758 for (
const QString &piece : qmlPath.split(
'.'_L1))
1759 pieces.append(piece.split(
"::"_L1));
1762 QString candidateName;
1763 const Node *moduleNode =
nullptr;
1764 qsizetype modulePrefixSize = 0;
1765 for (; modulePrefixSize < pieces.size(); ++modulePrefixSize) {
1766 candidateName += pieces.at(modulePrefixSize);
1767 const Node *node = tree
1768 ? tree->findNodeByNameAndType({candidateName}, &Node::isQmlModule)
1769 : findNodeByNameAndType({candidateName}, &Node::isQmlModule);
1774 candidateName +=
'.'_L1;
1777 if (modulePrefixSize == pieces.size())
1778 return findFunction ?
nullptr : moduleNode;
1782 pieces.remove(0, modulePrefixSize);
1783 qmlType = findQmlType(moduleNode->name(), pieces.takeFirst(), relative, tree);
1785 qmlType = findQmlType(pieces.takeFirst(), relative, tree);
1787 if (!qmlType || pieces.isEmpty())
1788 return findFunction ?
nullptr : qmlType;
1792 const auto findProperty = [searchType](
const QmlTypeNode *type,
const QString &name)
1794 const QmlPropertyNode *property = type->hasQmlProperty(name, searchType);
1802 while (pieces.size() > 1) {
1803 const QmlPropertyNode *property = findProperty(qmlType, pieces.first());
1808 ? findQmlType(moduleNode->name(), property->dataType(), relative, tree)
1809 : findQmlType(property->dataType(), relative, tree);
1814 pieces.removeFirst();
1820 const Parameters parameters(signature.trimmed());
1826 const QString memberName = pieces.join(
'.'_L1);
1827 if (
const QmlPropertyNode *property = findProperty(qmlType, memberName))
1832 return qmlType->findChildNode(memberName, Genus::QML);
1836
1837
1838
1839
1843 if (!node || fragment.isEmpty())
1846 ref = node
->tree()->getRef(fragment, node);
1847 return ref.isEmpty() ?
nullptr : node;
1851
1852
1853
1854
1855
1856
1857
1858
1862 const Node *node =
nullptr;
1864 Atom *atom =
const_cast<
Atom *>(a);
1865 QStringList targetPath = Utilities::pathAndFragment(atom->string());
1866 QString first = targetPath.first().trimmed();
1867 const QString fragment = targetPath.value(1);
1869 Tree *domain =
nullptr;
1873 domain = atomDomain;
1877 QString qmlName = first;
1878 Parameters::extractParameters(qmlName);
1879 if (!qmlName.contains(
"://"_L1) && !qmlName.contains(
' '_L1)
1880 && !qmlName.endsWith(
".html"_L1) && qmlName.contains(
'.'_L1)) {
1881 const auto flags = FindFlags::fromInt(a->flags());
1882 if (
const Node *found = findQmlNode(first, relative, flags))
1883 return setReferenceFromFragment(fragment, found, ref);
1887 if (first.isEmpty())
1890 if (first.endsWith(
".html"))
1891 node = domain->findNodeByNameAndType(QStringList(first), &
Node::isPageNode);
1892 else if (first.endsWith(QChar(
')'))) {
1893 QString function = first;
1894 const QString signature = Parameters::extractParameters(function);
1895 const Parameters parameters(signature.trimmed());
1897 const QStringList path = function.split(
"::"_L1);
1899 node = domain->findFunctionNode(path, parameters,
nullptr, genus);
1901 if (node ==
nullptr) {
1903 QStringList nodePath = first.split(
"::");
1905 targetPath.removeFirst();
1906 if (!targetPath.isEmpty())
1907 target = targetPath.takeFirst();
1908 if (relative && relative
->tree()->physicalModuleName() != domain->physicalModuleName())
1910 return domain->findNodeForTarget(nodePath, target, relative, flags, genus, ref);
1913 if (first.endsWith(
".html"))
1914 node = findNodeByNameAndType(QStringList(first), &Node::isPageNode);
1915 else if (first.endsWith(QChar(
')')))
1916 node = findFunctionNode(first, relative, genus);
1917 if (node ==
nullptr) {
1919 if (genus == Genus::QML && first.contains(
'.') && !first.contains(
"::")) {
1921 node = findTypeNode(first, relative, genus);
1923 return setReferenceFromFragment(fragment, node, ref);
1925 return findNodeForTarget(targetPath, relative, genus, ref, atom->flags());
1929 if (node !=
nullptr && ref.isEmpty()) {
1930 if (!node->url().isEmpty())
1932 targetPath.removeFirst();
1933 if (!targetPath.isEmpty()) {
1943
1944
1945
1946
1947
1948
1949
1950
1954 QList<Tree *> searchOrder =
this->searchOrder();
1973 bool inclusive{Config::instance().get(
1977 const auto tocTitles{Config::instance().get(configVar).asStringList()};
1979 for (
const auto &tocTitle : tocTitles) {
1980 if (
const auto candidateTarget = findNodeForTarget(tocTitle,
nullptr); candidateTarget && candidateTarget->isPageNode()) {
1981 auto tocPage{
static_cast<
const PageNode*>(candidateTarget)};
1983 Text body = tocPage->doc().body();
1985 auto *atom = body.firstAtom();
1987 std::pair<PageNode *, QString> prev {
nullptr, QString() };
1989 std::stack<
const PageNode *> tocStack;
1990 tocStack.push(inclusive ? tocPage :
nullptr);
1992 bool inItem =
false;
1999 switch (atom->type()) {
2000 case Atom::ListItemLeft:
2002 tocStack.push(
nullptr);
2005 case Atom::ListItemRight:
2045 auto candidatePage =
const_cast<Node *>(findNodeForAtom(atom,
nullptr, unused));
2046 if (!candidatePage || !candidatePage->isPageNode())
break;
2048 auto page{
static_cast<PageNode*>(candidatePage)};
2051 if (page == prev.first)
break;
2054 prev.first->setLink(
2095 prev.first->title(),
2100 if (page == tocPage)
2105 qsizetype popped = 0;
2106 while (tocStack.size() > 1 && !tocStack.top()) {
2111 page->setNavigationParent(tocStack.empty() ?
nullptr : tocStack.top());
2113 while (--popped > 0)
2114 tocStack.push(
nullptr);
2116 tocStack.push(page);
2118 prev = { page, atom->linkText() };
2122 case Atom::AnnotatedList:
2123 case Atom::GeneratedList: {
2124 if (
const auto *cn = getCollectionNode(atom->string(), NodeType::Group)) {
2125 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
2126 NodeList members{cn->members()};
2129 members.erase(std::remove_if(members.begin(), members.end(),
2131 return n->isIndexNode() || !n->isPageNode() || n->isExternalPage();
2133 if (members.isEmpty())
2136 if (sortOrder == Qt::DescendingOrder)
2137 std::sort(members.rbegin(), members.rend(), Node::nodeSortKeyOrNameLessThan);
2139 std::sort(members.begin(), members.end(), Node::nodeSortKeyOrNameLessThan);
2144 for (
auto *m : members) {
2145 auto *page =
static_cast<PageNode *>(m);
2147 prev.first->setLink(Node::NextLink, page->title(), page->fullName());
2148 page->setLink(Node::PreviousLink, prev.first->title(), prev.second);
2150 prev = { page, page->fullName() };
2160 atom = atom->next();
2163 Config::instance().get(configVar).location()
2164 .warning(QStringLiteral(
"Failed to find table of contents with title '%1'")
2170 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.
FunctionNode * findFunctionChild(const FunctionNode *clone)
Returns the function node that is a child of this node, such that the function described has the same...
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
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.
QmlTypeNode * findQmlType(const QString &qmid, const QString &name, const Node *relative=nullptr, Tree *tree=nullptr)
Returns the QML type node identified by the QML module id qmid and QML type name, or nullptr if no ty...
const Node * findQmlNode(const QString &path, const Node *relative, FindFlags flags, Tree *tree=nullptr)
Returns the node to a piece of QML API documentation that corresponds to the given path,...
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.
const Node * findNodeForTarget(const QString &target, const Node *relative, Genus genus, const QString &moduleName, QString *ref=nullptr, LinkReferenceOrigin origin=LinkReferenceOrigin::Auto, int searchFlags=0)
Finds the node for target relative to relative, with genus and module scoping.
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 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 generateIndex(const QString &fileName, const QString &url, const QString &title, const IndexSerializationContext &context)
Generates a qdoc index file and writes it to fileName.
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...
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...
A class representing a forest of Tree objects.
This class imports QDoc index files and serializes index sections for module indexes and WebXML outpu...
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.
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
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.