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