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
tree.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 "tree.h"
5
6#include "classnode.h"
8#include "doc.h"
9#include "enumnode.h"
10#include "functionnode.h"
11#include "htmlgenerator.h"
12#include "location.h"
13#include "node.h"
14#include "qdocdatabase.h"
15#include "text.h"
16#include "typedefnode.h"
17
19
20/*!
21 \class Tree
22
23 This class constructs and maintains a tree of instances of
24 the subclasses of Node.
25
26 This class is now private. Only class QDocDatabase has access.
27 Please don't change this. If you must access class Tree, do it
28 though the pointer to the singleton QDocDatabase.
29
30 Tree is being converted to a forest. A static member provides a
31 map of Tree *values with the module names as the keys. There is
32 one Tree in the map for each index file read, and there is one
33 tree that is not in the map for the module whose documentation
34 is being generated.
35 */
36
37/*!
38 \class TargetRec
39 \brief A record of a linkable target within the documentation.
40*/
41
42/*!
43 \enum TargetRec::TargetType
44
45 A type of a linkable target record.
46
47 \value Unknown
48 Unknown/target not set.
49 \value Target
50 A location marked with a \\target command.
51 \value Keyword
52 A location marked with a \\keyword command.
53 \value Contents
54 A table of contents item (section title).
55 \value ContentsKeyword
56 A \\keyword tied to a section title.
57*/
58
59/*!
60 Constructs a Tree. \a qdb is the pointer to the singleton
61 qdoc database that is constructing the tree. This might not
62 be necessary, and it might be removed later.
63
64 \a camelCaseModuleName is the project name for this tree
65 as it appears in the qdocconf file.
66 */
67Tree::Tree(const QString &camelCaseModuleName, QDocDatabase *qdb)
68 : m_camelCaseModuleName(camelCaseModuleName),
69 m_physicalModuleName(camelCaseModuleName.toLower()),
70 m_qdb(qdb),
71 m_root(nullptr, QString())
72{
73 m_root.setPhysicalModuleName(m_physicalModuleName);
74 m_root.setTree(this);
75}
76
77/*!
78 Destroys the Tree.
79
80 There are two maps of targets, keywords, and contents.
81 One map is indexed by ref, the other by title. Both maps
82 use the same set of TargetRec objects as the values,
83 so we only need to delete the values from one of them.
84
85 The Node instances themselves are destroyed by the root
86 node's (\c m_root) destructor.
87 */
88Tree::~Tree()
89{
90 qDeleteAll(m_nodesByTargetRef);
91 m_nodesByTargetRef.clear();
92 m_nodesByTargetTitle.clear();
93}
94
95/* API members */
96
97/*!
98 Calls findClassNode() first with \a path and \a start. If
99 it finds a node, the node is returned. If not, it calls
100 findNamespaceNode() with the same parameters. The result
101 is returned.
102 */
103Node *Tree::findNodeForInclude(const QStringList &path) const
104{
105 Node *n = findClassNode(path);
106 if (n == nullptr)
107 n = findNamespaceNode(path);
108 return n;
109}
110
111/*!
112 This function searches this tree for an Aggregate node with
113 the specified \a name. It returns the pointer to that node
114 or nullptr.
115
116 We might need to split the name on '::' but we assume the
117 name is a single word at the moment.
118 */
119Aggregate *Tree::findAggregate(const QString &name)
120{
121 QStringList path = name.split(QLatin1String("::"));
122 return static_cast<Aggregate *>(findNodeRecursive(path, 0, const_cast<NamespaceNode *>(root()),
123 &Node::isFirstClassAggregate));
124}
125
126/*!
127 Find the C++ class node named \a path. Begin the search at the
128 \a start node. If the \a start node is 0, begin the search
129 at the root of the tree. Only a C++ class node named \a path is
130 acceptible. If one is not found, 0 is returned.
131 */
132ClassNode *Tree::findClassNode(const QStringList &path, const Node *start) const
133{
134 if (start == nullptr)
135 start = const_cast<NamespaceNode *>(root());
136 return static_cast<ClassNode *>(findNodeRecursive(path, 0, start, &Node::isClassNode));
137}
138
139/*!
140 Find the Namespace node named \a path. Begin the search at
141 the root of the tree. Only a Namespace node named \a path
142 is acceptible. If one is not found, 0 is returned.
143 */
144NamespaceNode *Tree::findNamespaceNode(const QStringList &path) const
145{
146 Node *start = const_cast<NamespaceNode *>(root());
147 return static_cast<NamespaceNode *>(findNodeRecursive(path, 0, start, &Node::isNamespace));
148}
149
150/*!
151 This function searches for the node specified by \a path.
152 The matching node can be one of several different types
153 including a C++ class, a C++ namespace, or a C++ header
154 file.
155
156 I'm not sure if it can be a QML type, but if that is a
157 possibility, the code can easily accommodate it.
158
159 If a matching node is found, a pointer to it is returned.
160 Otherwise 0 is returned.
161 */
162Aggregate *Tree::findRelatesNode(const QStringList &path)
163{
164 Node *n = findNodeRecursive(path, 0, root(), &Node::isRelatableType);
165 return (((n != nullptr) && n->isAggregate()) ? static_cast<Aggregate *>(n) : nullptr);
166}
167
168/*!
169 Inserts function name \a funcName and function role \a funcRole into
170 the property function map for the specified \a property.
171 */
172void Tree::addPropertyFunction(PropertyNode *property, const QString &funcName,
173 PropertyNode::FunctionRole funcRole)
174{
175 m_unresolvedPropertyMap[property].insert(funcRole, funcName);
176}
177
178/*!
179 This function resolves C++ inheritance and reimplementation
180 settings for each C++ class node found in the tree beginning
181 at \a n. It also calls itself recursively for each C++ class
182 node or namespace node it encounters.
183
184 This function does not resolve QML inheritance.
185 */
186void Tree::resolveBaseClasses(Aggregate *n)
187{
188 for (auto it = n->constBegin(); it != n->constEnd(); ++it) {
189 if ((*it)->isClassNode()) {
190 auto *cn = static_cast<ClassNode *>(*it);
191 QList<RelatedClass> &bases = cn->baseClasses();
192 for (auto &base : bases) {
193 if (base.m_node == nullptr) {
194 Node *n = m_qdb->findClassNode(base.m_path);
195 /*
196 If the node for the base class was not found,
197 the reason might be that the subclass is in a
198 namespace and the base class is in the same
199 namespace, but the base class name was not
200 qualified with the namespace name. That is the
201 case most of the time. Then restart the search
202 at the parent of the subclass node (the namespace
203 node) using the unqualified base class name.
204 */
205 if (n == nullptr) {
206 Aggregate *parent = cn->parent();
207 if (parent != nullptr)
208 // Exclude the root namespace
209 if (parent->isNamespace() && !parent->name().isEmpty())
210 n = findClassNode(base.m_path, parent);
211 }
212 if (n != nullptr) {
213 auto *bcn = static_cast<ClassNode *>(n);
214 base.m_node = bcn;
215 bcn->addDerivedClass(base.m_access, cn);
216 }
217 }
218 }
219 resolveBaseClasses(cn);
220 } else if ((*it)->isNamespace()) {
221 resolveBaseClasses(static_cast<NamespaceNode *>(*it));
222 }
223 }
224}
225
226/*!
227 */
228void Tree::resolvePropertyOverriddenFromPtrs(Aggregate *n)
229{
230 for (auto node = n->constBegin(); node != n->constEnd(); ++node) {
231 if ((*node)->isClassNode()) {
232 auto *cn = static_cast<ClassNode *>(*node);
233 for (auto property = cn->constBegin(); property != cn->constEnd(); ++property) {
234 if ((*property)->isProperty())
235 cn->resolvePropertyOverriddenFromPtrs(static_cast<PropertyNode *>(*property));
236 }
237 resolvePropertyOverriddenFromPtrs(cn);
238 } else if ((*node)->isNamespace()) {
239 resolvePropertyOverriddenFromPtrs(static_cast<NamespaceNode *>(*node));
240 }
241 }
242}
243
244/*!
245 Resolves access functions associated with each PropertyNode stored
246 in \c m_unresolvedPropertyMap, and adds them into the property node.
247 This allows the property node to list the access functions when
248 generating their documentation.
249 */
250void Tree::resolveProperties()
251{
252 for (auto propEntry = m_unresolvedPropertyMap.constBegin();
253 propEntry != m_unresolvedPropertyMap.constEnd(); ++propEntry) {
254 PropertyNode *property = propEntry.key();
255 Aggregate *parent = property->parent();
256 QString getterName = (*propEntry)[PropertyNode::FunctionRole::Getter];
257 QString setterName = (*propEntry)[PropertyNode::FunctionRole::Setter];
258 QString resetterName = (*propEntry)[PropertyNode::FunctionRole::Resetter];
259 QString notifierName = (*propEntry)[PropertyNode::FunctionRole::Notifier];
260 QString bindableName = (*propEntry)[PropertyNode::FunctionRole::Bindable];
261
262 for (auto it = parent->constBegin(); it != parent->constEnd(); ++it) {
263 if ((*it)->isFunction()) {
264 auto *function = static_cast<FunctionNode *>(*it);
265 if (function->access() == property->access()
266 && (function->status() == property->status() || function->doc().isEmpty())) {
267 if (function->name() == getterName) {
269 } else if (function->name() == setterName) {
271 } else if (function->name() == resetterName) {
273 } else if (function->name() == notifierName) {
275 } else if (function->name() == bindableName) {
277 }
278 }
279 }
280 }
281 }
282
283 for (auto propEntry = m_unresolvedPropertyMap.constBegin();
284 propEntry != m_unresolvedPropertyMap.constEnd(); ++propEntry) {
285 PropertyNode *property = propEntry.key();
286 // redo it to set the property functions
287 if (property->overriddenFrom())
289 }
290
291 m_unresolvedPropertyMap.clear();
292}
293
294/*!
295 For each QML class node that points to a C++ class node,
296 follow its C++ class node pointer and set the C++ class
297 node's QML class node pointer back to the QML class node.
298 */
299void Tree::resolveCppToQmlLinks()
300{
301
302 const NodeList &children = m_root.childNodes();
303 for (auto *child : children) {
304 if (child->isQmlType()) {
305 auto *qcn = static_cast<QmlTypeNode *>(child);
306 auto *cn = const_cast<ClassNode *>(qcn->classNode());
307 if (cn)
308 cn->insertQmlNativeType(qcn);
309 }
310 }
311}
312
313/*!
314 For each \a aggregate, recursively set the \\since version based on
315 \\since information from the associated physical or logical module.
316 That is, C++ and QML types inherit the \\since of their module,
317 unless that command is explicitly used in the type documentation.
318
319 In addition, resolve the since information for individual enum
320 values.
321*/
322void Tree::resolveSince(Aggregate &aggregate)
323{
324 for (auto *child : aggregate.childNodes()) {
325 // Order matters; resolve since-clauses in enum values
326 // first as EnumNode is not an Aggregate
327 if (child->isEnumType())
328 resolveEnumValueSince(static_cast<EnumNode&>(*child));
329 if (!child->isAggregate())
330 continue;
331 if (!child->since().isEmpty())
332 continue;
333
334 if (const auto collectionNode = m_qdb->getModuleNode(child))
335 child->setSince(collectionNode->since());
336
337 resolveSince(static_cast<Aggregate&>(*child));
338 }
339}
340
341/*!
342 Resolve since information for values of enum node \a en.
343
344 Enum values are not derived from Node, but they can have
345 'since' information associated with them. Since-strings
346 for each enum item are initially stored in the Doc
347 instance of EnumNode as SinceTag atoms; parse the doc
348 and store them into each EnumItem.
349*/
350void Tree::resolveEnumValueSince(EnumNode &en)
351{
352 const QStringList enumItems{en.doc().enumItemNames()};
353 const Atom *atom = en.doc().body().firstAtom();
354 if (!atom)
355 return;
356 while ((atom = atom->find(Atom::ListTagLeft))) {
357 if (atom = atom->next(); !atom)
358 break;
359 if (auto val = atom->string(); enumItems.contains(val)) {
360 if (atom = atom->next(); atom && atom->next(Atom::SinceTagLeft))
361 en.setSince(val, atom->next()->next()->string());
362 }
363 }
364}
365
366/*!
367 Traverse this Tree and for each ClassNode found, remove
368 from its list of base classes any that are marked private
369 or internal. When a class is removed from a base class
370 list, promote its public pase classes to be base classes
371 of the class where the base class was removed. This is
372 done for documentation purposes. The function is recursive
373 on namespace nodes.
374 */
375void Tree::removePrivateAndInternalBases(NamespaceNode *rootNode)
376{
377 if (rootNode == nullptr)
378 rootNode = root();
379
380 for (auto node = rootNode->constBegin(); node != rootNode->constEnd(); ++node) {
381 if ((*node)->isClassNode())
382 static_cast<ClassNode *>(*node)->removePrivateAndInternalBases();
383 else if ((*node)->isNamespace())
384 removePrivateAndInternalBases(static_cast<NamespaceNode *>(*node));
385 }
386}
387
388/*!
389 */
390ClassList Tree::allBaseClasses(const ClassNode *classNode) const
391{
392 ClassList result;
393 const auto &baseClasses = classNode->baseClasses();
394 for (const auto &relatedClass : baseClasses) {
395 if (relatedClass.m_node != nullptr) {
396 result += relatedClass.m_node;
397 result += allBaseClasses(relatedClass.m_node);
398 }
399 }
400 return result;
401}
402
403/*!
404 Find the node with the specified \a path name that is of
405 the specified \a type and \a subtype. Begin the search at
406 the \a start node. If the \a start node is 0, begin the
407 search at the tree root. \a subtype is not used unless
408 \a type is \c{Page}.
409 */
410Node *Tree::findNodeByNameAndType(const QStringList &path, bool (Node::*isMatch)() const) const
411{
412 return findNodeRecursive(path, 0, root(), isMatch);
413}
414
415/*!
416 Recursive search for a node identified by \a path. Each
417 path element is a name. \a pathIndex specifies the index
418 of the name in \a path to try to match. \a start is the
419 node whose children shoulod be searched for one that has
420 that name. Each time a match is found, increment the
421 \a pathIndex and call this function recursively.
422
423 If the end of the path is reached (i.e. if a matching
424 node is found for each name in the \a path), the \a type
425 must match the type of the last matching node, and if the
426 type is \e{Page}, the \a subtype must match as well.
427
428 If the algorithm is successful, the pointer to the final
429 node is returned. Otherwise 0 is returned.
430 */
431Node *Tree::findNodeRecursive(const QStringList &path, int pathIndex, const Node *start,
432 bool (Node::*isMatch)() const) const
433{
434 if (start == nullptr || path.isEmpty())
435 return nullptr;
436 Node *node = const_cast<Node *>(start);
437 if (!node->isAggregate())
438 return ((pathIndex >= path.size()) ? node : nullptr);
439 auto *current = static_cast<Aggregate *>(node);
440 const NodeList &children = current->childNodes();
441 const QString &name = path.at(pathIndex);
442 for (auto *node : children) {
443 if (node == nullptr)
444 continue;
445 if (node->name() == name) {
446 if (pathIndex + 1 >= path.size()) {
447 if ((node->*(isMatch))())
448 return node;
449 continue;
450 } else { // Search the children of n for the next name in the path.
451 node = findNodeRecursive(path, pathIndex + 1, node, isMatch);
452 if (node != nullptr)
453 return node;
454 }
455 }
456 }
457 return nullptr;
458}
459
460/*!
461 Searches the tree for a node that matches the \a path plus
462 the \a target. The search begins at \a start and moves up
463 the parent chain from there, or, if \a start is 0, the search
464 begins at the root.
465
466 The \a flags can indicate whether to search base classes and/or
467 the enum values in enum types. \a genus further restricts
468 the type of nodes to match, i.e. CPP or QML.
469
470 If a matching node is found, \a ref is set to the HTML fragment
471 identifier to use for the link. On return, the optional
472 \a targetType parameter contains the type of the resolved
473 target; section title (Contents), \\target, \\keyword, or other
474 (Unknown).
475 */
476const Node *Tree::findNodeForTarget(const QStringList &path, const QString &target,
477 const Node *start, int flags, Node::Genus genus,
478 QString &ref, TargetRec::TargetType *targetType) const
479{
480 const Node *node = nullptr;
481
482 // Retrieves and sets ref from target for Node n.
483 // Returns n on valid (or empty) target, or nullptr on an invalid target.
484 auto set_ref_from_target = [this, &ref, &target](const Node *n) -> const Node* {
485 if (!target.isEmpty()) {
486 if (ref = getRef(target, n); ref.isEmpty())
487 return nullptr;
488 }
489 return n;
490 };
491
492 if (genus == Node::DontCare || genus == Node::DOC) {
493 if (node = findPageNodeByTitle(path.at(0)); node) {
494 if (node = set_ref_from_target(node); node)
495 return node;
496 }
497 }
498
499 const TargetRec *result = findUnambiguousTarget(path.join(QLatin1String("::")), genus);
500 if (result) {
501 ref = result->m_ref;
502 if (node = set_ref_from_target(result->m_node); node) {
503 // Delay returning references to section titles as we
504 // may find a better match below
505 if (result->m_type != TargetRec::Contents) {
506 if (targetType)
507 *targetType = result->m_type;
508 return node;
509 }
510 ref.clear();
511 }
512 }
513
514 const Node *current = start ? start : root();
515 /*
516 If the path contains one or two double colons ("::"),
517 check if the first two path elements refer to a QML type.
518 If so, path[0] is QML module identifier, and path[1] is
519 the type.
520 */
521 int path_idx = 0;
522 if ((genus == Node::QML || genus == Node::DontCare)
523 && path.size() >= 2 && !path[0].isEmpty()) {
524 if (auto *qcn = lookupQmlType(path.sliced(0, 2).join(QLatin1String("::"))); qcn) {
525 current = qcn;
526 // No further elements in the path, return the type
527 if (path.size() == 2)
528 return set_ref_from_target(qcn);
529 path_idx = 2;
530 }
531 }
532
533 while (current) {
534 if (current->isAggregate()) {
535 if (const Node *match = matchPathAndTarget(
536 path, path_idx, target, current, flags, genus, ref);
537 match != nullptr)
538 return match;
539 }
540 current = current->parent();
541 path_idx = 0;
542 }
543
544 if (node && result) {
545 // Fall back to previously found section title
546 ref = result->m_ref;
547 if (targetType)
548 *targetType = result->m_type;
549 }
550 return node;
551}
552
553/*!
554 First, the \a path is used to find a node. The \a path
555 matches some part of the node's fully quallified name.
556 If the \a target is not empty, it must match a target
557 in the matching node. If the matching of the \a path
558 and the \a target (if present) is successful, \a ref
559 is set from the \a target, and the pointer to the
560 matching node is returned. \a idx is the index into the
561 \a path where to begin the matching. The function is
562 recursive with idx being incremented for each recursive
563 call.
564
565 The matching node must be of the correct \a genus, i.e.
566 either QML or C++, but \a genus can be set to \c DontCare.
567 \a flags indicates whether to search base classes and
568 whether to search for an enum value. \a node points to
569 the node where the search should begin, assuming the
570 \a path is a not a fully-qualified name. \a node is
571 most often the root of this Tree.
572 */
573const Node *Tree::matchPathAndTarget(const QStringList &path, int idx, const QString &target,
574 const Node *node, int flags, Node::Genus genus,
575 QString &ref) const
576{
577 /*
578 If the path has been matched, then if there is a target,
579 try to match the target. If there is a target, but you
580 can't match it at the end of the path, give up; return 0.
581 */
582 if (idx == path.size()) {
583 if (!target.isEmpty()) {
584 ref = getRef(target, node);
585 if (ref.isEmpty())
586 return nullptr;
587 }
588 if (node->isFunction() && node->name() == node->parent()->name())
589 node = node->parent();
590 return node;
591 }
592
593 QString name = path.at(idx);
594 if (node->isAggregate()) {
595 NodeVector nodes;
596 static_cast<const Aggregate *>(node)->findChildren(name, nodes);
597 for (const auto *child : std::as_const(nodes)) {
598 if (genus != Node::DontCare && !(genus & child->genus()))
599 continue;
600 const Node *t = matchPathAndTarget(path, idx + 1, target, child, flags, genus, ref);
601 if (t && !t->isPrivate())
602 return t;
603 }
604 }
605 if (target.isEmpty() && (flags & SearchEnumValues)) {
606 const auto *enumNode = node->isAggregate() ?
607 findEnumNode(nullptr, node, path, idx) :
608 findEnumNode(node, nullptr, path, idx);
609 if (enumNode)
610 return enumNode;
611 }
612 if (((genus == Node::CPP) || (genus == Node::DontCare)) && node->isClassNode()
613 && (flags & SearchBaseClasses)) {
614 const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(node));
615 for (const auto *base : bases) {
616 const Node *t = matchPathAndTarget(path, idx, target, base, flags, genus, ref);
617 if (t && !t->isPrivate())
618 return t;
619 if (target.isEmpty() && (flags & SearchEnumValues)) {
620 if ((t = findEnumNode(base->findChildNode(path.at(idx), genus, flags), base, path, idx)))
621 return t;
622 }
623 }
624 }
625 return nullptr;
626}
627
628/*!
629 Searches the tree for a node that matches the \a path. The
630 search begins at \a start but can move up the parent chain
631 recursively if no match is found. The \a flags are used to
632 restrict the search.
633 */
634const Node *Tree::findNode(const QStringList &path, const Node *start, int flags,
635 Node::Genus genus) const
636{
637 const Node *current = start;
638 if (current == nullptr)
639 current = root();
640
641 do {
642 const Node *node = current;
643 int i;
644 int start_idx = 0;
645
646 /*
647 If the path contains one or two double colons ("::"),
648 check first to see if the first two path strings refer
649 to a QML element. If they do, path[0] will be the QML
650 module identifier, and path[1] will be the QML type.
651 If the answer is yes, the reference identifies a QML
652 type node.
653 */
654 if (((genus == Node::QML) || (genus == Node::DontCare)) && (path.size() >= 2)
655 && !path[0].isEmpty()) {
656 QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
657 if (qcn != nullptr) {
658 node = qcn;
659 if (path.size() == 2)
660 return node;
661 start_idx = 2;
662 }
663 }
664
665 for (i = start_idx; i < path.size(); ++i) {
666 if (node == nullptr || !node->isAggregate())
667 break;
668
669 // Clear the TypesOnly flag until the last path segment, as e.g. namespaces are not
670 // types. We also ignore module nodes as they are not aggregates and thus have no
671 // children.
672 int tmpFlags = (i < path.size() - 1) ? (flags & ~TypesOnly) | IgnoreModules : flags;
673
674 const Node *next = static_cast<const Aggregate *>(node)->findChildNode(path.at(i),
675 genus, tmpFlags);
676 const Node *enumNode = (flags & SearchEnumValues) ?
677 findEnumNode(next, node, path, i) : nullptr;
678
679 if (enumNode)
680 return enumNode;
681
682
683 if (!next && ((genus == Node::CPP) || (genus == Node::DontCare))
684 && node->isClassNode() && (flags & SearchBaseClasses)) {
685 const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(node));
686 for (const auto *base : bases) {
687 next = base->findChildNode(path.at(i), genus, tmpFlags);
688 if (flags & SearchEnumValues)
689 if ((enumNode = findEnumNode(next, base, path, i)))
690 return enumNode;
691 if (next)
692 break;
693 }
694 }
695 node = next;
696 }
697 if ((node != nullptr) && i == path.size())
698 return node;
699 current = current->parent();
700 } while (current != nullptr);
701
702 return nullptr;
703}
704
705
706/*!
707 \internal
708
709 Helper function to return an enum that matches the \a path at a specified \a offset.
710 If \a node is a valid enum node, the enum name is assumed to be included in the path
711 (i.e, a scoped enum). Otherwise, query the \a aggregate (typically, the class node)
712 for enum node that includes the value at the last position in \a path.
713 */
714const Node *Tree::findEnumNode(const Node *node, const Node *aggregate, const QStringList &path, int offset) const
715{
716 // Scoped enum (path ends in enum_name :: enum_value)
717 if (node && node->isEnumType() && offset == path.size() - 1) {
718 const auto *en = static_cast<const EnumNode*>(node);
719 if (en->isScoped() && en->hasItem(path.last()))
720 return en;
721 }
722
723 // Standard enum (path ends in class_name :: enum_value)
724 return (!node && aggregate && offset == path.size() - 1) ?
725 static_cast<const Aggregate *>(aggregate)->findEnumNodeForValue(path.last()) :
726 nullptr;
727}
728
729/*!
730 This function searches for a node with a canonical title
731 constructed from \a target. If the node it finds is \a node,
732 it returns the ref from that node. Otherwise it returns an
733 empty string.
734 */
735QString Tree::getRef(const QString &target, const Node *node) const
736{
737 auto it = m_nodesByTargetTitle.constFind(target);
738 if (it != m_nodesByTargetTitle.constEnd()) {
739 do {
740 if (it.value()->m_node == node)
741 return it.value()->m_ref;
742 ++it;
743 } while (it != m_nodesByTargetTitle.constEnd() && it.key() == target);
744 }
745 QString key = Utilities::asAsciiPrintable(target);
746 it = m_nodesByTargetRef.constFind(key);
747 if (it != m_nodesByTargetRef.constEnd()) {
748 do {
749 if (it.value()->m_node == node)
750 return it.value()->m_ref;
751 ++it;
752 } while (it != m_nodesByTargetRef.constEnd() && it.key() == key);
753 }
754 return QString();
755}
756
757/*!
758 Inserts a new target into the target table. \a name is the
759 key. The target record contains the \a type, a pointer to
760 the \a node, the \a priority. and a canonicalized form of
761 the \a name, which is later used.
762 */
763void Tree::insertTarget(const QString &name, const QString &title, TargetRec::TargetType type,
764 Node *node, int priority)
765{
766 auto *target = new TargetRec(name, type, node, priority);
767 m_nodesByTargetRef.insert(name, target);
768 m_nodesByTargetTitle.insert(title, target);
769}
770
771/*!
772 \internal
773
774 \a root is the root node of the tree to resolve targets for. This function
775 traverses the tree starting from the root node and processes each child
776 node. If the child node is an aggregate node, this function is called
777 recursively on the child node.
778 */
779void Tree::resolveTargets(Aggregate *root)
780{
781 for (auto *child : root->childNodes()) {
782 addToPageNodeByTitleMap(child);
783 populateTocSectionTargetMap(child);
784 addKeywordsToTargetMaps(child);
785 addTargetsToTargetMap(child);
786
787 if (child->isAggregate())
788 resolveTargets(static_cast<Aggregate *>(child));
789 }
790}
791
792/*!
793 \internal
794
795 Updates the target maps for targets associated with the given \a node.
796 */
797void Tree::addTargetsToTargetMap(Node *node) {
798 if (!node || !node->doc().hasTargets())
799 return;
800
801 for (Atom *i : std::as_const(node->doc().targets())) {
802 const QString ref = refForAtom(i);
803 const QString title = i->string();
804 if (!ref.isEmpty() && !title.isEmpty()) {
805 QString key = Utilities::asAsciiPrintable(title);
806 auto *target = new TargetRec(ref, TargetRec::Target, node, 2);
807 m_nodesByTargetRef.insert(key, target);
808 m_nodesByTargetTitle.insert(title, target);
809 }
810 }
811}
812
813/*
814 If atom \a a is immediately followed by a
815 section title (\section1..\section4 command),
816 returns the SectionLeft atom; otherwise nullptr.
817*/
818static const Atom *nextSection(const Atom *a)
819{
820 while (a && a->next(Atom::SectionRight))
821 a = a->next(); // skip closing section atoms
822 return a ? a->next(Atom::SectionLeft) : nullptr;
823}
824
825/*!
826 \internal
827
828 Updates the target maps for keywords associated with the given \a node.
829 */
830void Tree::addKeywordsToTargetMaps(Node *node) {
831 if (!node->doc().hasKeywords())
832 return;
833
834 for (Atom *i : std::as_const(node->doc().keywords())) {
835 QString ref = refForAtom(i);
836 QString title = i->string();
837 if (!ref.isEmpty() && !title.isEmpty()) {
838 auto *target = new TargetRec(ref, nextSection(i) ? TargetRec::ContentsKeyword : TargetRec::Keyword, node, 1);
839 m_nodesByTargetRef.insert(Utilities::asAsciiPrintable(title), target);
840 m_nodesByTargetTitle.insert(title, target);
841 if (!target->isEmpty())
842 i->append(target->m_ref);
843 }
844 }
845}
846
847/*!
848 \internal
849
850 Populates the map of targets for each section in the table of contents for
851 the given \a node while ensuring that each target has a unique reference.
852 */
853void Tree::populateTocSectionTargetMap(Node *node) {
854 if (!node || !node->doc().hasTableOfContents())
855 return;
856
857 QStack<Atom *> tocLevels;
858 QSet<QString> anchors;
859
860 qsizetype index = 0;
861
862 for (Atom *atom: std::as_const(node->doc().tableOfContents())) {
863 while (!tocLevels.isEmpty() && tocLevels.top()->string().toInt() >= atom->string().toInt())
864 tocLevels.pop();
865
866 tocLevels.push(atom);
867
868 QString ref = refForAtom(atom);
869 const QString &title = Text::sectionHeading(atom).toString();
870 if (ref.isEmpty() || title.isEmpty())
871 continue;
872
873 if (anchors.contains(ref)) {
874 QStringList refParts;
875 for (const auto tocLevel : tocLevels)
876 refParts << refForAtom(tocLevel);
877
878 refParts << QString::number(index);
879 ref = refParts.join(QLatin1Char('-'));
880 }
881
882 anchors.insert(ref);
883 if (atom->next(Atom::SectionHeadingLeft))
884 atom->next()->append(ref);
885 ++index;
886
887 const QString &key = Utilities::asAsciiPrintable(title);
888 auto *target = new TargetRec(ref, TargetRec::Contents, node, 3);
889 m_nodesByTargetRef.insert(key, target);
890 m_nodesByTargetTitle.insert(title, target);
891 }
892}
893
894/*!
895 \internal
896
897 Checks if the \a node's title is registered in the page nodes by title map.
898 If not, it stores the page node in the map.
899 */
900void Tree::addToPageNodeByTitleMap(Node *node) {
901 if (!node || !node->isTextPageNode())
902 return;
903
904 auto *pageNode = static_cast<PageNode *>(node);
905 QString key = pageNode->title();
906 if (key.isEmpty())
907 return;
908
909 if (key.contains(QChar(' ')))
910 key = Utilities::asAsciiPrintable(key);
911 const QList<PageNode *> nodes = m_pageNodesByTitle.values(key);
912
913 bool alreadyThere = std::any_of(nodes.cbegin(), nodes.cend(), [&](const auto &knownNode) {
914 return knownNode->isExternalPage() && knownNode->name() == pageNode->name();
915 });
916
917 if (!alreadyThere)
918 m_pageNodesByTitle.insert(key, pageNode);
919}
920
921/*!
922 Searches for a \a target anchor, matching the given \a genus, and returns
923 the associated TargetRec instance.
924 */
925const TargetRec *Tree::findUnambiguousTarget(const QString &target, Node::Genus genus) const
926{
927 auto findBestCandidate = [&](const TargetMap &tgtMap, const QString &key) {
928 TargetRec *best = nullptr;
929 auto [it, end] = tgtMap.equal_range(key);
930 while (it != end) {
931 TargetRec *candidate = it.value();
932 if ((genus == Node::DontCare) || (genus & candidate->genus())) {
933 if (!best || (candidate->m_priority < best->m_priority))
934 best = candidate;
935 }
936 ++it;
937 }
938 return best;
939 };
940
941 TargetRec *bestTarget = findBestCandidate(m_nodesByTargetTitle, target);
942 if (!bestTarget)
943 bestTarget = findBestCandidate(m_nodesByTargetRef, Utilities::asAsciiPrintable(target));
944
945 return bestTarget;
946}
947
948/*!
949 This function searches for a node with the specified \a title.
950 */
951const PageNode *Tree::findPageNodeByTitle(const QString &title) const
952{
953 PageNodeMultiMap::const_iterator it;
954 if (title.contains(QChar(' ')))
955 it = m_pageNodesByTitle.constFind(Utilities::asAsciiPrintable(title));
956 else
957 it = m_pageNodesByTitle.constFind(title);
958 if (it != m_pageNodesByTitle.constEnd()) {
959 /*
960 Reporting all these duplicate section titles is probably
961 overkill. We should report the duplicate file and let
962 that suffice.
963 */
964 PageNodeMultiMap::const_iterator j = it;
965 ++j;
966 if (j != m_pageNodesByTitle.constEnd() && j.key() == it.key()) {
967 while (j != m_pageNodesByTitle.constEnd()) {
968 if (j.key() == it.key() && j.value()->url().isEmpty()) {
969 break; // Just report one duplicate for now.
970 }
971 ++j;
972 }
973 if (j != m_pageNodesByTitle.cend()) {
974 it.value()->location().warning("This page title exists in more than one file: "
975 + title);
976 j.value()->location().warning("[It also exists here]");
977 }
978 }
979 return it.value();
980 }
981 return nullptr;
982}
983
984/*!
985 Returns a canonical title for the \a atom, if the \a atom
986 is a SectionLeft, SectionHeadingLeft, Keyword, or Target.
987
988 If a target or a keyword is immediately followed by a
989 section, the former adopts the title (ref) of the latter.
990 */
991QString Tree::refForAtom(const Atom *atom)
992{
993 Q_ASSERT(atom);
994
995 switch (atom->type()) {
997 atom = atom->next();
998 [[fallthrough]];
1000 if (atom->count() == 2)
1001 return atom->string(1);
1002 return Utilities::asAsciiPrintable(Text::sectionHeading(atom).toString());
1003 case Atom::Target:
1004 [[fallthrough]];
1005 case Atom::Keyword:
1006 if (const auto *section = nextSection(atom))
1007 return refForAtom(section);
1008 return Utilities::asAsciiPrintable(atom->string());
1009 default:
1010 return {};
1011 }
1012}
1013
1014/*!
1015 \fn const CNMap &Tree::groups() const
1016 Returns a const reference to the collection of all
1017 group nodes.
1018*/
1019
1020/*!
1021 \fn const ModuleMap &Tree::modules() const
1022 Returns a const reference to the collection of all
1023 module nodes.
1024*/
1025
1026/*!
1027 \fn const QmlModuleMap &Tree::qmlModules() const
1028 Returns a const reference to the collection of all
1029 QML module nodes.
1030*/
1031
1032/*!
1033 Returns a pointer to the collection map specified by \a type.
1034 Returns null if \a type is not specified.
1035 */
1036CNMap *Tree::getCollectionMap(Node::NodeType type)
1037{
1038 switch (type) {
1039 case Node::Group:
1040 return &m_groups;
1041 case Node::Module:
1042 return &m_modules;
1043 case Node::QmlModule:
1044 return &m_qmlModules;
1045 default:
1046 break;
1047 }
1048 return nullptr;
1049}
1050
1051/*!
1052 Searches this tree for a collection named \a name with the
1053 specified \a type. If the collection is found, a pointer
1054 to it is returned. If a collection is not found, null is
1055 returned.
1056 */
1057CollectionNode *Tree::getCollection(const QString &name, Node::NodeType type)
1058{
1059 CNMap *map = getCollectionMap(type);
1060 if (map) {
1061 auto it = map->constFind(name);
1062 if (it != map->cend())
1063 return it.value();
1064 }
1065 return nullptr;
1066}
1067
1068/*!
1069 Find the group, module, or QML module named \a name and return a
1070 pointer to that collection node. \a type specifies which kind of
1071 collection node you want. If a collection node with the specified \a
1072 name and \a type is not found, a new one is created, and the pointer
1073 to the new one is returned.
1074
1075 If a new collection node is created, its parent is the tree
1076 root, and the new collection node is marked \e{not seen}.
1077
1078 \a genus must be specified, i.e. it must not be \c{DontCare}.
1079 If it is \c{DontCare}, 0 is returned, which is a programming
1080 error.
1081 */
1082CollectionNode *Tree::findCollection(const QString &name, Node::NodeType type)
1083{
1084 CNMap *m = getCollectionMap(type);
1085 if (!m) // error
1086 return nullptr;
1087 auto it = m->constFind(name);
1088 if (it != m->cend())
1089 return it.value();
1090 CollectionNode *cn = new CollectionNode(type, root(), name);
1092 m->insert(name, cn);
1093 return cn;
1094}
1095
1096/*! \fn CollectionNode *Tree::findGroup(const QString &name)
1097 Find the group node named \a name and return a pointer
1098 to it. If the group node is not found, add a new group
1099 node named \a name and return a pointer to the new one.
1100
1101 If a new group node is added, its parent is the tree root,
1102 and the new group node is marked \e{not seen}.
1103 */
1104
1105/*! \fn CollectionNode *Tree::findModule(const QString &name)
1106 Find the module node named \a name and return a pointer
1107 to it. If a matching node is not found, add a new module
1108 node named \a name and return a pointer to that one.
1109
1110 If a new module node is added, its parent is the tree root,
1111 and the new module node is marked \e{not seen}.
1112 */
1113
1114/*! \fn CollectionNode *Tree::findQmlModule(const QString &name)
1115 Find the QML module node named \a name and return a pointer
1116 to it. If a matching node is not found, add a new QML module
1117 node named \a name and return a pointer to that one.
1118
1119 If a new QML module node is added, its parent is the tree root,
1120 and the new node is marked \e{not seen}.
1121 */
1122
1123/*! \fn CollectionNode *Tree::addGroup(const QString &name)
1124 Looks up the group node named \a name in the collection
1125 of all group nodes. If a match is found, a pointer to the
1126 node is returned. Otherwise, a new group node named \a name
1127 is created and inserted into the collection, and the pointer
1128 to that node is returned.
1129 */
1130
1131/*! \fn CollectionNode *Tree::addModule(const QString &name)
1132 Looks up the module node named \a name in the collection
1133 of all module nodes. If a match is found, a pointer to the
1134 node is returned. Otherwise, a new module node named \a name
1135 is created and inserted into the collection, and the pointer
1136 to that node is returned.
1137 */
1138
1139/*! \fn CollectionNode *Tree::addQmlModule(const QString &name)
1140 Looks up the QML module node named \a name in the collection
1141 of all QML module nodes. If a match is found, a pointer to the
1142 node is returned. Otherwise, a new QML module node named \a name
1143 is created and inserted into the collection, and the pointer
1144 to that node is returned.
1145 */
1146
1147/*!
1148 Looks up the group node named \a name in the collection
1149 of all group nodes. If a match is not found, a new group
1150 node named \a name is created and inserted into the collection.
1151 Then append \a node to the group's members list, and append the
1152 group name to the list of group names in \a node. The parent of
1153 \a node is not changed by this function. Returns a pointer to
1154 the group node.
1155 */
1156CollectionNode *Tree::addToGroup(const QString &name, Node *node)
1157{
1158 CollectionNode *cn = findGroup(name);
1159 if (!node->isInternal()) {
1160 cn->addMember(node);
1161 node->appendGroupName(name);
1162 }
1163 return cn;
1164}
1165
1166/*!
1167 Looks up the module node named \a name in the collection
1168 of all module nodes. If a match is not found, a new module
1169 node named \a name is created and inserted into the collection.
1170 Then append \a node to the module's members list. The parent of
1171 \a node is not changed by this function. Returns the module node.
1172 */
1173CollectionNode *Tree::addToModule(const QString &name, Node *node)
1174{
1175 CollectionNode *cn = findModule(name);
1176 cn->addMember(node);
1177 node->setPhysicalModuleName(name);
1178 return cn;
1179}
1180
1181/*!
1182 Looks up the QML module named \a name. If it isn't there,
1183 create it. Then append \a node to the QML module's member
1184 list. The parent of \a node is not changed by this function.
1185 Returns the pointer to the QML module node.
1186 */
1187CollectionNode *Tree::addToQmlModule(const QString &name, Node *node)
1188{
1189 QStringList qmid;
1190 QStringList dotSplit;
1191 QStringList blankSplit = name.split(QLatin1Char(' '));
1192 qmid.append(blankSplit[0]);
1193 if (blankSplit.size() > 1) {
1194 qmid.append(blankSplit[0] + blankSplit[1]);
1195 dotSplit = blankSplit[1].split(QLatin1Char('.'));
1196 qmid.append(blankSplit[0] + dotSplit[0]);
1197 }
1198
1199 CollectionNode *cn = findQmlModule(blankSplit[0]);
1200 cn->addMember(node);
1201 node->setQmlModule(cn);
1202 if (node->isQmlType()) {
1203 QmlTypeNode *n = static_cast<QmlTypeNode *>(node);
1204 for (int i = 0; i < qmid.size(); ++i) {
1205 QString key = qmid[i] + "::" + node->name();
1206 insertQmlType(key, n);
1207 }
1208 }
1209 return cn;
1210}
1211
1212/*!
1213 If the QML type map does not contain \a key, insert node
1214 \a n with the specified \a key.
1215 */
1216void Tree::insertQmlType(const QString &key, QmlTypeNode *n)
1217{
1218 if (!m_qmlTypeMap.contains(key))
1219 m_qmlTypeMap.insert(key, n);
1220}
1221
1222/*!
1223 Finds the function node with the specifried name \a path that
1224 also has the specified \a parameters and returns a pointer to
1225 the first matching function node if one is found.
1226
1227 This function begins searching the tree at \a relative for
1228 the \l {FunctionNode} {function node} identified by \a path
1229 that has the specified \a parameters. The \a flags are
1230 used to restrict the search. If a matching node is found, a
1231 pointer to it is returned. Otherwise, nullis returned. If
1232 \a relative is ull, the search begins at the tree root.
1233 */
1234const FunctionNode *Tree::findFunctionNode(const QStringList &path, const Parameters &parameters,
1235 const Node *relative, Node::Genus genus) const
1236{
1237 if (path.size() == 3 && !path[0].isEmpty()
1238 && ((genus == Node::QML) || (genus == Node::DontCare))) {
1239 QmlTypeNode *qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
1240 if (qcn == nullptr) {
1241 QStringList p(path[1]);
1242 Node *n = findNodeByNameAndType(p, &Node::isQmlType);
1243 if ((n != nullptr) && n->isQmlType())
1244 qcn = static_cast<QmlTypeNode *>(n);
1245 }
1246 if (qcn != nullptr)
1247 return static_cast<const FunctionNode *>(qcn->findFunctionChild(path[2], parameters));
1248 }
1249
1250 if (relative == nullptr)
1251 relative = root();
1252 else if (genus != Node::DontCare) {
1253 if (!(genus & relative->genus()))
1254 relative = root();
1255 }
1256
1257 do {
1258 Node *node = const_cast<Node *>(relative);
1259 int i;
1260
1261 for (i = 0; i < path.size(); ++i) {
1262 if (node == nullptr || !node->isAggregate())
1263 break;
1264
1265 Aggregate *aggregate = static_cast<Aggregate *>(node);
1266 Node *next = nullptr;
1267 if (i == path.size() - 1)
1268 next = aggregate->findFunctionChild(path.at(i), parameters);
1269 else
1270 next = aggregate->findChildNode(path.at(i), genus);
1271
1272 if ((next == nullptr) && aggregate->isClassNode()) {
1273 const ClassList bases = allBaseClasses(static_cast<const ClassNode *>(aggregate));
1274 for (auto *base : bases) {
1275 if (i == path.size() - 1)
1276 next = base->findFunctionChild(path.at(i), parameters);
1277 else
1278 next = base->findChildNode(path.at(i), genus);
1279
1280 if (next != nullptr)
1281 break;
1282 }
1283 }
1284
1285 node = next;
1286 } // for (i = 0; i < path.size(); ++i)
1287
1288 if (node && i == path.size() && node->isFunction()) {
1289 // A function node was found at the end of the path.
1290 // If it is not marked private, return it. If it is
1291 // marked private, then if it overrides a function,
1292 // find that function instead because it might not
1293 // be marked private. If all the overloads are
1294 // marked private, return the original function node.
1295 // This should be replace with findOverriddenFunctionNode().
1296 const FunctionNode *fn = static_cast<const FunctionNode *>(node);
1297 const FunctionNode *FN = fn;
1298 while (FN->isPrivate() && !FN->overridesThis().isEmpty()) {
1299 QStringList path = FN->overridesThis().split("::");
1300 FN = m_qdb->findFunctionNode(path, parameters, relative, genus);
1301 if (FN == nullptr)
1302 break;
1303 if (!FN->isPrivate())
1304 return FN;
1305 }
1306 return fn;
1307 }
1308 relative = relative->parent();
1309 } while (relative);
1310 return nullptr;
1311}
1312
1313/*!
1314 Search this tree recursively from \a parent to find a function
1315 node with the specified \a tag. If no function node is found
1316 with the required \a tag, return 0.
1317 */
1318FunctionNode *Tree::findFunctionNodeForTag(const QString &tag, Aggregate *parent)
1319{
1320 if (parent == nullptr)
1321 parent = root();
1322 const NodeList &children = parent->childNodes();
1323 for (Node *n : children) {
1324 if (n != nullptr && n->isFunction() && n->hasTag(tag))
1325 return static_cast<FunctionNode *>(n);
1326 }
1327 for (Node *n : children) {
1328 if (n != nullptr && n->isAggregate()) {
1329 n = findFunctionNodeForTag(tag, static_cast<Aggregate *>(n));
1330 if (n != nullptr)
1331 return static_cast<FunctionNode *>(n);
1332 }
1333 }
1334 return nullptr;
1335}
1336
1337/*!
1338 There should only be one macro node for macro name \a t.
1339 The macro node is not built until the \macro command is seen.
1340 */
1341FunctionNode *Tree::findMacroNode(const QString &t, const Aggregate *parent)
1342{
1343 if (parent == nullptr)
1344 parent = root();
1345 const NodeList &children = parent->childNodes();
1346 for (Node *n : children) {
1347 if (n != nullptr && (n->isMacro() || n->isFunction()) && n->name() == t)
1348 return static_cast<FunctionNode *>(n);
1349 }
1350 for (Node *n : children) {
1351 if (n != nullptr && n->isAggregate()) {
1352 FunctionNode *fn = findMacroNode(t, static_cast<Aggregate *>(n));
1353 if (fn != nullptr)
1354 return fn;
1355 }
1356 }
1357 return nullptr;
1358}
1359
1360/*!
1361 Add the class and struct names in \a arg to the \e {don't document}
1362 map.
1363 */
1364void Tree::addToDontDocumentMap(QString &arg)
1365{
1366 arg.remove(QChar('('));
1367 arg.remove(QChar(')'));
1368 QString t = arg.simplified();
1369 QStringList sl = t.split(QChar(' '));
1370 if (sl.isEmpty())
1371 return;
1372 for (const QString &s : sl) {
1373 if (!m_dontDocumentMap.contains(s))
1374 m_dontDocumentMap.insert(s, nullptr);
1375 }
1376}
1377
1378/*!
1379 The \e {don't document} map has been loaded with the names
1380 of classes and structs in the current module that are not
1381 documented and should not be documented. Now traverse the
1382 map, and for each class or struct name, find the class node
1383 that represents that class or struct and mark it with the
1384 \C DontDocument status.
1385
1386 This results in a map of the class and struct nodes in the
1387 module that are in the public API but are not meant to be
1388 used by anyone. They are only used internally, but for one
1389 reason or another, they must have public visibility.
1390 */
1392{
1393 for (auto it = m_dontDocumentMap.begin(); it != m_dontDocumentMap.end(); ++it) {
1394 Aggregate *node = findAggregate(it.key());
1395 if (node != nullptr)
1397 }
1398}
1399
1400QT_END_NAMESPACE
FunctionNode * findFunctionChild(const FunctionNode *clone)
Returns the function node that is a child of this node, such that the function described has the same...
const NodeList & childNodes() const
Returns a const reference to the child list.
Definition aggregate.h:41
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:18
AtomType type() const
Return the type of this atom.
Definition atom.h:149
@ ListTagLeft
Definition atom.h:64
@ Target
Definition atom.h:102
@ SectionRight
Definition atom.h:81
@ SectionHeadingLeft
Definition atom.h:82
@ SinceTagLeft
Definition atom.h:87
@ SectionLeft
Definition atom.h:80
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:146
const Atom * next(AtomType t) const
Return the next Atom in the list if it is of AtomType t.
Definition atom.cpp:289
const Atom * find(AtomType t) const
Starting from this Atom, searches the linked list for the atom of specified type t and returns it.
Definition atom.cpp:259
The ClassNode represents a C++ class.
Definition classnode.h:21
void removePrivateAndInternalBases()
Remove private and internal bases classes from this class's list of base classes.
A class for holding the members of a collection of doc pages.
void addMember(Node *node) override
Appends node to the collection node's member list, if and only if it isn't already in the member list...
bool hasTableOfContents() const
Definition doc.cpp:253
bool hasKeywords() const
Definition doc.cpp:258
bool hasTargets() const
Definition doc.cpp:263
bool isScoped() const
Definition enumnode.h:31
This node is used to represent any kind of function being documented.
This class represents a C++ namespace.
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:271
bool isPrivate() const
Returns true if this node's access is Private.
Definition node.h:146
virtual void setQmlModule(CollectionNode *)
If this is a QmlTypeNode, this function sets the QML type's QML module pointer to the CollectionNode ...
Definition node.h:298
NodeType
An unsigned char value that identifies an object as a particular subclass of Node.
Definition node.h:54
@ Module
Definition node.h:71
@ QmlModule
Definition node.h:73
@ Group
Definition node.h:70
bool isFunction(Genus g=DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
Definition node.h:135
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
Definition node.h:155
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:849
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:132
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Definition node.h:187
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:244
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
Definition node.h:170
Access access() const
Returns the node's Access setting, which can be Public, Protected, or Private.
Definition node.h:264
Genus
An unsigned char value that specifies whether the Node represents a C++ element, a QML element,...
Definition node.h:81
@ DontCare
Definition node.h:82
@ CPP
Definition node.h:83
@ DOC
Definition node.h:85
@ QML
Definition node.h:84
Genus genus() const
Returns this node's Genus.
Definition node.h:124
LinkType
An unsigned char value that probably should be moved out of the Node base class.
Definition node.h:112
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:177
void setStatus(Status t)
Sets the node's status to t.
Definition node.cpp:560
@ DontDocument
Definition node.h:94
Status status() const
Returns the node's status value.
Definition node.h:278
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:18
A class for parsing and managing a function parameter list.
Definition parameters.h:57
This class describes one instance of using the Q_PROPERTY macro.
const PropertyNode * overriddenFrom() const
void addFunction(FunctionNode *function, FunctionRole role)
void setOverriddenFrom(const PropertyNode *baseProperty)
Sets this property's {overridden from} property to baseProperty, which indicates that this property o...
void addSignal(FunctionNode *function, FunctionRole role)
Definition text.h:12
static Text sectionHeading(const Atom *sectionBegin)
Definition text.cpp:176
This class constructs and maintains a tree of instances of the subclasses of Node.
Definition tree.h:56
void markDontDocumentNodes()
The {don't document} map has been loaded with the names of classes and structs in the current module ...
Definition tree.cpp:1391
void addToDontDocumentMap(QString &arg)
Add the class and struct names in arg to the {don't document} map.
Definition tree.cpp:1364
Node * findNodeByNameAndType(const QStringList &path, bool(Node::*isMatch)() const) const
Find the node with the specified path name that is of the specified type and subtype.
Definition tree.cpp:410
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:41
QList< ClassNode * > ClassList
Definition node.h:42
QList< Node * > NodeVector
Definition node.h:43
QMap< QString, CollectionNode * > CNMap
Definition node.h:48
@ SearchBaseClasses
@ SearchEnumValues
@ IgnoreModules
@ TypesOnly
A record of a linkable target within the documentation.
Definition tree.h:25
Node * m_node
Definition tree.h:44
Node::Genus genus() const
Definition tree.h:42
int m_priority
Definition tree.h:47
TargetType
A type of a linkable target record.
Definition tree.h:27
@ Contents
Definition tree.h:27
TargetType m_type
Definition tree.h:46
static const Atom * nextSection(const Atom *a)
Definition tree.cpp:818
QMultiMap< QString, TargetRec * > TargetMap
Definition tree.h:50