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
aggregate.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 "aggregate.h"
5
6#include "config.h"
7#include "functionnode.h"
10#include "parameters.h"
11#include "typedefnode.h"
12#include "qdocdatabase.h"
14#include "qmltypenode.h"
16#include <vector>
17
18using namespace Qt::Literals::StringLiterals;
19
20QT_BEGIN_NAMESPACE
21
22/*!
23 \class Aggregate
24 */
25
26/*! \fn Aggregate::Aggregate(NodeType type, Aggregate *parent, const QString &name)
27 The constructor should never be called directly. It is only called
28 by the constructors of subclasses of Aggregate. Those constructors
29 pass the node \a type they want to create, the \a parent of the new
30 node, and its \a name.
31 */
32
33/*!
34 Recursively set all non-related members in the list of children to
35 \nullptr, after which each aggregate can safely delete all children
36 in their list. Aggregate's destructor calls this only on the root
37 namespace node.
38 */
39void Aggregate::dropNonRelatedMembers()
40{
41 for (auto &child : m_children) {
42 if (!child)
43 continue;
44 if (child->parent() != this)
45 child = nullptr;
46 else if (child->isAggregate())
47 static_cast<Aggregate*>(child)->dropNonRelatedMembers();
48 }
49}
50
51/*!
52 Destroys this Aggregate; deletes each child.
53 */
55{
56 // If this is the root, clear non-related children first
57 if (isNamespace() && name().isEmpty())
58 dropNonRelatedMembers();
59
60 m_enumChildren.clear();
61 m_nonfunctionMap.clear();
62 m_functionMap.clear();
63 qDeleteAll(m_children.begin(), m_children.end());
64 m_children.clear();
65}
66
67/*!
68 If \a genus is \c{Node::DontCare}, find the first node in
69 this node's child list that has the given \a name. If this
70 node is a QML type, be sure to also look in the children
71 of its property group nodes. Return the matching node or \c nullptr.
72
73 If \a genus is either \c{Node::CPP} or \c {Node::QML}, then
74 find all this node's children that have the given \a name,
75 and return the one that satisfies the \a genus requirement.
76 */
77Node *Aggregate::findChildNode(const QString &name, Genus genus, int findFlags) const
78{
79 if (genus == Genus::DontCare) {
80 Node *node = m_nonfunctionMap.value(name);
81 if (node)
82 return node;
83 } else {
84 const NodeList &nodes = m_nonfunctionMap.values(name);
85 for (auto *node : nodes) {
86 if (node->isInternal())
87 continue;
88 if (hasCommonGenusType(genus, node->genus())) {
89 if (findFlags & TypesOnly) {
90 if (!node->isTypedef() && !node->isClassNode()
91 && !node->isQmlType() && !node->isEnumType())
92 continue;
93 } else if (findFlags & IgnoreModules && node->isModule())
94 continue;
95 return node;
96 }
97 }
98 }
99 if (genus != Genus::DontCare && !(hasCommonGenusType(genus, this->genus())))
100 return nullptr;
101
102 if (findFlags & TypesOnly)
103 return nullptr;
104
105 auto it = m_functionMap.find(name);
106 return it != m_functionMap.end() ? (*(*it).begin()) : nullptr;
107}
108
109/*!
110 Find all the child nodes of this node that are named
111 \a name and return them in \a nodes.
112 */
113void Aggregate::findChildren(const QString &name, NodeVector &nodes) const
114{
115 nodes.clear();
116 const auto &functions = m_functionMap.value(name);
117 nodes.reserve(functions.size() + m_nonfunctionMap.count(name));
118 for (auto f : functions)
119 nodes.emplace_back(f);
120 auto [it, end] = m_nonfunctionMap.equal_range(name);
121 while (it != end) {
122 nodes.emplace_back(*it);
123 ++it;
124 }
125}
126
127/*!
128 This function searches for a child node of this Aggregate,
129 such that the child node has the spacified \a name and the
130 function \a isMatch returns true for the node. The function
131 passed must be one of the isXxx() functions in class Node
132 that tests the node type.
133 */
134Node *Aggregate::findNonfunctionChild(const QString &name, bool (Node::*isMatch)() const)
135{
136 const NodeList &nodes = m_nonfunctionMap.values(name);
137 for (auto *node : nodes) {
138 if ((node->*(isMatch))())
139 return node;
140 }
141 return nullptr;
142}
143
144/*!
145 Find a function node that is a child of this node, such that
146 the function node has the specified \a name and \a parameters.
147 If \a parameters is empty but no matching function is found
148 that has no parameters, return the first non-internal primary
149 function or overload, whether it has parameters or not.
150
151 \sa normalizeOverloads()
152 */
153FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters &parameters)
154{
155 auto map_it = m_functionMap.find(name);
156 if (map_it == m_functionMap.end())
157 return nullptr;
158
159 // If parameters is empty (e.g., from \overload command), don't try exact matching.
160 // Instead, find the best available function based on isPrimaryOverload flag.
161 if (parameters.isEmpty()) {
162 FunctionNode *fallback = nullptr;
163 FunctionNode *lastResort = nullptr;
164 FunctionNode *deletedFallback = nullptr;
165
166 for (auto *fn : *map_it) {
167 // Primary overload takes highest priority - return immediately
168 if (fn->isPrimaryOverload() && !fn->isInternal())
169 return fn;
170
171 // Remember first non-deprecated, non-internal, non-deleted as fallback.
172 // Deleted functions shouldn't be primary link targets - users linking
173 // to ClassName() want a usable constructor, not a deleted copy ctor.
174 if (!fallback && !fn->isInternal() && !fn->isDeprecated()
175 && !fn->isDeletedAsWritten())
176 fallback = fn;
177
178 // Remember first non-internal, non-deleted as last resort
179 if (!lastResort && !fn->isInternal() && !fn->isDeletedAsWritten())
180 lastResort = fn;
181
182 // Deleted functions are valid link targets when no other option exists
183 if (!deletedFallback && !fn->isInternal())
184 deletedFallback = fn;
185 }
186
187 if (fallback)
188 return fallback;
189
190 if (lastResort)
191 return lastResort;
192
193 // Fall back to deleted functions when they're the only option
194 return deletedFallback;
195 }
196
197 // Try exact parameter match
198 auto match_it = std::find_if((*map_it).begin(), (*map_it).end(),
199 [&parameters](const FunctionNode *fn) {
200 if (fn->isInternal())
201 return false;
202 if (parameters.count() != fn->parameters().count())
203 return false;
204 for (int i = 0; i < parameters.count(); ++i)
205 if (parameters.at(i).type() != fn->parameters().at(i).type())
206 return false;
207 return true;
208 });
209
210 return (match_it != (*map_it).end()) ? *match_it : nullptr;
211}
212
213/*!
214 Returns the function node that is a child of this node, such
215 that the function described has the same name and signature
216 as the function described by the function node \a clone.
217
218 Returns \nullptr if no matching function was found.
219 */
221{
222 auto funcs_it = m_functionMap.find(clone->name());
223 if (funcs_it == m_functionMap.end())
224 return nullptr;
225
226 auto func_it = std::find_if((*funcs_it).begin(), (*funcs_it).end(),
227 [clone](const FunctionNode *fn) {
228 return compare(clone, fn) == 0;
229 });
230
231 return func_it != (*funcs_it).end() ? *func_it : nullptr;
232}
233
234
235/*!
236 \internal
237 Warn about documented, non-private children under undocumented parents, unless:
238
239 \list
240 \li The \a child's parent() doesn't match \a aggregate (indicating a related
241 non-member), to avoid duplicate warnings as the node appears under multiple
242 aggregates.
243 \li The child is private (private members don't generate output).
244 \li The child is explicitly marked \c{\\internal} (we check the child's own
245 status, not inherited internal status from the parent).
246 \li The parent is a proxy node (automatically generated, no documentation).
247 \li The parent is a namespace node (handled separately by
248 NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace()).
249 \li The parent is marked with the \c{\\dontdocument} command.
250 \li The child is marked with the \c{\\dontdocument} command.
251 \li The child has auto-generated documentation. These docs are created by QDoc,
252 not written by a human, so warning about them would be confusing.
253 \li The \c{-showinternal} command-line option is set (internal nodes generate
254 output, so the warning is not needed).
255 \li The \c{-no-linkerrors} command-line option is set (avoids false positives
256 when the aggregate is documented outside the current project).
257 \li The file path of the child declaration matches \e internalfilepatterns.
258 \endlist
259
260 \note We check \c{child->status()} directly rather than \c{child->isInternal()}
261 because \c{isInternal()} also considers the parent's status. Since the parent
262 is undocumented (and thus marked Internal), \c{isInternal()} would incorrectly
263 return true for all children, suppressing the warning entirely.
264
265 \sa NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace()
266*/
267static void warnAboutDocumentedChildInUndocumentedParent(const Node *aggregate, const Node *child)
268{
269 Q_ASSERT(child);
270 const auto *parent{child->parent()};
271 if (parent && parent == aggregate && !child->isPrivate()
272 && child->status() != Status::Internal && !parent->isProxyNode()
273 && !parent->isNamespace() && !parent->isDontDocument() && !parent->hasDoc()) {
274
275 if (child->isDontDocument())
276 return;
277
279 return;
280
281 auto &config = Config::instance();
282
283 if (InclusionFilter::processInternalDocs(config.createInclusionPolicy()))
284 return;
285
286 if (config.get(CONFIG_NOLINKERRORS).asBool())
287 return;
288
289 if (child->genus() == Genus::CPP && !child->declLocation().isEmpty()) {
290 if (Config::matchesInternalFilePattern(
291 child->declLocation().filePath(),
292 config.getInternalFilePatternsCompiled()))
293 return;
294 }
295
296 child->doc().location().warning(
297 "No output generated for %1 '%2' because '%3' is undocumented"_L1
298 .arg(child->nodeTypeString(),
299 child->plainFullName(),
300 child->parent()->name()));
301 }
302}
303
304/*!
305 Mark all child nodes that have no documentation as having
306 internal status. QDoc will then ignore them for documentation purposes.
307 */
309{
310 for (auto *child : std::as_const(m_children)) {
311 if (!child->hasDoc() && !child->isDontDocument()) {
312 if (!child->docMustBeGenerated()) {
313 if (child->isFunction()) {
314 if (static_cast<FunctionNode *>(child)->hasAssociatedProperties())
315 continue;
316 } else if (child->isTypedef() && child->isInAPI()) {
317 if (static_cast<TypedefNode *>(child)->hasAssociatedEnum())
318 continue;
319 }
320 child->setStatus(Status::Internal);
321 }
322 } else {
323 warnAboutDocumentedChildInUndocumentedParent(this, child);
324 }
325 if (child->isAggregate()) {
326 static_cast<Aggregate *>(child)->markUndocumentedChildrenInternal();
327 }
328 }
329}
330
331/*!
332 Adopts each non-aggregate C++ node (function/macro, typedef, enum, variable,
333 or a shared comment node with genus Node::CPP) to the aggregate specified in
334 the node's documentation using the \\relates command.
335
336 If the target Aggregate is not found in the primary tree, creates a new
337 ProxyNode to use as the parent. If the target Aggregate is not found at all,
338 reports it.
339*/
341{
342 auto *database = QDocDatabase::qdocDB();
343
344 for (auto *node : m_children) {
345 if (node->genus() != Genus::CPP)
346 continue;
347
348 if (!node->isAggregate()) {
349 const auto &relates_args = node->doc().metaCommandArgs("relates"_L1);
350 if (relates_args.isEmpty())
351 continue;
352 // Hidden friends are marked as related non-members during
353 // initial parsing (they belong to their enclosing class).
354 // An explicit \relates directive should still relocate them
355 // when the function participates in a different class's
356 // protocol (e.g. qHashEquals as a QHash customization point).
357 // Skip only if already adopted by a different \relates target.
358 if (node->isRelatedNonmember() && node->parent() != this)
359 continue;
360
361 auto *aggregate = database->findRelatesNode(relates_args[0].first.split("::"_L1));
362 if (!aggregate)
363 Location().report("Failed to find \\relates target '%1' for %2"_L1
364 .arg(relates_args[0].first, node->fullName()));
365
366 if (!aggregate || aggregate->isIndexNode())
367 aggregate = new ProxyNode(this, relates_args[0].first);
368 else if (node->parent() == aggregate)
369 continue;
370
371 aggregate->adoptChild(node);
372 node->setRelatedNonmember(true);
373 } else {
374 static_cast<Aggregate*>(node)->resolveRelates();
375 }
376 }
377}
378
379/*!
380 Sorts the lists of overloads in the function map and assigns overload
381 numbers.
382
383 For sorting, active functions take precedence over internal ones, as well
384 as ones marked as \\overload - the latter ones typically do not contain
385 full documentation, so selecting them as the \e primary function
386 would cause unnecessary warnings to be generated. However, functions
387 explicitly marked with \\overload primary take precedence over other
388 overloads and will be selected as the primary function.
389
390 Otherwise, the order is set as determined by FunctionNode::compare().
391 */
393{
394 for (auto &map_it : m_functionMap) {
395 if (map_it.size() == 1) {
396 map_it.front()->setOverloadNumber(0);
397 } else if (map_it.size() > 1) {
398 // Check for multiple primary overloads before sorting
399 std::vector<const FunctionNode*> primaryOverloads;
400 for (const auto *fn : map_it) {
401 if (!fn->isPrimaryOverload())
402 continue;
403
404 // Check if we already have a primary from a different location
405 const auto *currentLocation = &(fn->doc().location());
406 for (const auto *existingPrimary : primaryOverloads) {
407 const auto *existingLocation = &(existingPrimary->doc().location());
408
409 if (*currentLocation != *existingLocation) {
410 fn->doc().location().warning(
411 "Multiple primary overloads for '%1'. The previous primary is here: %2"_L1
412 .arg(fn->name(), existingPrimary->doc().location().toString()));
413 break;
414 }
415 }
416
417 primaryOverloads.push_back(fn);
418 }
419
420 std::sort(map_it.begin(), map_it.end(),
421 [](const FunctionNode *f1, const FunctionNode *f2) -> bool {
422 if (f1->isInternal() != f2->isInternal())
423 return f2->isInternal();
424 // Prioritize functions marked with \overload primary
425 if (f1->isPrimaryOverload() != f2->isPrimaryOverload())
426 return f1->isPrimaryOverload();
427 if (f1->isOverload() != f2->isOverload())
428 return f2->isOverload();
429 // Prioritize documented over undocumented
430 if (f1->hasDoc() != f2->hasDoc())
431 return f1->hasDoc();
432 return (compare(f1, f2) < 0);
433 });
434 // Set overload numbers only if the functions are documented.
435 // They are not visible if undocumented.
436 signed short n{0};
437 for (auto *fn : map_it) {
438 if (fn->hasDoc())
439 fn->setOverloadNumber(n++);
440 }
441 }
442 }
443
444 for (auto *node : std::as_const(m_children)) {
445 if (node->isAggregate())
446 static_cast<Aggregate *>(node)->normalizeOverloads();
447 }
448}
449
450/*!
451 Returns a const reference to the list of child nodes of this
452 aggregate that are not function nodes. The list is sorted using
453 \l Node::nodeLessThan().
454
455 \warning Only call this function after the node tree is fully
456 constructed (all parsing is done).
457 */
459{
460 if (!m_nonfunctionList.isEmpty())
461 return m_nonfunctionList;
462
463 m_nonfunctionList = m_children;
464 // Erase functions
465 m_nonfunctionList.erase(
466 std::remove_if(m_nonfunctionList.begin(), m_nonfunctionList.end(),
467 [](const Node* node) {
468 return node->isFunction();
469 }),
470 m_nonfunctionList.end());
471 // Sort based on node properties
472 std::sort(m_nonfunctionList.begin(), m_nonfunctionList.end(), Node::nodeLessThan);
473 return m_nonfunctionList;
474}
475
476/*! \fn bool Aggregate::isAggregate() const
477 Returns \c true because this node is an instance of Aggregate,
478 which means it can have children.
479 */
480
481/*!
482 Finds the enum type node that has \a enumValue as one of
483 its enum values and returns a pointer to it. Returns 0 if
484 no enum type node is found that has \a enumValue as one
485 of its values.
486 */
487const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
488{
489 for (const auto *node : m_enumChildren) {
490 const auto *en = static_cast<const EnumNode *>(node);
491 if (en->hasItem(enumValue))
492 return en;
493 }
494 return nullptr;
495}
496
497/*!
498 Adds the \a child to this node's child map using \a title
499 as the key. The \a child is not added to the child list
500 again, because it is presumed to already be there. We just
501 want to be able to find the child by its \a title.
502 */
503void Aggregate::addChildByTitle(Node *child, const QString &title)
504{
505 m_nonfunctionMap.insert(title, child);
506}
507
508/*!
509 Adds the \a child to this node's child list and sets the child's
510 parent pointer to this Aggregate. It then mounts the child with
511 mountChild().
512
513 The \a child is then added to this Aggregate's searchable maps
514 and lists.
515
516 \note This function does not test the child's parent pointer
517 for null before changing it. If the child's parent pointer
518 is not null, then it is being reparented. The child becomes
519 a child of this Aggregate, but it also remains a child of
520 the Aggregate that is it's old parent. But the child will
521 only have one parent, and it will be this Aggregate. The is
522 because of the \c relates command.
523
524 \sa mountChild(), dismountChild()
525 */
527{
528 m_children.append(child);
529 child->setParent(this);
530 child->setUrl(QString());
532
533 if (child->isFunction()) {
534 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
535 } else if (!child->name().isEmpty()) {
536 m_nonfunctionMap.insert(child->name(), child);
537 if (child->isEnumType())
538 m_enumChildren.append(child);
539 }
540}
541
542/*!
543 This Aggregate becomes the adoptive parent of \a child. The
544 \a child knows this Aggregate as its parent, but its former
545 parent continues to have pointers to the child in its child
546 list and in its searchable data structures. But the child is
547 also added to the child list and searchable data structures
548 of this Aggregate.
549 */
551{
552 if (child->parent() != this) {
553 m_children.append(child);
554 child->setParent(this);
555 if (child->isFunction()) {
556 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
557 } else if (!child->name().isEmpty()) {
558 m_nonfunctionMap.insert(child->name(), child);
559 if (child->isEnumType())
560 m_enumChildren.append(child);
561 }
562 if (child->isSharedCommentNode()) {
563 auto *scn = static_cast<SharedCommentNode *>(child);
564 for (Node *n : scn->collective())
565 adoptChild(n);
566 }
567 }
568}
569
570/*!
571 If this node has a child that is a QML property named \a n and that
572 also matches \a attached, return a pointer to that child.
573 */
575{
577 for (auto *child : std::as_const(m_children)) {
578 if (child->nodeType() == goal) {
579 if (child->name() == n) {
580 if (attached == AnyProperties
581 || (child->isAttached() && attached == AttachedProperties)
582 || (!child->isAttached() && attached == UnattachedProperties))
583 return static_cast<QmlPropertyNode *>(child);
584 }
585 }
586 }
587 return nullptr;
588}
589
590/*!
591 Returns \c true if this aggregate has multiple function
592 overloads matching the name of \a fn.
593
594 \note Assumes \a fn is a member of this aggregate.
595*/
596bool Aggregate::hasOverloads(const FunctionNode *fn) const
597{
598 auto it = m_functionMap.find(fn->name());
599 return !(it == m_functionMap.end()) && (it.value().size() > 1);
600}
601
602/*
603 When deciding whether to include a function in the function
604 index, if the function is marked private, don't include it.
605 If the function is marked obsolete, don't include it. If the
606 function is marked internal, don't include it. Or if the
607 function is a destructor or any kind of constructor, don't
608 include it. Otherwise include it.
609 */
610static bool keep(FunctionNode *fn)
611{
613 return false;
614 return true;
615}
616
617/*!
618 Insert all functions declared in this aggregate into the
619 \a functionIndex. Call the function recursively for each
620 child that is an aggregate.
621
622 Only include functions that are in the public API and
623 that are not constructors or destructors.
624 */
626{
627 for (auto functions : m_functionMap) {
628 std::for_each(functions.begin(), functions.end(),
629 [&functionIndex](FunctionNode *fn) {
630 if (keep(fn))
631 functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
632 }
633 );
634 }
635
636 for (Node *node : std::as_const(m_children)) {
637 if (node->isAggregate() && !node->isPrivate() && !node->isDontDocument())
638 static_cast<Aggregate *>(node)->findAllFunctions(functionIndex);
639 }
640}
641
642/*!
643 For each child of this node, if the child is a namespace node,
644 insert the child into the \a namespaces multimap. If the child
645 is an aggregate, call this function recursively for that child.
646
647 When the function called with the root node of a tree, it finds
648 all the namespace nodes in that tree and inserts them into the
649 \a namespaces multimap.
650
651 The root node of a tree is a namespace, but it has no name, so
652 it is not inserted into the map. So, if this function is called
653 for each tree in the qdoc database, it finds all the namespace
654 nodes in the database.
655 */
657{
658 for (auto *node : std::as_const(m_children)) {
659 if (node->isAggregate() && !node->isPrivate()) {
660 if (node->isNamespace() && !node->name().isEmpty())
661 namespaces.insert(node->name(), node);
662 static_cast<Aggregate *>(node)->findAllNamespaces(namespaces);
663 }
664 }
665}
666
667/*!
668 Returns true if this aggregate contains at least one child
669 that is marked obsolete. Otherwise returns false.
670 */
672{
673 for (const auto *node : m_children)
674 if (!node->isPrivate() && node->isDeprecated()) {
675 if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef()
676 || node->isTypeAlias() || node->isVariable() || node->isQmlProperty())
677 return true;
678 }
679 return false;
680}
681
682/*!
683 Finds all the obsolete C++ classes and QML types in this
684 aggregate and all the C++ classes and QML types with obsolete
685 members, and inserts them into maps used elsewhere for
686 generating documentation.
687 */
689{
690 for (auto *node : std::as_const(m_children)) {
691 if (!node->isPrivate()) {
692 if (node->isDeprecated()) {
693 if (node->isClassNode())
694 QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node);
695 else if (node->isQmlType())
696 QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node);
697 } else if (node->isClassNode()) {
698 auto *a = static_cast<Aggregate *>(node);
699 if (a->hasObsoleteMembers())
700 QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node);
701 } else if (node->isQmlType()) {
702 auto *a = static_cast<Aggregate *>(node);
703 if (a->hasObsoleteMembers())
704 QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(),
705 node);
706 } else if (node->isAggregate()) {
707 static_cast<Aggregate *>(node)->findAllObsoleteThings();
708 }
709 }
710 }
711}
712
713/*!
714 Finds all the C++ classes, QML types, QML basic types, and examples
715 in this aggregate and inserts them into appropriate maps for later
716 use in generating documentation.
717 */
719{
720 for (auto *node : std::as_const(m_children)) {
721 if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument()
722 && node->tree()->camelCaseModuleName() != QString("QDoc")) {
723 if (node->isClassNode()) {
724 QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node);
725 } else if (node->isQmlType()) {
726 QString name = node->name().toLower();
727 QDocDatabase::qmlTypes().insert(name, node);
728 // also add to the QML basic type map
729 if (node->isQmlBasicType())
730 QDocDatabase::qmlBasicTypes().insert(name, node);
731 } else if (node->isExample()) {
732 // use the module index title as key for the example map
733 QString title = node->tree()->indexTitle();
734 if (!QDocDatabase::examples().contains(title, node))
735 QDocDatabase::examples().insert(title, node);
736 } else if (node->isAggregate()) {
737 static_cast<Aggregate *>(node)->findAllClasses();
738 }
739 }
740 }
741}
742
743/*!
744 Find all the attribution pages in this node and insert them
745 into \a attributions.
746 */
748{
749 for (auto *node : std::as_const(m_children)) {
750 if (!node->isPrivate()) {
751 if (node->isPageNode() && static_cast<PageNode*>(node)->isAttribution())
752 attributions.insert(node->tree()->indexTitle(), node);
753 else if (node->isAggregate())
754 static_cast<Aggregate *>(node)->findAllAttributions(attributions);
755 }
756 }
757}
758
759/*!
760 Finds all the nodes in this node where a \e{since} command appeared
761 in the qdoc comment and sorts them into maps according to the kind
762 of node.
763
764 This function is used for generating the "New Classes... in x.y"
765 section on the \e{What's New in Qt x.y} page.
766 */
768{
769 for (auto *node : std::as_const(m_children)) {
770 if (node->isRelatedNonmember() && node->parent() != this)
771 continue;
772 QString sinceString = node->since();
773 // Insert a new entry into each map for each new since string found.
774 if (node->isInAPI() && !sinceString.isEmpty()) {
775 // operator[] will insert a default-constructed value into the
776 // map if key is not found, which is what we want here.
777 auto &nsmap = QDocDatabase::newSinceMaps()[sinceString];
778 auto &ncmap = QDocDatabase::newClassMaps()[sinceString];
779 auto &nqcmap = QDocDatabase::newQmlTypeMaps()[sinceString];
780
781 if (node->isFunction()) {
782 // Insert functions into the general since map.
783 auto *fn = static_cast<FunctionNode *>(node);
784 if (!fn->isDeprecated() && !fn->isSomeCtor() && !fn->isDtor())
785 nsmap.insert(fn->name(), fn);
786 } else if (node->isClassNode()) {
787 // Insert classes into the since and class maps.
788 QString name = node->qualifyWithParentName();
789 nsmap.insert(name, node);
790 ncmap.insert(name, node);
791 } else if (node->isQmlType()) {
792 // Insert QML elements into the since and element maps.
793 QString name = node->qualifyWithParentName();
794 nsmap.insert(name, node);
795 nqcmap.insert(name, node);
796 } else if (node->isQmlProperty()) {
797 // Insert QML properties into the since map.
798 nsmap.insert(node->name(), node);
799 } else {
800 // Insert external documents into the general since map.
801 QString name = node->qualifyWithParentName();
802 nsmap.insert(name, node);
803 }
804 }
805 // Enum values - a special case as EnumItem is not a Node subclass
806 if (node->isInAPI() && node->isEnumType()) {
807 for (const auto &val : static_cast<EnumNode *>(node)->items()) {
808 sinceString = val.since();
809 if (sinceString.isEmpty())
810 continue;
811 // Insert to enum value map
812 QDocDatabase::newEnumValueMaps()[sinceString].insert(
813 node->name() + "::" + val.name(), node);
814 // Ugly hack: Insert into general map with an empty key -
815 // we need something in there to mark the corresponding
816 // section populated. See Sections class constructor.
817 QDocDatabase::newSinceMaps()[sinceString].replace(QString(), node);
818 }
819 }
820
821 // Recursively find child nodes with since commands.
822 if (node->isAggregate())
823 static_cast<Aggregate *>(node)->findAllSince();
824 }
825}
826
827/*!
828 Resolves the inheritance information for all QML type children
829 of this aggregate.
830*/
832{
833 NodeMap previousSearches;
834 for (auto *child : std::as_const(m_children)) {
835 if (!child->isQmlType())
836 continue;
837 static_cast<QmlTypeNode *>(child)->resolveInheritance(previousSearches);
838 }
839
840 // At this point we check for cycles in the inheritance of QML types.
841 for (auto *child : std::as_const(m_children)) {
842 if (child->isQmlType())
843 static_cast<QmlTypeNode *>(child)->checkInheritance();
844 }
845}
846
847/*!
848 Returns a word representing the kind of Aggregate this node is.
849 Currently recognizes class, struct, union, and namespace.
850 If \a cap is true, the word is capitalised.
851 */
852QString Aggregate::typeWord(bool cap) const
853{
854 if (cap) {
855 switch (nodeType()) {
856 case NodeType::Class:
857 return "Class"_L1;
858 case NodeType::Struct:
859 return "Struct"_L1;
860 case NodeType::Union:
861 return "Union"_L1;
862 case NodeType::Namespace:
863 return "Namespace"_L1;
864 default:
865 break;
866 }
867 } else {
868 switch (nodeType()) {
869 case NodeType::Class:
870 return "class"_L1;
871 case NodeType::Struct:
872 return "struct"_L1;
873 case NodeType::Union:
874 return "union"_L1;
875 case NodeType::Namespace:
876 return "namespace"_L1;
877 default:
878 break;
879 }
880 }
881 return QString();
882}
883
884/*! \fn int Aggregate::count() const
885 Returns the number of children in the child list.
886 */
887
888/*! \fn const NodeList &Aggregate::childNodes() const
889 Returns a const reference to the child list.
890 */
891
892/*! \fn NodeList::ConstIterator Aggregate::constBegin() const
893 Returns a const iterator pointing at the beginning of the child list.
894 */
895
896/*! \fn NodeList::ConstIterator Aggregate::constEnd() const
897 Returns a const iterator pointing at the end of the child list.
898 */
899
900/*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const
901 If this Aggregate is a QmlTypeNode, this function returns a pointer to
902 the QmlTypeNode that is its base type. Otherwise it returns \c nullptr.
903 A QmlTypeNode doesn't always have a base type, so even when this Aggregate
904 is aQmlTypeNode, the pointer returned can be \c nullptr.
905 */
906
907/*! \fn FunctionMap &Aggregate::functionMap()
908 Returns a reference to this Aggregate's function map, which
909 is a map of all the children of this Aggregate that are
910 FunctionNodes.
911 */
912
913/*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t)
914 Appends the list of node pointers to the list of elements that are
915 related to this Aggregate but are documented in a different module.
916
917 \sa relatedByProxy()
918 */
919
920/*! \fn NodeList &Aggregate::relatedByProxy()
921 Returns a reference to a list of node pointers where each element
922 points to a node in an index file for some other module, such that
923 whatever the node represents was documented in that other module,
924 but it is related to this Aggregate, so when the documentation for
925 this Aggregate is written, it will contain links to elements in the
926 other module.
927 */
928
929QT_END_NAMESPACE
static void warnAboutDocumentedChildInUndocumentedParent(const Node *aggregate, const Node *child)
static bool keep(FunctionNode *fn)
void resolveRelates()
Adopts each non-aggregate C++ node (function/macro, typedef, enum, variable, or a shared comment node...
void adoptChild(Node *child)
This Aggregate becomes the adoptive parent of child.
QString typeWord(bool cap) const
Returns a word representing the kind of Aggregate this node is.
void resolveQmlInheritance()
Resolves the inheritance information for all QML type children of this aggregate.
void addChildByTitle(Node *child, const QString &title)
Adds the child to this node's child map using title as the key.
bool hasOverloads(const FunctionNode *fn) const
Returns true if this aggregate has multiple function overloads matching the name of fn.
void findAllObsoleteThings()
Finds all the obsolete C++ classes and QML types in this aggregate and all the C++ classes and QML ty...
~Aggregate() override
Destroys this Aggregate; deletes each child.
Definition aggregate.cpp:54
void findChildren(const QString &name, NodeVector &nodes) const
Find all the child nodes of this node that are named name and return them in nodes.
bool hasObsoleteMembers() const
Returns true if this aggregate contains at least one child that is marked obsolete.
FunctionNode * findFunctionChild(const QString &name, const Parameters &parameters)
Find a function node that is a child of this node, such that the function node has the specified name...
void findAllSince()
Finds all the nodes in this node where a {since} command appeared in the qdoc comment and sorts them ...
NodeList m_children
Definition aggregate.h:90
void normalizeOverloads()
Sorts the lists of overloads in the function map and assigns overload numbers.
Node * findNonfunctionChild(const QString &name, bool(Node::*)() const)
This function searches for a child node of this Aggregate, such that the child node has the spacified...
PropertySearchType
Definition aggregate.h:25
void findAllFunctions(NodeMapMap &functionIndex)
Insert all functions declared in this aggregate into the functionIndex.
void findAllNamespaces(NodeMultiMap &namespaces)
For each child of this node, if the child is a namespace node, insert the child into the namespaces m...
void markUndocumentedChildrenInternal()
Mark all child nodes that have no documentation as having internal status.
QmlPropertyNode * hasQmlProperty(const QString &, PropertySearchType attached=AnyProperties) const
If this node has a child that is a QML property named n and that also matches attached,...
void addChild(Node *child)
Adds the child to this node's child list and sets the child's parent pointer to this Aggregate.
Node * findChildNode(const QString &name, Genus genus, int findFlags=0) const
If genus is {Node::DontCare}, find the first node in this node's child list that has the given name.
Definition aggregate.cpp:77
FunctionNode * findFunctionChild(const FunctionNode *clone)
Returns the function node that is a child of this node, such that the function described has the same...
const NodeList & nonfunctionList()
Returns a const reference to the list of child nodes of this aggregate that are not function nodes.
void findAllClasses()
Finds all the C++ classes, QML types, QML basic types, and examples in this aggregate and inserts the...
void findAllAttributions(NodeMultiMap &attributions)
Find all the attribution pages in this node and insert them into attributions.
const EnumNode * findEnumNodeForValue(const QString &enumValue) const
Finds the enum type node that has enumValue as one of its enum values and returns a pointer to it.
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:89
bool isAutoGenerated() const
Returns true if this documentation was auto-generated by QDoc rather than written by an author.
Definition doc.cpp:242
This node is used to represent any kind of function being documented.
const Parameters & parameters() const
bool isDeprecated() const override
\reimp
bool isDtor() const
friend int compare(const FunctionNode *f1, const FunctionNode *f2)
Compares FunctionNode f1 with f2, assumed to have identical names.
bool isSomeCtor() const
static bool processInternalDocs(const InclusionPolicy &policy)
bool isEmpty() const
Returns true if there is no file name set yet; returns false otherwise.
Definition location.h:45
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
Status
Specifies the status of the QQmlIncubator.
#define CONFIG_NOLINKERRORS
Definition config.h:418
NodeType
Definition genustypes.h:150
QList< Node * > NodeList
Definition node.h:45
QList< Node * > NodeVector
Definition node.h:47
QMap< QString, Node * > NodeMap
Definition node.h:48
QMap< QString, NodeMap > NodeMapMap
Definition node.h:49
QMultiMap< QString, Node * > NodeMultiMap
Definition node.h:50
@ TypesOnly
@ Internal
Definition status.h:15
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isDontDocument() const
Returns true if this node's status is DontDocument.
Definition node.h:92
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:235
bool isPrivate() const
Returns true if this node's access is Private.
Definition node.h:111
void setIndexNodeFlag(bool isIndexNode=true)
Sets a flag in this Node that indicates the node was created for something in an index file.
Definition node.h:181
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:108
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:124
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:863
NodeType nodeType() const override
Returns this node's type.
Definition node.h:82
Genus genus() const override
Returns this node's Genus.
Definition node.h:85
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:93
virtual Status status() const
Returns the node's status value.
Definition node.h:239
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:208
bool isProxyNode() const
Returns true if the node type is Proxy.
Definition node.h:113
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
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
Definition node.h:229
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:933
void setParent(Aggregate *n)
Sets the node's parent pointer to n.
Definition node.h:180
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:106
static bool nodeLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
Definition node.cpp:79
A class for parsing and managing a function parameter list.
Definition main.cpp:28
bool isEmpty() const
Definition parameters.h:32
const Parameter & at(int i) const
Definition parameters.h:36
int count() const
Definition parameters.h:34