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 const reference to the list of child nodes of this
461 aggregate that are not function nodes. The list is sorted using
462 \l Node::nodeLessThan().
463
464 \warning Only call this function after the node tree is fully
465 constructed (all parsing is done).
466 */
468{
469 if (!m_nonfunctionList.isEmpty())
470 return m_nonfunctionList;
471
472 m_nonfunctionList = m_children;
473 // Erase functions
474 m_nonfunctionList.erase(
475 std::remove_if(m_nonfunctionList.begin(), m_nonfunctionList.end(),
476 [](const Node* node) {
477 return node->isFunction();
478 }),
479 m_nonfunctionList.end());
480 // Sort based on node properties
481 std::sort(m_nonfunctionList.begin(), m_nonfunctionList.end(), Node::nodeLessThan);
482 return m_nonfunctionList;
483}
484
485/*! \fn bool Aggregate::isAggregate() const
486 Returns \c true because this node is an instance of Aggregate,
487 which means it can have children.
488 */
489
490/*!
491 Finds the enum type node that has \a enumValue as one of
492 its enum values and returns a pointer to it. Returns 0 if
493 no enum type node is found that has \a enumValue as one
494 of its values.
495 */
496const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
497{
498 for (const auto *node : m_enumChildren) {
499 const auto *en = static_cast<const EnumNode *>(node);
500 if (en->hasItem(enumValue))
501 return en;
502 }
503 return nullptr;
504}
505
506/*!
507 Adds the \a child to this node's child map using \a title
508 as the key. The \a child is not added to the child list
509 again, because it is presumed to already be there. We just
510 want to be able to find the child by its \a title.
511 */
512void Aggregate::addChildByTitle(Node *child, const QString &title)
513{
514 m_nonfunctionMap.insert(title, child);
515}
516
517/*!
518 Adds the \a child to this node's child list and sets the child's
519 parent pointer to this Aggregate. It then mounts the child with
520 mountChild().
521
522 The \a child is then added to this Aggregate's searchable maps
523 and lists.
524
525 \note This function does not test the child's parent pointer
526 for null before changing it. If the child's parent pointer
527 is not null, then it is being reparented. The child becomes
528 a child of this Aggregate, but it also remains a child of
529 the Aggregate that is it's old parent. But the child will
530 only have one parent, and it will be this Aggregate. The is
531 because of the \c relates command.
532
533 \sa mountChild(), dismountChild()
534 */
536{
537 m_children.append(child);
538 child->setParent(this);
539 child->setUrl(QString());
541
542 if (child->isFunction()) {
543 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
544 } else if (!child->name().isEmpty()) {
545 m_nonfunctionMap.insert(child->name(), child);
546 if (child->isEnumType())
547 m_enumChildren.append(child);
548 }
549}
550
551/*!
552 This Aggregate becomes the adoptive parent of \a child. The
553 \a child knows this Aggregate as its parent, but its former
554 parent continues to have pointers to the child in its child
555 list and in its searchable data structures. But the child is
556 also added to the child list and searchable data structures
557 of this Aggregate.
558 */
560{
561 if (child->parent() != this) {
562 m_children.append(child);
563 child->setParent(this);
564 if (child->isFunction()) {
565 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
566 } else if (!child->name().isEmpty()) {
567 m_nonfunctionMap.insert(child->name(), child);
568 if (child->isEnumType())
569 m_enumChildren.append(child);
570 }
571 if (child->isSharedCommentNode()) {
572 auto *scn = static_cast<SharedCommentNode *>(child);
573 for (Node *n : scn->collective())
574 adoptChild(n);
575 }
576 }
577}
578
579/*!
580 If this node has a child that is a QML property named \a n and that
581 also matches \a attached, return a pointer to that child.
582 */
584{
586 for (auto *child : std::as_const(m_children)) {
587 if (child->nodeType() == goal) {
588 if (child->name() == n) {
589 if (attached == AnyProperties
590 || (child->isAttached() && attached == AttachedProperties)
591 || (!child->isAttached() && attached == UnattachedProperties))
592 return static_cast<QmlPropertyNode *>(child);
593 }
594 }
595 }
596 return nullptr;
597}
598
599/*!
600 Returns \c true if this aggregate has multiple function
601 overloads matching the name of \a fn.
602
603 \note Assumes \a fn is a member of this aggregate.
604*/
605bool Aggregate::hasOverloads(const FunctionNode *fn) const
606{
607 auto it = m_functionMap.find(fn->name());
608 return !(it == m_functionMap.end()) && (it.value().size() > 1);
609}
610
611/*
612 When deciding whether to include a function in the function
613 index, if the function is marked private, don't include it.
614 If the function is marked obsolete, don't include it. If the
615 function is marked internal, don't include it. Or if the
616 function is a destructor or any kind of constructor, don't
617 include it. Otherwise include it.
618 */
619static bool keep(FunctionNode *fn)
620{
622 return false;
623 return true;
624}
625
626/*!
627 Insert all functions declared in this aggregate into the
628 \a functionIndex. Call the function recursively for each
629 child that is an aggregate.
630
631 Only include functions that are in the public API and
632 that are not constructors or destructors.
633 */
635{
636 for (auto functions : m_functionMap) {
637 std::for_each(functions.begin(), functions.end(),
638 [&functionIndex](FunctionNode *fn) {
639 if (keep(fn))
640 functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
641 }
642 );
643 }
644
645 for (Node *node : std::as_const(m_children)) {
646 if (node->isAggregate() && !node->isPrivate() && !node->isDontDocument())
647 static_cast<Aggregate *>(node)->findAllFunctions(functionIndex);
648 }
649}
650
651/*!
652 For each child of this node, if the child is a namespace node,
653 insert the child into the \a namespaces multimap. If the child
654 is an aggregate, call this function recursively for that child.
655
656 When the function called with the root node of a tree, it finds
657 all the namespace nodes in that tree and inserts them into the
658 \a namespaces multimap.
659
660 The root node of a tree is a namespace, but it has no name, so
661 it is not inserted into the map. So, if this function is called
662 for each tree in the qdoc database, it finds all the namespace
663 nodes in the database.
664 */
666{
667 for (auto *node : std::as_const(m_children)) {
668 if (node->isAggregate() && !node->isPrivate()) {
669 if (node->isNamespace() && !node->name().isEmpty())
670 namespaces.insert(node->name(), node);
671 static_cast<Aggregate *>(node)->findAllNamespaces(namespaces);
672 }
673 }
674}
675
676/*!
677 Returns true if this aggregate contains at least one child
678 that is marked obsolete. Otherwise returns false.
679 */
681{
682 for (const auto *node : m_children)
683 if (!node->isPrivate() && node->isDeprecated()) {
684 if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef()
685 || node->isTypeAlias() || node->isVariable() || node->isQmlProperty())
686 return true;
687 }
688 return false;
689}
690
691/*!
692 Finds all the obsolete C++ classes and QML types in this
693 aggregate and all the C++ classes and QML types with obsolete
694 members, and inserts them into maps used elsewhere for
695 generating documentation.
696 */
698{
699 for (auto *node : std::as_const(m_children)) {
700 if (!node->isPrivate()) {
701 if (node->isDeprecated()) {
702 if (node->isClassNode())
703 QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node);
704 else if (node->isQmlType())
705 QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node);
706 } else if (node->isClassNode()) {
707 auto *a = static_cast<Aggregate *>(node);
708 if (a->hasObsoleteMembers())
709 QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node);
710 } else if (node->isQmlType()) {
711 auto *a = static_cast<Aggregate *>(node);
712 if (a->hasObsoleteMembers())
713 QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(),
714 node);
715 } else if (node->isAggregate()) {
716 static_cast<Aggregate *>(node)->findAllObsoleteThings();
717 }
718 }
719 }
720}
721
722/*!
723 Finds all the C++ classes, QML types, QML basic types, and examples
724 in this aggregate and inserts them into appropriate maps for later
725 use in generating documentation.
726 */
728{
729 for (auto *node : std::as_const(m_children)) {
730 if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument()
731 && node->tree()->camelCaseModuleName() != QString("QDoc")) {
732 if (node->isClassNode()) {
733 QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node);
734 } else if (node->isQmlType()) {
735 QString name = node->name().toLower();
736 QDocDatabase::qmlTypes().insert(name, node);
737 // also add to the QML basic type map
738 if (node->isQmlBasicType())
739 QDocDatabase::qmlBasicTypes().insert(name, node);
740 } else if (node->isExample()) {
741 // use the module index title as key for the example map
742 QString title = node->tree()->indexTitle();
743 if (!QDocDatabase::examples().contains(title, node))
744 QDocDatabase::examples().insert(title, node);
745 } else if (node->isAggregate()) {
746 static_cast<Aggregate *>(node)->findAllClasses();
747 }
748 }
749 }
750}
751
752/*!
753 Find all the attribution pages in this node and insert them
754 into \a attributions.
755 */
757{
758 for (auto *node : std::as_const(m_children)) {
759 if (!node->isPrivate()) {
760 if (node->isPageNode() && static_cast<PageNode*>(node)->isAttribution())
761 attributions.insert(node->tree()->indexTitle(), node);
762 else if (node->isAggregate())
763 static_cast<Aggregate *>(node)->findAllAttributions(attributions);
764 }
765 }
766}
767
768/*!
769 Finds all the nodes in this node where a \e{since} command appeared
770 in the qdoc comment and sorts them into maps according to the kind
771 of node.
772
773 This function is used for generating the "New Classes... in x.y"
774 section on the \e{What's New in Qt x.y} page.
775 */
777{
778 for (auto *node : std::as_const(m_children)) {
779 if (node->isRelatedNonmember() && node->parent() != this)
780 continue;
781 QString sinceString = node->since();
782 // Insert a new entry into each map for each new since string found.
783 if (node->isInAPI() && !sinceString.isEmpty()) {
784 // operator[] will insert a default-constructed value into the
785 // map if key is not found, which is what we want here.
786 auto &nsmap = QDocDatabase::newSinceMaps()[sinceString];
787 auto &ncmap = QDocDatabase::newClassMaps()[sinceString];
788 auto &nqcmap = QDocDatabase::newQmlTypeMaps()[sinceString];
789
790 if (node->isFunction()) {
791 // Insert functions into the general since map.
792 auto *fn = static_cast<FunctionNode *>(node);
793 if (!fn->isDeprecated() && !fn->isSomeCtor() && !fn->isDtor())
794 nsmap.insert(fn->name(), fn);
795 } else if (node->isClassNode()) {
796 // Insert classes into the since and class maps.
797 QString name = node->qualifyWithParentName();
798 nsmap.insert(name, node);
799 ncmap.insert(name, node);
800 } else if (node->isQmlType()) {
801 // Insert QML elements into the since and element maps.
802 QString name = node->qualifyWithParentName();
803 nsmap.insert(name, node);
804 nqcmap.insert(name, node);
805 } else if (node->isQmlProperty()) {
806 // Insert QML properties into the since map.
807 nsmap.insert(node->name(), node);
808 } else if (node->isConcept()) {
809 // Insert concepts with a qualified name
810 nsmap.insert(node->qualifyWithParentName(), node);
811 } else {
812 // Insert external documents into the general since map.
813 QString name = node->qualifyWithParentName();
814 nsmap.insert(name, node);
815 }
816 }
817 // Enum values - a special case as EnumItem is not a Node subclass
818 if (node->isInAPI() && node->isEnumType()) {
819 for (const auto &val : static_cast<EnumNode *>(node)->items()) {
820 sinceString = val.since();
821 if (sinceString.isEmpty())
822 continue;
823 // Insert to enum value map
824 QDocDatabase::newEnumValueMaps()[sinceString].insert(
825 node->name() + "::" + val.name(), node);
826 // Ugly hack: Insert into general map with an empty key -
827 // we need something in there to mark the corresponding
828 // section populated. See Sections class constructor.
829 QDocDatabase::newSinceMaps()[sinceString].replace(QString(), node);
830 }
831 }
832
833 // Recursively find child nodes with since commands.
834 if (node->isAggregate())
835 static_cast<Aggregate *>(node)->findAllSince();
836 }
837}
838
839/*!
840 Resolves the inheritance information for all QML type children
841 of this aggregate.
842*/
844{
845 NodeMap previousSearches;
846 for (auto *child : std::as_const(m_children)) {
847 if (!child->isQmlType())
848 continue;
849 static_cast<QmlTypeNode *>(child)->resolveInheritance(previousSearches);
850 }
851
852 // At this point we check for cycles in the inheritance of QML types.
853 for (auto *child : std::as_const(m_children)) {
854 if (child->isQmlType())
855 static_cast<QmlTypeNode *>(child)->checkInheritance();
856 }
857}
858
859/*!
860 Returns a word representing the kind of Aggregate this node is.
861 Currently recognizes class, struct, union, and namespace.
862 If \a cap is true, the word is capitalised.
863 */
864QString Aggregate::typeWord(bool cap) const
865{
866 if (cap) {
867 switch (nodeType()) {
868 case NodeType::Class:
869 return "Class"_L1;
870 case NodeType::Struct:
871 return "Struct"_L1;
872 case NodeType::Union:
873 return "Union"_L1;
874 case NodeType::Namespace:
875 return "Namespace"_L1;
876 default:
877 break;
878 }
879 } else {
880 switch (nodeType()) {
881 case NodeType::Class:
882 return "class"_L1;
883 case NodeType::Struct:
884 return "struct"_L1;
885 case NodeType::Union:
886 return "union"_L1;
887 case NodeType::Namespace:
888 return "namespace"_L1;
889 default:
890 break;
891 }
892 }
893 return QString();
894}
895
896/*! \fn int Aggregate::count() const
897 Returns the number of children in the child list.
898 */
899
900/*! \fn const NodeList &Aggregate::childNodes() const
901 Returns a const reference to the child list.
902 */
903
904/*! \fn NodeList::ConstIterator Aggregate::constBegin() const
905 Returns a const iterator pointing at the beginning of the child list.
906 */
907
908/*! \fn NodeList::ConstIterator Aggregate::constEnd() const
909 Returns a const iterator pointing at the end of the child list.
910 */
911
912/*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const
913 If this Aggregate is a QmlTypeNode, this function returns a pointer to
914 the QmlTypeNode that is its base type. Otherwise it returns \c nullptr.
915 A QmlTypeNode doesn't always have a base type, so even when this Aggregate
916 is aQmlTypeNode, the pointer returned can be \c nullptr.
917 */
918
919/*! \fn FunctionMap &Aggregate::functionMap()
920 Returns a reference to this Aggregate's function map, which
921 is a map of all the children of this Aggregate that are
922 FunctionNodes.
923 */
924
925/*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t)
926 Appends the list of node pointers to the list of elements that are
927 related to this Aggregate but are documented in a different module.
928
929 \sa relatedByProxy()
930 */
931
932/*! \fn NodeList &Aggregate::relatedByProxy()
933 Returns a reference to a list of node pointers where each element
934 points to a node in an index file for some other module, such that
935 whatever the node represents was documented in that other module,
936 but it is related to this Aggregate, so when the documentation for
937 this Aggregate is written, it will contain links to elements in the
938 other module.
939 */
940
941QT_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:154
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:871
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:945
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
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