Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
nodeextractor.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "aggregate.h"
7#include "atom.h"
8#include "classnode.h"
9#include "codemarker.h"
10#include "collectionnode.h"
12#include "config.h"
13#include "doc.h"
14#include "enumnode.h"
15#include "functionnode.h"
16#include "hrefresolver.h"
18#include "ir/contentbuilder.h"
19#include "pagenode.h"
20#include "parameters.h"
21#include "propertynode.h"
23#include "qmltypenode.h"
24#include "sections.h"
26#include "text.h"
27#include "typedefnode.h"
28#include "utilities.h"
29#include "variablenode.h"
30
31#include "location.h"
32
33#include <QRegularExpression>
34
36
37using namespace Qt::Literals;
38
40{
41 const Location &loc = node->doc().location();
42 return [loc](QtMsgType type, const QString &message) {
43 switch (type) {
44 case QtWarningMsg:
45 loc.warning(message);
46 break;
47 default:
48 loc.warning(message);
49 break;
50 }
51 };
52}
53
54static QString resolveHref(const HrefResolver *resolver, const Node *target, const Node *relative)
55{
56 if (!resolver)
57 return target->url();
58 auto result = resolver->hrefForNode(target, relative);
59 if (const auto *href = std::get_if<QString>(&result))
60 return *href;
61 return {};
62}
63
64namespace NodeExtractor {
65
66/*!
67 \internal
68 Extract page-level metadata from a PageNode into a value-type struct.
69
70 This function reads classification, identity, brief, and body fields
71 from the given PageNode and returns them as an IR::PageMetadata value.
72 Body content is populated via ContentBuilder, which transforms the
73 atom chain into structured content blocks. Format-conditional atoms
74 are skipped unconditionally since the template generator builds a
75 format-agnostic IR.
76
77 For aggregate pages (classes, QML types, namespaces), member listings
78 are extracted via the Sections infrastructure and stored as frozen
79 SectionIR values.
80
81 The caller (TemplateGenerator) invokes this before passing the
82 result to IR::Builder, ensuring Builder never includes PageNode
83 or other Node subclass headers.
84*/
85IR::PageMetadata extractPageMetadata(const PageNode *pn, const HrefResolver *hrefResolver)
86{
87 Q_ASSERT_X(pn, "NodeExtractor::extractPageMetadata",
88 "PageNode pointer must be non-null");
89 IR::PageMetadata pm;
90
91 pm.nodeType = pn->nodeType();
92 pm.genus = pn->genus();
93 pm.status = pn->status();
94 pm.access = pn->access();
95
96 if (pn->isQmlType()) {
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;
101 } else {
102 pm.title = pn->title();
103 pm.fullTitle = pn->fullTitle();
104 }
105
106 pm.url = pn->url();
107 pm.since = pn->since();
108 pm.deprecatedSince = pn->deprecatedSince();
109 pm.brief = pn->doc().briefText().toString();
110
111 const Text &bodyText = pn->doc().body();
112 if (const Atom *firstAtom = bodyText.firstAtom()) {
113 // Offset section heading levels to account for page structure.
114 // QDoc's \section1 maps to level 1, but pages already use <h1>
115 // for the title. The legacy generators apply a node-type-dependent
116 // offset; we replicate the same mapping here.
117 const int headingOffset = [&] {
118 switch (pn->nodeType()) {
120 case NodeType::Class:
121 case NodeType::Struct:
122 case NodeType::Union:
123 case NodeType::Module:
124 return 2;
128 case NodeType::Page:
129 case NodeType::Group:
130 return 1;
131 default:
132 return 3;
133 }
134 }();
135 IR::ContentBuilder contentBuilder(IR::BriefHandling::Skip, headingOffset,
136 diagnosticHandlerFor(pn));
137 pm.body = contentBuilder.build(firstAtom);
138 }
139
140 if (pn->isAggregate()) {
141 const auto *aggregate = static_cast<const Aggregate *>(pn);
142 pm.summarySections = extractSummarySections(aggregate, hrefResolver);
143 pm.detailSections = extractDetailSections(aggregate, hrefResolver);
144 }
145
146 if (pn->isQmlType()) {
147 const auto *qcn = static_cast<const QmlTypeNode *>(pn);
148 pm.qmlTypeData = extractQmlTypeData(qcn, hrefResolver);
149 }
150
151 if (pn->isCollectionNode()) {
152 const auto *cn = static_cast<const CollectionNode *>(pn);
153 pm.collectionData = extractCollectionData(cn, hrefResolver);
154 }
155
156 return pm;
157}
158
159/*!
160 \internal
161 Extract QML type metadata from a QmlTypeNode.
162
163 Populates import statement, inheritance chain, inherited-by list,
164 native C++ type link, and singleton/value-type flags. InclusionFilter
165 is applied to match the legacy generator's visibility filtering.
166*/
167IR::QmlTypeData extractQmlTypeData(const QmlTypeNode *qcn, const HrefResolver *hrefResolver)
168{
169 IR::QmlTypeData data;
170 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
171
172 if (!qcn->logicalModuleName().isEmpty()) {
173 bool includeImport = true;
174 const CollectionNode *collection = qcn->logicalModule();
175 if (collection) {
176 const NodeContext context = collection->createContext();
177 includeImport = InclusionFilter::isIncluded(policy, context);
178 }
179 if (includeImport) {
180 QStringList parts = QStringList()
181 << "import"_L1 << qcn->logicalModuleName() << qcn->logicalModuleVersion();
182 data.importStatement = parts.join(' '_L1).trimmed();
183 }
184 }
185
188
189 QmlTypeNode *base = qcn->qmlBaseNode();
190 while (base) {
191 const NodeContext context = base->createContext();
192 if (InclusionFilter::isIncluded(policy, context))
193 break;
194 base = base->qmlBaseNode();
195 }
196
197 NodeList subs;
198 QmlTypeNode::subclasses(qcn, subs, true);
199
200 if (base) {
201 IR::QmlTypeData::InheritsInfo inheritsInfo;
202 inheritsInfo.name = base->name();
203 inheritsInfo.href = resolveHref(hrefResolver, base, qcn);
204 const CollectionNode *baseModule = base->logicalModule();
205 if (baseModule) {
206 const NodeContext moduleContext = baseModule->createContext();
207 if (InclusionFilter::isIncluded(policy, moduleContext))
208 inheritsInfo.moduleName = base->logicalModuleName();
209 }
210 data.inherits = inheritsInfo;
211 }
212
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)});
219 }
220 std::sort(filteredSubs.begin(), filteredSubs.end(),
221 [](const IR::QmlTypeData::InheritedByEntry &a,
222 const IR::QmlTypeData::InheritedByEntry &b) {
223 return a.name < b.name;
224 });
225 data.inheritedBy = filteredSubs;
226 }
227
228 ClassNode *cn = qcn->classNode();
229 if (cn && cn->isQmlNativeType()) {
230 const NodeContext context = cn->createContext();
231 if (InclusionFilter::isIncluded(policy, context))
232 data.nativeType = IR::QmlTypeData::NativeTypeInfo{cn->name(), resolveHref(hrefResolver, cn, qcn)};
233 }
234
235 return data;
236}
237
238/*!
239 \internal
240 Extract collection metadata from a CollectionNode.
241
242 Populates module identity, CMake/qmake build variables, technology
243 preview state, and pre-sorted member listings. For C++ modules,
244 members are categorized into separate namespace and class lists.
245 For groups and QML modules, a single flat member list is produced.
246
247 All member lists are filtered through InclusionFilter (excluding
248 internal entries) and exclude deprecated nodes, then sorted
249 alphabetically by name (case-insensitive).
250*/
251IR::CollectionData extractCollectionData(const CollectionNode *cn, const HrefResolver *hrefResolver)
252{
253 IR::CollectionData data;
254
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();
262
263 data.isModule = cn->isModule();
264 data.isQmlModule = cn->isQmlModule();
265 data.isGroup = cn->isGroup();
266 data.noAutoList = cn->noAutoList();
267
268 if (cn->noAutoList())
269 return data;
270
271 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
272
273 auto makeMemberEntry = [hrefResolver, cn](const Node *node) -> IR::CollectionData::MemberEntry {
274 return { node->name(), resolveHref(hrefResolver, node, cn), node->doc().briefText().toString() };
275 };
276
277 auto sortEntries = [](QList<IR::CollectionData::MemberEntry> &entries) {
278 std::sort(entries.begin(), entries.end(),
279 [](const IR::CollectionData::MemberEntry &a,
280 const IR::CollectionData::MemberEntry &b) {
281 return a.name.compare(b.name, Qt::CaseInsensitive) < 0;
282 });
283 };
284
285 if (cn->isModule()) {
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));
291 }
292 sortEntries(data.namespaces);
293
294 const NodeMap classMap = cn->getMembers([](const Node *n) { return n->isClassNode(); });
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));
299 }
300 sortEntries(data.classes);
301 } else {
302 for (const auto *node : cn->members()) {
303 if (!node->isInAPI())
304 continue;
305 const NodeContext context = node->createContext();
306 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
307 data.members.append(makeMemberEntry(node));
308 }
309 sortEntries(data.members);
310 }
311
312 return data;
313}
314
315/*!
316 \internal
317 Build categorized summary sections for an aggregate node.
318
319 Delegates to the Sections class for member distribution, then extracts
320 results into frozen SectionIR values. The section variant (C++ class,
321 QML type, or generic) is chosen based on the aggregate's node type.
322*/
323QList<IR::SectionIR> extractSummarySections(const Aggregate *aggregate, const HrefResolver *hrefResolver)
324{
325 Sections sections(aggregate);
326
327 const auto &sv = sections.summarySections();
328
329 QList<IR::SectionIR> result;
330 for (const auto &section : sv) {
331 if (section.isEmpty())
332 continue;
333
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();
339
340 // SharedCommentNode groups several declarations under one doc comment.
341 // Expand them into individual MemberIR entries so each function appears
342 // in the member table. This means the IR member count may exceed the
343 // Section::members() count.
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);
351 }
352 } else {
353 IR::MemberIR irMember = extractMemberIR(member, hrefResolver, aggregate);
354 irMember.href = "#"_L1 + hrefResolver->anchorForNode(member);
355 irSection.members.append(irMember);
356 }
357 }
358
359 for (const auto *reimpl : section.reimplementedMembers())
360 irSection.reimplementedMembers.append(extractMemberIR(reimpl, hrefResolver, aggregate));
361
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);
368 }
369
370 result.append(irSection);
371 }
372 return result;
373}
374
375/*!
376 \internal
377 Build categorized detail sections for an aggregate node.
378
379 Iterates Sections::detailsSections() and extracts full member
380 documentation including body content, anchor IDs, and metadata.
381 SharedCommentNode groups share a single documentation body across
382 their children, with each child getting its own anchorId and synopsis.
383*/
384QList<IR::SectionIR> extractDetailSections(const Aggregate *aggregate, const HrefResolver *hrefResolver)
385{
386 Sections sections(aggregate);
387 const auto &sv = sections.detailsSections();
388
389 QList<IR::SectionIR> result;
390 for (const auto &section : sv) {
391 if (section.isEmpty())
392 continue;
393
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();
399
400 for (const auto *member : section.members()) {
401 if (member->isSharedCommentNode()) {
402 const auto *scn = static_cast<const SharedCommentNode *>(member);
403
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);
410 }
411
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));
419 }
420 }
421
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);
427 }
428 } else {
429 irSection.members.append(extractMemberIR(member, hrefResolver, aggregate, MemberExtractionLevel::Detail));
430 }
431 }
432
433 result.append(irSection);
434 }
435 return result;
436}
437
439{
440 switch (ts) {
441 case Node::Reentrant:
442 return "reentrant"_L1;
443 case Node::ThreadSafe:
444 return "thread-safe"_L1;
445 default:
446 return {};
447 }
448}
449
450/*!
451 \internal
452 Build a MemberIR from a single Node.
453
454 Extracts identity, classification, and type-specific data from the node.
455 FunctionNode provides signatures, parameters, and overload metadata.
456 EnumNode provides scoped/unscoped signature and enum value listings.
457 PropertyNode provides a qualified data type signature.
458
459 When \a level is MemberExtractionLevel::Detail, also populates
460 detail documentation fields: anchorId, synopsis, since,
461 threadSafety, comparisonCategory, noexcept metadata, body (via
462 ContentBuilder), and alsoList.
463*/
464IR::MemberIR extractMemberIR(const Node *node, const HrefResolver *hrefResolver, const Node *relative, MemberExtractionLevel level)
465{
466 const bool includeDetail = (level == MemberExtractionLevel::Detail);
467 IR::MemberIR member;
468
469 member.name = node->name();
470 member.fullName = node->plainFullName();
471 member.href = resolveHref(hrefResolver, node, relative);
472 member.brief = node->doc().briefText().toString();
473
474 member.nodeType = node->nodeType();
475 member.access = node->access();
476 member.status = node->status();
477
478 if (node->isFunction()) {
479 const auto *fn = static_cast<const FunctionNode *>(node);
480 member.signature = fn->signature(
482 member.isStatic = fn->isStatic();
483 member.isConst = fn->isConst();
484 member.isVirtual = !fn->isNonvirtual();
485 member.isSignal = fn->isSignal();
486 member.isSlot = fn->isSlot();
487 member.overloadNumber = fn->overloadNumber();
488 member.isPrimaryOverload = fn->isPrimaryOverload();
489
490 const Parameters &params = fn->parameters();
491 for (int i = 0; i < params.count(); ++i) {
492 IR::ParameterIR param;
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);
497 }
498 } else if (node->isEnumType()) {
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());
503
504 for (const auto &item : en->items()) {
505 IR::EnumValueIR ev;
506 ev.name = item.name();
507 ev.value = item.value();
508 ev.since = item.since();
509 member.enumValues.append(ev);
510 }
511 } else if (node->isQmlProperty()) {
512 const auto *qpn = static_cast<const QmlPropertyNode *>(node);
513 member.signature = qpn->name() + " : "_L1 + qpn->dataType();
514 member.dataType = qpn->dataType();
515 member.isAttached = qpn->isAttached();
516 member.isDefault = qpn->isDefault();
517 member.isReadOnly = qpn->isReadOnly();
518 member.isRequired = qpn->isRequired();
519 } else if (node->isProperty()) {
520 const auto *pn = static_cast<const PropertyNode *>(node);
521 member.signature = pn->name() + " : "_L1 + pn->qualifiedDataType();
522 } else if (node->isTypedef()) {
523 const auto *td = static_cast<const TypedefNode *>(node);
524 member.signature = td->associatedEnum()
525 ? "flags "_L1 + td->name()
526 : td->name();
527 } else if (node->nodeType() == NodeType::Variable) {
528 const auto *vn = static_cast<const VariableNode *>(node);
529 member.signature = vn->leftType() + vn->name() + vn->rightType();
530 } else {
531 member.signature = node->name();
532 }
533
534 if (includeDetail) {
535 member.anchorId = hrefResolver->anchorForNode(node);
536 member.synopsis = member.signature;
537 member.since = node->since();
538 member.threadSafety = threadSafenessString(node->threadSafeness());
539
541 if (!catStr.empty())
542 member.comparisonCategory = QString::fromStdString(catStr);
543
544 if (node->isFunction()) {
545 const auto *fn = static_cast<const FunctionNode *>(node);
546 const auto &noexcept_ = fn->getNoexcept();
547 if (noexcept_) {
548 member.isNoexcept = true;
549 member.noexceptNote = *noexcept_;
550 }
551 }
552
553 const Text &bodyText = node->doc().body();
554 if (const Atom *firstAtom = bodyText.firstAtom()) {
555 IR::ContentBuilder contentBuilder(IR::BriefHandling::Include, 0,
556 diagnosticHandlerFor(node));
557 member.body = contentBuilder.build(firstAtom);
558 }
559
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);
567 }
568 }
569 }
570
571 return member;
572}
573
574static QString stripCodeMarkerTags(const QString &marked)
575{
576 static const QRegularExpression tagRegex(
577 "<@[a-z]+[^>]*>|</@[a-z]+>"_L1,
578 QRegularExpression::InvertedGreedinessOption);
579 QString result = marked;
580 result.remove(tagRegex);
581 return result;
582}
583
584/*!
585 \internal
586 Extract a grouped all-members listing for a QML type.
587
588 Constructs a Sections object from the QmlTypeNode, extracts
589 allMembersSection().classNodesList() to group members by
590 originating QML type, and builds AllMemberEntry items with
591 QML-specific hints and property group nesting.
592*/
593static IR::AllMembersIR extractQmlAllMembersIR(const QmlTypeNode *qcn, const HrefResolver *hrefResolver)
594{
595 IR::AllMembersIR result;
596 result.typeName = qcn->name();
597 result.typeHref = resolveHref(hrefResolver, qcn, qcn);
598 result.isQmlType = true;
599
600 Sections sections(qcn);
602 if (groupedMembers.isEmpty())
603 return result;
604
605 CodeMarker *marker = CodeMarker::markerForLanguage("QML"_L1);
606 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
607
608 std::function<IR::AllMemberEntry(Node *)> buildEntry = [&](Node *node) -> IR::AllMemberEntry {
609 IR::AllMemberEntry entry;
610 entry.signature = stripCodeMarkerTags(
611 marker->markedUpQmlItem(node, true));
612 entry.href = resolveHref(hrefResolver, node, qcn);
613
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);
623 }
624
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))
631 continue;
632 entry.children.append(buildEntry(child));
633 }
634 }
635
636 return entry;
637 };
638
639 auto isVisible = [&policy](Node *node) {
640 const NodeContext context = node->createContext();
641 return InclusionFilter::isIncluded(policy, context)
642 && !(node->isSharingComment() && node->sharedCommentNode()->isPropertyGroup());
643 };
644
645 for (const auto &[originType, nodes] : groupedMembers) {
646 Q_ASSERT(originType);
647 if (nodes.isEmpty())
648 continue;
649
650 IR::MemberGroup group;
651 if (originType != qcn) {
652 group.typeName = originType->name();
653 group.typeHref = resolveHref(hrefResolver, originType, qcn);
654 }
655
656 for (auto *node : nodes) {
657 if (isVisible(node))
658 group.members.append(buildEntry(node));
659 }
660
661 result.memberGroups.append(group);
662 }
663
664 return result;
665}
666
667/*!
668 \internal
669 Extract a flat all-members listing for a C++ class or namespace.
670
671 Constructs a Sections object from the aggregate, extracts
672 allMembersSection().members(), builds AllMemberEntry for each
673 visible member, and returns an AllMembersIR with isQmlType=false.
674*/
675static IR::AllMembersIR extractCppAllMembersIR(const Aggregate *aggregate, const HrefResolver *hrefResolver)
676{
677 IR::AllMembersIR result;
678 result.typeName = aggregate->plainFullName();
679 result.typeHref = resolveHref(hrefResolver, aggregate, aggregate);
680 result.isQmlType = false;
681
682 Sections sections(aggregate);
683 const Section &allMembers = sections.allMembersSection();
684 if (allMembers.isEmpty())
685 return result;
686
687 CodeMarker *marker = CodeMarker::markerForCode(QString());
688 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
689
690 for (const auto *node : allMembers.members()) {
691 if (node->name().isEmpty())
692 continue;
693 const NodeContext context = node->createContext();
694 if (!InclusionFilter::isIncluded(policy, context))
695 continue;
696
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);
702 }
703
704 return result;
705}
706
707/*!
708 \internal
709 Extract all-members IR for a page node.
710
711 Dispatches to the QML or C++ extraction function based on the page
712 type. Returns std::nullopt for page types that don't have member
713 listing pages (generic pages, QML basic types) or when the listing
714 would be empty.
715*/
716std::optional<IR::AllMembersIR> extractAllMembersIR(const PageNode *pn, const HrefResolver *hrefResolver)
717{
718 if (pn->isQmlType()) {
719 const auto *qcn = static_cast<const QmlTypeNode *>(pn);
720 if (qcn->isQmlBasicType())
721 return std::nullopt;
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()) {
726 hasMember = true;
727 break;
728 }
729 }
730 if (!hasMember)
731 return std::nullopt;
732 return result;
733 }
734
735 if (pn->isAggregate() && (pn->isClassNode() || pn->isNamespace())) {
736 const auto *aggregate = static_cast<const Aggregate *>(pn);
737 auto result = extractCppAllMembersIR(aggregate, hrefResolver);
738 if (result.members.isEmpty())
739 return std::nullopt;
740 return result;
741 }
742
743 return std::nullopt;
744}
745
746} // namespace NodeExtractor
747
748QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
The ClassNode represents a C++ class.
Definition classnode.h:23
bool isQmlNativeType()
Definition classnode.h:54
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.
Definition doc.cpp:89
const Text & body() const
Definition doc.cpp:114
Text briefText(bool inclusive=false) const
Definition doc.cpp:126
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.
Definition location.h:20
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:19
bool noAutoList() const
Returns the value of the no auto-list flag.
Definition pagenode.h:42
ClassNode * classNode() const override
If this is a QmlTypeNode, this function returns the pointer to the C++ ClassNode that this QML type r...
Definition qmltypenode.h:27
static void subclasses(const Node *base, NodeList &subs, bool recurse=false)
Loads the list subs with the nodes of all the subclasses of base.
bool isSingleton() const
Definition qmltypenode.h:31
QmlTypeNode * qmlBaseNode() const override
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
Definition qmltypenode.h:47
CollectionNode * logicalModule() const override
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
Definition qmltypenode.h:40
A class for containing the elements of one documentation section.
Definition sections.h:17
ClassNodesList & classNodesList()
Definition sections.h:52
bool isEmpty() const
Definition sections.h:35
A class for creating vectors of collections for documentation.
Definition sections.h:80
SectionVector & summarySections()
Definition sections.h:150
Sections(const Aggregate *aggregate)
This constructor builds the section vectors based on the type of the aggregate node.
Definition sections.cpp:371
SectionVector & detailsSections()
Definition sections.h:151
Section & allMembersSection()
Definition sections.h:152
Definition text.h:12
const Atom * firstAtom() const
Definition text.h:34
static std::string comparisonCategoryAsString(ComparisonCategory category)
NodeType
Definition genustypes.h:150
Definition builder.cpp:14
IR::CollectionData extractCollectionData(const CollectionNode *cn, const HrefResolver *hrefResolver)
IR::MemberIR extractMemberIR(const Node *node, const HrefResolver *hrefResolver, const Node *relative, MemberExtractionLevel level)
std::optional< IR::AllMembersIR > extractAllMembersIR(const PageNode *pn, const HrefResolver *hrefResolver)
QList< IR::SectionIR > extractSummarySections(const Aggregate *aggregate, const HrefResolver *hrefResolver)
static IR::AllMembersIR extractQmlAllMembersIR(const QmlTypeNode *qcn, const HrefResolver *hrefResolver)
IR::QmlTypeData extractQmlTypeData(const QmlTypeNode *qcn, const HrefResolver *hrefResolver)
QList< IR::SectionIR > extractDetailSections(const Aggregate *aggregate, const HrefResolver *hrefResolver)
IR::PageMetadata extractPageMetadata(const PageNode *pn, const HrefResolver *hrefResolver)
static QString threadSafenessString(Node::ThreadSafeness ts)
static IR::AllMembersIR extractCppAllMembersIR(const Aggregate *aggregate, const HrefResolver *hrefResolver)
static QString stripCodeMarkerTags(const QString &marked)
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:45
QMap< QString, Node * > NodeMap
Definition node.h:48
static QString resolveHref(const HrefResolver *resolver, const Node *target, const Node *relative)
static IR::DiagnosticHandler diagnosticHandlerFor(const Node *node)
MemberExtractionLevel
QList< ClassNodes > ClassNodesList
Definition sections.h:14
A single entry in an all-members listing page.
Definition member.h:96
Intermediate representation of the all-members listing page.
Definition member.h:112
Intermediate representation of a single documentable member.
Definition member.h:34
bool isPrimaryOverload
Definition member.h:47
bool isConst
Definition member.h:52
int overloadNumber
Definition member.h:46
bool isAttached
Definition member.h:58
bool isDefault
Definition member.h:59
bool isSlot
Definition member.h:55
bool isRequired
Definition member.h:61
bool isStatic
Definition member.h:51
bool isNoexcept
Definition member.h:70
bool isSignal
Definition member.h:54
Access access
Definition member.h:42
NodeType nodeType
Definition member.h:41
bool isReadOnly
Definition member.h:60
bool isVirtual
Definition member.h:53
Status status
Definition member.h:43
Intermediate representation of a function parameter.
Definition member.h:20
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.
Definition node.h:235
bool isGroup() const
Returns true if the node type is Group.
Definition node.h:104
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:108
bool isTypedef() const
Returns true if the node type is Typedef.
Definition node.h:126
bool isQmlBasicType() const
Returns true if the node type is QmlBasicType.
Definition node.h:117
ComparisonCategory comparisonCategory() const
Definition node.h:184
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:121
NodeType nodeType() const override
Returns this node's type.
Definition node.h:82
Genus genus() const override
Returns this node's Genus.
Definition node.h:85
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:93
virtual Status status() const
Returns the node's status value.
Definition node.h:239
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
Definition node.h:136
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
Definition node.h:228
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:100
bool isProperty() const
Returns true if the node type is Property.
Definition node.h:112
NodeContext createContext() const
Definition node.cpp:175
bool isModule() const
Returns true if the node type is Module.
Definition node.h:107
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
Definition node.h:58
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:143
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
Definition node.h:144
bool isQmlModule() const
Returns true if the node type is QmlModule.
Definition node.h:118
@ SignatureReturnType
Definition node.h:68
@ SignatureDefaultValues
Definition node.h:67
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Definition node.h:120
A class for parsing and managing a function parameter list.
Definition main.cpp:28
const Parameter & at(int i) const
Definition parameters.h:36
int count() const
Definition parameters.h:34