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