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