21#include "ir/contentbuilder.h"
22#include "ir/signaturespan.h"
42#include <QRegularExpression>
50using namespace Qt::Literals;
55 return [loc](QtMsgType type,
const QString &message) {
71 auto result = resolver->hrefForNode(target, relative);
72 if (
const auto *href = std::get_if<QString>(&result))
81 QString deprecatedSince;
83 QString deprecatedSinceQualified;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102std::optional<DeprecationData> extractDeprecationData(
const Node *node)
105 const auto &version = node->deprecatedSince();
109 DeprecationData data{version, NodeText::nodeTypeDescription(node), version};
110 if (!version.isEmpty() && node
->isQmlNode() && !node->logicalModuleName().isEmpty())
111 data.deprecatedSinceQualified = node->logicalModuleName() +
' '_L1 + version;
119const Node *findConceptNodeForRelative(
const Node *relative,
const QString &name)
125 return qdb->findConceptNode(name);
146void appendRequiresSpansWithLinks(QList<IR::SignatureSpan> &out,
147 const QString &requiresText,
148 const QStringList &conceptNames,
149 const HrefResolver *hrefResolver,
150 const Node *relative)
152 auto emitFallback = [&out, &requiresText]() {
155 req.text =
" requires "_L1 + requiresText;
159 if (conceptNames.isEmpty() || requiresText.isEmpty()) {
164 QStringList sorted = conceptNames;
165 std::sort(sorted.begin(), sorted.end(),
166 [](
const QString &a,
const QString &b) {
return a.size() > b.size(); });
173 QHash<QString, QString> targetForDisplay;
174 QStringList escapedAlternatives;
175 escapedAlternatives.reserve(sorted.size() * 2);
176 for (
const QString &name : sorted) {
177 if (!targetForDisplay.contains(name)) {
178 targetForDisplay.insert(name, name);
179 escapedAlternatives.append(QRegularExpression::escape(name));
181 const QString tail = name.section(
"::"_L1, -1);
182 if (tail != name && !targetForDisplay.contains(tail)) {
183 targetForDisplay.insert(tail, name);
184 escapedAlternatives.append(QRegularExpression::escape(tail));
187 const QRegularExpression conceptRegex(
188 u"\\b("_s + escapedAlternatives.join(u"|"_s) + u")\\b"_s);
189 if (!conceptRegex.isValid()) {
194 auto it = conceptRegex.globalMatch(requiresText);
204 lead.text =
" requires "_L1;
208 while (it.hasNext()) {
209 const auto match = it.next();
210 if (match.capturedStart() > pos) {
213 textSpan.text = requiresText.mid(pos, match.capturedStart() - pos);
214 out.append(textSpan);
216 const QString matched = match.captured(1);
217 const QString target = targetForDisplay.value(matched, matched);
218 const Node *cn = findConceptNodeForRelative(relative, target);
219 const QString href = cn ? resolveHref(hrefResolver, cn, relative) : QString();
223 if (href.isEmpty()) {
232 pos = match.capturedEnd();
234 if (pos < requiresText.size()) {
237 tail.text = requiresText.mid(pos);
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
290 SemanticOrigins *origins)
292 Q_ASSERT_X(pn,
"NodeExtractor::extractPageMetadata",
293 "PageNode pointer must be non-null");
302 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
303 QString suffix = qcn->isQmlBasicType() ?
" QML Value Type"_L1 :
" QML Type"_L1;
304 pm.title = pn->name() + suffix;
305 pm.fullTitle = pm.title;
310 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
311 pm.fullTitle = aggregate->plainFullName();
312 pm.title = pm.fullTitle;
314 pm.title = pn->title();
315 pm.fullTitle = pn->fullTitle();
318 pm.url = hrefResolver->fileName(pn);
319 const QString baseUrl = Config::instance().get(
CONFIG_URL).asString();
320 if (!baseUrl.isEmpty() && !pm.url.isEmpty() && !pm.url.contains(
"://"_L1)) {
322 + (baseUrl.endsWith(u'/') ? QString{} : QStringLiteral(
"/"))
325 pm.since = pn->since();
326 pm.deprecatedSince = pn->deprecatedSince();
327 if (
const auto deprecation = extractDeprecationData(pn)) {
328 pm.typeNoun = deprecation->typeNoun;
329 pm.deprecatedSinceQualified = deprecation->deprecatedSinceQualified;
331 pm.brief = pn
->doc().briefText().toString();
339 const int headingOffset = [&] {
358 diagnosticHandlerFor(pn));
359 pm.body = contentBuilder.build(firstAtom);
363 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
364 pm.summarySections = extractSummarySections(aggregate, hrefResolver);
365 pm.detailSections = extractDetailSections(aggregate, hrefResolver, origins);
369 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
370 pm.qmlTypeData = extractQmlTypeData(qcn, hrefResolver);
374 const auto *cn =
static_cast<
const CollectionNode *>(pn);
375 pm.collectionData = extractCollectionData(cn, hrefResolver);
379 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
380 pm.cppReferenceData = extractCppReferenceData(aggregate, hrefResolver);
389
390
391
392
393
394
395
396
397
398
399
400
401
405 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
407 if (!qcn->logicalModuleName().isEmpty()) {
408 bool includeImport =
true;
415 QStringList parts = QStringList()
416 <<
"import"_L1 << qcn->logicalModuleName() << qcn->logicalModuleVersion();
417 data.importStatement = parts.join(
' '_L1).trimmed();
437 inheritsInfo.name = base->name();
438 inheritsInfo.href = resolveHref(hrefResolver, base, qcn);
443 inheritsInfo.moduleName = base->logicalModuleName();
445 data.inherits = inheritsInfo;
448 if (!subs.isEmpty()) {
449 QList<IR::QmlTypeData::InheritedByEntry> filteredSubs;
450 for (
const auto *sub : std::as_const(subs)) {
451 const NodeContext context = sub->createContext();
452 if (InclusionFilter::isIncluded(policy, context))
453 filteredSubs.append({sub->name(), resolveHref(hrefResolver, sub, qcn)});
455 std::sort(filteredSubs.begin(), filteredSubs.end(),
458 return a.name < b.name;
460 data.inheritedBy = filteredSubs;
467 data.nativeType = IR::QmlTypeData::NativeTypeInfo{cn->name(), resolveHref(hrefResolver, cn, qcn)};
479
480
481
482
483
484
485
486
487
488
489
490
495 data.logicalModuleName = cn->logicalModuleName();
496 data.logicalModuleVersion = cn->logicalModuleVersion();
497 data.qtVariable = cn->qtVariable();
514 const QString rawCmakePackage = cn->cmakePackage();
515 const QString rawCmakeComponent = cn->cmakeComponent();
516 const QString rawCmakeTargetItem = cn->cmakeTargetItem();
517 if (!rawCmakePackage.isEmpty() || !rawCmakeComponent.isEmpty()) {
518 const QString package = rawCmakePackage.isEmpty()
519 ?
"Qt"_L1 + QString::number(QT_VERSION_MAJOR)
521 data.cmakePackage = package;
522 data.cmakeComponent = rawCmakeComponent;
523 if (!rawCmakeTargetItem.isEmpty())
524 data.cmakeTargetItem = rawCmakeTargetItem;
525 else if (!rawCmakeComponent.isEmpty())
526 data.cmakeTargetItem = package +
"::"_L1 + rawCmakeComponent;
529 data.state = cn->state();
540 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
543 return { node->name(), resolveHref(hrefResolver, node, cn), node->doc().briefText().toString() };
546 auto sortEntries = [](QList<IR::CollectionData::MemberEntry> &entries) {
547 std::sort(entries.begin(), entries.end(),
550 return a.name.compare(b.name, Qt::CaseInsensitive) < 0;
556 for (
auto *node : nsMap.values()) {
557 const NodeContext context = node->createContext();
558 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
559 data.namespaces.append(makeMemberEntry(node));
561 sortEntries(data.namespaces);
564 for (
auto *node : classMap.values()) {
565 const NodeContext context = node->createContext();
566 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
567 data.classes.append(makeMemberEntry(node));
569 sortEntries(data.classes);
571 for (
const auto *node : cn->members()) {
572 if (!node->isInAPI())
574 const NodeContext context = node->createContext();
575 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
576 data.members.append(makeMemberEntry(node));
578 sortEntries(data.members);
585 const HrefResolver *hrefResolver,
586 const Node *relative);
589
590
591
592
593
594
595
596
597
598
599
600
601
610 data.typeWord = aggregate->typeWord(
false);
613 auto ancestors = aggregate->plainFullName().split(
"::"_L1);
614 ancestors.pop_back();
615 data.ancestorNames = ancestors;
617 if (aggregate->includeFile())
618 data.headerInclude = *aggregate->includeFile();
620 if (!aggregate->physicalModuleName().isEmpty()) {
623 if (cn && (!cn->cmakeComponent().isEmpty() || !cn->cmakePackage().isEmpty())) {
624 const QString package = cn->cmakePackage().isEmpty()
625 ?
"Qt"_L1 + QString::number(QT_VERSION_MAJOR)
626 : cn->cmakePackage();
628 if (cn->cmakeComponent().isEmpty())
629 findPkg =
"find_package("_L1 + package +
" REQUIRED)"_L1;
631 findPkg =
"find_package("_L1 + package +
" REQUIRED COMPONENTS "_L1
632 + cn->cmakeComponent() +
")"_L1;
635 if (!cn->cmakeTargetItem().isEmpty()) {
636 target = cn->cmakeTargetItem();
637 }
else if (cn->cmakeComponent().isEmpty()) {
638 target = package +
"::"_L1 + package;
640 target = package +
"::"_L1 + cn->cmakeComponent();
643 data.cmakeFindPackage = findPkg;
644 data.cmakeTargetLinkLibraries =
645 "target_link_libraries(mytarget PRIVATE "_L1 + target +
")"_L1;
647 if (cn && !cn->qtVariable().isEmpty())
648 data.qmakeVariable =
"QT += "_L1 + cn->qtVariable();
651 auto statusOpt = formatStatus(aggregate, qdb);
653 data.statusText = *statusOpt;
655 data.statusCssClass =
"deprecated"_L1;
656 else if (!aggregate->deprecatedSince().isEmpty())
657 data.statusCssClass =
"pending-deprecation"_L1;
659 data.statusCssClass =
"preliminary"_L1;
661 data.statusCssClass =
"status"_L1;
665 auto *classNode =
const_cast<ClassNode *>(
static_cast<
const ClassNode *>(aggregate));
667 if (classNode->isQmlNativeType()) {
668 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
669 const NodeContext context = classNode->createContext();
671 QList<QmlTypeNode *> nativeTypes{classNode->qmlNativeTypes().cbegin(),
672 classNode->qmlNativeTypes().cend()};
673 if (!nativeTypes.isEmpty()) {
675 data.qmlNativeType = IR::CppReferenceData::QmlNativeTypeLink{
676 nativeTypes.first()->name(),
677 resolveHref(hrefResolver, nativeTypes.first(), aggregate)
683 const auto *metaTags = classNode->doc().metaTagMap();
684 if (metaTags && metaTags->contains(u"qdoc-suppress-inheritance"_s))
688 const auto &baseClasses = classNode->baseClasses();
689 for (
const auto &bc : baseClasses) {
691 data.baseClasses.append({
692 bc.m_node->plainFullName(),
693 resolveHref(hrefResolver, bc.m_node, aggregate),
699 const auto &derivedClasses = classNode->derivedClasses();
700 for (
const auto &dc : derivedClasses) {
702 data.derivedClasses.append({
703 dc.m_node->plainFullName(),
704 resolveHref(hrefResolver, dc.m_node, aggregate)
708 std::sort(data.derivedClasses.begin(), data.derivedClasses.end(),
711 return a.name.compare(b.name, Qt::CaseInsensitive) < 0;
718 data.templateDeclSpans = buildTemplateDeclSpans(&templateDecl, hrefResolver, aggregate);
719 data.referencedConcepts.reserve(
int(templateDecl.referenced_concepts.size()));
720 for (
const auto &s : templateDecl.referenced_concepts)
721 data.referencedConcepts.append(QString::fromStdString(s));
725 if (selfCategory != ComparisonCategory::None)
726 data.selfComparisonCategory = QString::fromStdString(comparisonCategoryAsString(selfCategory));
728 const auto *comparesMap = aggregate
->doc().comparesWithMap();
729 if (comparesMap && !comparesMap->isEmpty()) {
730 for (
auto [key, description] : comparesMap->asKeyValueRange()) {
731 IR::CppReferenceData::ComparisonEntry entry;
732 entry.category = QString::fromStdString(comparisonCategoryAsString(key));
734 const QStringList types{description.firstAtom()->string().split(
';'_L1)};
735 entry.comparableTypes = types;
737 if (description.firstAtom()->next() != description.lastAtom()) {
738 Text descText = Text::subText(description.firstAtom()->next(),
739 description.lastAtom());
740 entry.description = descText.toString();
742 data.comparisonEntries.append(entry);
751 tsInfo.level =
"non-reentrant"_L1;
754 tsInfo.level =
"reentrant"_L1;
757 tsInfo.level =
"thread-safe"_L1;
763 NodeList reentrant, threadsafe, nonreentrant;
764 bool hasExceptions =
false;
765 for (
const auto *child : aggregate->childNodes()) {
766 if (!child->isDeprecated()) {
767 switch (child->threadSafeness()) {
768 case Node::Reentrant:
769 reentrant.append(
const_cast<Node *>(child));
770 if (ts == Node::ThreadSafe) hasExceptions =
true;
772 case Node::ThreadSafe:
773 threadsafe.append(
const_cast<Node *>(child));
774 if (ts == Node::Reentrant) hasExceptions =
true;
776 case Node::NonReentrant:
777 nonreentrant.append(
const_cast<Node *>(child));
778 hasExceptions =
true;
786 for (
const auto *node : std::as_const(reentrant)) {
787 tsInfo.reentrantExceptions.append({
788 node->plainFullName(),
789 resolveHref(hrefResolver, node, aggregate)
792 for (
const auto *node : std::as_const(threadsafe)) {
793 tsInfo.threadSafeExceptions.append({
794 node->plainFullName(),
795 resolveHref(hrefResolver, node, aggregate)
798 for (
const auto *node : std::as_const(nonreentrant)) {
799 tsInfo.nonReentrantExceptions.append({
800 node->plainFullName(),
801 resolveHref(hrefResolver, node, aggregate)
805 data.threadSafety =
std::move(tsInfo);
808 const QStringList &groupNames = aggregate->groupNames();
809 if (!groupNames.isEmpty()) {
811 for (
const auto &groupName : groupNames) {
812 auto it = groupMap.find(groupName);
813 if (it == groupMap.end() || !*it)
815 CollectionNode *group = *it;
820 qdb->mergeCollections(group);
821 if (group->wasSeen()) {
824 resolveHref(hrefResolver, group, aggregate)
831 const auto *ns =
static_cast<
const NamespaceNode *>(aggregate);
832 if (!ns->hasDoc() && ns->docNode()) {
834 data.fullNamespaceHref = resolveHref(hrefResolver, ns->docNode(), aggregate);
835 data.fullNamespaceModuleName = ns->docNode()->tree()->camelCaseModuleName();
843
844
845
846
847
848
849
856 QList<IR::SectionIR> result;
857 for (
const auto §ion : sv) {
858 if (section.isEmpty())
861 IR::SectionIR irSection;
862 irSection.title = section.title();
863 irSection.id = TextUtils::asAsciiPrintable(section.title());
864 irSection.singular = section.singular();
865 irSection.plural = section.plural();
871 for (
const auto *member : section.members()) {
872 if (member->isSharedCommentNode()) {
873 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
874 for (
const auto *child : scn->collective()) {
875 IR::MemberIR irMember = extractMemberIR(child, hrefResolver, aggregate);
876 irMember.href =
"#"_L1 + hrefResolver->anchorForNode(child);
877 irSection.members.append(irMember);
880 IR::MemberIR irMember = extractMemberIR(member, hrefResolver, aggregate);
881 irMember.href =
"#"_L1 + hrefResolver->anchorForNode(member);
882 irSection.members.append(irMember);
886 for (
const auto *reimpl : section.reimplementedMembers())
887 irSection.reimplementedMembers.append(extractMemberIR(reimpl, hrefResolver, aggregate));
889 for (
const auto &[base, count] : section.inheritedMembers()) {
890 IR::InheritedMembersIR inherited;
891 inherited.className = base->plainFullName();
892 inherited.count = count;
893 inherited.href = resolveHref(hrefResolver, base, aggregate);
894 irSection.inheritedMembers.append(inherited);
897 result.append(irSection);
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
928 SemanticOrigins *origins)
933 QList<IR::SectionIR> result;
934 for (
const auto §ion : sv) {
935 if (section.isEmpty())
938 IR::SectionIR irSection;
939 irSection.title = section.title();
940 irSection.id = TextUtils::asAsciiPrintable(section.title());
941 irSection.singular = section.singular();
942 irSection.plural = section.plural();
946 QList<
const Node *> sectionOrigins;
948 for (
const auto *member : section.members()) {
949 if (member->isSharedCommentNode()) {
950 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
956 IR::SharedDetailGroup group;
957 group.firstIndex =
static_cast<
int>(irSection.members.size());
958 group.count =
static_cast<
int>(scn->collective().size());
959 group.status = scn->status();
960 group.isPlural = !scn->isPropertyGroup() && group.count > 1;
965 group.anchorId = hrefResolver->anchorForNode(scn);
966 if (
const auto deprecation = extractDeprecationData(scn)) {
967 group.deprecatedSince = deprecation->deprecatedSince;
968 group.deprecatedSinceQualified = deprecation->deprecatedSinceQualified;
969 const Node *described = group.isPlural ? scn->collective().first() : scn;
970 const auto number = group.isPlural ? NodeText::GrammaticalNumber::Plural
971 : NodeText::GrammaticalNumber::Singular;
972 group.typeNoun = NodeText::nodeTypeDescription(described, number);
975 const Text &bodyText = scn->doc().body();
976 if (
const Atom *firstAtom = bodyText.firstAtom()) {
977 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
978 diagnosticHandlerFor(scn));
979 group.body = contentBuilder.build(firstAtom);
982 const QList<Text> &alsoTexts = scn->doc().alsoList();
983 for (
const Text &alsoText : alsoTexts) {
984 if (
const Atom *firstAtom = alsoText.firstAtom()) {
985 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
986 diagnosticHandlerFor(scn));
987 group.alsoList.append(contentBuilder.build(firstAtom));
991 for (
const auto *child : scn->collective()) {
992 IR::MemberIR irMember = extractMemberIR(child, hrefResolver, aggregate, MemberExtractionLevel::Detail);
997 irMember.body.clear();
998 irMember.alsoList.clear();
999 irMember.sharedGroup =
static_cast<
int>(irSection.sharedGroups.size());
1002 sectionOrigins.append(irMember.anchorId.isEmpty() ?
nullptr : scn);
1003 irSection.members.append(irMember);
1005 irSection.sharedGroups.append(group);
1007 IR::MemberIR irMember = extractMemberIR(member, hrefResolver, aggregate, MemberExtractionLevel::Detail);
1008 sectionOrigins.append(irMember.anchorId.isEmpty() ?
nullptr : member);
1009 irSection.members.append(irMember);
1014 origins->append(std::move(sectionOrigins));
1015 result.append(irSection);
1024 QSet<QString> ownedAnchors;
1025 for (
const auto §ion : result)
1026 for (
const auto &member : section.members)
1027 if (!member.anchorId.isEmpty())
1028 ownedAnchors.insert(member.anchorId);
1030 for (
auto §ion : result)
1031 for (
auto &group : section.sharedGroups) {
1032 if (group.anchorId.isEmpty())
1034 if (ownedAnchors.contains(group.anchorId))
1035 group.anchorId.clear();
1037 ownedAnchors.insert(group.anchorId);
1046 case Node::Reentrant:
1047 return "reentrant"_L1;
1048 case Node::ThreadSafe:
1049 return "thread-safe"_L1;
1056
1057
1058
1059
1060
1061
1062
1065 for (
auto &block : blocks) {
1066 if (block.type == IR::BlockType::DefinitionList
1067 && block.attributes.value(QLatin1String(
"listType"))
1069 for (
auto &entry : block.children) {
1070 if (entry.type != IR::BlockType::DefinitionTerm || entry.inlineContent.isEmpty())
1073 for (
const IR::InlineContent &content : entry.inlineContent)
1074 raw += content.plainText();
1075 const QString qualified = en->qualifiedValueName(raw);
1076 if (qualified != raw) {
1077 IR::InlineContent text;
1078 text.type = IR::InlineType::Text;
1079 text.text = qualified;
1080 entry.inlineContent = { text };
1084 qualifyEnumValueTerms(en, block.children);
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1107 member.name = node->name();
1108 member.fullName = node->plainFullName();
1109 member.href = resolveHref(hrefResolver, node, relative);
1115 if (
const auto deprecation = extractDeprecationData(node)) {
1116 member.deprecatedSince = deprecation->deprecatedSince;
1117 member.typeNoun = deprecation->typeNoun;
1118 member.deprecatedSinceQualified = deprecation->deprecatedSinceQualified;
1122 const auto *fn =
static_cast<
const FunctionNode *>(node);
1123 member.signature = fn->signature(
1134 for (
int i = 0; i < params
.count(); ++i) {
1136 param.type = params
.at(i
).type();
1137 param.name = params
.at(i
).name();
1138 param.defaultValue = params
.at(i
).defaultValue();
1139 member.parameters.append(param);
1142 const auto *en =
static_cast<
const EnumNode *>(node);
1143 member.signature = en->isScoped()
1144 ?
"enum class %1"_L1.arg(en->name())
1145 :
"enum %1"_L1.arg(en->name());
1147 for (
const auto &item : en->items()) {
1149 ev.name = item.name();
1150 ev.value = item.value();
1151 ev.since = item.since();
1152 member.enumValues.append(ev);
1155 const auto *qpn =
static_cast<
const QmlPropertyNode *>(node);
1156 member.signature = qpn->name() +
" : "_L1 + qpn->dataType();
1157 member.dataType = qpn->dataType();
1163 const auto *pn =
static_cast<
const PropertyNode *>(node);
1164 member.signature = pn->name() +
" : "_L1 + pn->qualifiedDataType();
1166 const auto *td =
static_cast<
const TypedefNode *>(node);
1167 member.signature = td->associatedEnum()
1168 ?
"flags "_L1 + td->name()
1171 const auto *vn =
static_cast<
const VariableNode *>(node);
1172 member.signature = vn->leftType() + vn->name() + vn->rightType();
1174 member.signature = node->name();
1177 if (includeDetail) {
1178 member.anchorId = hrefResolver->anchorForNode(node);
1179 member.synopsis = member.signature;
1180 member.since = node->since();
1181 member.threadSafety = threadSafenessString(node->threadSafeness());
1184 if (!catStr.empty())
1185 member.comparisonCategory = QString::fromStdString(catStr);
1188 const auto *fn =
static_cast<
const FunctionNode *>(node);
1189 const auto &noexcept_ = fn->getNoexcept();
1192 member.noexceptNote = *noexcept_;
1199 diagnosticHandlerFor(node));
1200 member.body = contentBuilder.build(firstAtom);
1202 qualifyEnumValueTerms(
static_cast<
const EnumNode *>(node), member.body);
1205 const QList<Text> &alsoTexts = node
->doc().alsoList();
1206 for (
const Text &alsoText : alsoTexts) {
1207 if (
const Atom *firstAtom = alsoText.firstAtom()) {
1208 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
1209 diagnosticHandlerFor(node));
1210 QList<IR::ContentBlock> blocks = contentBuilder.build(firstAtom);
1211 member.alsoList.append(blocks);
1217 member.signatureSpans = buildSignatureSpans(node, hrefResolver, relative, spanStyle);
1224 QList<IR::SignatureSpan> spans;
1225 QString pendingWord;
1227 for (
int i = 0; i <= typeString.size(); ++i) {
1229 if (i != typeString.size())
1230 ch = typeString.at(i);
1232 QChar lower = ch.toLower();
1233 if ((lower >=
'a'_L1 && lower <=
'z'_L1) || ch.digitValue() >= 0
1234 || ch ==
'_'_L1 || ch ==
':'_L1) {
1237 if (!pendingWord.isEmpty()) {
1238 bool isProbablyType = (pendingWord !=
"const"_L1);
1241 span.text = pendingWord;
1244 pendingWord.clear();
1249 span.text = QString(ch);
1259 QString extraStr = CodeMarker::extraSynopsis(node, style);
1260 if (extraStr.isEmpty())
1266 static const QRegularExpression extrefRegex(
1267 u"<@extref target=\"([^\"]+)\">([^<]+)</@extref>"_s);
1269 QList<IR::SignatureSpan> spans;
1274 auto it = extrefRegex.globalMatch(extraStr);
1275 while (it.hasNext()) {
1276 auto match = it.next();
1277 if (match.capturedStart() > pos) {
1280 textSpan.text = extraStr.mid(pos, match.capturedStart() - pos);
1281 wrapper.children.append(textSpan);
1285 ref.text = match.captured(2);
1286 ref.href =
"https://en.cppreference.com/w/cpp/language/"_L1 + match.captured(1);
1287 wrapper.children.append(ref);
1288 pos = match.capturedEnd();
1290 if (pos < extraStr.size()) {
1293 textSpan.text = extraStr.mid(pos);
1294 wrapper.children.append(textSpan);
1297 if (wrapper.children.isEmpty()) {
1298 wrapper.text = extraStr;
1300 spans.append(wrapper);
1305 const HrefResolver *hrefResolver,
1306 const Node *relative)
1313 declSpan.text =
"template"_L1;
1317 open.text =
" <"_L1;
1318 declSpan.children.append(open);
1321 for (
const auto ¶m : templateDecl->parameters) {
1322 if (param.sfinae_constraint)
1325 IR::SignatureSpan comma;
1326 comma.role = IR::SpanRole::Text;
1327 comma.text =
", "_L1;
1328 declSpan.children.append(comma);
1331 switch (param.kind) {
1332 case RelaxedTemplateParameter::Kind::TypeTemplateParameter: {
1333 if (param.concept_name) {
1334 const QString fq = QString::fromStdString(*param.concept_name);
1335 const QString unqualified = fq.section(
"::"_L1, -1);
1338 const Node *conceptNode = findConceptNodeForRelative(relative, fq);
1339 IR::SignatureSpan link;
1340 link.role = IR::SpanRole::Link;
1341 link.text = unqualified;
1342 link.href = resolveHref(hrefResolver, conceptNode, relative);
1343 declSpan.children.append(link);
1345 IR::SignatureSpan kw;
1346 kw.role = IR::SpanRole::Text;
1347 kw.text =
"typename"_L1;
1348 declSpan.children.append(kw);
1352 case RelaxedTemplateParameter::Kind::TemplateTemplateParameter: {
1353 IR::SignatureSpan kw;
1354 kw.role = IR::SpanRole::Text;
1355 kw.text =
"typename"_L1;
1356 declSpan.children.append(kw);
1359 case RelaxedTemplateParameter::Kind::NonTypeTemplateParameter: {
1360 if (!param.valued_declaration.type.empty()) {
1361 auto typeSpans = buildTypeSpans(QString::fromStdString(param.valued_declaration.type));
1362 declSpan.children.append(typeSpans);
1368 if (param.is_parameter_pack) {
1369 IR::SignatureSpan dots;
1370 dots.role = IR::SpanRole::Text;
1371 dots.text =
"..."_L1;
1372 declSpan.children.append(dots);
1375 if (!param.valued_declaration.name.empty()) {
1376 IR::SignatureSpan space;
1377 space.role = IR::SpanRole::Text;
1378 space.text =
" "_L1;
1379 declSpan.children.append(space);
1381 IR::SignatureSpan nameSpan;
1382 nameSpan.role = IR::SpanRole::Parameter;
1383 nameSpan.text = QString::fromStdString(param.valued_declaration.name);
1384 declSpan.children.append(nameSpan);
1387 if (!param.valued_declaration.initializer.empty()) {
1388 IR::SignatureSpan eq;
1389 eq.role = IR::SpanRole::Text;
1391 declSpan.children.append(eq);
1393 if (param.kind == RelaxedTemplateParameter::Kind::TypeTemplateParameter
1394 || param.kind == RelaxedTemplateParameter::Kind::TemplateTemplateParameter) {
1395 auto typeSpans = buildTypeSpans(QString::fromStdString(param.valued_declaration.initializer));
1396 declSpan.children.append(typeSpans);
1398 IR::SignatureSpan val;
1399 val.role = IR::SpanRole::Text;
1400 val.text = QString::fromStdString(param.valued_declaration.initializer);
1401 declSpan.children.append(val);
1410 close.text =
">"_L1;
1411 declSpan.children.append(close);
1413 if (templateDecl->requires_clause && !templateDecl->requires_clause->empty()) {
1414 const QString reqText = QString::fromStdString(*templateDecl->requires_clause);
1415 QStringList conceptNames;
1416 conceptNames.reserve(
int(templateDecl->referenced_concepts.size()));
1417 for (
const auto &s : templateDecl->referenced_concepts)
1418 conceptNames.append(QString::fromStdString(s));
1419 appendRequiresSpansWithLinks(declSpan.children, reqText, conceptNames,
1420 hrefResolver, relative);
1423 return { declSpan };
1427 const HrefResolver *hrefResolver,
1428 const Node *relative,
1431 QList<IR::SignatureSpan> spans;
1433 auto appendText = [&spans](
const QString &text) {
1440 auto appendName = [&spans, node, hrefResolver, relative](
const QString &name) {
1444 span.href = resolveHref(hrefResolver, node, relative);
1448 auto appendTypeSpans = [&spans](
const QString &type,
bool trailingSpace) {
1449 auto typeSpans = buildTypeSpans(type);
1450 spans.append(typeSpans);
1451 if (trailingSpace && !type.isEmpty()
1452 && !type.endsWith(
'*'_L1) && !type.endsWith(
'&'_L1)) {
1455 space.text =
" "_L1;
1456 spans.append(space);
1462 auto extras = buildExtraSpans(node, style);
1463 if (!extras.isEmpty()) {
1464 spans.append(extras);
1470 QString nameText = node->name();
1477 nameText = node->parent()->name() +
"::"_L1 + nameText;
1486 appendText(Node::nodeTypeString(node->nodeType()) +
" "_L1);
1488 appendName(nameText);
1492 span.text = nameText;
1497 const auto *func =
static_cast<
const FunctionNode *>(node);
1500 if (
auto templateDecl = node->templateDecl()) {
1501 auto tmplSpans = buildTemplateDeclSpans(&*templateDecl, hrefResolver, relative);
1502 spans.append(tmplSpans);
1508 if (!func->isNonvirtual())
1509 appendText(
"virtual "_L1);
1513 appendTypeSpans(func->returnTypeString(),
true);
1516 appendName(nameText);
1520 span.text = nameText;
1524 if (!func->isMacroWithoutParams()) {
1526 if (!func->parameters().isEmpty()) {
1527 const Parameters ¶meters = func->parameters();
1528 for (
int i = 0; i < parameters
.count(); ++i) {
1530 appendText(
", "_L1);
1532 QString pName = param.name();
1533 QString type = param.type();
1534 QString value = param.defaultValue();
1535 qsizetype insertPos = param.nameInsertionPoint();
1537 appendTypeSpans(type.left(insertPos),
false);
1540 paramSpan.text = pName;
1541 spans.append(paramSpan);
1542 appendTypeSpans(type.mid(insertPos),
false);
1545 appendTypeSpans(type, trailingSpace);
1549 paramSpan.text = pName;
1550 spans.append(paramSpan);
1554 appendText(
" = "_L1 + value);
1560 if (func->isConst())
1561 appendText(
" const"_L1);
1564 if (func->isFinal())
1565 appendText(
" final"_L1);
1566 if (func->isOverride())
1567 appendText(
" override"_L1);
1568 if (func->isPureVirtual())
1569 appendText(
" = 0"_L1);
1571 appendText(
" &"_L1);
1572 else if (func->isRefRef())
1573 appendText(
" &&"_L1);
1575 if (!func->returnType().isEmpty() && func->returnType() !=
"void"_L1) {
1576 appendText(
" : "_L1);
1577 appendTypeSpans(func->returnTypeString(),
false);
1581 appendText(
" &"_L1);
1582 else if (func->isRefRef())
1583 appendText(
" &&"_L1);
1584 if (
const auto &req = func->trailingRequiresClause(); req && !req->isEmpty())
1585 appendRequiresSpansWithLinks(spans, *req, func->referencedConcepts(),
1586 hrefResolver, relative);
1591 const auto *enume =
static_cast<
const EnumNode *>(node);
1592 appendText(
"enum"_L1);
1593 if (enume->isScoped())
1594 appendText(
" class"_L1);
1595 if (!enume->isAnonymous()) {
1598 appendName(nameText);
1602 span.text = nameText;
1607 appendText(
" { "_L1);
1608 const int MaxEnumValues = 6;
1609 QStringList documentedItems = enume->doc().enumItemNames();
1610 if (documentedItems.isEmpty()) {
1611 const auto &enumItems = enume->items();
1612 for (
const auto &item : enumItems)
1613 documentedItems << item.name();
1615 const QStringList omitItems = enume->doc().omitEnumItemNames();
1616 for (
const auto &item : omitItems)
1617 documentedItems.removeAll(item);
1619 if (documentedItems.size() > MaxEnumValues) {
1620 const QString last = documentedItems.last();
1621 documentedItems = documentedItems.mid(0, MaxEnumValues - 1);
1622 documentedItems +=
"..."_L1;
1623 documentedItems += last;
1625 appendText(documentedItems.join(
", "_L1));
1626 if (!documentedItems.isEmpty())
1634 if (
auto templateDecl = node->templateDecl()) {
1635 auto tmplSpans = buildTemplateDeclSpans(&*templateDecl, hrefResolver, relative);
1636 spans.append(tmplSpans);
1641 appendName(nameText);
1645 span.text = nameText;
1651 if (
static_cast<
const TypedefNode *>(node)->associatedEnum())
1652 appendText(
"flags "_L1);
1654 appendName(nameText);
1658 span.text = nameText;
1664 const auto *property =
static_cast<
const PropertyNode *>(node);
1666 appendName(nameText);
1670 span.text = nameText;
1673 appendText(
" : "_L1);
1674 appendTypeSpans(property->qualifiedDataType(),
false);
1678 const auto *property =
static_cast<
const QmlPropertyNode *>(node);
1680 appendName(nameText);
1684 span.text = nameText;
1687 appendText(
" : "_L1);
1688 appendTypeSpans(property->dataType(),
false);
1692 const auto *variable =
static_cast<
const VariableNode *>(node);
1695 appendName(nameText);
1699 span.text = nameText;
1702 appendText(
" : "_L1);
1703 appendTypeSpans(variable->dataType(),
false);
1705 appendTypeSpans(variable->leftType(),
true);
1707 appendName(nameText);
1711 span.text = nameText;
1714 appendText(variable->rightType());
1720 appendName(nameText);
1724 span.text = nameText;
1734
1735
1736
1737
1738
1739
1740
1741
1743 const HrefResolver *hrefResolver,
1744 const Node *relative)
1746 QList<IR::SignatureSpan> spans;
1748 auto appendText = [&spans](
const QString &text) {
1755 auto appendTypeSpans = [&spans](
const QString &type,
bool trailingSpace) {
1756 auto typeSpans = buildTypeSpans(type);
1757 spans.append(typeSpans);
1758 if (trailingSpace && !type.isEmpty()
1759 && !type.endsWith(
'*'_L1) && !type.endsWith(
'&'_L1)) {
1762 space.text =
" "_L1;
1763 spans.append(space);
1769 nameSpan.text = node->name();
1770 nameSpan.href = resolveHref(hrefResolver, node, relative);
1773 const auto *pn =
static_cast<
const QmlPropertyNode *>(node);
1774 spans.append(nameSpan);
1775 appendText(
" : "_L1);
1776 appendTypeSpans(pn->dataType(),
false);
1778 const auto *func =
static_cast<
const FunctionNode *>(node);
1779 if (!func->returnType().isEmpty())
1780 appendTypeSpans(func->returnTypeString(),
true);
1781 spans.append(nameSpan);
1783 if (!func->parameters().isEmpty()) {
1784 const Parameters ¶meters = func->parameters();
1785 for (
int i = 0; i < parameters
.count(); ++i) {
1787 appendText(
", "_L1);
1788 QString pName = parameters
.at(i
).name();
1789 QString type = parameters
.at(i
).type();
1790 if (!pName.isEmpty()) {
1791 appendTypeSpans(type,
true);
1794 paramSpan.text = pName;
1795 spans.append(paramSpan);
1799 paramSpan.text = type;
1800 spans.append(paramSpan);
1806 spans.append(nameSpan);
1809 auto extras = buildExtraSpans(node, Section::Summary);
1810 if (!extras.isEmpty()) {
1812 spans.append(extras);
1821 for (
const auto &span : spans)
1822 result += span.plainText();
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1841 const HrefResolver *hrefResolver,
1842 const Node *relative,
1845 if (node->isQmlNode() && !node->isEnumType())
1846 return buildQmlItemSpans(node, hrefResolver, relative);
1847 return buildCppSynopsisSpans(node, hrefResolver, relative, style);
1851
1852
1853
1854
1855
1856
1857
1858
1862 result.typeName = qcn->name();
1863 result.typeHref = resolveHref(hrefResolver, qcn, qcn);
1868 if (groupedMembers.isEmpty())
1871 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1874 IR::AllMemberEntry entry;
1875 entry.signatureSpans = buildQmlItemSpans(node, hrefResolver, qcn);
1876 entry.signature = plainTextFromSpans(entry.signatureSpans);
1877 entry.href = resolveHref(hrefResolver, node, qcn);
1879 if (node->isQmlProperty()) {
1880 auto *qpn =
static_cast<QmlPropertyNode *>(node);
1881 QStringList qmlHints = qpn->hints();
1882 if (qpn->isAttached() && !qmlHints.contains(
"attached"_L1))
1883 qmlHints <<
"attached"_L1;
1884 for (
const auto &h : std::as_const(qmlHints))
1885 entry.hints.append(h);
1886 }
else if (node->isAttached()) {
1887 entry.hints.append(
"attached"_L1);
1890 if (node->isPropertyGroup()) {
1891 entry.isPropertyGroup =
true;
1892 const auto *scn =
static_cast<SharedCommentNode *>(node);
1893 for (
auto *child : scn->collective()) {
1894 const NodeContext childContext = child->createContext();
1895 if (!InclusionFilter::isIncluded(policy, childContext))
1897 entry.children.append(buildEntry(child));
1904 auto isVisible = [&policy](
Node *node) {
1906 return InclusionFilter::isIncluded(policy, context)
1907 && !(node->isSharingComment() && node->sharedCommentNode()->isPropertyGroup());
1910 for (
const auto &[originType, nodes] : groupedMembers) {
1911 Q_ASSERT(originType);
1912 if (nodes.isEmpty())
1915 IR::MemberGroup group;
1916 if (originType != qcn) {
1917 group.typeName = originType->name();
1918 group.typeHref = resolveHref(hrefResolver, originType, qcn);
1921 for (
auto *node : nodes) {
1922 if (isVisible(node))
1923 group.members.append(buildEntry(node));
1926 result.memberGroups.append(group);
1933
1934
1935
1936
1937
1938
1939
1943 result.typeName = aggregate->plainFullName();
1944 result.typeHref = resolveHref(hrefResolver, aggregate, aggregate);
1952 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1954 for (
const auto *node : allMembers.members()) {
1955 if (node->name().isEmpty())
1957 const NodeContext context = node->createContext();
1958 if (!InclusionFilter::isIncluded(policy, context))
1960 if (node->isFunction()
1961 &&
static_cast<
const FunctionNode *>(node)->isIgnored())
1964 IR::AllMemberEntry entry;
1965 entry.signatureSpans = buildSignatureSpans(node, hrefResolver, aggregate, Section::AllMembers);
1966 entry.signature = plainTextFromSpans(entry.signatureSpans);
1967 entry.href = resolveHref(hrefResolver, node, aggregate);
1968 result.members.append(entry);
1975
1976
1977
1978
1979
1980
1981
1982
1986 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
1987 if (qcn->isQmlBasicType())
1988 return std::nullopt;
1989 auto result = extractQmlAllMembersIR(qcn, hrefResolver);
1990 bool hasMember =
false;
1991 for (
const auto &group : std::as_const(result.memberGroups)) {
1992 if (!group.members.isEmpty()) {
1998 return std::nullopt;
2003 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
2004 auto result = extractCppAllMembersIR(aggregate, hrefResolver);
2005 if (result.members.isEmpty())
2006 return std::nullopt;
2010 return std::nullopt;
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2035 const Config &config = Config::instance();
2039 const QString homepage = config.get(navDot +
CONFIG_HOMEPAGE).asString();
2040 const QString hometitle = config.get(navDot +
CONFIG_HOMETITLE).asString(homepage);
2042 const QString landingtitle = config.get(navDot +
CONFIG_LANDINGTITLE).asString(landingpage);
2046 const QString qmltypestitle = config.get(navDot +
CONFIG_QMLTYPESTITLE).asString(
"QML Types"_L1);
2048 const QString pageTitle = pn->title();
2051 auto resolveCrumb = [&](
const QString &targetName)
2052 -> std::pair<QString, CrumbState> {
2053 const Node *target = qdb->findNodeForTarget(targetName, pn);
2055 return {{}, CrumbState::Unresolved};
2057 return {{}, CrumbState::Current};
2058 return {resolveHref(hrefResolver, target, pn), CrumbState::Link};
2061 if (!homepage.isEmpty()) {
2062 auto [href, state] = resolveCrumb(homepage);
2063 if (state == CrumbState::Current)
2065 nav.breadcrumbs.append({hometitle,
std::move(href), state});
2068 if (!landingpage.isEmpty()) {
2069 auto [href, state] = resolveCrumb(landingpage);
2070 if (state != CrumbState::Current)
2071 nav.breadcrumbs.append({landingtitle,
std::move(href), state});
2075 const bool hasClassesCrumb = !cppclassespage.isEmpty() && !cppclassestitle.isEmpty();
2076 if (hasClassesCrumb) {
2077 auto [href, state] = resolveCrumb(cppclassespage);
2078 nav.breadcrumbs.append({cppclassestitle,
std::move(href), state});
2082 QString moduleState;
2083 if (moduleNode && !moduleNode->state().isEmpty())
2084 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
2086 if (!pn->physicalModuleName().isEmpty() && moduleNode
2087 && (!moduleState.isEmpty() || moduleNode->title() != cppclassespage)) {
2088 const QString moduleText = hasClassesCrumb || moduleNode->title().isEmpty()
2089 ? moduleNode->name() : moduleNode->title();
2090 nav.breadcrumbs.append({moduleText + moduleState,
2091 resolveHref(hrefResolver, moduleNode, pn),
2094 nav.breadcrumbs.append({pn->name(), {}, CrumbState
::Current});
2096 const bool hasTypesCrumb = !qmltypespage.isEmpty() && !qmltypestitle.isEmpty();
2097 if (hasTypesCrumb) {
2098 auto [href, state] = resolveCrumb(qmltypespage);
2099 nav.breadcrumbs.append({qmltypestitle,
std::move(href), state});
2103 QString moduleState;
2104 if (moduleNode && !moduleNode->state().isEmpty())
2105 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
2108 && (!moduleState.isEmpty() || moduleNode->title() != qmltypespage)) {
2109 const QString moduleText = hasTypesCrumb || moduleNode->title().isEmpty()
2110 ? moduleNode->name() : moduleNode->title();
2111 nav.breadcrumbs.append({moduleText + moduleState,
2112 resolveHref(hrefResolver, moduleNode, pn),
2115 nav.breadcrumbs.append({pn->name(), {}, CrumbState
::Current});
2117 auto currentNode = pn;
2118 std::deque<
const Node *> navNodes;
2119 qsizetype navItems = 0;
2121 if (
std::find(navNodes.cbegin(), navNodes.cend(),
2126 if (navNodes.empty()) {
2127 const QStringList groups = pn->groupNames();
2128 for (
const auto &groupName : groups) {
2129 const auto *groupNode = qdb->findNodeByNameAndType(
2130 QStringList{groupName}, &Node::isGroup);
2131 if (groupNode && !groupNode->title().isEmpty()) {
2132 navNodes.push_front(groupNode);
2137 for (
const auto *navNode : navNodes) {
2138 if (navNode->isPageNode())
2139 nav.breadcrumbs.append({navNode->title(),
2140 resolveHref(hrefResolver, navNode, pn),
2143 if (!nav.breadcrumbs.isEmpty())
2144 nav.breadcrumbs.append({pageTitle, {}, CrumbState
::Current});
2147 const auto &linkMap = pn->links();
2150 const Node *target = qdb->findNodeForTarget(linkPair.first, pn);
2153 if (target && target != pn) {
2154 href = resolveHref(hrefResolver, target, pn);
2155 title = (linkPair.first == linkPair.second && !target->title().isEmpty())
2156 ? target->title() : linkPair.second;
2158 href = linkPair.first;
2159 title = linkPair.second;
2165 const Node *target = qdb->findNodeForTarget(linkPair.first, pn);
2168 if (target && target != pn) {
2169 href = resolveHref(hrefResolver, target, pn);
2170 title = (linkPair.first == linkPair.second && !target->title().isEmpty())
2171 ? target->title() : linkPair.second;
2173 href = linkPair.first;
2174 title = linkPair.second;
2180 const Node *target = qdb->findNodeForTarget(linkPair.first, pn);
2183 if (target && target != pn) {
2184 href = resolveHref(hrefResolver, target, pn);
2185 title = (linkPair.first == linkPair.second && !target->title().isEmpty())
2186 ? target->title() : linkPair.second;
2188 href = linkPair.first;
2189 title = linkPair.second;
2194 const QString formatDot =
"HTML"_L1 + Config::dot;
2195 nav
.tocDepth = config.get(formatDot +
"tocdepth"_L1).asInt();
bool hasObsoleteMembers() const
Returns true if this aggregate contains at least one child that is marked obsolete.
The Atom class is the fundamental unit for representing documents internally.
The ClassNode represents a C++ class.
A class for holding the members of a collection of doc pages.
NodeMap getMembers(NodeType type) const
The Config class contains the configuration variables for controlling how qdoc produces documentation...
const Location & location() const
Returns the starting location of a qdoc comment.
const Text & body() const
Text briefText(bool inclusive=false) const
Converts Atom chains to QList<IR::ContentBlock> trees.
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
The Location class provides a way to mark a location in a file.
A PageNode is a Node that generates a documentation page.
const PageNode * navigationParent() const
bool noAutoList() const
Returns the value of the no auto-list flag.
The Parameter class describes one function parameter.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
const CollectionNode * getModuleNode(const Node *relative)
Returns the collection node representing the module that relative node belongs to,...
const CNMap & groups()
Returns a const reference to the collection of all group nodes in the primary tree.
Status
Specifies the status of the QQmlIncubator.
ClassNode * classNode() const override
If this is a QmlTypeNode, this function returns the pointer to the C++ ClassNode that this QML type r...
static void subclasses(const Node *base, NodeList &subs, bool recurse=false)
Loads the list subs with the nodes of all the subclasses of base.
QmlTypeNode * qmlBaseNode() const override
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
CollectionNode * logicalModule() const override
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
A class for containing the elements of one documentation section.
ClassNodesList & classNodesList()
A class for creating vectors of collections for documentation.
SectionVector & summarySections()
Sections(const Aggregate *aggregate)
This constructor builds the section vectors based on the type of the aggregate node.
bool hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVector *details_spv) const
Returns true if any sections in this object contain obsolete members.
SectionVector & detailsSections()
Section & allMembersSection()
const Atom * firstAtom() const
static std::string comparisonCategoryAsString(ComparisonCategory category)
#define CONFIG_CPPCLASSESTITLE
#define CONFIG_QMLTYPESPAGE
#define CONFIG_CPPCLASSESPAGE
#define CONFIG_NAVIGATION
#define CONFIG_LANDINGPAGE
#define CONFIG_LANDINGTITLE
#define CONFIG_QMLTYPESTITLE
QMap< QString, Node * > NodeMap
QList< const Section * > SectionPtrVector
QList< ClassNodes > ClassNodesList
A single entry in an all-members listing page.
Intermediate representation of the all-members listing page.
Intermediate representation of a single documentable member.
Intermediate representation of a function parameter.
Represents a single span within a structured signature.
The Node class is the base class for all the nodes in QDoc's parse tree.
const Doc & doc() const
Returns a reference to the node's Doc data member.
bool isQmlNode() const
Returns true if this node's Genus value is QML.
bool isGroup() const
Returns true if the node type is Group.
bool isNamespace() const
Returns true if the node type is Namespace.
bool isTypedef() const
Returns true if the node type is Typedef.
bool isQmlBasicType() const
Returns true if the node type is QmlBasicType.
ComparisonCategory comparisonCategory() const
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
Genus genus() const override
Returns this node's Genus.
bool isEnumType() const
Returns true if the node type is Enum.
virtual Status status() const
Returns the node's status value.
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
static bool nodeNameLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
bool isProxyNode() const
Returns true if the node type is Proxy.
const std::optional< RelaxedTemplateDeclaration > & templateDecl() const
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
ThreadSafeness threadSafeness() const
Returns the thread safeness value for whatever this node represents.
bool isProperty() const
Returns true if the node type is Property.
NodeContext createContext() const
bool isModule() const
Returns true if the node type is Module.
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
A class for parsing and managing a function parameter list.
const Parameter & at(int i) const