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
sections.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "sections.h"
5
6#include "aggregate.h"
7#include "classnode.h"
8#include "config.h"
9#include "enumnode.h"
10#include "functionnode.h"
11#include "generator.h"
12#include "genustypes.h"
15#include "utilities.h"
16#include "namespacenode.h"
17#include "node.h"
19#include "qmltypenode.h"
21#include "typedefnode.h"
22#include "variablenode.h"
23
24#include <QtCore/qobjectdefs.h>
25#include <QtCore/qset.h>
26
28
29QList<Section> Sections::s_stdSummarySections {
30 { "Namespaces", "namespace", "namespaces", "", Section::Summary },
31 { "Classes", "class", "classes", "", Section::Summary },
32 { "Types", "type", "types", "", Section::Summary },
33 { "Variables", "variable", "variables", "", Section::Summary },
34 { "Static Variables", "static variable", "static variables", "", Section::Summary },
35 { "Functions", "function", "functions", "", Section::Summary },
36 { "Macros", "macro", "macros", "", Section::Summary },
37};
38
39QList<Section> Sections::s_stdDetailsSections {
40 { "Namespaces", "namespace", "namespaces", "nmspace", Section::Details },
41 { "Classes", "class", "classes", "classes", Section::Details },
42 { "Type Documentation", "type", "types", "types", Section::Details },
43 { "Variable Documentation", "variable", "variables", "vars", Section::Details },
44 { "Static Variables", "static variable", "static variables", QString(), Section::Details },
45 { "Function Documentation", "function", "functions", "func", Section::Details },
46 { "Macro Documentation", "macro", "macros", "macros", Section::Details },
47};
48
49QList<Section> Sections::s_stdCppClassSummarySections {
50 { "Public Types", "public type", "public types", "", Section::Summary },
51 { "Properties", "property", "properties", "", Section::Summary },
52 { "Public Functions", "public function", "public functions", "", Section::Summary },
53 { "Public Slots", "public slot", "public slots", "", Section::Summary },
54 { "Signals", "signal", "signals", "", Section::Summary },
55 { "Public Variables", "public variable", "public variables", "", Section::Summary },
56 { "Static Public Members", "static public member", "static public members", "", Section::Summary },
57 { "Protected Types", "protected type", "protected types", "", Section::Summary },
58 { "Protected Functions", "protected function", "protected functions", "", Section::Summary },
59 { "Protected Slots", "protected slot", "protected slots", "", Section::Summary },
60 { "Protected Variables", "protected type", "protected variables", "", Section::Summary },
61 { "Static Protected Members", "static protected member", "static protected members", "", Section::Summary },
62 { "Private Types", "private type", "private types", "", Section::Summary },
63 { "Private Functions", "private function", "private functions", "", Section::Summary },
64 { "Private Slots", "private slot", "private slots", "", Section::Summary },
65 { "Private Variables", "private variable", "private variables", "", Section::Summary },
66 { "Static Private Members", "static private member", "static private members", "", Section::Summary },
67 { "Related Non-Members", "related non-member", "related non-members", "", Section::Summary },
68 { "Macros", "macro", "macros", "", Section::Summary },
69};
70
71QList<Section> Sections::s_stdCppClassDetailsSections {
72 { "Member Type Documentation", "member", "members", "types", Section::Details },
73 { "Property Documentation", "member", "members", "prop", Section::Details },
74 { "Member Function Documentation", "member", "members", "func", Section::Details },
75 { "Member Variable Documentation", "member", "members", "vars", Section::Details },
76 { "Related Non-Members", "member", "members", "relnonmem", Section::Details },
77 { "Macro Documentation", "member", "members", "macros", Section::Details },
78};
79
80QList<Section> Sections::s_stdQmlTypeSummarySections {
81 { "Enumerations", "enumeration", "enumerations", "", Section::Summary },
82 { "Properties", "property", "properties", "", Section::Summary },
83 { "Attached Properties", "attached property", "attached properties", "", Section::Summary },
84 { "Signals", "signal", "signals", "", Section::Summary },
85 { "Signal Handlers", "signal handler", "signal handlers", "", Section::Summary },
86 { "Attached Signals", "attached signal", "attached signals", "", Section::Summary },
87 { "Methods", "method", "methods", "", Section::Summary },
88 { "Attached Methods", "attached method", "attached methods", "", Section::Summary },
89};
90
91QList<Section> Sections::s_stdQmlTypeDetailsSections {
92 { "Enumeration Documentation", "member", "members", "qmlenum", Section::Details },
93 { "Property Documentation", "member", "members", "qmlprop", Section::Details },
94 { "Attached Property Documentation", "member", "members", "qmlattprop", Section::Details },
95 { "Signal Documentation", "signal", "signals", "qmlsig", Section::Details },
96 { "Signal Handler Documentation", "signal handler", "signal handlers", "qmlsighan", Section::Details },
97 { "Attached Signal Documentation", "signal", "signals", "qmlattsig", Section::Details },
98 { "Method Documentation", "member", "members", "qmlmeth", Section::Details },
99 { "Attached Method Documentation", "member", "members", "qmlattmeth", Section::Details },
100};
101
102QList<Section> Sections::s_sinceSections {
103 { "New Namespaces", "", "", "", Section::Details },
104 { "New Classes", "", "", "", Section::Details },
105 { "New Member Functions", "", "", "", Section::Details },
106 { "New Functions in Namespaces", "", "", "", Section::Details },
107 { "New Global Functions", "", "", "", Section::Details },
108 { "New Macros", "", "", "", Section::Details },
109 { "New Enum Types", "", "", "", Section::Details },
110 { "New Enum Values", "", "", "", Section::Details },
111 { "New Type Aliases", "", "", "", Section::Details },
112 { "New Properties", "", "", "", Section::Details },
113 { "New Variables", "", "", "", Section::Details },
114 { "New QML Types", "", "", "", Section::Details },
115 { "New QML Enumeration Types", "", "", "", Section::Details },
116 { "New QML Properties", "", "", "", Section::Details },
117 { "New QML Signals", "", "", "", Section::Details },
118 { "New QML Signal Handlers", "", "", "", Section::Details },
119 { "New QML Methods", "", "", "", Section::Details },
120};
121
122QList<Section> Sections::s_allMembers{ { "", "member", "members", "", Section::AllMembers } };
123
124/*!
125 \class Section
126 \brief A class for containing the elements of one documentation section
127 */
128
129/*!
130 The destructor must delete the members of collections
131 when the members are allocated on the heap.
132 */
134{
135 clear();
136}
137
138/*!
139 A Section is now an element in a static vector, so we
140 don't have to repeatedly construct and destroy them. But
141 we do need to clear them before each call to build the
142 sections for a C++ or QML entity.
143 */
145{
146 m_reimplementedMemberMap.clear();
147 m_members.clear();
148 m_obsoleteMembers.clear();
149 m_reimplementedMembers.clear();
150 m_inheritedMembers.clear();
151 m_classNodesList.clear();
152 m_aggregate = nullptr;
153}
154
155/*!
156 Construct a name for the \a node that can be used for sorting
157 a set of nodes into equivalence classes.
158 */
160{
161 QString nodeName{node->name()};
162
163 int numDigits = 0;
164 for (qsizetype i = nodeName.size() - 1; i > 0; --i) {
165 if (nodeName.at(i).digitValue() == -1)
166 break;
167 ++numDigits;
168 }
169
170 // we want 'qint8' to appear before 'qint16'
171 if (numDigits > 0) {
172 for (int i = 0; i < 4 - numDigits; ++i)
173 nodeName.insert(nodeName.size() - numDigits - 1, QLatin1Char('0'));
174 }
175
176 if (node->isClassNode())
177 return QLatin1Char('A') + nodeName;
178
179 if (node->isFunction(Genus::CPP)) {
180 const auto *fn = static_cast<const FunctionNode *>(node);
181
182 QString sortNo;
183 if (fn->isCtor())
184 sortNo = QLatin1String("C");
185 else if (fn->isCCtor())
186 sortNo = QLatin1String("D");
187 else if (fn->isMCtor())
188 sortNo = QLatin1String("E");
189 else if (fn->isDtor())
190 sortNo = QLatin1String("F");
191 else if (nodeName.startsWith(QLatin1String("operator")) && nodeName.size() > 8
192 && !nodeName[8].isLetterOrNumber())
193 sortNo = QLatin1String("H");
194 else
195 sortNo = QLatin1String("G");
196
197 return sortNo + nodeName + QLatin1Char(' ') + QString::number(fn->overloadNumber(), 36);
198 }
199
200 if (node->isFunction(Genus::QML))
201 return QLatin1Char('E') + nodeName + QLatin1Char(' ') +
202 QString::number(static_cast<const FunctionNode*>(node)->overloadNumber(), 36);
203
204 if (node->isProperty() || node->isVariable())
205 return QLatin1Char('G') + nodeName;
206
207 return QLatin1Char('B') + nodeName;
208}
209
210/*!
211 Inserts the \a node into this section if it is appropriate
212 for this section.
213 */
214void Section::insert(Node *node)
215{
216 bool irrelevant = false;
217 bool inherited = false;
218 if (!node->isRelatedNonmember()) {
219 Aggregate *p = node->parent();
220 if (!p->isNamespace() && p != m_aggregate) {
221 if (!p->isQmlType() || !p->isAbstract())
222 inherited = true;
223 }
224 }
225
226 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
227 const NodeContext context = node->createContext();
228
229 if (!InclusionFilter::isIncluded(policy, context)) {
230 irrelevant = true;
231 } else if (node->isFunction()) {
232 auto *func = static_cast<FunctionNode *>(node);
233 irrelevant = (inherited && (func->isSomeCtor() || func->isDtor()));
234 } else if (node->isClassNode() || node->isEnumType() || node->isTypedef()
235 || node->isVariable()) {
236 irrelevant = (inherited && m_style != AllMembers);
237 if (!irrelevant && m_style == Details && node->isTypedef()) {
238 const auto *tdn = static_cast<const TypedefNode *>(node);
239 if (tdn->associatedEnum())
240 irrelevant = true;
241 }
242 }
243
244 if (!irrelevant) {
245 QString key = sortName(node);
246 if (node->isDeprecated()) {
247 m_obsoleteMembers.push_back(node);
248 } else {
249 if (!inherited || m_style == AllMembers)
250 m_members.push_back(node);
251
252 if (inherited && (node->parent()->isClassNode() || node->parent()->isNamespace())) {
253 if (m_inheritedMembers.isEmpty()
254 || m_inheritedMembers.last().first != node->parent()) {
255 std::pair<Aggregate *, int> p(node->parent(), 0);
256 m_inheritedMembers.append(p);
257 }
258 m_inheritedMembers.last().second++;
259 }
260 }
261 }
262}
263
264/*!
265 Returns \c true if the \a node is a reimplemented member
266 function of the current class. If true, the \a node is
267 inserted into the reimplemented member map. True
268 is returned only if \a node is inserted into the map.
269 That is, false is returned if the \a node is already in
270 the map.
271 */
273{
274 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
275 const NodeContext context = node->createContext();
276
277 // Use specialized visibility check for reimplemented members
279 const auto *fn = static_cast<const FunctionNode *>(node);
280 if (!fn->overridesThis().isEmpty()) {
281 if (fn->parent() == m_aggregate) {
282 QString key = sortName(fn);
283 if (!m_reimplementedMemberMap.contains(key)) {
284 m_reimplementedMemberMap.insert(key, node);
285 return true;
286 }
287 }
288 }
289 }
290 return false;
291}
292
293/*!
294 If this section is not empty, convert its maps to sequential
295 structures for better traversal during doc generation.
296 */
298{
299 // TODO:TEMPORARY:INTERMEDIATE: Section uses a series of maps
300 // to internally manage the categorization of the various members
301 // of an aggregate. It further uses a secondary "flattened"
302 // (usually vector) version that is later used by consumers of a
303 // Section content.
304 //
305 // One of the uses of those maps is that of ordering, by using
306 // keys generated with `sortName`.
307 // Nonetheless, this is the only usage that comes from the keys,
308 // as they are neither necessary nor used outside of the internal
309 // code for Section.
310 //
311 // Hence, the codebase is moving towards removing the maps in
312 // favor of building a flattened, consumer ready, version of the
313 // categorization directly, cutting the intermediate conversion
314 // step.
315 //
316 // To do so while keeping as much of the old behavior as possible,
317 // we provide a sorting for the flattened version that is based on
318 // `sortName`, as the previous ordering was.
319 //
320 // This acts as a relatively heavy pessimization, as `sortName`,
321 // used as a comparator, can be called multiple times for each
322 // Node, while before it would have been called almost-once.
323 //
324 // Instead of fixing this issue, by for example caching the
325 // sortName of each Node instance, we temporarily keep the
326 // pessimization while the various maps are removed.
327 //
328 // When all the maps are removed, we can remove `sortName`, which
329 // produces strings to use as key requiring a few allocations and
330 // expensive operations, with an actual comparator function, which
331 // should be more lightweight and more than offset the
332 // multiple-calls.
333 static auto node_less_than = [](const Node* left, const Node* right) {
334 // For shared comment nodes, compare the names of the first child
335 // nodes instead of the names of the nodes themselves, which are
336 // usually empty.
338 left = static_cast<const SharedCommentNode *>(left)->collective().first();
340 right = static_cast<const SharedCommentNode *>(right)->collective().first();
341 return sortName(left) < sortName(right);
342 };
343
344 std::stable_sort(m_members.begin(), m_members.end(), node_less_than);
345 std::stable_sort(m_obsoleteMembers.begin(), m_obsoleteMembers.end(), node_less_than);
346
347 m_reimplementedMembers = m_reimplementedMemberMap.values().toVector();
348
349 for (auto &cn : m_classNodesList) {
350 std::stable_sort(cn.second.begin(), cn.second.end(), node_less_than);
351 }
352}
353
354/*!
355 \class Sections
356 \brief A class for creating vectors of collections for documentation
357
358 Each element in a vector is an instance of Section, which
359 contains all the elements that will be documented in one
360 section of a reference documentation page.
361 */
362
363/*!
364 This constructor builds the vectors of sections based on the
365 type of the \a aggregate node.
366 */
367Sections::Sections(Aggregate *aggregate) : m_aggregate(aggregate)
368{
369 initAggregate(s_allMembers, m_aggregate);
370 switch (m_aggregate->nodeType()) {
371 case NodeType::Class:
372 case NodeType::Struct:
373 case NodeType::Union:
374 initAggregate(s_stdCppClassSummarySections, m_aggregate);
375 initAggregate(s_stdCppClassDetailsSections, m_aggregate);
377 break;
380 initAggregate(s_stdQmlTypeSummarySections, m_aggregate);
381 initAggregate(s_stdQmlTypeDetailsSections, m_aggregate);
383 break;
386 case NodeType::Proxy:
387 default:
388 initAggregate(s_stdSummarySections, m_aggregate);
389 initAggregate(s_stdDetailsSections, m_aggregate);
391 break;
392 }
393}
394
395/*!
396 This constructor builds a vector of sections from the \e since
397 node map, \a nsmap
398 */
399Sections::Sections(const NodeMultiMap &nsmap) : m_aggregate(nullptr)
400{
401 if (nsmap.isEmpty())
402 return;
403 SectionVector &sections = sinceSections();
404 for (auto it = nsmap.constBegin(); it != nsmap.constEnd(); ++it) {
405 Node *node = it.value();
406 switch (node->nodeType()) {
407 case NodeType::QmlType:
408 sections[SinceQmlTypes].appendMember(node);
409 break;
410 case NodeType::Namespace:
411 sections[SinceNamespaces].appendMember(node);
412 break;
413 case NodeType::Class:
414 case NodeType::Struct:
415 case NodeType::Union:
416 sections[SinceClasses].appendMember(node);
417 break;
418 case NodeType::Enum: {
419 // The map can contain an enum node with \since, or an enum node
420 // with \value containing a since-clause. In the latter case,
421 // key() is an empty string.
422 if (!it.key().isEmpty())
423 sections[SinceEnumTypes].appendMember(node);
424 else
425 sections[SinceEnumValues].appendMember(node);
426 break;
427 }
428 case NodeType::Typedef:
429 case NodeType::TypeAlias:
430 sections[SinceTypeAliases].appendMember(node);
431 break;
432 case NodeType::Function: {
433 const auto *fn = static_cast<const FunctionNode *>(node);
434 switch (fn->metaness()) {
435 case FunctionNode::QmlSignal:
436 sections[SinceQmlSignals].appendMember(node);
437 break;
438 case FunctionNode::QmlSignalHandler:
439 sections[SinceQmlSignalHandlers].appendMember(node);
440 break;
441 case FunctionNode::QmlMethod:
442 sections[SinceQmlMethods].appendMember(node);
443 break;
444 default:
445 if (fn->isMacro())
446 sections[SinceMacros].appendMember(node);
447 else {
448 Node *p = fn->parent();
449 if (p) {
450 if (p->isClassNode())
451 sections[SinceMemberFunctions].appendMember(node);
452 else if (p->isNamespace()) {
453 if (p->name().isEmpty())
454 sections[SinceGlobalFunctions].appendMember(node);
455 else
456 sections[SinceNamespaceFunctions].appendMember(node);
457 } else
458 sections[SinceGlobalFunctions].appendMember(node);
459 } else
460 sections[SinceGlobalFunctions].appendMember(node);
461 }
462 break;
463 }
464 break;
465 }
466 case NodeType::Property:
467 sections[SinceProperties].appendMember(node);
468 break;
469 case NodeType::SharedComment:
470 if (node->isPropertyGroup())
471 sections[SinceQmlProperties].appendMember(node);
472 break;
473 case NodeType::Variable:
474 sections[SinceVariables].appendMember(node);
475 break;
476 case NodeType::QmlProperty:
477 sections[SinceQmlProperties].appendMember(node);
478 break;
479 case NodeType::QmlEnum:
480 sections[SinceQmlEnumTypes].appendMember(node);
481 break;
482 default:
483 break;
484 }
485 }
486}
487
488/*!
489 The behavior of the destructor depends on the type of the
490 Aggregate node that was passed to the constructor. If the
491 constructor was passed a multimap, the destruction is a
492 bit different because there was no Aggregate node.
493 */
495{
496 if (m_aggregate) {
497 switch (m_aggregate->nodeType()) {
498 case NodeType::Class:
499 case NodeType::Struct:
500 case NodeType::Union:
504 break;
510 break;
511 default:
515 break;
516 }
517 m_aggregate = nullptr;
518 } else {
520 }
521}
522
523/*!
524 Initialize the Aggregate in each Section of vector \a v with \a aggregate.
525 */
526void Sections::initAggregate(SectionVector &v, Aggregate *aggregate)
527{
528 for (Section &section : v)
529 section.setAggregate(aggregate);
530}
531
532/*!
533 Reset each Section in vector \a v to its initialized state.
534 */
535void Sections::clear(QList<Section> &v)
536{
537 for (Section &section : v)
538 section.clear();
539}
540
541/*!
542 Linearize the maps in each Section in \a v.
543 */
544void Sections::reduce(QList<Section> &v)
545{
546 for (Section &section : v)
547 section.reduce();
548}
549
550/*!
551 \internal
552
553 Returns the node to test when distributing \a node based on
554 Node::nodeType().
555
556 It returns either \a node itself, or if \a node is a shared comment
557 node, the first node in its collective.
558*/
560{
561 if (node && node->isSharedCommentNode() && node->hasDoc()) {
562 if (auto *scn = static_cast<SharedCommentNode *>(node); scn->collective().size())
563 return scn->collective().first(); // TODO: warn about mixed node types in collective?
564 }
565 return node;
566}
567
568/*!
569 This is a private helper function for buildStdRefPageSections().
570 */
571void Sections::stdRefPageSwitch(SectionVector &v, Node *n)
572{
574 switch (t->nodeType()) {
575 case NodeType::Namespace:
576 v[StdNamespaces].insert(n);
577 return;
578 case NodeType::Class:
579 case NodeType::Struct:
580 case NodeType::Union:
581 v[StdClasses].insert(n);
582 return;
583 case NodeType::Enum:
584 case NodeType::Typedef:
585 case NodeType::TypeAlias:
586 v[StdTypes].insert(n);
587 return;
588 case NodeType::Function: {
589 auto *func = static_cast<FunctionNode *>(t);
590 if (func->isMacro())
591 v[StdMacros].insert(n);
592 else
593 v[StdFunctions].insert(n);
594 }
595 return;
596 case NodeType::Variable: {
597 const auto *var = static_cast<const VariableNode *>(t);
598 if (!var->doc().isEmpty()) {
599 if (var->isStatic())
600 v[StdStaticVariables].insert(n);
601 else
602 v[StdVariables].insert(n);
603 }
604 }
605 return;
606 default:
607 return;
608 }
609}
610
611/*!
612 Build the section vectors for a standard reference page,
613 when the aggregate node is not a C++ class or a QML type.
614
615 If this is for a namespace page then if the namespace node
616 itself does not have documentation, only its children that
617 have documentation should be documented. In other words,
618 there are cases where a namespace is declared but does not
619 have documentation, but some of the elements declared in
620 that namespace do have documentation.
621
622 This special processing of namespaces that do not have a
623 documentation comment is meant to allow documenting its
624 members that do have documentation while avoiding posting
625 error messages for its members that are not documented.
626 */
628{
629 const NamespaceNode *ns = nullptr;
630 bool documentAll = true; // document all the children
631 if (m_aggregate->isNamespace()) {
632 ns = static_cast<const NamespaceNode *>(m_aggregate);
633 if (!ns->hasDoc())
634 documentAll = false; // only document children that have documentation
635 }
636 for (auto it = m_aggregate->constBegin(); it != m_aggregate->constEnd(); ++it) {
637 Node *n = *it;
638 if (documentAll || n->hasDoc()) {
639 stdRefPageSwitch(stdSummarySections(), n);
641 stdRefPageSwitch(stdDetailsSections(), n);
642 }
643 }
644 if (!m_aggregate->relatedByProxy().isEmpty()) {
645 const QList<Node *> &relatedBy = m_aggregate->relatedByProxy();
646 for (const auto &node : relatedBy)
647 stdRefPageSwitch(stdSummarySections(), node);
648 }
649 /*
650 If we are building the sections for the reference page
651 for a namespace node, include all the namespace node's
652 included children in the sections.
653 */
654 if (ns && !ns->includedChildren().isEmpty()) {
655 const QList<Node *> &children = ns->includedChildren();
656 for (const auto &child : children) {
657 if (documentAll || child->hasDoc())
658 stdRefPageSwitch(stdSummarySections(), child);
659 }
660 }
664}
665
666/*!
667 Inserts the node \a n in one of the entries in the vector \a v
668 depending on the node's type, access attribute, and a few other
669 attributes if the node is a signal, slot, or function.
670 */
671void Sections::distributeNodeInSummaryVector(SectionVector &sv, Node *n)
672{
674 return;
675 if (n->isFunction()) {
676 auto *fn = static_cast<FunctionNode *>(n);
677 if (fn->isRelatedNonmember()) {
678 if (fn->isMacro())
679 sv[Macros].insert(n);
680 else
681 sv[RelatedNonmembers].insert(n);
682 return;
683 }
684 if (fn->isIgnored())
685 return;
686 if (fn->isSlot()) {
687 if (fn->isPublic())
688 sv[PublicSlots].insert(fn);
689 else if (fn->isPrivate())
690 sv[PrivateSlots].insert(fn);
691 else
692 sv[ProtectedSlots].insert(fn);
693 } else if (fn->isSignal()) {
694 if (fn->isPublic())
695 sv[Signals].insert(fn);
696 } else if (fn->isPublic()) {
697 if (fn->isStatic())
698 sv[StaticPublicMembers].insert(fn);
699 else if (!sv[PublicFunctions].insertReimplementedMember(fn))
700 sv[PublicFunctions].insert(fn);
701 } else if (fn->isPrivate()) {
702 if (fn->isStatic())
703 sv[StaticPrivateMembers].insert(fn);
704 else if (!sv[PrivateFunctions].insertReimplementedMember(fn))
705 sv[PrivateFunctions].insert(fn);
706 } else { // protected
707 if (fn->isStatic())
708 sv[StaticProtectedMembers].insert(fn);
709 else if (!sv[ProtectedFunctions].insertReimplementedMember(fn))
710 sv[ProtectedFunctions].insert(fn);
711 }
712 return;
713 }
715 sv[RelatedNonmembers].insert(n);
716 return;
717 }
718 if (n->isVariable()) {
719 if (n->isStatic()) {
720 if (n->isPublic())
721 sv[StaticPublicMembers].insert(n);
722 else if (n->isPrivate())
723 sv[StaticPrivateMembers].insert(n);
724 else
725 sv[StaticProtectedMembers].insert(n);
726 } else {
727 if (n->isPublic())
728 sv[PublicVariables].insert(n);
729 else if (n->isProtected())
730 sv[ProtectedVariables].insert(n);
731 else if (n->isPrivate())
732 sv[PrivateVariables].insert(n);
733 }
734 return;
735 }
736 /*
737 Getting this far means the node is either a property
738 or some kind of type, like an enum or a typedef.
739 */
740 if (n->isTypedef() && (n->name() == QLatin1String("QtGadgetHelper")))
741 return;
742 if (n->isProperty())
743 sv[Properties].insert(n);
744 else if (n->isPublic() && n->isInAPI())
745 sv[PublicTypes].insert(n);
746 else if (n->isPrivate())
747 sv[PrivateTypes].insert(n);
748 else if (n->isProtected())
749 sv[ProtectedTypes].insert(n);
750}
751
752/*!
753 Inserts the node \a n in one of the entries in the vector \a v
754 depending on the node's type, access attribute, and a few other
755 attributes if the node is a signal, slot, or function.
756 */
757void Sections::distributeNodeInDetailsVector(SectionVector &dv, Node *n)
758{
760 return;
761
763 if (t->isFunction()) {
764 auto *fn = static_cast<FunctionNode *>(t);
765 if (fn->isRelatedNonmember()) {
766 if (fn->isMacro())
767 dv[DetailsMacros].insert(n);
768 else
769 dv[DetailsRelatedNonmembers].insert(n);
770 return;
771 }
772 if (fn->isIgnored())
773 return;
774 if (!fn->hasAssociatedProperties() || !fn->doc().isEmpty())
775 dv[DetailsMemberFunctions].insert(n);
776 return;
777 }
779 dv[DetailsRelatedNonmembers].insert(n);
780 return;
781 }
782 if (t->isEnumType(Genus::CPP) || t->isTypedef()) {
783 if (t->name() != QLatin1String("QtGadgetHelper"))
784 dv[DetailsMemberTypes].insert(n);
785 return;
786 }
787 if (t->isProperty())
788 dv[DetailsProperties].insert(n);
789 else if (t->isVariable() && !t->doc().isEmpty())
790 dv[DetailsMemberVariables].insert(n);
791}
792
793void Sections::distributeQmlNodeInDetailsVector(SectionVector &dv, Node *n)
794{
796 return;
797
799 if (t != n && n->isPropertyGroup()) {
800 dv[QmlProperties].insert(n);
801 return;
802 }
803
804 if (t->isQmlProperty()) {
805 auto *pn = static_cast<QmlPropertyNode *>(t);
806 if (pn->isAttached())
807 dv[QmlAttachedProperties].insert(n);
808 else
809 dv[QmlProperties].insert(n);
810 } else if (t->isEnumType(Genus::QML)) {
811 dv[QmlEnumTypes].insert(n);
812 } else if (t->isFunction()) {
813 auto *fn = static_cast<FunctionNode *>(t);
814 if (fn->isQmlSignal()) {
815 if (fn->isAttached())
816 dv[QmlAttachedSignals].insert(n);
817 else
818 dv[QmlSignals].insert(n);
819 } else if (fn->isQmlSignalHandler()) {
820 dv[QmlSignalHandlers].insert(n);
821 } else if (fn->isQmlMethod()) {
822 if (fn->isAttached())
823 dv[QmlAttachedMethods].insert(n);
824 else
825 dv[QmlMethods].insert(n);
826 }
827 }
828}
829
830/*!
831 Distributes a node \a n into the correct place in the summary section vector \a sv.
832 Nodes that are sharing a comment are handled recursively - for recursion, the \a
833 sharing parameter is set to \c true.
834 */
835void Sections::distributeQmlNodeInSummaryVector(SectionVector &sv, Node *n, bool sharing)
836{
837 if (n->isSharingComment() && !sharing)
838 return;
839 if (n->isQmlProperty()) {
840 auto *pn = static_cast<QmlPropertyNode *>(n);
841 if (pn->isAttached())
842 sv[QmlAttachedProperties].insert(pn);
843 else
844 sv[QmlProperties].insert(pn);
845 } else if (n->isEnumType(Genus::QML)) {
846 sv[QmlEnumTypes].insert(n);
847 } else if (n->isFunction()) {
848 auto *fn = static_cast<FunctionNode *>(n);
849 if (fn->isQmlSignal()) {
850 if (fn->isAttached())
851 sv[QmlAttachedSignals].insert(fn);
852 else
853 sv[QmlSignals].insert(fn);
854 } else if (fn->isQmlSignalHandler()) {
855 sv[QmlSignalHandlers].insert(fn);
856 } else if (fn->isQmlMethod()) {
857 if (fn->isAttached())
858 sv[QmlAttachedMethods].insert(fn);
859 else
860 sv[QmlMethods].insert(fn);
861 }
862 } else if (n->isSharedCommentNode()) {
863 auto *scn = static_cast<SharedCommentNode *>(n);
864 if (scn->isPropertyGroup()) {
865 sv[QmlProperties].insert(scn);
866 } else {
867 for (const auto &child : scn->collective())
868 distributeQmlNodeInSummaryVector(sv, child, true);
869 }
870 }
871}
872
873static void pushBaseClasses(QStack<ClassNode *> &stack, ClassNode *cn)
874{
875 const QList<RelatedClass> baseClasses = cn->baseClasses();
876 for (const auto &cls : baseClasses) {
877 if (cls.m_node)
878 stack.prepend(cls.m_node);
879 }
880}
881
882/*!
883 Build the section vectors for a standard reference page,
884 when the aggregate node is a C++.
885 */
887{
890 Section &allMembers = allMembersSection();
891
892 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
893
894 for (auto it = m_aggregate->constBegin(); it != m_aggregate->constEnd(); ++it) {
895 Node *n = *it;
896 const NodeContext context = n->createContext();
899 allMembers.insert(n);
900 }
901 distributeNodeInSummaryVector(summarySections, n);
902 distributeNodeInDetailsVector(detailsSections, n);
903 }
904 if (!m_aggregate->relatedByProxy().isEmpty()) {
905 const QList<Node *> relatedBy = m_aggregate->relatedByProxy();
906 for (const auto &node : relatedBy)
907 distributeNodeInSummaryVector(summarySections, node);
908 }
909
910 QStack<ClassNode *> stack;
911 QSet<ClassNode *> visited;
912 auto *cn = static_cast<ClassNode *>(m_aggregate);
913
914 pushBaseClasses(stack, cn);
915 while (!stack.isEmpty()) {
916 ClassNode *cur = stack.pop();
917 if (visited.contains(cur))
918 continue;
919 visited.insert(cur);
920 for (Node *n : cur->childNodes()) {
921 const NodeContext context = n->createContext();
922 if (InclusionFilter::isIncluded(policy, context) && !n->isProperty()
923 && !n->isRelatedNonmember() && !n->isSharedCommentNode()) {
924 allMembers.insert(n);
925 }
926 }
927 pushBaseClasses(stack, cur);
928 }
929 reduce(summarySections);
930 reduce(detailsSections);
931 allMembers.reduce();
932}
933
934/*!
935 Build the section vectors for a standard reference page,
936 when the aggregate node is a QML type.
937 */
939{
940 ClassNodes *classNodes = nullptr;
943 Section &allMembers = allMembersSection();
944
945 const Aggregate *qtn = m_aggregate;
946 while (qtn) {
947 if (!qtn->isAbstract() || !classNodes)
948 classNodes = &allMembers.classNodesList().emplace_back(static_cast<const QmlTypeNode*>(qtn), NodeVector{});
949 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
950 for (const auto n : qtn->childNodes()) {
951 const NodeContext context = n->createContext();
952 if (!InclusionFilter::isIncluded(policy, context))
953 continue;
954
955 // Skip overridden property/function documentation from abstract base type
956 if (qtn != m_aggregate && qtn->isAbstract()) {
957 NodeList candidates;
958 m_aggregate->findChildren(n->name(), candidates);
959 if (std::any_of(candidates.cbegin(), candidates.cend(), [&n](const Node *c) {
960 if (c->nodeType() == n->nodeType()) {
961 if (!n->isFunction() ||
962 compare(static_cast<const FunctionNode *>(n),
963 static_cast<const FunctionNode *>(c)) == 0)
964 return true;
965 }
966 return false;
967 })) {
968 continue;
969 }
970 }
971
972 if (!n->isSharedCommentNode() || n->isPropertyGroup()) {
973 allMembers.insert(n);
974 classNodes->second.push_back(n);
975 }
976
977
978 if (qtn == m_aggregate || qtn->isAbstract()) {
979 distributeQmlNodeInSummaryVector(summarySections, n);
980 distributeQmlNodeInDetailsVector(detailsSections, n);
981 }
982 }
983 if (qtn->qmlBaseNode() == qtn) {
984 qCDebug(lcQdoc, "error: circular type definition: '%s' inherits itself",
985 qPrintable(qtn->name()));
986 break;
987 }
988 qtn = qtn->qmlBaseNode();
989 }
990
991 reduce(summarySections);
992 reduce(detailsSections);
993 allMembers.reduce();
994}
995
996/*!
997 Returns true if any sections in this object contain obsolete
998 members. If it returns false, then \a summary_spv and \a details_spv
999 have not been modified. Otherwise, both vectors will contain pointers
1000 to the sections that contain obsolete members.
1001 */
1003 SectionPtrVector *details_spv) const
1004{
1005 const SectionVector *sections = nullptr;
1006 if (m_aggregate->isClassNode())
1007 sections = &stdCppClassSummarySections();
1008 else if (m_aggregate->isQmlType())
1009 sections = &stdQmlTypeSummarySections();
1010 else
1011 sections = &stdSummarySections();
1012 for (const auto &section : *sections) {
1013 if (!section.obsoleteMembers().isEmpty())
1014 summary_spv->append(&section);
1015 }
1016 if (m_aggregate->isClassNode())
1017 sections = &stdCppClassDetailsSections();
1018 else if (m_aggregate->isQmlType())
1019 sections = &stdQmlTypeDetailsSections();
1020 else
1021 sections = &stdDetailsSections();
1022 for (const auto &it : *sections) {
1023 if (!it.obsoleteMembers().isEmpty())
1024 details_spv->append(&it);
1025 }
1026 return !summary_spv->isEmpty();
1027}
1028
1029QT_END_NAMESPACE
virtual QmlTypeNode * qmlBaseNode() const
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
Definition aggregate.h:55
NodeList & relatedByProxy()
Returns a reference to a list of node pointers where each element points to a node in an index file f...
Definition aggregate.h:71
The ClassNode represents a C++ class.
Definition classnode.h:23
This node is used to represent any kind of function being documented.
bool isQmlMethod() const
bool isDtor() const
bool isSignal() const
bool isQmlSignal() const
bool isIgnored() const
In some cases, it is ok for a public function to be not documented.
bool isCCtor() const
bool isMCtor() const
bool isCtor() const
bool isQmlSignalHandler() const
bool isSomeCtor() const
bool isSlot() const
static bool isReimplementedMemberVisible(const InclusionPolicy &policy, const NodeContext &context)
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
This class represents a C++ namespace.
const NodeList & includedChildren() const
Returns a const reference to the namespace node's list of included children, which contains pointers ...
A class for containing the elements of one documentation section.
Definition sections.h:17
void clear()
A Section is now an element in a static vector, so we don't have to repeatedly construct and destroy ...
Definition sections.cpp:144
void insert(Node *node)
Inserts the node into this section if it is appropriate for this section.
Definition sections.cpp:214
void reduce()
If this section is not empty, convert its maps to sequential structures for better traversal during d...
Definition sections.cpp:297
ClassNodesList & classNodesList()
Definition sections.h:55
@ Summary
Definition sections.h:19
@ Details
Definition sections.h:19
@ AllMembers
Definition sections.h:19
bool insertReimplementedMember(Node *node)
Returns true if the node is a reimplemented member function of the current class.
Definition sections.cpp:272
~Section()
The destructor must delete the members of collections when the members are allocated on the heap.
Definition sections.cpp:133
A class for creating vectors of collections for documentation.
Definition sections.h:82
const SectionVector & stdCppClassDetailsSections() const
Definition sections.h:171
void buildStdCppClassRefPageSections()
Build the section vectors for a standard reference page, when the aggregate node is a C++.
Definition sections.cpp:886
Sections(Aggregate *aggregate)
This constructor builds the vectors of sections based on the type of the aggregate node.
Definition sections.cpp:367
SectionVector & stdCppClassSummarySections()
Definition sections.h:160
SectionVector & stdQmlTypeSummarySections()
Definition sections.h:162
~Sections()
The behavior of the destructor depends on the type of the Aggregate node that was passed to the const...
Definition sections.cpp:494
SectionVector & stdDetailsSections()
Definition sections.h:159
const SectionVector & stdQmlTypeDetailsSections() const
Definition sections.h:179
const SectionVector & stdCppClassSummarySections() const
Definition sections.h:167
const SectionVector & stdQmlTypeSummarySections() const
Definition sections.h:175
void buildStdRefPageSections()
Build the section vectors for a standard reference page, when the aggregate node is not a C++ class o...
Definition sections.cpp:627
void clear(SectionVector &v)
Reset each Section in vector v to its initialized state.
Definition sections.cpp:535
SectionVector & stdCppClassDetailsSections()
Definition sections.h:161
void reduce(SectionVector &v)
Linearize the maps in each Section in v.
Definition sections.cpp:544
const SectionVector & stdDetailsSections() const
Definition sections.h:166
void buildStdQmlTypeRefPageSections()
Build the section vectors for a standard reference page, when the aggregate node is a QML type.
Definition sections.cpp:938
SectionVector & stdQmlTypeDetailsSections()
Definition sections.h:163
SectionVector & sinceSections()
Definition sections.h:157
Sections(const NodeMultiMap &nsmap)
This constructor builds a vector of sections from the since node map, nsmap.
Definition sections.cpp:399
bool hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVector *details_spv) const
Returns true if any sections in this object contain obsolete members.
SectionVector & stdSummarySections()
Definition sections.h:158
const SectionVector & stdSummarySections() const
Definition sections.h:165
static Section & allMembersSection()
Definition sections.h:156
bool isPropertyGroup() const override
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
const EnumNode * associatedEnum() const
Definition typedefnode.h:27
NodeType
Definition genustypes.h:150
Combined button and popup list for selecting options.
QList< Node * > NodeVector
Definition node.h:46
QMultiMap< QString, Node * > NodeMultiMap
Definition generator.h:35
QString sortName(const Node *node)
Construct a name for the node that can be used for sorting a set of nodes into equivalence classes.
Definition sections.cpp:159
static Node * nodeToTestForDistribution(Node *node)
Definition sections.cpp:559
static void pushBaseClasses(QStack< ClassNode * > &stack, ClassNode *cn)
Definition sections.cpp:873
std::pair< const QmlTypeNode *, NodeVector > ClassNodes
Definition sections.h:13
QList< const Section * > SectionPtrVector
Definition sections.h:79
QList< Section > SectionVector
Definition sections.h:78
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:242
virtual bool isStatic() const
Returns true if the FunctionNode represents a static function.
Definition node.h:159
bool isEnumType(Genus g) const
Definition node.h:104
bool isPrivate() const
Returns true if this node's access is Private.
Definition node.h:118
virtual bool isAbstract() const
Returns true if the ClassNode or QmlTypeNode is marked abstract.
Definition node.h:142
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:115
bool isTypedef() const
Returns true if the node type is Typedef.
Definition node.h:133
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:128
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:131
NodeType nodeType() const override
Returns this node's type.
Definition node.h:89
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:100
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:215
bool isPublic() const
Returns true if this node's access is Public.
Definition node.h:121
bool isVariable() const
Returns true if the node type is Variable.
Definition node.h:138
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
Definition node.h:141
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:107
bool isProperty() const
Returns true if the node type is Property.
Definition node.h:119
NodeContext createContext() const
Definition node.cpp:162
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
Definition node.h:158
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
Definition node.h:256
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:905
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
Definition node.h:129
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:150
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Definition node.h:127