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 has \c Internal or \c InternalAuto status (we check the child's
245 own 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 InternalAuto), \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()
273 && !parent->isProxyNode() && !parent->isNamespace() && !parent->isDontDocument()
274 && !parent->hasDoc()) {
275
276 if (child->isDontDocument())
277 return;
278
280 return;
281
282 auto &config = Config::instance();
283
284 if (InclusionFilter::processInternalDocs(config.createInclusionPolicy()))
285 return;
286
287 if (config.get(CONFIG_NOLINKERRORS).asBool())
288 return;
289
290 if (child->genus() == Genus::CPP && !child->declLocation().isEmpty()) {
291 if (Config::matchesInternalFilePattern(
292 child->declLocation().filePath(),
293 config.getInternalFilePatternsCompiled()))
294 return;
295 }
296
297 child->doc().location().warning(
298 "No output generated for %1 '%2' because '%3' is undocumented"_L1
299 .arg(child->nodeTypeString(),
300 child->plainFullName(),
301 child->parent()->name()));
302 }
303}
304
305/*!
306 Mark all child nodes that have no documentation as having
307 internal status. QDoc will then ignore them for documentation purposes.
308 */
310{
311 for (auto *child : std::as_const(m_children)) {
312 if (!child->hasDoc() && !child->isDontDocument()) {
313 if (!child->docMustBeGenerated()) {
314 if (child->isFunction()) {
315 if (static_cast<FunctionNode *>(child)->hasAssociatedProperties())
316 continue;
317 } else if (child->isTypedef() && child->isInAPI()) {
318 if (static_cast<TypedefNode *>(child)->hasAssociatedEnum())
319 continue;
320 }
321 child->setStatus(Status::InternalAuto);
322 }
323 } else {
324 warnAboutDocumentedChildInUndocumentedParent(this, child);
325 }
326 if (child->isAggregate()) {
327 static_cast<Aggregate *>(child)->markUndocumentedChildrenInternal();
328 }
329 }
330}
331
332/*!
333 Adopts each non-aggregate C++ node (function/macro, typedef, enum, variable,
334 or a shared comment node with genus Node::CPP) to the aggregate specified in
335 the node's documentation using the \\relates command.
336
337 If the target Aggregate is not found in the primary tree, creates a new
338 ProxyNode to use as the parent. If the target Aggregate is not found at all,
339 reports it.
340*/
342{
343 auto *database = QDocDatabase::qdocDB();
344
345 for (auto *node : m_children) {
346 if (node->genus() != Genus::CPP)
347 continue;
348
349 if (!node->isAggregate()) {
350 const auto &relates_args = node->doc().metaCommandArgs("relates"_L1);
351 if (relates_args.isEmpty())
352 continue;
353 // Hidden friends are marked as related non-members during
354 // initial parsing (they belong to their enclosing class).
355 // An explicit \relates directive should still relocate them
356 // when the function participates in a different class's
357 // protocol (e.g. qHashEquals as a QHash customization point).
358 // Skip only if already adopted by a different \relates target.
359 if (node->isRelatedNonmember() && node->parent() != this)
360 continue;
361
362 auto *aggregate = database->findRelatesNode(relates_args[0].first.split("::"_L1));
363 if (!aggregate)
364 Location().report("Failed to find \\relates target '%1' for %2"_L1
365 .arg(relates_args[0].first, node->fullName()));
366
367 if (!aggregate || aggregate->isIndexNode())
368 aggregate = new ProxyNode(this, relates_args[0].first);
369 else if (node->parent() == aggregate)
370 continue;
371
372 aggregate->adoptChild(node);
373 node->setRelatedNonmember(true);
374 } else {
375 static_cast<Aggregate*>(node)->resolveRelates();
376 }
377 }
378}
379
380/*!
381 Sorts the lists of overloads in the function map and assigns overload
382 numbers.
383
384 For sorting, active functions take precedence over internal ones, as well
385 as ones marked as \\overload - the latter ones typically do not contain
386 full documentation, so selecting them as the \e primary function
387 would cause unnecessary warnings to be generated. However, functions
388 explicitly marked with \\overload primary take precedence over other
389 overloads and will be selected as the primary function.
390
391 Otherwise, the order is set as determined by FunctionNode::compare().
392 */
394{
395 for (auto &map_it : m_functionMap) {
396 if (map_it.size() == 1) {
397 map_it.front()->setOverloadNumber(0);
398 } else if (map_it.size() > 1) {
399 // Check for multiple primary overloads before sorting
400 std::vector<const FunctionNode*> primaryOverloads;
401 for (const auto *fn : map_it) {
402 if (!fn->isPrimaryOverload())
403 continue;
404
405 // Check if we already have a primary from a different location
406 const auto *currentLocation = &(fn->doc().location());
407 for (const auto *existingPrimary : primaryOverloads) {
408 const auto *existingLocation = &(existingPrimary->doc().location());
409
410 if (*currentLocation != *existingLocation) {
411 fn->doc().location().warning(
412 "Multiple primary overloads for '%1'. The previous primary is here: %2"_L1
413 .arg(fn->name(), existingPrimary->doc().location().toString()));
414 break;
415 }
416 }
417
418 primaryOverloads.push_back(fn);
419 }
420
421 std::sort(map_it.begin(), map_it.end(),
422 [](const FunctionNode *f1, const FunctionNode *f2) -> bool {
423 if (f1->isInternal() != f2->isInternal())
424 return f2->isInternal();
425 // Prioritize functions marked with \overload primary
426 if (f1->isPrimaryOverload() != f2->isPrimaryOverload())
427 return f1->isPrimaryOverload();
428 if (f1->isOverload() != f2->isOverload())
429 return f2->isOverload();
430 // Prioritize documented over undocumented
431 if (f1->hasDoc() != f2->hasDoc())
432 return f1->hasDoc();
433 return (compare(f1, f2) < 0);
434 });
435 // Set overload numbers only if the functions are documented.
436 // They are not visible if undocumented.
437 signed short n{0};
438 for (auto *fn : map_it) {
439 if (fn->hasDoc())
440 fn->setOverloadNumber(n++);
441 }
442 }
443 }
444
445 for (auto *node : std::as_const(m_children)) {
446 if (node->isAggregate())
447 static_cast<Aggregate *>(node)->normalizeOverloads();
448 }
449}
450
451/*!
452 Returns a const reference to the list of child nodes of this
453 aggregate that are not function nodes. The list is sorted using
454 \l Node::nodeLessThan().
455
456 \warning Only call this function after the node tree is fully
457 constructed (all parsing is done).
458 */
460{
461 if (!m_nonfunctionList.isEmpty())
462 return m_nonfunctionList;
463
464 m_nonfunctionList = m_children;
465 // Erase functions
466 m_nonfunctionList.erase(
467 std::remove_if(m_nonfunctionList.begin(), m_nonfunctionList.end(),
468 [](const Node* node) {
469 return node->isFunction();
470 }),
471 m_nonfunctionList.end());
472 // Sort based on node properties
473 std::sort(m_nonfunctionList.begin(), m_nonfunctionList.end(), Node::nodeLessThan);
474 return m_nonfunctionList;
475}
476
477/*! \fn bool Aggregate::isAggregate() const
478 Returns \c true because this node is an instance of Aggregate,
479 which means it can have children.
480 */
481
482/*!
483 Finds the enum type node that has \a enumValue as one of
484 its enum values and returns a pointer to it. Returns 0 if
485 no enum type node is found that has \a enumValue as one
486 of its values.
487 */
488const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
489{
490 for (const auto *node : m_enumChildren) {
491 const auto *en = static_cast<const EnumNode *>(node);
492 if (en->hasItem(enumValue))
493 return en;
494 }
495 return nullptr;
496}
497
498/*!
499 Adds the \a child to this node's child map using \a title
500 as the key. The \a child is not added to the child list
501 again, because it is presumed to already be there. We just
502 want to be able to find the child by its \a title.
503 */
504void Aggregate::addChildByTitle(Node *child, const QString &title)
505{
506 m_nonfunctionMap.insert(title, child);
507}
508
509/*!
510 Adds the \a child to this node's child list and sets the child's
511 parent pointer to this Aggregate. It then mounts the child with
512 mountChild().
513
514 The \a child is then added to this Aggregate's searchable maps
515 and lists.
516
517 \note This function does not test the child's parent pointer
518 for null before changing it. If the child's parent pointer
519 is not null, then it is being reparented. The child becomes
520 a child of this Aggregate, but it also remains a child of
521 the Aggregate that is it's old parent. But the child will
522 only have one parent, and it will be this Aggregate. The is
523 because of the \c relates command.
524
525 \sa mountChild(), dismountChild()
526 */
528{
529 m_children.append(child);
530 child->setParent(this);
531 child->setUrl(QString());
533
534 if (child->isFunction()) {
535 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
536 } else if (!child->name().isEmpty()) {
537 m_nonfunctionMap.insert(child->name(), child);
538 if (child->isEnumType())
539 m_enumChildren.append(child);
540 }
541}
542
543/*!
544 This Aggregate becomes the adoptive parent of \a child. The
545 \a child knows this Aggregate as its parent, but its former
546 parent continues to have pointers to the child in its child
547 list and in its searchable data structures. But the child is
548 also added to the child list and searchable data structures
549 of this Aggregate.
550 */
552{
553 if (child->parent() != this) {
554 m_children.append(child);
555 child->setParent(this);
556 if (child->isFunction()) {
557 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
558 } else if (!child->name().isEmpty()) {
559 m_nonfunctionMap.insert(child->name(), child);
560 if (child->isEnumType())
561 m_enumChildren.append(child);
562 }
563 if (child->isSharedCommentNode()) {
564 auto *scn = static_cast<SharedCommentNode *>(child);
565 for (Node *n : scn->collective())
566 adoptChild(n);
567 }
568 }
569}
570
571/*!
572 If this node has a child that is a QML property named \a n and that
573 also matches \a attached, return a pointer to that child.
574 */
576{
578 for (auto *child : std::as_const(m_children)) {
579 if (child->nodeType() == goal) {
580 if (child->name() == n) {
581 if (attached == AnyProperties
582 || (child->isAttached() && attached == AttachedProperties)
583 || (!child->isAttached() && attached == UnattachedProperties))
584 return static_cast<QmlPropertyNode *>(child);
585 }
586 }
587 }
588 return nullptr;
589}
590
591/*!
592 Returns \c true if this aggregate has multiple function
593 overloads matching the name of \a fn.
594
595 \note Assumes \a fn is a member of this aggregate.
596*/
597bool Aggregate::hasOverloads(const FunctionNode *fn) const
598{
599 auto it = m_functionMap.find(fn->name());
600 return !(it == m_functionMap.end()) && (it.value().size() > 1);
601}
602
603/*
604 When deciding whether to include a function in the function
605 index, if the function is marked private, don't include it.
606 If the function is marked obsolete, don't include it. If the
607 function is marked internal, don't include it. Or if the
608 function is a destructor or any kind of constructor, don't
609 include it. Otherwise include it.
610 */
611static bool keep(FunctionNode *fn)
612{
614 return false;
615 return true;
616}
617
618/*!
619 Insert all functions declared in this aggregate into the
620 \a functionIndex. Call the function recursively for each
621 child that is an aggregate.
622
623 Only include functions that are in the public API and
624 that are not constructors or destructors.
625 */
627{
628 for (auto functions : m_functionMap) {
629 std::for_each(functions.begin(), functions.end(),
630 [&functionIndex](FunctionNode *fn) {
631 if (keep(fn))
632 functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
633 }
634 );
635 }
636
637 for (Node *node : std::as_const(m_children)) {
638 if (node->isAggregate() && !node->isPrivate() && !node->isDontDocument())
639 static_cast<Aggregate *>(node)->findAllFunctions(functionIndex);
640 }
641}
642
643/*!
644 For each child of this node, if the child is a namespace node,
645 insert the child into the \a namespaces multimap. If the child
646 is an aggregate, call this function recursively for that child.
647
648 When the function called with the root node of a tree, it finds
649 all the namespace nodes in that tree and inserts them into the
650 \a namespaces multimap.
651
652 The root node of a tree is a namespace, but it has no name, so
653 it is not inserted into the map. So, if this function is called
654 for each tree in the qdoc database, it finds all the namespace
655 nodes in the database.
656 */
658{
659 for (auto *node : std::as_const(m_children)) {
660 if (node->isAggregate() && !node->isPrivate()) {
661 if (node->isNamespace() && !node->name().isEmpty())
662 namespaces.insert(node->name(), node);
663 static_cast<Aggregate *>(node)->findAllNamespaces(namespaces);
664 }
665 }
666}
667
668/*!
669 Returns true if this aggregate contains at least one child
670 that is marked obsolete. Otherwise returns false.
671 */
673{
674 for (const auto *node : m_children)
675 if (!node->isPrivate() && node->isDeprecated()) {
676 if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef()
677 || node->isTypeAlias() || node->isVariable() || node->isQmlProperty())
678 return true;
679 }
680 return false;
681}
682
683/*!
684 Finds all the obsolete C++ classes and QML types in this
685 aggregate and all the C++ classes and QML types with obsolete
686 members, and inserts them into maps used elsewhere for
687 generating documentation.
688 */
690{
691 for (auto *node : std::as_const(m_children)) {
692 if (!node->isPrivate()) {
693 if (node->isDeprecated()) {
694 if (node->isClassNode())
695 QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node);
696 else if (node->isQmlType())
697 QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node);
698 } else if (node->isClassNode()) {
699 auto *a = static_cast<Aggregate *>(node);
700 if (a->hasObsoleteMembers())
701 QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node);
702 } else if (node->isQmlType()) {
703 auto *a = static_cast<Aggregate *>(node);
704 if (a->hasObsoleteMembers())
705 QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(),
706 node);
707 } else if (node->isAggregate()) {
708 static_cast<Aggregate *>(node)->findAllObsoleteThings();
709 }
710 }
711 }
712}
713
714/*!
715 Finds all the C++ classes, QML types, QML basic types, and examples
716 in this aggregate and inserts them into appropriate maps for later
717 use in generating documentation.
718 */
720{
721 for (auto *node : std::as_const(m_children)) {
722 if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument()
723 && node->tree()->camelCaseModuleName() != QString("QDoc")) {
724 if (node->isClassNode()) {
725 QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node);
726 } else if (node->isQmlType()) {
727 QString name = node->name().toLower();
728 QDocDatabase::qmlTypes().insert(name, node);
729 // also add to the QML basic type map
730 if (node->isQmlBasicType())
731 QDocDatabase::qmlBasicTypes().insert(name, node);
732 } else if (node->isExample()) {
733 // use the module index title as key for the example map
734 QString title = node->tree()->indexTitle();
735 if (!QDocDatabase::examples().contains(title, node))
736 QDocDatabase::examples().insert(title, node);
737 } else if (node->isAggregate()) {
738 static_cast<Aggregate *>(node)->findAllClasses();
739 }
740 }
741 }
742}
743
744/*!
745 Find all the attribution pages in this node and insert them
746 into \a attributions.
747 */
749{
750 for (auto *node : std::as_const(m_children)) {
751 if (!node->isPrivate()) {
752 if (node->isPageNode() && static_cast<PageNode*>(node)->isAttribution())
753 attributions.insert(node->tree()->indexTitle(), node);
754 else if (node->isAggregate())
755 static_cast<Aggregate *>(node)->findAllAttributions(attributions);
756 }
757 }
758}
759
760/*!
761 Finds all the nodes in this node where a \e{since} command appeared
762 in the qdoc comment and sorts them into maps according to the kind
763 of node.
764
765 This function is used for generating the "New Classes... in x.y"
766 section on the \e{What's New in Qt x.y} page.
767 */
769{
770 for (auto *node : std::as_const(m_children)) {
771 if (node->isRelatedNonmember() && node->parent() != this)
772 continue;
773 QString sinceString = node->since();
774 // Insert a new entry into each map for each new since string found.
775 if (node->isInAPI() && !sinceString.isEmpty()) {
776 // operator[] will insert a default-constructed value into the
777 // map if key is not found, which is what we want here.
778 auto &nsmap = QDocDatabase::newSinceMaps()[sinceString];
779 auto &ncmap = QDocDatabase::newClassMaps()[sinceString];
780 auto &nqcmap = QDocDatabase::newQmlTypeMaps()[sinceString];
781
782 if (node->isFunction()) {
783 // Insert functions into the general since map.
784 auto *fn = static_cast<FunctionNode *>(node);
785 if (!fn->isDeprecated() && !fn->isSomeCtor() && !fn->isDtor())
786 nsmap.insert(fn->name(), fn);
787 } else if (node->isClassNode()) {
788 // Insert classes into the since and class maps.
789 QString name = node->qualifyWithParentName();
790 nsmap.insert(name, node);
791 ncmap.insert(name, node);
792 } else if (node->isQmlType()) {
793 // Insert QML elements into the since and element maps.
794 QString name = node->qualifyWithParentName();
795 nsmap.insert(name, node);
796 nqcmap.insert(name, node);
797 } else if (node->isQmlProperty()) {
798 // Insert QML properties into the since map.
799 nsmap.insert(node->name(), node);
800 } else {
801 // Insert external documents into the general since map.
802 QString name = node->qualifyWithParentName();
803 nsmap.insert(name, node);
804 }
805 }
806 // Enum values - a special case as EnumItem is not a Node subclass
807 if (node->isInAPI() && node->isEnumType()) {
808 for (const auto &val : static_cast<EnumNode *>(node)->items()) {
809 sinceString = val.since();
810 if (sinceString.isEmpty())
811 continue;
812 // Insert to enum value map
813 QDocDatabase::newEnumValueMaps()[sinceString].insert(
814 node->name() + "::" + val.name(), node);
815 // Ugly hack: Insert into general map with an empty key -
816 // we need something in there to mark the corresponding
817 // section populated. See Sections class constructor.
818 QDocDatabase::newSinceMaps()[sinceString].replace(QString(), node);
819 }
820 }
821
822 // Recursively find child nodes with since commands.
823 if (node->isAggregate())
824 static_cast<Aggregate *>(node)->findAllSince();
825 }
826}
827
828/*!
829 Resolves the inheritance information for all QML type children
830 of this aggregate.
831*/
833{
834 NodeMap previousSearches;
835 for (auto *child : std::as_const(m_children)) {
836 if (!child->isQmlType())
837 continue;
838 static_cast<QmlTypeNode *>(child)->resolveInheritance(previousSearches);
839 }
840
841 // At this point we check for cycles in the inheritance of QML types.
842 for (auto *child : std::as_const(m_children)) {
843 if (child->isQmlType())
844 static_cast<QmlTypeNode *>(child)->checkInheritance();
845 }
846}
847
848/*!
849 Returns a word representing the kind of Aggregate this node is.
850 Currently recognizes class, struct, union, and namespace.
851 If \a cap is true, the word is capitalised.
852 */
853QString Aggregate::typeWord(bool cap) const
854{
855 if (cap) {
856 switch (nodeType()) {
857 case NodeType::Class:
858 return "Class"_L1;
859 case NodeType::Struct:
860 return "Struct"_L1;
861 case NodeType::Union:
862 return "Union"_L1;
863 case NodeType::Namespace:
864 return "Namespace"_L1;
865 default:
866 break;
867 }
868 } else {
869 switch (nodeType()) {
870 case NodeType::Class:
871 return "class"_L1;
872 case NodeType::Struct:
873 return "struct"_L1;
874 case NodeType::Union:
875 return "union"_L1;
876 case NodeType::Namespace:
877 return "namespace"_L1;
878 default:
879 break;
880 }
881 }
882 return QString();
883}
884
885/*! \fn int Aggregate::count() const
886 Returns the number of children in the child list.
887 */
888
889/*! \fn const NodeList &Aggregate::childNodes() const
890 Returns a const reference to the child list.
891 */
892
893/*! \fn NodeList::ConstIterator Aggregate::constBegin() const
894 Returns a const iterator pointing at the beginning of the child list.
895 */
896
897/*! \fn NodeList::ConstIterator Aggregate::constEnd() const
898 Returns a const iterator pointing at the end of the child list.
899 */
900
901/*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const
902 If this Aggregate is a QmlTypeNode, this function returns a pointer to
903 the QmlTypeNode that is its base type. Otherwise it returns \c nullptr.
904 A QmlTypeNode doesn't always have a base type, so even when this Aggregate
905 is aQmlTypeNode, the pointer returned can be \c nullptr.
906 */
907
908/*! \fn FunctionMap &Aggregate::functionMap()
909 Returns a reference to this Aggregate's function map, which
910 is a map of all the children of this Aggregate that are
911 FunctionNodes.
912 */
913
914/*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t)
915 Appends the list of node pointers to the list of elements that are
916 related to this Aggregate but are documented in a different module.
917
918 \sa relatedByProxy()
919 */
920
921/*! \fn NodeList &Aggregate::relatedByProxy()
922 Returns a reference to a list of node pointers where each element
923 points to a node in an index file for some other module, such that
924 whatever the node represents was documented in that other module,
925 but it is related to this Aggregate, so when the documentation for
926 this Aggregate is written, it will contain links to elements in the
927 other module.
928 */
929
930QT_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:428
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
@ InternalAuto
Definition status.h:16
@ 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:93
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:236
bool isPrivate() const
Returns true if this node's access is Private.
Definition node.h:112
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:182
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:109
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:125
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:868
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:94
virtual Status status() const
Returns the node's status value.
Definition node.h:240
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:209
bool isProxyNode() const
Returns true if the node type is Proxy.
Definition node.h:114
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:101
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
Definition node.h:230
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:942
void setParent(Aggregate *n)
Sets the node's parent pointer to n.
Definition node.h:181
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:107
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