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