18#include "ir/contentbuilder.h"
33#include <QRegularExpression>
37using namespace Qt::Literals;
42 return [loc](QtMsgType type,
const QString &message) {
58 auto result = resolver->hrefForNode(target, relative);
59 if (
const auto *href = std::get_if<QString>(&result))
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
87 Q_ASSERT_X(pn,
"NodeExtractor::extractPageMetadata",
88 "PageNode pointer must be non-null");
97 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
98 QString suffix = qcn->isQmlBasicType() ?
" QML Value Type"_L1 :
" QML Type"_L1;
99 pm.title = pn->name() + suffix;
100 pm.fullTitle = pm.title;
102 pm.title = pn->title();
103 pm.fullTitle = pn->fullTitle();
107 pm.since = pn->since();
108 pm.deprecatedSince = pn->deprecatedSince();
109 pm.brief = pn
->doc().briefText().toString();
117 const int headingOffset = [&] {
136 diagnosticHandlerFor(pn));
137 pm.body = contentBuilder.build(firstAtom);
141 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
142 pm.summarySections = extractSummarySections(aggregate, hrefResolver);
143 pm.detailSections = extractDetailSections(aggregate, hrefResolver);
147 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
148 pm.qmlTypeData = extractQmlTypeData(qcn, hrefResolver);
152 const auto *cn =
static_cast<
const CollectionNode *>(pn);
153 pm.collectionData = extractCollectionData(cn, hrefResolver);
160
161
162
163
164
165
166
170 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
172 if (!qcn->logicalModuleName().isEmpty()) {
173 bool includeImport =
true;
180 QStringList parts = QStringList()
181 <<
"import"_L1 << qcn->logicalModuleName() << qcn->logicalModuleVersion();
182 data.importStatement = parts.join(
' '_L1).trimmed();
202 inheritsInfo.name = base->name();
203 inheritsInfo.href = resolveHref(hrefResolver, base, qcn);
208 inheritsInfo.moduleName = base->logicalModuleName();
210 data.inherits = inheritsInfo;
213 if (!subs.isEmpty()) {
214 QList<IR::QmlTypeData::InheritedByEntry> filteredSubs;
215 for (
const auto *sub : std::as_const(subs)) {
216 const NodeContext context = sub->createContext();
217 if (InclusionFilter::isIncluded(policy, context))
218 filteredSubs.append({sub->name(), resolveHref(hrefResolver, sub, qcn)});
220 std::sort(filteredSubs.begin(), filteredSubs.end(),
223 return a.name < b.name;
225 data.inheritedBy = filteredSubs;
231 if (InclusionFilter::isIncluded(policy, context))
232 data.nativeType = IR::QmlTypeData::NativeTypeInfo{cn->name(), resolveHref(hrefResolver, cn, qcn)};
239
240
241
242
243
244
245
246
247
248
249
250
255 data.logicalModuleName = cn->logicalModuleName();
256 data.logicalModuleVersion = cn->logicalModuleVersion();
257 data.qtVariable = cn->qtVariable();
258 data.cmakePackage = cn->cmakePackage();
259 data.cmakeComponent = cn->cmakeComponent();
260 data.cmakeTargetItem = cn->cmakeTargetItem();
261 data.state = cn->state();
271 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
274 return { node->name(), resolveHref(hrefResolver, node, cn), node->doc().briefText().toString() };
277 auto sortEntries = [](QList<IR::CollectionData::MemberEntry> &entries) {
278 std::sort(entries.begin(), entries.end(),
281 return a.name.compare(b.name, Qt::CaseInsensitive) < 0;
287 for (
auto *node : nsMap.values()) {
288 const NodeContext context = node->createContext();
289 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
290 data.namespaces.append(makeMemberEntry(node));
292 sortEntries(data.namespaces);
295 for (
auto *node : classMap.values()) {
296 const NodeContext context = node->createContext();
297 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
298 data.classes.append(makeMemberEntry(node));
300 sortEntries(data.classes);
302 for (
const auto *node : cn->members()) {
303 if (!node->isInAPI())
305 const NodeContext context = node->createContext();
306 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
307 data.members.append(makeMemberEntry(node));
309 sortEntries(data.members);
316
317
318
319
320
321
322
329 QList<IR::SectionIR> result;
330 for (
const auto §ion : sv) {
331 if (section.isEmpty())
334 IR::SectionIR irSection;
335 irSection.title = section.title();
336 irSection.id = Utilities::asAsciiPrintable(section.title());
337 irSection.singular = section.singular();
338 irSection.plural = section.plural();
344 for (
const auto *member : section.members()) {
345 if (member->isSharedCommentNode()) {
346 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
347 for (
const auto *child : scn->collective()) {
348 IR::MemberIR irMember = extractMemberIR(child, hrefResolver, aggregate);
349 irMember.href =
"#"_L1 + hrefResolver->anchorForNode(child);
350 irSection.members.append(irMember);
353 IR::MemberIR irMember = extractMemberIR(member, hrefResolver, aggregate);
354 irMember.href =
"#"_L1 + hrefResolver->anchorForNode(member);
355 irSection.members.append(irMember);
359 for (
const auto *reimpl : section.reimplementedMembers())
360 irSection.reimplementedMembers.append(extractMemberIR(reimpl, hrefResolver, aggregate));
362 for (
const auto &[base, count] : section.inheritedMembers()) {
363 IR::InheritedMembersIR inherited;
364 inherited.className = base->plainFullName();
365 inherited.count = count;
366 inherited.href = resolveHref(hrefResolver, base, aggregate);
367 irSection.inheritedMembers.append(inherited);
370 result.append(irSection);
376
377
378
379
380
381
382
383
389 QList<IR::SectionIR> result;
390 for (
const auto §ion : sv) {
391 if (section.isEmpty())
394 IR::SectionIR irSection;
395 irSection.title = section.title();
396 irSection.id = Utilities::asAsciiPrintable(section.title());
397 irSection.singular = section.singular();
398 irSection.plural = section.plural();
400 for (
const auto *member : section.members()) {
401 if (member->isSharedCommentNode()) {
402 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
404 QList<IR::ContentBlock> sharedBody;
405 const Text &bodyText = scn->doc().body();
406 if (
const Atom *firstAtom = bodyText.firstAtom()) {
407 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
408 diagnosticHandlerFor(scn));
409 sharedBody = contentBuilder.build(firstAtom);
412 QList<IR::ContentBlock> sharedAlso;
413 const QList<Text> &alsoTexts = scn->doc().alsoList();
414 for (
const Text &alsoText : alsoTexts) {
415 if (
const Atom *firstAtom = alsoText.firstAtom()) {
416 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
417 diagnosticHandlerFor(scn));
418 sharedAlso.append(contentBuilder.build(firstAtom));
422 for (
const auto *child : scn->collective()) {
423 IR::MemberIR irMember = extractMemberIR(child, hrefResolver, aggregate, MemberExtractionLevel::Detail);
424 irMember.body = sharedBody;
425 irMember.alsoList = sharedAlso;
426 irSection.members.append(irMember);
429 irSection.members.append(extractMemberIR(member, hrefResolver, aggregate, MemberExtractionLevel::Detail));
433 result.append(irSection);
441 case Node::Reentrant:
442 return "reentrant"_L1;
443 case Node::ThreadSafe:
444 return "thread-safe"_L1;
451
452
453
454
455
456
457
458
459
460
461
462
463
469 member.name = node->name();
470 member.fullName = node->plainFullName();
471 member.href = resolveHref(hrefResolver, node, relative);
479 const auto *fn =
static_cast<
const FunctionNode *>(node);
480 member.signature = fn->signature(
491 for (
int i = 0; i < params
.count(); ++i) {
493 param.type = params
.at(i
).type();
494 param.name = params
.at(i
).name();
495 param.defaultValue = params
.at(i
).defaultValue();
496 member.parameters.append(param);
499 const auto *en =
static_cast<
const EnumNode *>(node);
500 member.signature = en->isScoped()
501 ? QStringLiteral(
"enum class %1").arg(en->name())
502 : QStringLiteral(
"enum %1").arg(en->name());
504 for (
const auto &item : en->items()) {
506 ev.name = item.name();
507 ev.value = item.value();
508 ev.since = item.since();
509 member.enumValues.append(ev);
512 const auto *qpn =
static_cast<
const QmlPropertyNode *>(node);
513 member.signature = qpn->name() +
" : "_L1 + qpn->dataType();
514 member.dataType = qpn->dataType();
520 const auto *pn =
static_cast<
const PropertyNode *>(node);
521 member.signature = pn->name() +
" : "_L1 + pn->qualifiedDataType();
523 const auto *td =
static_cast<
const TypedefNode *>(node);
524 member.signature = td->associatedEnum()
525 ?
"flags "_L1 + td->name()
528 const auto *vn =
static_cast<
const VariableNode *>(node);
529 member.signature = vn->leftType() + vn->name() + vn->rightType();
531 member.signature = node->name();
535 member.anchorId = hrefResolver->anchorForNode(node);
536 member.synopsis = member.signature;
537 member.since = node->since();
538 member.threadSafety = threadSafenessString(node->threadSafeness());
542 member.comparisonCategory = QString::fromStdString(catStr);
545 const auto *fn =
static_cast<
const FunctionNode *>(node);
546 const auto &noexcept_ = fn->getNoexcept();
549 member.noexceptNote = *noexcept_;
556 diagnosticHandlerFor(node));
557 member.body = contentBuilder.build(firstAtom);
560 const QList<Text> &alsoTexts = node
->doc().alsoList();
561 for (
const Text &alsoText : alsoTexts) {
562 if (
const Atom *firstAtom = alsoText.firstAtom()) {
563 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
564 diagnosticHandlerFor(node));
565 QList<IR::ContentBlock> blocks = contentBuilder.build(firstAtom);
566 member.alsoList.append(blocks);
576 static const QRegularExpression tagRegex(
577 "<@[a-z]+[^>]*>|</@[a-z]+>"_L1,
578 QRegularExpression::InvertedGreedinessOption);
579 QString result = marked;
580 result.remove(tagRegex);
585
586
587
588
589
590
591
592
596 result.typeName = qcn->name();
597 result.typeHref = resolveHref(hrefResolver, qcn, qcn);
602 if (groupedMembers.isEmpty())
605 CodeMarker *marker = CodeMarker::markerForLanguage(
"QML"_L1);
606 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
609 IR::AllMemberEntry entry;
610 entry.signature = stripCodeMarkerTags(
611 marker->markedUpQmlItem(node,
true));
612 entry.href = resolveHref(hrefResolver, node, qcn);
614 if (node->isQmlProperty()) {
615 auto *qpn =
static_cast<QmlPropertyNode *>(node);
616 QStringList qmlHints = qpn->hints();
617 if (qpn->isAttached() && !qmlHints.contains(
"attached"_L1))
618 qmlHints <<
"attached"_L1;
619 for (
const auto &h : std::as_const(qmlHints))
620 entry.hints.append(h);
621 }
else if (node->isAttached()) {
622 entry.hints.append(
"attached"_L1);
625 if (node->isPropertyGroup()) {
626 entry.isPropertyGroup =
true;
627 const auto *scn =
static_cast<SharedCommentNode *>(node);
628 for (
auto *child : scn->collective()) {
629 const NodeContext childContext = child->createContext();
630 if (!InclusionFilter::isIncluded(policy, childContext))
632 entry.children.append(buildEntry(child));
639 auto isVisible = [&policy](
Node *node) {
641 return InclusionFilter::isIncluded(policy, context)
642 && !(node->isSharingComment() && node->sharedCommentNode()->isPropertyGroup());
645 for (
const auto &[originType, nodes] : groupedMembers) {
646 Q_ASSERT(originType);
650 IR::MemberGroup group;
651 if (originType != qcn) {
652 group.typeName = originType->name();
653 group.typeHref = resolveHref(hrefResolver, originType, qcn);
656 for (
auto *node : nodes) {
658 group.members.append(buildEntry(node));
661 result.memberGroups.append(group);
668
669
670
671
672
673
674
678 result.typeName = aggregate->plainFullName();
679 result.typeHref = resolveHref(hrefResolver, aggregate, aggregate);
687 CodeMarker *marker = CodeMarker::markerForCode(QString());
688 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
690 for (
const auto *node : allMembers.members()) {
691 if (node->name().isEmpty())
693 const NodeContext context = node->createContext();
694 if (!InclusionFilter::isIncluded(policy, context))
697 IR::AllMemberEntry entry;
698 entry.signature = stripCodeMarkerTags(
699 marker->markedUpSynopsis(node, aggregate, Section::AllMembers));
700 entry.href = resolveHref(hrefResolver, node, aggregate);
701 result.members.append(entry);
708
709
710
711
712
713
714
715
719 const auto *qcn =
static_cast<
const QmlTypeNode *>(pn);
720 if (qcn->isQmlBasicType())
722 auto result = extractQmlAllMembersIR(qcn, hrefResolver);
723 bool hasMember =
false;
724 for (
const auto &group : std::as_const(result.memberGroups)) {
725 if (!group.members.isEmpty()) {
736 const auto *aggregate =
static_cast<
const Aggregate *>(pn);
737 auto result = extractCppAllMembersIR(aggregate, hrefResolver);
738 if (result.members.isEmpty())
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
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.
bool noAutoList() const
Returns the value of the no auto-list flag.
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.
SectionVector & detailsSections()
Section & allMembersSection()
const Atom * firstAtom() const
static std::string comparisonCategoryAsString(ComparisonCategory category)
Combined button and popup list for selecting options.
QMap< QString, Node * > NodeMap
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.
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 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.
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.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
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.
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.
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