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