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
165 for (auto *fn : *map_it) {
166 // Primary overload takes highest priority - return immediately
167 if (fn->isPrimaryOverload() && !fn->isInternal())
168 return fn;
169
170 // Remember first non-deprecated, non-internal as fallback
171 if (!fallback && !fn->isInternal() && !fn->isDeprecated())
172 fallback = fn;
173
174 // Remember first non-internal as last resort
175 if (!lastResort && !fn->isInternal())
176 lastResort = fn;
177 }
178
179 if (fallback)
180 return fallback;
181
182 if (lastResort)
183 return lastResort;
184
185 return nullptr;
186 }
187
188 // Try exact parameter match
189 auto match_it = std::find_if((*map_it).begin(), (*map_it).end(),
190 [&parameters](const FunctionNode *fn) {
191 if (fn->isInternal())
192 return false;
193 if (parameters.count() != fn->parameters().count())
194 return false;
195 for (int i = 0; i < parameters.count(); ++i)
196 if (parameters.at(i).type() != fn->parameters().at(i).type())
197 return false;
198 return true;
199 });
200
201 return (match_it != (*map_it).end()) ? *match_it : nullptr;
202}
203
204/*!
205 Returns the function node that is a child of this node, such
206 that the function described has the same name and signature
207 as the function described by the function node \a clone.
208
209 Returns \nullptr if no matching function was found.
210 */
212{
213 auto funcs_it = m_functionMap.find(clone->name());
214 if (funcs_it == m_functionMap.end())
215 return nullptr;
216
217 auto func_it = std::find_if((*funcs_it).begin(), (*funcs_it).end(),
218 [clone](const FunctionNode *fn) {
219 return compare(clone, fn) == 0;
220 });
221
222 return func_it != (*funcs_it).end() ? *func_it : nullptr;
223}
224
225
226/*!
227 \internal
228 Warn about documented, non-private children under undocumented parents - unless
229 the \a child is explicitly set \internal, or their parent() does not match \a
230 aggregate, indicating that \a child is a related non-member. The latter
231 condition avoids duplicate warnings as the node appears under multiple
232 aggregates.
233
234 The warning is skipped for children of proxy nodes and namespace nodes. Proxies
235 have no documentation as they're automatically generated. For namespaces, this
236 check is done separately after merging potentially multiple namespace nodes
237 referring to the same namespace; see
238 NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace().
239
240 Likewise, the warning is skipped for children of aggregates marked with the
241 \\dontdocument command.
242
243 If either \c {-no-linkerrors} or \c {-showinternal} command-line option is set,
244 these warnings are not generated. \c {-no-linkerrors} avoids false positives
245 in cases where the aggregate is documented outside the current project and was
246 not loaded from index. With \c {-showinternal} set, the warning is not required as
247 internal nodes generate output.
248*/
249static void warnAboutDocumentedChildInUndocumentedParent(const Node *aggregate, const Node *child)
250{
251 Q_ASSERT(child);
252 const auto *parent{child->parent()};
253 if (parent && parent == aggregate && !child->isPrivate() && child->status() != Node::Internal
254 && !parent->isProxyNode() && !parent->isNamespace() && !parent->isDontDocument()
255 && !parent->hasDoc()) {
256 const auto &config{Config::instance()};
257 const InclusionPolicy policy = config.createInclusionPolicy();
258 if (!config.get(CONFIG_NOLINKERRORS).asBool() && !InclusionFilter::processInternalDocs(policy))
259 child->doc().location().warning(
260 "No output generated for %1 '%2' because '%3' is undocumented"_L1
261 .arg(child->nodeTypeString(),
262 child->plainFullName(),
263 child->parent()->name()));
264 }
265}
266
267/*!
268 Mark all child nodes that have no documentation as having
269 internal status. QDoc will then ignore them for documentation purposes.
270 */
272{
273 for (auto *child : std::as_const(m_children)) {
274 if (!child->hasDoc() && !child->isDontDocument()) {
275 if (!child->docMustBeGenerated()) {
276 if (child->isFunction()) {
277 if (static_cast<FunctionNode *>(child)->hasAssociatedProperties())
278 continue;
279 } else if (child->isTypedef() && child->isInAPI()) {
280 if (static_cast<TypedefNode *>(child)->hasAssociatedEnum())
281 continue;
282 }
283 child->setStatus(Node::Internal);
284 }
285 } else {
286 warnAboutDocumentedChildInUndocumentedParent(this, child);
287 }
288 if (child->isAggregate()) {
289 static_cast<Aggregate *>(child)->markUndocumentedChildrenInternal();
290 }
291 }
292}
293
294/*!
295 Adopts each non-aggregate C++ node (function/macro, typedef, enum, variable,
296 or a shared comment node with genus Node::CPP) to the aggregate specified in
297 the node's documentation using the \\relates command.
298
299 If the target Aggregate is not found in the primary tree, creates a new
300 ProxyNode to use as the parent. If the target Aggregate is not found at all,
301 reports it.
302*/
304{
305 auto *database = QDocDatabase::qdocDB();
306
307 for (auto *node : m_children) {
308 if (node->isRelatedNonmember())
309 continue;
310 if (node->genus() != Genus::CPP)
311 continue;
312
313 if (!node->isAggregate()) {
314 const auto &relates_args = node->doc().metaCommandArgs("relates"_L1);
315 if (relates_args.isEmpty())
316 continue;
317
318 auto *aggregate = database->findRelatesNode(relates_args[0].first.split("::"_L1));
319 if (!aggregate)
320 Location().report("Failed to find \\relates target '%1' for %2"_L1
321 .arg(relates_args[0].first, node->fullName()));
322
323 if (!aggregate || aggregate->isIndexNode())
324 aggregate = new ProxyNode(this, relates_args[0].first);
325 else if (node->parent() == aggregate)
326 continue;
327
328 aggregate->adoptChild(node);
329 node->setRelatedNonmember(true);
330 } else {
331 static_cast<Aggregate*>(node)->resolveRelates();
332 }
333 }
334}
335
336/*!
337 Sorts the lists of overloads in the function map and assigns overload
338 numbers.
339
340 For sorting, active functions take precedence over internal ones, as well
341 as ones marked as \\overload - the latter ones typically do not contain
342 full documentation, so selecting them as the \e primary function
343 would cause unnecessary warnings to be generated. However, functions
344 explicitly marked with \\overload primary take precedence over other
345 overloads and will be selected as the primary function.
346
347 Otherwise, the order is set as determined by FunctionNode::compare().
348 */
350{
351 for (auto &map_it : m_functionMap) {
352 if (map_it.size() == 1) {
353 map_it.front()->setOverloadNumber(0);
354 } else if (map_it.size() > 1) {
355 // Check for multiple primary overloads before sorting
356 std::vector<const FunctionNode*> primaryOverloads;
357 for (const auto *fn : map_it) {
358 if (!fn->isPrimaryOverload())
359 continue;
360
361 // Check if we already have a primary from a different location
362 const auto *currentLocation = &(fn->doc().location());
363 for (const auto *existingPrimary : primaryOverloads) {
364 const auto *existingLocation = &(existingPrimary->doc().location());
365
366 if (*currentLocation != *existingLocation) {
367 fn->doc().location().warning(
368 "Multiple primary overloads for '%1'. The previous primary is here: %2"_L1
369 .arg(fn->name(), existingPrimary->doc().location().toString()));
370 break;
371 }
372 }
373
374 primaryOverloads.push_back(fn);
375 }
376
377 std::sort(map_it.begin(), map_it.end(),
378 [](const FunctionNode *f1, const FunctionNode *f2) -> bool {
379 if (f1->isInternal() != f2->isInternal())
380 return f2->isInternal();
381 // Prioritize functions marked with \overload primary
382 if (f1->isPrimaryOverload() != f2->isPrimaryOverload())
383 return f1->isPrimaryOverload();
384 if (f1->isOverload() != f2->isOverload())
385 return f2->isOverload();
386 // Prioritize documented over undocumented
387 if (f1->hasDoc() != f2->hasDoc())
388 return f1->hasDoc();
389 return (compare(f1, f2) < 0);
390 });
391 // Set overload numbers only if the functions are documented.
392 // They are not visible if undocumented.
393 signed short n{0};
394 for (auto *fn : map_it) {
395 if (fn->hasDoc())
396 fn->setOverloadNumber(n++);
397 }
398 }
399 }
400
401 for (auto *node : std::as_const(m_children)) {
402 if (node->isAggregate())
403 static_cast<Aggregate *>(node)->normalizeOverloads();
404 }
405}
406
407/*!
408 Returns a const reference to the list of child nodes of this
409 aggregate that are not function nodes. The list is sorted using
410 \l Node::nodeLessThan().
411
412 \warning Only call this function after the node tree is fully
413 constructed (all parsing is done).
414 */
416{
417 if (!m_nonfunctionList.isEmpty())
418 return m_nonfunctionList;
419
420 m_nonfunctionList = m_children;
421 // Erase functions
422 m_nonfunctionList.erase(
423 std::remove_if(m_nonfunctionList.begin(), m_nonfunctionList.end(),
424 [](const Node* node) {
425 return node->isFunction();
426 }),
427 m_nonfunctionList.end());
428 // Sort based on node properties
429 std::sort(m_nonfunctionList.begin(), m_nonfunctionList.end(), Node::nodeLessThan);
430 return m_nonfunctionList;
431}
432
433/*! \fn bool Aggregate::isAggregate() const
434 Returns \c true because this node is an instance of Aggregate,
435 which means it can have children.
436 */
437
438/*!
439 Finds the enum type node that has \a enumValue as one of
440 its enum values and returns a pointer to it. Returns 0 if
441 no enum type node is found that has \a enumValue as one
442 of its values.
443 */
444const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
445{
446 for (const auto *node : m_enumChildren) {
447 const auto *en = static_cast<const EnumNode *>(node);
448 if (en->hasItem(enumValue))
449 return en;
450 }
451 return nullptr;
452}
453
454/*!
455 Adds the \a child to this node's child map using \a title
456 as the key. The \a child is not added to the child list
457 again, because it is presumed to already be there. We just
458 want to be able to find the child by its \a title.
459 */
460void Aggregate::addChildByTitle(Node *child, const QString &title)
461{
462 m_nonfunctionMap.insert(title, child);
463}
464
465/*!
466 Adds the \a child to this node's child list and sets the child's
467 parent pointer to this Aggregate. It then mounts the child with
468 mountChild().
469
470 The \a child is then added to this Aggregate's searchable maps
471 and lists.
472
473 \note This function does not test the child's parent pointer
474 for null before changing it. If the child's parent pointer
475 is not null, then it is being reparented. The child becomes
476 a child of this Aggregate, but it also remains a child of
477 the Aggregate that is it's old parent. But the child will
478 only have one parent, and it will be this Aggregate. The is
479 because of the \c relates command.
480
481 \sa mountChild(), dismountChild()
482 */
484{
485 m_children.append(child);
486 child->setParent(this);
487 child->setUrl(QString());
489
490 if (child->isFunction()) {
491 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
492 } else if (!child->name().isEmpty()) {
493 m_nonfunctionMap.insert(child->name(), child);
494 if (child->isEnumType())
495 m_enumChildren.append(child);
496 }
497}
498
499/*!
500 This Aggregate becomes the adoptive parent of \a child. The
501 \a child knows this Aggregate as its parent, but its former
502 parent continues to have pointers to the child in its child
503 list and in its searchable data structures. But the child is
504 also added to the child list and searchable data structures
505 of this Aggregate.
506 */
508{
509 if (child->parent() != this) {
510 m_children.append(child);
511 child->setParent(this);
512 if (child->isFunction()) {
513 m_functionMap[child->name()].emplace_back(static_cast<FunctionNode *>(child));
514 } else if (!child->name().isEmpty()) {
515 m_nonfunctionMap.insert(child->name(), child);
516 if (child->isEnumType())
517 m_enumChildren.append(child);
518 }
519 if (child->isSharedCommentNode()) {
520 auto *scn = static_cast<SharedCommentNode *>(child);
521 for (Node *n : scn->collective())
522 adoptChild(n);
523 }
524 }
525}
526
527/*!
528 If this node has a child that is a QML property named \a n, return a
529 pointer to that child. Otherwise, return \nullptr.
530 */
531QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n) const
532{
534 for (auto *child : std::as_const(m_children)) {
535 if (child->nodeType() == goal) {
536 if (child->name() == n)
537 return static_cast<QmlPropertyNode *>(child);
538 }
539 }
540 return nullptr;
541}
542
543/*!
544 If this node has a child that is a QML property named \a n and that
545 also matches \a attached, return a pointer to that child.
546 */
547QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n, bool attached) const
548{
550 for (auto *child : std::as_const(m_children)) {
551 if (child->nodeType() == goal) {
552 if (child->name() == n && child->isAttached() == attached)
553 return static_cast<QmlPropertyNode *>(child);
554 }
555 }
556 return nullptr;
557}
558
559/*!
560 Returns \c true if this aggregate has multiple function
561 overloads matching the name of \a fn.
562
563 \note Assumes \a fn is a member of this aggregate.
564*/
565bool Aggregate::hasOverloads(const FunctionNode *fn) const
566{
567 auto it = m_functionMap.find(fn->name());
568 return !(it == m_functionMap.end()) && (it.value().size() > 1);
569}
570
571/*
572 When deciding whether to include a function in the function
573 index, if the function is marked private, don't include it.
574 If the function is marked obsolete, don't include it. If the
575 function is marked internal, don't include it. Or if the
576 function is a destructor or any kind of constructor, don't
577 include it. Otherwise include it.
578 */
579static bool keep(FunctionNode *fn)
580{
582 return false;
583 return true;
584}
585
586/*!
587 Insert all functions declared in this aggregate into the
588 \a functionIndex. Call the function recursively for each
589 child that is an aggregate.
590
591 Only include functions that are in the public API and
592 that are not constructors or destructors.
593 */
595{
596 for (auto functions : m_functionMap) {
597 std::for_each(functions.begin(), functions.end(),
598 [&functionIndex](FunctionNode *fn) {
599 if (keep(fn))
600 functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
601 }
602 );
603 }
604
605 for (Node *node : std::as_const(m_children)) {
606 if (node->isAggregate() && !node->isPrivate() && !node->isDontDocument())
607 static_cast<Aggregate *>(node)->findAllFunctions(functionIndex);
608 }
609}
610
611/*!
612 For each child of this node, if the child is a namespace node,
613 insert the child into the \a namespaces multimap. If the child
614 is an aggregate, call this function recursively for that child.
615
616 When the function called with the root node of a tree, it finds
617 all the namespace nodes in that tree and inserts them into the
618 \a namespaces multimap.
619
620 The root node of a tree is a namespace, but it has no name, so
621 it is not inserted into the map. So, if this function is called
622 for each tree in the qdoc database, it finds all the namespace
623 nodes in the database.
624 */
626{
627 for (auto *node : std::as_const(m_children)) {
628 if (node->isAggregate() && !node->isPrivate()) {
629 if (node->isNamespace() && !node->name().isEmpty())
630 namespaces.insert(node->name(), node);
631 static_cast<Aggregate *>(node)->findAllNamespaces(namespaces);
632 }
633 }
634}
635
636/*!
637 Returns true if this aggregate contains at least one child
638 that is marked obsolete. Otherwise returns false.
639 */
641{
642 for (const auto *node : m_children)
643 if (!node->isPrivate() && node->isDeprecated()) {
644 if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef()
645 || node->isTypeAlias() || node->isVariable() || node->isQmlProperty())
646 return true;
647 }
648 return false;
649}
650
651/*!
652 Finds all the obsolete C++ classes and QML types in this
653 aggregate and all the C++ classes and QML types with obsolete
654 members, and inserts them into maps used elsewhere for
655 generating documentation.
656 */
658{
659 for (auto *node : std::as_const(m_children)) {
660 if (!node->isPrivate()) {
661 if (node->isDeprecated()) {
662 if (node->isClassNode())
663 QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node);
664 else if (node->isQmlType())
665 QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node);
666 } else if (node->isClassNode()) {
667 auto *a = static_cast<Aggregate *>(node);
668 if (a->hasObsoleteMembers())
669 QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node);
670 } else if (node->isQmlType()) {
671 auto *a = static_cast<Aggregate *>(node);
672 if (a->hasObsoleteMembers())
673 QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(),
674 node);
675 } else if (node->isAggregate()) {
676 static_cast<Aggregate *>(node)->findAllObsoleteThings();
677 }
678 }
679 }
680}
681
682/*!
683 Finds all the C++ classes, QML types, QML basic types, and examples
684 in this aggregate and inserts them into appropriate maps for later
685 use in generating documentation.
686 */
688{
689 for (auto *node : std::as_const(m_children)) {
690 if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument()
691 && node->tree()->camelCaseModuleName() != QString("QDoc")) {
692 if (node->isClassNode()) {
693 QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node);
694 } else if (node->isQmlType()) {
695 QString name = node->name().toLower();
696 QDocDatabase::qmlTypes().insert(name, node);
697 // also add to the QML basic type map
698 if (node->isQmlBasicType())
699 QDocDatabase::qmlBasicTypes().insert(name, node);
700 } else if (node->isExample()) {
701 // use the module index title as key for the example map
702 QString title = node->tree()->indexTitle();
703 if (!QDocDatabase::examples().contains(title, node))
704 QDocDatabase::examples().insert(title, node);
705 } else if (node->isAggregate()) {
706 static_cast<Aggregate *>(node)->findAllClasses();
707 }
708 }
709 }
710}
711
712/*!
713 Find all the attribution pages in this node and insert them
714 into \a attributions.
715 */
717{
718 for (auto *node : std::as_const(m_children)) {
719 if (!node->isPrivate()) {
720 if (node->isPageNode() && static_cast<PageNode*>(node)->isAttribution())
721 attributions.insert(node->tree()->indexTitle(), node);
722 else if (node->isAggregate())
723 static_cast<Aggregate *>(node)->findAllAttributions(attributions);
724 }
725 }
726}
727
728/*!
729 Finds all the nodes in this node where a \e{since} command appeared
730 in the qdoc comment and sorts them into maps according to the kind
731 of node.
732
733 This function is used for generating the "New Classes... in x.y"
734 section on the \e{What's New in Qt x.y} page.
735 */
737{
738 for (auto *node : std::as_const(m_children)) {
739 if (node->isRelatedNonmember() && node->parent() != this)
740 continue;
741 QString sinceString = node->since();
742 // Insert a new entry into each map for each new since string found.
743 if (node->isInAPI() && !sinceString.isEmpty()) {
744 // operator[] will insert a default-constructed value into the
745 // map if key is not found, which is what we want here.
746 auto &nsmap = QDocDatabase::newSinceMaps()[sinceString];
747 auto &ncmap = QDocDatabase::newClassMaps()[sinceString];
748 auto &nqcmap = QDocDatabase::newQmlTypeMaps()[sinceString];
749
750 if (node->isFunction()) {
751 // Insert functions into the general since map.
752 auto *fn = static_cast<FunctionNode *>(node);
753 if (!fn->isDeprecated() && !fn->isSomeCtor() && !fn->isDtor())
754 nsmap.insert(fn->name(), fn);
755 } else if (node->isClassNode()) {
756 // Insert classes into the since and class maps.
757 QString name = node->qualifyWithParentName();
758 nsmap.insert(name, node);
759 ncmap.insert(name, node);
760 } else if (node->isQmlType()) {
761 // Insert QML elements into the since and element maps.
762 QString name = node->qualifyWithParentName();
763 nsmap.insert(name, node);
764 nqcmap.insert(name, node);
765 } else if (node->isQmlProperty()) {
766 // Insert QML properties into the since map.
767 nsmap.insert(node->name(), node);
768 } else {
769 // Insert external documents into the general since map.
770 QString name = node->qualifyWithParentName();
771 nsmap.insert(name, node);
772 }
773 }
774 // Enum values - a special case as EnumItem is not a Node subclass
775 if (node->isInAPI() && node->isEnumType()) {
776 for (const auto &val : static_cast<EnumNode *>(node)->items()) {
777 sinceString = val.since();
778 if (sinceString.isEmpty())
779 continue;
780 // Insert to enum value map
781 QDocDatabase::newEnumValueMaps()[sinceString].insert(
782 node->name() + "::" + val.name(), node);
783 // Ugly hack: Insert into general map with an empty key -
784 // we need something in there to mark the corresponding
785 // section populated. See Sections class constructor.
786 QDocDatabase::newSinceMaps()[sinceString].replace(QString(), node);
787 }
788 }
789
790 // Recursively find child nodes with since commands.
791 if (node->isAggregate())
792 static_cast<Aggregate *>(node)->findAllSince();
793 }
794}
795
796/*!
797 Resolves the inheritance information for all QML type children
798 of this aggregate.
799*/
801{
802 NodeMap previousSearches;
803 for (auto *child : std::as_const(m_children)) {
804 if (!child->isQmlType())
805 continue;
806 static_cast<QmlTypeNode *>(child)->resolveInheritance(previousSearches);
807 }
808
809 // At this point we check for cycles in the inheritance of QML types.
810 for (auto *child : std::as_const(m_children)) {
811 if (child->isQmlType())
812 static_cast<QmlTypeNode *>(child)->checkInheritance();
813 }
814}
815
816/*!
817 Returns a word representing the kind of Aggregate this node is.
818 Currently recognizes class, struct, union, and namespace.
819 If \a cap is true, the word is capitalised.
820 */
821QString Aggregate::typeWord(bool cap) const
822{
823 if (cap) {
824 switch (nodeType()) {
825 case NodeType::Class:
826 return "Class"_L1;
827 case NodeType::Struct:
828 return "Struct"_L1;
829 case NodeType::Union:
830 return "Union"_L1;
831 case NodeType::Namespace:
832 return "Namespace"_L1;
833 default:
834 break;
835 }
836 } else {
837 switch (nodeType()) {
838 case NodeType::Class:
839 return "class"_L1;
840 case NodeType::Struct:
841 return "struct"_L1;
842 case NodeType::Union:
843 return "union"_L1;
844 case NodeType::Namespace:
845 return "namespace"_L1;
846 default:
847 break;
848 }
849 }
850 return QString();
851}
852
853/*! \fn int Aggregate::count() const
854 Returns the number of children in the child list.
855 */
856
857/*! \fn const NodeList &Aggregate::childNodes() const
858 Returns a const reference to the child list.
859 */
860
861/*! \fn NodeList::ConstIterator Aggregate::constBegin() const
862 Returns a const iterator pointing at the beginning of the child list.
863 */
864
865/*! \fn NodeList::ConstIterator Aggregate::constEnd() const
866 Returns a const iterator pointing at the end of the child list.
867 */
868
869/*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const
870 If this Aggregate is a QmlTypeNode, this function returns a pointer to
871 the QmlTypeNode that is its base type. Otherwise it returns \c nullptr.
872 A QmlTypeNode doesn't always have a base type, so even when this Aggregate
873 is aQmlTypeNode, the pointer returned can be \c nullptr.
874 */
875
876/*! \fn FunctionMap &Aggregate::functionMap()
877 Returns a reference to this Aggregate's function map, which
878 is a map of all the children of this Aggregate that are
879 FunctionNodes.
880 */
881
882/*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t)
883 Appends the list of node pointers to the list of elements that are
884 related to this Aggregate but are documented in a different module.
885
886 \sa relatedByProxy()
887 */
888
889/*! \fn NodeList &Aggregate::relatedByProxy()
890 Returns a reference to a list of node pointers where each element
891 points to a node in an index file for some other module, such that
892 whatever the node represents was documented in that other module,
893 but it is related to this Aggregate, so when the documentation for
894 this Aggregate is written, it will contain links to elements in the
895 other module.
896 */
897
898QT_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.
QmlPropertyNode * hasQmlProperty(const QString &) const
If this node has a child that is a QML property named n, return a pointer to that child.
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:84
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...
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.
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...
QmlPropertyNode * hasQmlProperty(const QString &, bool attached) const
If this node has a child that is a QML property named n and that also matches attached,...
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.
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
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
#define CONFIG_NOLINKERRORS
Definition config.h:413
NodeType
Definition genustypes.h:150
QList< Node * > NodeList
Definition node.h:44
QList< Node * > NodeVector
Definition node.h:46
QMap< QString, Node * > NodeMap
Definition node.h:47
QMap< QString, NodeMap > NodeMapMap
Definition node.h:48
QMultiMap< QString, Node * > NodeMultiMap
Definition node.h:49
@ TypesOnly
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:99
bool isPrivate() const
Returns true if this node's access is Private.
Definition node.h:118
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:188
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:115
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
Definition node.h:131
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:848
NodeType nodeType() const override
Returns this node's type.
Definition node.h:89
Genus genus() const override
Returns this node's Genus.
Definition node.h:92
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:100
virtual Status status() const
Returns the node's status value.
Definition node.h:249
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:215
bool isProxyNode() const
Returns true if the node type is Proxy.
Definition node.h:120
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:107
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
Definition node.cpp:905
void setParent(Aggregate *n)
Sets the node's parent pointer to n.
Definition node.h:187
@ Internal
Definition node.h:61
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:113
static bool nodeLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
Definition node.cpp:78
A class for parsing and managing a function parameter list.
Definition main.cpp:28
bool isEmpty() const
Definition parameters.h:70
const Parameter & at(int i) const
Definition parameters.h:74
int count() const
Definition parameters.h:72