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 documented 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.
337 if (left->isSharedCommentNode())
338 left = static_cast<const SharedCommentNode *>(left)->collective().first();
339 if (right->isSharedCommentNode())
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 static_cast<SharedCommentNode *>(n)->sort();
675 return;
676 }
677 if (n->isFunction()) {
678 auto *fn = static_cast<FunctionNode *>(n);
679 if (fn->isRelatedNonmember()) {
680 if (fn->isMacro())
681 sv[Macros].insert(n);
682 else
683 sv[RelatedNonmembers].insert(n);
684 return;
685 }
686 if (fn->isIgnored())
687 return;
688 if (fn->isSlot()) {
689 if (fn->isPublic())
690 sv[PublicSlots].insert(fn);
691 else if (fn->isPrivate())
692 sv[PrivateSlots].insert(fn);
693 else
694 sv[ProtectedSlots].insert(fn);
695 } else if (fn->isSignal()) {
696 if (fn->isPublic() && fn->isInAPI())
697 sv[Signals].insert(fn);
698 } else if (fn->isPublic()) {
699 if (fn->isStatic() && fn->isInAPI())
700 sv[StaticPublicMembers].insert(fn);
701 else if (!sv[PublicFunctions].insertReimplementedMember(fn) && fn->isInAPI())
702 sv[PublicFunctions].insert(fn);
703 } else if (fn->isPrivate()) {
704 if (fn->isStatic())
705 sv[StaticPrivateMembers].insert(fn);
706 else if (!sv[PrivateFunctions].insertReimplementedMember(fn))
707 sv[PrivateFunctions].insert(fn);
708 } else { // protected
709 if (fn->isStatic())
710 sv[StaticProtectedMembers].insert(fn);
711 else if (!sv[ProtectedFunctions].insertReimplementedMember(fn))
712 sv[ProtectedFunctions].insert(fn);
713 }
714 return;
715 }
717 sv[RelatedNonmembers].insert(n);
718 return;
719 }
720 if (n->isVariable()) {
721 if (n->isStatic()) {
722 if (n->isPublic())
723 sv[StaticPublicMembers].insert(n);
724 else if (n->isPrivate())
725 sv[StaticPrivateMembers].insert(n);
726 else
727 sv[StaticProtectedMembers].insert(n);
728 } else {
729 if (n->isPublic())
730 sv[PublicVariables].insert(n);
731 else if (n->isProtected())
732 sv[ProtectedVariables].insert(n);
733 else if (n->isPrivate())
734 sv[PrivateVariables].insert(n);
735 }
736 return;
737 }
738 /*
739 Getting this far means the node is either a property
740 or some kind of type, like an enum or a typedef.
741 */
742 if (n->isTypedef() && (n->name() == QLatin1String("QtGadgetHelper")))
743 return;
744 if (n->isProperty())
745 sv[Properties].insert(n);
746 else if (n->isPublic() && n->isInAPI())
747 sv[PublicTypes].insert(n);
748 else if (n->isPrivate())
749 sv[PrivateTypes].insert(n);
750 else if (n->isProtected())
751 sv[ProtectedTypes].insert(n);
752}
753
754/*!
755 Inserts the node \a n in one of the entries in the vector \a v
756 depending on the node's type, access attribute, and a few other
757 attributes if the node is a signal, slot, or function.
758 */
759void Sections::distributeNodeInDetailsVector(SectionVector &dv, Node *n)
760{
762 return;
763
765 if (t->isFunction()) {
766 auto *fn = static_cast<FunctionNode *>(t);
767 if (fn->isRelatedNonmember()) {
768 if (fn->isMacro())
769 dv[DetailsMacros].insert(n);
770 else
771 dv[DetailsRelatedNonmembers].insert(n);
772 return;
773 }
774 if (fn->isIgnored())
775 return;
776 if (!fn->hasAssociatedProperties() || !fn->doc().isEmpty())
777 dv[DetailsMemberFunctions].insert(n);
778 return;
779 }
781 dv[DetailsRelatedNonmembers].insert(n);
782 return;
783 }
784 if (t->isEnumType(Genus::CPP) || t->isTypedef()) {
785 if (t->name() != QLatin1String("QtGadgetHelper"))
786 dv[DetailsMemberTypes].insert(n);
787 return;
788 }
789 if (t->isProperty())
790 dv[DetailsProperties].insert(n);
791 else if (t->isVariable() && !t->doc().isEmpty())
792 dv[DetailsMemberVariables].insert(n);
793}
794
795void Sections::distributeQmlNodeInDetailsVector(SectionVector &dv, Node *n)
796{
798 return;
799
801 if (t != n && n->isPropertyGroup()) {
802 dv[QmlProperties].insert(n);
803 return;
804 }
805
806 if (t->isQmlProperty()) {
807 auto *pn = static_cast<QmlPropertyNode *>(t);
808 if (pn->isAttached())
809 dv[QmlAttachedProperties].insert(n);
810 else
811 dv[QmlProperties].insert(n);
812 } else if (t->isEnumType(Genus::QML)) {
813 dv[QmlEnumTypes].insert(n);
814 } else if (t->isFunction()) {
815 auto *fn = static_cast<FunctionNode *>(t);
816 if (fn->isQmlSignal()) {
817 if (fn->isAttached())
818 dv[QmlAttachedSignals].insert(n);
819 else
820 dv[QmlSignals].insert(n);
821 } else if (fn->isQmlSignalHandler()) {
822 dv[QmlSignalHandlers].insert(n);
823 } else if (fn->isQmlMethod()) {
824 if (fn->isAttached())
825 dv[QmlAttachedMethods].insert(n);
826 else
827 dv[QmlMethods].insert(n);
828 }
829 }
830}
831
832/*!
833 Distributes a node \a n into the correct place in the summary section vector \a sv.
834 Nodes that are sharing a comment are handled recursively - for recursion, the \a
835 sharing parameter is set to \c true.
836 */
837void Sections::distributeQmlNodeInSummaryVector(SectionVector &sv, Node *n, bool sharing)
838{
839 if (n->isSharingComment() && !sharing)
840 return;
841 if (n->isQmlProperty()) {
842 auto *pn = static_cast<QmlPropertyNode *>(n);
843 if (pn->isAttached())
844 sv[QmlAttachedProperties].insert(pn);
845 else
846 sv[QmlProperties].insert(pn);
847 } else if (n->isEnumType(Genus::QML)) {
848 sv[QmlEnumTypes].insert(n);
849 } else if (n->isFunction()) {
850 auto *fn = static_cast<FunctionNode *>(n);
851 if (fn->isQmlSignal()) {
852 if (fn->isAttached())
853 sv[QmlAttachedSignals].insert(fn);
854 else
855 sv[QmlSignals].insert(fn);
856 } else if (fn->isQmlSignalHandler()) {
857 sv[QmlSignalHandlers].insert(fn);
858 } else if (fn->isQmlMethod()) {
859 if (fn->isAttached())
860 sv[QmlAttachedMethods].insert(fn);
861 else
862 sv[QmlMethods].insert(fn);
863 }
864 } else if (n->isSharedCommentNode()) {
865 auto *scn = static_cast<SharedCommentNode *>(n);
866 if (scn->isPropertyGroup()) {
867 sv[QmlProperties].insert(scn);
868 } else {
869 for (const auto &child : scn->collective())
870 distributeQmlNodeInSummaryVector(sv, child, true);
871 }
872 }
873}
874
875static void pushBaseClasses(QStack<ClassNode *> &stack, ClassNode *cn)
876{
877 const QList<RelatedClass> baseClasses = cn->baseClasses();
878 for (const auto &cls : baseClasses) {
879 if (cls.m_node)
880 stack.prepend(cls.m_node);
881 }
882}
883
884/*!
885 Build the section vectors for a standard reference page,
886 when the aggregate node is a C++.
887 */
889{
892 Section &allMembers = allMembersSection();
893
894 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
895
896 for (auto it = m_aggregate->constBegin(); it != m_aggregate->constEnd(); ++it) {
897 Node *n = *it;
898 const NodeContext context = n->createContext();
901 allMembers.insert(n);
902 }
903 distributeNodeInSummaryVector(summarySections, n);
904 distributeNodeInDetailsVector(detailsSections, n);
905 }
906 if (!m_aggregate->relatedByProxy().isEmpty()) {
907 const QList<Node *> relatedBy = m_aggregate->relatedByProxy();
908 for (const auto &node : relatedBy)
909 distributeNodeInSummaryVector(summarySections, node);
910 }
911
912 QStack<ClassNode *> stack;
913 QSet<ClassNode *> visited;
914 auto *cn = static_cast<ClassNode *>(m_aggregate);
915
916 pushBaseClasses(stack, cn);
917 while (!stack.isEmpty()) {
918 ClassNode *cur = stack.pop();
919 if (visited.contains(cur))
920 continue;
921 visited.insert(cur);
922 for (Node *n : cur->childNodes()) {
923 const NodeContext context = n->createContext();
924 if (InclusionFilter::isIncluded(policy, context) && !n->isProperty()
925 && !n->isRelatedNonmember() && !n->isSharedCommentNode()) {
926 allMembers.insert(n);
927 }
928 }
929 pushBaseClasses(stack, cur);
930 }
931 reduce(summarySections);
932 reduce(detailsSections);
933 allMembers.reduce();
934}
935
936/*!
937 Build the section vectors for a standard reference page,
938 when the aggregate node is a QML type.
939 */
941{
942 ClassNodes *classNodes = nullptr;
945 Section &allMembers = allMembersSection();
946
947 const Aggregate *qtn = m_aggregate;
948 while (qtn) {
949 if (!qtn->isAbstract() || !classNodes)
950 classNodes = &allMembers.classNodesList().emplace_back(static_cast<const QmlTypeNode*>(qtn), NodeVector{});
951 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
952 for (const auto n : qtn->childNodes()) {
953 const NodeContext context = n->createContext();
954 if (!InclusionFilter::isIncluded(policy, context))
955 continue;
956
957 // Skip overridden property/function documentation from abstract base type
958 if (qtn != m_aggregate && qtn->isAbstract()) {
959 NodeList candidates;
960 m_aggregate->findChildren(n->name(), candidates);
961 if (std::any_of(candidates.cbegin(), candidates.cend(), [&n](const Node *c) {
962 if (c->nodeType() == n->nodeType()) {
963 if (!n->isFunction() ||
964 compare(static_cast<const FunctionNode *>(n),
965 static_cast<const FunctionNode *>(c)) == 0)
966 return true;
967 }
968 return false;
969 })) {
970 continue;
971 }
972 }
973
974 if (!n->isSharedCommentNode() || n->isPropertyGroup()) {
975 allMembers.insert(n);
976 classNodes->second.push_back(n);
977 }
978
979
980 if (qtn == m_aggregate || qtn->isAbstract()) {
981 distributeQmlNodeInSummaryVector(summarySections, n);
982 distributeQmlNodeInDetailsVector(detailsSections, n);
983 }
984 }
985 if (qtn->qmlBaseNode() == qtn) {
986 qCDebug(lcQdoc, "error: circular type definition: '%s' inherits itself",
987 qPrintable(qtn->name()));
988 break;
989 }
990 qtn = qtn->qmlBaseNode();
991 }
992
993 reduce(summarySections);
994 reduce(detailsSections);
995 allMembers.reduce();
996}
997
998/*!
999 Returns true if any sections in this object contain obsolete
1000 members. If it returns false, then \a summary_spv and \a details_spv
1001 have not been modified. Otherwise, both vectors will contain pointers
1002 to the sections that contain obsolete members.
1003 */
1005 SectionPtrVector *details_spv) const
1006{
1007 const SectionVector *sections = nullptr;
1008 if (m_aggregate->isClassNode())
1009 sections = &stdCppClassSummarySections();
1010 else if (m_aggregate->isQmlType())
1011 sections = &stdQmlTypeSummarySections();
1012 else
1013 sections = &stdSummarySections();
1014 for (const auto &section : *sections) {
1015 if (!section.obsoleteMembers().isEmpty())
1016 summary_spv->append(&section);
1017 }
1018 if (m_aggregate->isClassNode())
1019 sections = &stdCppClassDetailsSections();
1020 else if (m_aggregate->isQmlType())
1021 sections = &stdQmlTypeDetailsSections();
1022 else
1023 sections = &stdDetailsSections();
1024 for (const auto &it : *sections) {
1025 if (!it.obsoleteMembers().isEmpty())
1026 details_spv->append(&it);
1027 }
1028 return !summary_spv->isEmpty();
1029}
1030
1031QT_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
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:888
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:940
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
NodeType
Definition genustypes.h:150
Combined button and popup list for selecting options.
QList< Node * > NodeVector
Definition node.h:47
QMultiMap< QString, Node * > NodeMultiMap
Definition generator.h:36
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:875
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.
virtual bool isStatic() const
Returns true if the FunctionNode represents a static function.
Definition node.h:152
bool isEnumType(Genus g) const
Definition node.h:97
virtual bool isAbstract() const
Returns true if the ClassNode or QmlTypeNode is marked abstract.
Definition node.h:135
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 isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:121
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:124
NodeType nodeType() const override
Returns this node's type.
Definition node.h:82
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:93
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:208
bool isVariable() const
Returns true if the node type is Variable.
Definition node.h:131
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
Definition node.h:134
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
virtual bool isInAPI() const
Returns true if this node is considered to be part of the API as per the InclusionPolicy retrieved fr...
Definition node.cpp:917
bool isProperty() const
Returns true if the node type is Property.
Definition node.h:112
NodeContext createContext() const
Definition node.cpp:174
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
Definition node.h:151
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
Definition node.h:246
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:932
bool isRelatedNonmember() const
Returns true if this is a related nonmember of something.
Definition node.h:122
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:143
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Definition node.h:120