1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "node.h"
30 
31 #include "codemarker.h"
32 #include "config.h"
33 #include "cppcodeparser.h"
34 #include "generator.h"
35 #include "puredocparser.h"
36 #include "qdocdatabase.h"
37 #include "tokenizer.h"
38 #include "tree.h"
39 
40 #include <QtCore/qdebug.h>
41 #include <QtCore/quuid.h>
42 #include <QtCore/qversionnumber.h>
43 
44 #include <algorithm>
45 
46 QT_BEGIN_NAMESPACE
47 
48 int Node::propertyGroupCount_ = 0;
49 QStringMap Node::operators_;
50 QMap<QString, Node::NodeType> Node::goals_;
51 
52 /*!
53   \class Node
54   \brief The Node class is the base class for all the nodes in QDoc's parse tree.
55 
56   Class Node is the base class of all the node subclasses. There is a subclass of Node
57   for each type of entity that QDoc can document. The types of entities that QDoc can
58   document are listed in the enum type NodeType.
59 
60   After ClangCodeParser has parsed all the header files to build its precompiled header,
61   it then visits the clang Abstract Syntax Tree (AST). For each node in the AST that it
62   determines is in the public API and must be documented, it creates an instance of one
63   of the Node subclasses and adds it to the QDoc Tree.
64 
65   Each instance of a sublass of Node has a parent pointer to link it into the Tree. The
66   parent pointer is obtained by calling \l {parent()}, which returns a pointer to an
67   instance of the Node subclass, Aggregate, which is never instantiated directly, but
68   as the base class for certain subclasses of Node that can have children. For example,
69   ClassNode and QmlTypeNode can have children, so they both inherit Aggregate, while
70   PropertyNode and QmlPropertyNode can not have children, so they both inherit Node.
71 
72   \sa Aggregate, ClassNode, PropertyNode
73  */
74 
75 /*!
76   Initialize the map of search goals. This is called once
77   by QDocDatabase::initializeDB(). The map key is a string
78   representing a value in the enum Node::NodeType. The map value
79   is the enum value.
80 
81   There should be an entry in the map for each value in the
82   NodeType enum.
83  */
initialize()84 void Node::initialize()
85 {
86     goals_.insert("namespace", Node::Namespace);
87     goals_.insert("class", Node::Class);
88     goals_.insert("struct", Node::Struct);
89     goals_.insert("union", Node::Union);
90     goals_.insert("header", Node::HeaderFile);
91     goals_.insert("headerfile", Node::HeaderFile);
92     goals_.insert("page", Node::Page);
93     goals_.insert("enum", Node::Enum);
94     goals_.insert("example", Node::Example);
95     goals_.insert("externalpage", Node::ExternalPage);
96     goals_.insert("typedef", Node::Typedef);
97     goals_.insert("typealias", Node::TypeAlias);
98     goals_.insert("function", Node::Function);
99     goals_.insert("proxy", Node::Proxy);
100     goals_.insert("property", Node::Property);
101     goals_.insert("variable", Node::Variable);
102     goals_.insert("group", Node::Group);
103     goals_.insert("module", Node::Module);
104     goals_.insert("qmltype", Node::QmlType);
105     goals_.insert("qmlmodule", Node::QmlModule);
106     goals_.insert("qmlproperty", Node::QmlProperty);
107     goals_.insert("qmlsignal", Node::Function);
108     goals_.insert("qmlsignalhandler", Node::Function);
109     goals_.insert("qmlmethod", Node::Function);
110     goals_.insert("qmlbasictype", Node::QmlBasicType);
111     goals_.insert("sharedcomment", Node::SharedComment);
112     goals_.insert("collection", Node::Collection);
113 }
114 
115 /*!
116   If this Node's type is \a from, change the type to \a to
117   and return \c true. Otherwise return false. This function
118   is used to change Qml node types to Javascript node types,
119   because these nodes are created as Qml nodes before it is
120   discovered that the entity represented by the node is not
121   Qml but javascript.
122 
123   Note that if the function returns true, which means the node
124   type was indeed changed, then the node's Genus is also changed
125   from QML to JS.
126 
127   The function also works in the other direction, but there is
128   no use case for that.
129  */
changeType(NodeType from,NodeType to)130 bool Node::changeType(NodeType from, NodeType to)
131 {
132     if (nodeType_ == from) {
133         nodeType_ = to;
134         switch (to) {
135         case QmlType:
136         case QmlModule:
137         case QmlProperty:
138         case QmlBasicType:
139             setGenus(Node::QML);
140             break;
141         case JsType:
142         case JsModule:
143         case JsProperty:
144         case JsBasicType:
145             setGenus(Node::JS);
146             break;
147         default:
148             setGenus(Node::CPP);
149             break;
150         }
151         return true;
152     }
153     return false;
154 }
155 
156 /*!
157   Returns \c true if the node \a n1 is less than node \a n2. The
158   comparison is performed by comparing properties of the nodes
159   in order of increasing complexity.
160  */
nodeNameLessThan(const Node * n1,const Node * n2)161 bool Node::nodeNameLessThan(const Node *n1, const Node *n2)
162 {
163 #define LT_RETURN_IF_NOT_EQUAL(a, b)                                                               \
164     if ((a) != (b))                                                                                \
165         return (a) < (b);
166 
167     if (n1->isPageNode() && n2->isPageNode()) {
168         LT_RETURN_IF_NOT_EQUAL(n1->fullName(), n2->fullName());
169         LT_RETURN_IF_NOT_EQUAL(n1->fullTitle(), n2->fullTitle());
170     }
171 
172     if (n1->isFunction() && n2->isFunction()) {
173         const FunctionNode *f1 = static_cast<const FunctionNode *>(n1);
174         const FunctionNode *f2 = static_cast<const FunctionNode *>(n2);
175 
176         LT_RETURN_IF_NOT_EQUAL(f1->isConst(), f2->isConst());
177         LT_RETURN_IF_NOT_EQUAL(f1->signature(false, false), f2->signature(false, false));
178     }
179 
180     LT_RETURN_IF_NOT_EQUAL(n1->nodeType(), n2->nodeType());
181     LT_RETURN_IF_NOT_EQUAL(n1->name(), n2->name());
182     LT_RETURN_IF_NOT_EQUAL(n1->access(), n2->access());
183     LT_RETURN_IF_NOT_EQUAL(n1->location().filePath(), n2->location().filePath());
184 
185     return false;
186 }
187 
188 /*!
189   \enum Node::NodeType
190 
191   An unsigned char value that identifies an object as a
192   particular subclass of Node.
193 
194   \value NoType The node type has not been set yet.
195   \value Namespace The Node subclass is NamespaceNode, which represents a C++
196          namespace.
197   \value Class The Node subclass is ClassNode, which represents a C++ class.
198   \value Struct The Node subclass is ClassNode, which represents a C struct.
199   \value Union The Node subclass is ClassNode, which represents a C union
200          (currently no known uses).
201   \value HeaderFile The Node subclass is HeaderNode, which represents a header
202          file.
203   \value Page The Node subclass is PageNode, which represents a text page from
204          a .qdoc file.
205   \value Enum The Node subclass is EnumNode, which represents an enum type or
206          enum class.
207   \value Example The Node subclass is ExampleNode, which represents an example
208          subdirectory.
209   \value ExternalPage The Node subclass is ExternalPageNode, which is for
210          linking to an external page.
211   \value Function The Node subclass is FunctionNode, which can represent C++,
212          QML, and Javascript functions.
213   \value Typedef The Node subclass is TypedefNode, which represents a C++
214          typedef.
215   \value Property The Node subclass is PropertyNode, which represents a use of
216          Q_Property.
217   \value Variable The Node subclass is VariableNode, which represents a global
218          variable or class data member.
219   \value Group The Node subclass is CollectionNode, which represents a group of
220          documents.
221   \value Module The Node subclass is CollectionNode, which represents a C++
222          module.
223   \value QmlType The Node subclass is QmlTypeNode, which represents a QML type.
224   \value QmlModule The Node subclass is CollectionNode, which represents a QML
225          module.
226   \value QmlProperty The Node subclass is QmlPropertyNode, which represents a
227          property in a QML type.
228   \value QmlBasicType The Node subclass is QmlBasicTypeNode, which represents a
229          basic type like int, etc.
230   \value JsType The Node subclass is QmlTypeNode, which represents a javascript
231          type.
232   \value JsModule The Node subclass is CollectionNode, which represents a
233          javascript module.
234   \value JsProperty The Node subclass is QmlPropertyNode, which represents a
235          javascript property.
236   \value JsBasicType The Node subclass is QmlBasicTypeNode, which represents a
237          basic type like int, etc.
238   \value SharedComment The Node subclass is SharedCommentNode, which represents
239          a collection of nodes that share the same documentation comment.
240   \omitvalue Collection
241   \value Proxy The Node subclass is ProxyNode, which represents one or more
242          entities that are documented in the current module but which actually
243          reside in a different module.
244   \omitvalue LastType
245 */
246 
247 /*!
248   \enum Node::Genus
249 
250   An unsigned char value that specifies whether the Node represents a
251   C++ element, a QML element, a javascript element, or a text document.
252   The Genus values are also passed to search functions to specify the
253   Genus of Tree Node that can satisfy the search.
254 
255   \value DontCare The Genus is not specified. Used when calling Tree search functions to indicate
256                   the search can accept any Genus of Node.
257   \value CPP The Node represents a C++ element.
258   \value JS The Node represents a javascript element.
259   \value QML The Node represents a QML element.
260   \value DOC The Node represents a text document.
261 */
262 
263 /*!
264   \enum Node::Access
265 
266   An unsigned char value that indicates the C++ access level.
267 
268   \value Public The element has public access.
269   \value Protected The element has protected access.
270   \value Private The element has private access.
271 */
272 
273 /*!
274   \enum Node::Status
275 
276   An unsigned char that specifies the status of the documentation element in
277   the documentation set.
278 
279   \value Obsolete The element is obsolete and no longer exists in the software.
280   \value Deprecated The element has been deprecated but still exists in the software.
281   \value Preliminary The element is new; the documentation is preliminary.
282   \value Active The element is current.
283   \value Internal The element is for internal use only, not to be published.
284   \value DontDocument The element is not to be documented.
285 */
286 
287 /*!
288   \enum Node::ThreadSafeness
289 
290   An unsigned char that specifies the degree of thread-safeness of the element.
291 
292   \value UnspecifiedSafeness The thread-safeness is not specified.
293   \value NonReentrant The element is not reentrant.
294   \value Reentrant The element is reentrant.
295   \value ThreadSafe The element is threadsafe.
296 */
297 
298 /*!
299   \enum Node::LinkType
300 
301   An unsigned char value that probably should be moved out of the Node base class.
302 
303   \value StartLink
304   \value NextLink
305   \value PreviousLink
306   \value ContentsLink
307  */
308 
309 /*!
310   \enum Node::PageType
311 
312   An unsigned char value that indicates what kind of documentation page
313   the Node represents. I think it is not very useful anymore.
314 
315   \value NoPageType
316   \value AttributionPage
317   \value ApiPage
318   \value ArticlePage
319   \value ExamplePage
320   \value HowToPage
321   \value OverviewPage
322   \value TutorialPage
323   \value FAQPage
324   \omitvalue OnBeyondZebra
325 */
326 
327 /*!
328   \enum Node::FlagValue
329 
330   A value used in PropertyNode and QmlPropertyNode that can be -1, 0, or +1.
331   Properties and QML properties have flags, which can be 0 or 1, false or true,
332   or not set. FlagValueDefault is the not set value. In other words, if a flag
333   is set to FlagValueDefault, the meaning is the flag has not been set.
334 
335   \value FlagValueDefault -1 Not set.
336   \value FlagValueFalse 0 False.
337   \value FlagValueTrue 1 True.
338 */
339 
340 /*!
341   \fn Node::~Node()
342 
343   The default destructor is virtual so any subclass of Node can be
344   deleted by deleting a pointer to Node.
345  */
346 
347 /*! \fn bool Node::isActive() const
348   Returns true if this node's status is \c Active.
349  */
350 
351 /*! \fn bool Node::isAnyType() const
352   Always returns true. I'm not sure why this is here.
353  */
354 
355 /*! \fn bool Node::isClass() const
356   Returns true if the node type is \c Class.
357  */
358 
359 /*! \fn bool Node::isCppNode() const
360   Returns true if this node's Genus value is \c CPP.
361  */
362 
363 /*! \fn bool Node::isDeprecated() const
364   Returns true if this node's status is \c Deprecated.
365  */
366 
367 /*! \fn bool Node::isDontDocument() const
368   Returns true if this node's status is \c DontDocument.
369  */
370 
371 /*! \fn bool Node::isEnumType() const
372   Returns true if the node type is \c Enum.
373  */
374 
375 /*! \fn bool Node::isExample() const
376   Returns true if the node type is \c Example.
377  */
378 
379 /*! \fn bool Node::isExternalPage() const
380   Returns true if the node type is \c ExternalPage.
381  */
382 
383 /*! \fn bool Node::isFunction(Genus g = DontCare) const
384   Returns true if this is a FunctionNode and its Genus is set to \a g.
385  */
386 
387 /*! \fn bool Node::isGroup() const
388   Returns true if the node type is \c Group.
389  */
390 
391 /*! \fn bool Node::isHeader() const
392   Returns true if the node type is \c HeaderFile.
393  */
394 
395 /*! \fn bool Node::isIndexNode() const
396   Returns true if this node was created from something in an index file.
397  */
398 
399 /*! \fn bool Node::isJsBasicType() const
400   Returns true if the node type is \c JsBasicType.
401  */
402 
403 /*! \fn bool Node::isJsModule() const
404   Returns true if the node type is \c JsModule.
405  */
406 
407 /*! \fn bool Node::isJsNode() const
408   Returns true if this node's Genus value is \c JS.
409  */
410 
411 /*! \fn bool Node::isJsProperty() const
412   Returns true if the node type is \c JsProperty.
413  */
414 
415 /*! \fn bool Node::isJsType() const
416   Returns true if the node type is \c JsType.
417  */
418 
419 /*! \fn bool Node::isModule() const
420   Returns true if the node type is \c Module.
421  */
422 
423 /*! \fn bool Node::isNamespace() const
424   Returns true if the node type is \c Namespace.
425  */
426 
427 /*! \fn bool Node::isObsolete() const
428   Returns true if this node's status is \c Obsolete.
429  */
430 
431 /*! \fn bool Node::isPage() const
432   Returns true if the node type is \c Page.
433  */
434 
435 /*! \fn bool Node::isPreliminary() const
436   Returns true if this node's status is \c Preliminary.
437  */
438 
439 /*! \fn bool Node::isPrivate() const
440   Returns true if this node's access is \c Private.
441  */
442 
443 /*! \fn bool Node::isProperty() const
444   Returns true if the node type is \c Property.
445  */
446 
447 /*! \fn bool Node::isProxyNode() const
448   Returns true if the node type is \c Proxy.
449  */
450 
451 /*! \fn bool Node::isPublic() const
452   Returns true if this node's access is \c Public.
453  */
454 
455 /*! \fn bool Node::isProtected() const
456   Returns true if this node's access is \c Protected.
457  */
458 
459 /*! \fn bool Node::isQmlBasicType() const
460   Returns true if the node type is \c QmlBasicType.
461  */
462 
463 /*! \fn bool Node::isQmlModule() const
464   Returns true if the node type is \c QmlModule.
465  */
466 
467 /*! \fn bool Node::isQmlNode() const
468   Returns true if this node's Genus value is \c QML.
469  */
470 
471 /*! \fn bool Node::isQmlProperty() const
472   Returns true if the node type is \c QmlProperty.
473  */
474 
475 /*! \fn bool Node::isQmlType() const
476   Returns true if the node type is \c QmlType.
477  */
478 
479 /*! \fn bool Node::isRelatedNonmember() const
480   Returns true if this is a related nonmember of something.
481  */
482 
483 /*! \fn bool Node::isStruct() const
484   Returns true if the node type is \c Struct.
485  */
486 
487 /*! \fn bool Node::isSharedCommentNode() const
488   Returns true if the node type is \c SharedComment.
489  */
490 
491 /*! \fn bool Node::isTypeAlias() const
492   Returns true if the node type is \c Typedef.
493  */
494 
495 /*! \fn bool Node::isTypedef() const
496   Returns true if the node type is \c Typedef.
497  */
498 
499 /*! \fn bool Node::isUnion() const
500   Returns true if the node type is \c Union.
501  */
502 
503 /*! \fn bool Node::isVariable() const
504   Returns true if the node type is \c Variable.
505  */
506 
507 /*! \fn bool Node::isGenericCollection() const
508   Returns true if the node type is \c Collection.
509  */
510 
511 /*! \fn bool Node::isAbstract() const
512   Returns true if the ClassNode or QmlTypeNode is marked abstract.
513 */
514 
515 /*! \fn bool Node::isAggregate() const
516   Returns true if this node is an aggregate, which means it
517   inherits Aggregate and can therefore have children.
518 */
519 
520 /*! \fn bool Node::isFirstClassAggregate() const
521   Returns true if this Node is an Aggregate but not a ProxyNode.
522 */
523 
524 /*! \fn bool Node::isAlias() const
525   Returns true if this QML property is marked as an alias.
526 */
527 
528 /*! \fn bool Node::isAttached() const
529   Returns true if the QML property or QML method node is marked as attached.
530 */
531 
532 /*! \fn bool Node::isClassNode() const
533   Returns true if this is an instance of ClassNode.
534 */
535 
536 /*! \fn bool Node::isCollectionNode() const
537   Returns true if this is an instance of CollectionNode.
538 */
539 
540 /*! \fn bool Node::isDefault() const
541   Returns true if the QML property node is marked as default.
542 */
543 
544 /*! \fn bool Node::isMacro() const
545   returns true if either FunctionNode::isMacroWithParams() or
546   FunctionNode::isMacroWithoutParams() returns true.
547 */
548 
549 /*! \fn bool Node::isPageNode() const
550   Returns true if this node represents something that generates a documentation
551   page. In other words, if this Node's subclass inherits PageNode, then this
552   function will return \e true.
553 */
554 
555 /*! \fn bool Node::isQtQuickNode() const
556   Returns true if this node represents a QML element in the QtQuick module.
557 */
558 
559 /*! \fn bool Node::isReadOnly() const
560   Returns true if the QML property node is marked as a read-only property.
561 */
562 
563 /*! \fn bool Node::isRelatableType() const
564   Returns true if this node is something you can relate things to with
565   the \e relates command. NamespaceNode, ClassNode, HeaderNode, and
566   ProxyNode are relatable types.
567 */
568 
569 /*! \fn bool Node::isMarkedReimp() const
570   Returns true if the FunctionNode is marked as a reimplemented function.
571   That means it is virtual in the base class and it is reimplemented in
572   the subclass.
573 */
574 
575 /*! \fn bool Node::isPropertyGroup() const
576   Returns true if the node is a SharedCommentNode for documenting
577   multiple C++ properties or multiple QML properties.
578 */
579 
580 /*! \fn bool Node::isStatic() const
581   Returns true if the FunctionNode represents a static function.
582 */
583 
584 /*! \fn bool Node::isTextPageNode() const
585   Returns true if the node is a PageNode but not an Aggregate.
586 */
587 
588 /*!
589   Returns this node's name member. Appends "()" to the returned
590   name if this node is a function node, but not if it is a macro
591   because macro names normally appear without parentheses.
592  */
plainName() const593 QString Node::plainName() const
594 {
595     if (isFunction() && !isMacro())
596         return name_ + QLatin1String("()");
597     return name_;
598 }
599 
600 /*!
601   Constructs and returns the node's fully qualified name by
602   recursively ascending the parent links and prepending each
603   parent name + "::". Breaks out when reaching a HeaderNode,
604   or when the parent pointer is \a relative. Typically, calls
605   to this function pass \c nullptr for \a relative.
606  */
plainFullName(const Node * relative) const607 QString Node::plainFullName(const Node *relative) const
608 {
609     if (name_.isEmpty())
610         return QLatin1String("global");
611     if (isHeader())
612         return plainName();
613 
614     QStringList parts;
615     const Node *node = this;
616     while (node && !node->isHeader()) {
617         parts.prepend(node->plainName());
618         if (node->parent() == relative || node->parent()->name().isEmpty())
619             break;
620         node = node->parent();
621     }
622     return parts.join(QLatin1String("::"));
623 }
624 
625 /*!
626   Constructs and returns the node's fully qualified signature
627   by recursively ascending the parent links and prepending each
628   parent name + "::" to the plain signature. The return type is
629   not included.
630  */
plainSignature() const631 QString Node::plainSignature() const
632 {
633     if (name_.isEmpty())
634         return QLatin1String("global");
635 
636     QString fullName;
637     const Node *node = this;
638     while (node) {
639         fullName.prepend(node->signature(false, true));
640         if (node->parent()->name().isEmpty())
641             break;
642         fullName.prepend(QLatin1String("::"));
643         node = node->parent();
644     }
645     return fullName;
646 }
647 
648 /*!
649   Constructs and returns this node's full name. The full name is
650   often just the title(). When it is not the title, it is the
651   plainFullName().
652  */
fullName(const Node * relative) const653 QString Node::fullName(const Node *relative) const
654 {
655     if ((isTextPageNode() || isGroup()) && !title().isEmpty())
656         return title();
657     return plainFullName(relative);
658 }
659 
660 /*!
661   Try to match this node's type with one of the \a types.
662   If a match is found, return true. If no match is found,
663   return false.
664  */
match(const QVector<int> & types) const665 bool Node::match(const QVector<int> &types) const
666 {
667     for (int i = 0; i < types.size(); ++i) {
668         if (nodeType() == types.at(i))
669             return true;
670     }
671     return false;
672 }
673 
674 /*!
675   Sets this Node's Doc to \a doc. If \a replace is false and
676   this Node already has a Doc, and if this doc is not marked
677   with the \\reimp command, a warning is reported that the
678   existing Doc is being overridden, and it reports where the
679   previous Doc was found. If \a replace is true, the Doc is
680   replaced silently.
681  */
setDoc(const Doc & doc,bool replace)682 void Node::setDoc(const Doc &doc, bool replace)
683 {
684     if (!doc_.isEmpty() && !replace && !doc.isMarkedReimp()) {
685         doc.location().warning(tr("Overrides a previous doc"));
686         doc_.location().warning(tr("(The previous doc is here)"));
687     }
688     doc_ = doc;
689 }
690 
691 /*!
692   Construct a node with the given \a type and having the
693   given \a parent and \a name. The new node is added to the
694   parent's child list.
695  */
Node(NodeType type,Aggregate * parent,const QString & name)696 Node::Node(NodeType type, Aggregate *parent, const QString &name)
697     : nodeType_(type),
698       access_(Public),
699       safeness_(UnspecifiedSafeness),
700       pageType_(NoPageType),
701       status_(Active),
702       indexNodeFlag_(false),
703       relatedNonmember_(false),
704       hadDoc_(false),
705       parent_(parent),
706       sharedCommentNode_(nullptr),
707       name_(name)
708 {
709     if (parent_)
710         parent_->addChild(this);
711     outSubDir_ = Generator::outputSubdir();
712     if (operators_.isEmpty()) {
713         operators_.insert("++", "inc");
714         operators_.insert("--", "dec");
715         operators_.insert("==", "eq");
716         operators_.insert("!=", "ne");
717         operators_.insert("<<", "lt-lt");
718         operators_.insert(">>", "gt-gt");
719         operators_.insert("+=", "plus-assign");
720         operators_.insert("-=", "minus-assign");
721         operators_.insert("*=", "mult-assign");
722         operators_.insert("/=", "div-assign");
723         operators_.insert("%=", "mod-assign");
724         operators_.insert("&=", "bitwise-and-assign");
725         operators_.insert("|=", "bitwise-or-assign");
726         operators_.insert("^=", "bitwise-xor-assign");
727         operators_.insert("<<=", "bitwise-left-shift-assign");
728         operators_.insert(">>=", "bitwise-right-shift-assign");
729         operators_.insert("||", "logical-or");
730         operators_.insert("&&", "logical-and");
731         operators_.insert("()", "call");
732         operators_.insert("[]", "subscript");
733         operators_.insert("->", "pointer");
734         operators_.insert("->*", "pointer-star");
735         operators_.insert("+", "plus");
736         operators_.insert("-", "minus");
737         operators_.insert("*", "mult");
738         operators_.insert("/", "div");
739         operators_.insert("%", "mod");
740         operators_.insert("|", "bitwise-or");
741         operators_.insert("&", "bitwise-and");
742         operators_.insert("^", "bitwise-xor");
743         operators_.insert("!", "not");
744         operators_.insert("~", "bitwise-not");
745         operators_.insert("<=", "lt-eq");
746         operators_.insert(">=", "gt-eq");
747         operators_.insert("<", "lt");
748         operators_.insert(">", "gt");
749         operators_.insert("=", "assign");
750         operators_.insert(",", "comma");
751         operators_.insert("delete[]", "delete-array");
752         operators_.insert("delete", "delete");
753         operators_.insert("new[]", "new-array");
754         operators_.insert("new", "new");
755     }
756     setPageType(getPageType(type));
757     setGenus(getGenus(type));
758 }
759 
760 /*!
761   Determines the appropriate PageType value for the NodeType
762   value \a t and returns that PageType value.
763  */
getPageType(Node::NodeType t)764 Node::PageType Node::getPageType(Node::NodeType t)
765 {
766     switch (t) {
767     case Node::Namespace:
768     case Node::Class:
769     case Node::Struct:
770     case Node::Union:
771     case Node::HeaderFile:
772     case Node::Enum:
773     case Node::Function:
774     case Node::Typedef:
775     case Node::Property:
776     case Node::Variable:
777     case Node::QmlType:
778     case Node::QmlProperty:
779     case Node::QmlBasicType:
780     case Node::JsType:
781     case Node::JsProperty:
782     case Node::JsBasicType:
783     case Node::SharedComment:
784         return Node::ApiPage;
785     case Node::Example:
786         return Node::ExamplePage;
787     case Node::Page:
788     case Node::ExternalPage:
789         return Node::NoPageType;
790     case Node::Group:
791     case Node::Module:
792     case Node::QmlModule:
793     case Node::JsModule:
794     case Node::Collection:
795         return Node::OverviewPage;
796     case Node::Proxy:
797     default:
798         return Node::NoPageType;
799     }
800 }
801 
802 /*!
803   Determines the appropriate Genus value for the NodeType
804   value \a t and returns that Genus value. Note that this
805   function is called in the Node() constructor. It always
806   returns Node::CPP when \a t is Node::Function, which
807   means the FunctionNode() constructor must determine its
808   own Genus value separately, because class FunctionNode
809   is a subclass of Node.
810  */
getGenus(Node::NodeType t)811 Node::Genus Node::getGenus(Node::NodeType t)
812 {
813     switch (t) {
814     case Node::Enum:
815     case Node::Class:
816     case Node::Struct:
817     case Node::Union:
818     case Node::Module:
819     case Node::Typedef:
820     case Node::Property:
821     case Node::Variable:
822     case Node::Function:
823     case Node::Namespace:
824     case Node::HeaderFile:
825         return Node::CPP;
826     case Node::QmlType:
827     case Node::QmlModule:
828     case Node::QmlProperty:
829     case Node::QmlBasicType:
830         return Node::QML;
831     case Node::JsType:
832     case Node::JsModule:
833     case Node::JsProperty:
834     case Node::JsBasicType:
835         return Node::JS;
836     case Node::Page:
837     case Node::Group:
838     case Node::Example:
839     case Node::ExternalPage:
840         return Node::DOC;
841     case Node::Collection:
842     case Node::SharedComment:
843     case Node::Proxy:
844     default:
845         return Node::DontCare;
846     }
847 }
848 
849 /*! \fn QString Node::url() const
850   Returns the node's URL, which is the url of the documentation page
851   created for the node or the url of an external page if the node is
852   an ExternalPageNode. The url is used for generating a link to the
853   page the node represents.
854 
855   \sa Node::setUrl()
856  */
857 
858 /*! \fn void Node::setUrl(const QString &url)
859   Sets the node's URL to \a url, which is the url to the page that the
860   node represents. This function is only called when an index file is
861   read. In other words, a node's url is set when qdoc decides where its
862   page will be and what its name will be, which happens when qdoc writes
863   the index file for the module being documented.
864 
865   \sa QDocIndexFiles
866  */
867 
868 /*!
869   Returns this node's page type as a string, for use as an
870   attribute value in XML or HTML.
871  */
pageTypeString() const872 QString Node::pageTypeString() const
873 {
874     return pageTypeString(pageType_);
875 }
876 
877 /*!
878   Returns the page type \a t as a string, for use as an
879   attribute value in XML or HTML.
880  */
pageTypeString(PageType t)881 QString Node::pageTypeString(PageType t)
882 {
883     switch (t) {
884     case Node::AttributionPage:
885         return QLatin1String("attribution");
886     case Node::ApiPage:
887         return QLatin1String("api");
888     case Node::ArticlePage:
889         return QLatin1String("article");
890     case Node::ExamplePage:
891         return QLatin1String("example");
892     case Node::HowToPage:
893         return QLatin1String("howto");
894     case Node::OverviewPage:
895         return QLatin1String("overview");
896     case Node::TutorialPage:
897         return QLatin1String("tutorial");
898     case Node::FAQPage:
899         return QLatin1String("faq");
900     default:
901         return QLatin1String("article");
902     }
903 }
904 
905 /*!
906   Returns this node's type as a string for use as an
907   attribute value in XML or HTML.
908  */
nodeTypeString() const909 QString Node::nodeTypeString() const
910 {
911     if (isFunction()) {
912         const FunctionNode *fn = static_cast<const FunctionNode *>(this);
913         return fn->kindString();
914     }
915     return nodeTypeString(nodeType());
916 }
917 
918 /*!
919   Returns the node type \a t as a string for use as an
920   attribute value in XML or HTML.
921  */
nodeTypeString(NodeType t)922 QString Node::nodeTypeString(NodeType t)
923 {
924     switch (t) {
925     case Namespace:
926         return QLatin1String("namespace");
927     case Class:
928         return QLatin1String("class");
929     case Struct:
930         return QLatin1String("struct");
931     case Union:
932         return QLatin1String("union");
933     case HeaderFile:
934         return QLatin1String("header");
935     case Page:
936         return QLatin1String("page");
937     case Enum:
938         return QLatin1String("enum");
939     case Example:
940         return QLatin1String("example");
941     case ExternalPage:
942         return QLatin1String("external page");
943     case TypeAlias:
944         return QLatin1String("alias");
945     case Typedef:
946         return QLatin1String("typedef");
947     case Function:
948         return QLatin1String("function");
949     case Property:
950         return QLatin1String("property");
951     case Proxy:
952         return QLatin1String("proxy");
953     case Variable:
954         return QLatin1String("variable");
955     case Group:
956         return QLatin1String("group");
957     case Module:
958         return QLatin1String("module");
959 
960     case QmlType:
961         return QLatin1String("QML type");
962     case QmlBasicType:
963         return QLatin1String("QML basic type");
964     case QmlModule:
965         return QLatin1String("QML module");
966     case QmlProperty:
967         return QLatin1String("QML property");
968 
969     case JsType:
970         return QLatin1String("JS type");
971     case JsBasicType:
972         return QLatin1String("JS basic type");
973     case JsModule:
974         return QLatin1String("JS module");
975     case JsProperty:
976         return QLatin1String("JS property");
977 
978     case SharedComment:
979         return QLatin1String("shared comment");
980     case Collection:
981         return QLatin1String("collection");
982     default:
983         break;
984     }
985     return QString();
986 }
987 
988 /*!
989   Set the page type according to the string \a t.
990  */
setPageType(const QString & t)991 void Node::setPageType(const QString &t)
992 {
993     if ((t == "API") || (t == "api"))
994         pageType_ = ApiPage;
995     else if (t == "howto")
996         pageType_ = HowToPage;
997     else if (t == "overview")
998         pageType_ = OverviewPage;
999     else if (t == "tutorial")
1000         pageType_ = TutorialPage;
1001     else if (t == "faq")
1002         pageType_ = FAQPage;
1003     else if (t == "article")
1004         pageType_ = ArticlePage;
1005     else if (t == "example")
1006         pageType_ = ExamplePage;
1007 }
1008 
1009 /*! Converts the boolean value \a b to an enum representation
1010   of the boolean type, which includes an enum value for the
1011   \e {default value} of the item, i.e. true, false, or default.
1012  */
toFlagValue(bool b)1013 Node::FlagValue Node::toFlagValue(bool b)
1014 {
1015     return b ? FlagValueTrue : FlagValueFalse;
1016 }
1017 
1018 /*!
1019   Converts the enum \a fv back to a boolean value.
1020   If \a fv is neither the true enum value nor the
1021   false enum value, the boolean value returned is
1022   \a defaultValue.
1023 
1024   Note that runtimeDesignabilityFunction() should be called
1025   first. If that function returns the name of a function, it
1026   means the function must be called at runtime to determine
1027   whether the property is Designable.
1028  */
fromFlagValue(FlagValue fv,bool defaultValue)1029 bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
1030 {
1031     switch (fv) {
1032     case FlagValueTrue:
1033         return true;
1034     case FlagValueFalse:
1035         return false;
1036     default:
1037         return defaultValue;
1038     }
1039 }
1040 
1041 /*!
1042   This function creates a pair that describes a link.
1043   The pair is composed from \a link and \a desc. The
1044   \a linkType is the map index the pair is filed under.
1045  */
setLink(LinkType linkType,const QString & link,const QString & desc)1046 void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
1047 {
1048     QPair<QString, QString> linkPair;
1049     linkPair.first = link;
1050     linkPair.second = desc;
1051     linkMap_[linkType] = linkPair;
1052 }
1053 
1054 /*!
1055     Sets the information about the project and version a node was introduced
1056     in, unless the version is lower than the 'ignoresince.<project>'
1057     configuration variable.
1058  */
setSince(const QString & since)1059 void Node::setSince(const QString &since)
1060 {
1061     QStringList parts = since.split(QLatin1Char(' '));
1062     QString project;
1063     if (parts.size() > 1)
1064         project = Config::dot + parts.first();
1065 
1066     QVersionNumber cutoff =
1067             QVersionNumber::fromString(Config::instance().getString(CONFIG_IGNORESINCE + project))
1068                     .normalized();
1069 
1070     if (!cutoff.isNull() && QVersionNumber::fromString(parts.last()).normalized() < cutoff)
1071         return;
1072 
1073     since_ = parts.join(QLatin1Char(' '));
1074 }
1075 
1076 /*!
1077   Returns a string representing the access specifier.
1078  */
accessString() const1079 QString Node::accessString() const
1080 {
1081     switch (access_) {
1082     case Protected:
1083         return QLatin1String("protected");
1084     case Private:
1085         return QLatin1String("private");
1086     case Public:
1087     default:
1088         break;
1089     }
1090     return QLatin1String("public");
1091 }
1092 
1093 /*!
1094   Extract a class name from the type \a string and return it.
1095  */
extractClassName(const QString & string) const1096 QString Node::extractClassName(const QString &string) const
1097 {
1098     QString result;
1099     for (int i = 0; i <= string.size(); ++i) {
1100         QChar ch;
1101         if (i != string.size())
1102             ch = string.at(i);
1103 
1104         QChar lower = ch.toLower();
1105         if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) || ch.digitValue() >= 0
1106             || ch == QLatin1Char('_') || ch == QLatin1Char(':')) {
1107             result += ch;
1108         } else if (!result.isEmpty()) {
1109             if (result != QLatin1String("const"))
1110                 return result;
1111             result.clear();
1112         }
1113     }
1114     return result;
1115 }
1116 
1117 /*!
1118   Returns the thread safeness value for whatever this node
1119   represents. But if this node has a parent and the thread
1120   safeness value of the parent is the same as the thread
1121   safeness value of this node, what is returned is the
1122   value \c{UnspecifiedSafeness}. Why?
1123  */
threadSafeness() const1124 Node::ThreadSafeness Node::threadSafeness() const
1125 {
1126     if (parent_ && safeness_ == parent_->inheritedThreadSafeness())
1127         return UnspecifiedSafeness;
1128     return safeness_;
1129 }
1130 
1131 /*!
1132   If this node has a parent, the parent's thread safeness
1133   value is returned. Otherwise, this node's thread safeness
1134   value is returned. Why?
1135  */
inheritedThreadSafeness() const1136 Node::ThreadSafeness Node::inheritedThreadSafeness() const
1137 {
1138     if (parent_ && safeness_ == UnspecifiedSafeness)
1139         return parent_->inheritedThreadSafeness();
1140     return safeness_;
1141 }
1142 
1143 /*!
1144   If this node is a QML or JS type node, return a pointer to
1145   it. If it is a child of a QML or JS type node, return the
1146   pointer to its parent QMLor JS type node. Otherwise return
1147   0;
1148  */
qmlTypeNode()1149 QmlTypeNode *Node::qmlTypeNode()
1150 {
1151     if (isQmlNode() || isJsNode()) {
1152         Node *n = this;
1153         while (n && !(n->isQmlType() || n->isJsType()))
1154             n = n->parent();
1155         if (n && (n->isQmlType() || n->isJsType()))
1156             return static_cast<QmlTypeNode *>(n);
1157     }
1158     return nullptr;
1159 }
1160 
1161 /*!
1162   If this node is a QML node, find its QML class node,
1163   and return a pointer to the C++ class node from the
1164   QML class node. That pointer will be null if the QML
1165   class node is a component. It will be non-null if
1166   the QML class node is a QML element.
1167  */
declarativeCppNode()1168 ClassNode *Node::declarativeCppNode()
1169 {
1170     QmlTypeNode *qcn = qmlTypeNode();
1171     if (qcn)
1172         return qcn->classNode();
1173     return nullptr;
1174 }
1175 
1176 /*!
1177   Returns \c true if the node's status is \c Internal, or if
1178   its parent is a class with \c Internal status.
1179  */
isInternal() const1180 bool Node::isInternal() const
1181 {
1182     if (status() == Internal)
1183         return true;
1184     if (parent() && parent()->status() == Internal)
1185         return true;
1186     return false;
1187 }
1188 
1189 /*! \fn void Node::markInternal()
1190   Sets the node's access to Private and its status to Internal.
1191  */
1192 
1193 /*!
1194   Returns a pointer to the root of the Tree this node is in.
1195  */
root() const1196 Aggregate *Node::root() const
1197 {
1198     if (parent() == nullptr)
1199         return (this->isAggregate() ? static_cast<Aggregate *>(const_cast<Node *>(this)) : nullptr);
1200     Aggregate *t = parent();
1201     while (t->parent() != nullptr)
1202         t = t->parent();
1203     return t;
1204 }
1205 
1206 /*!
1207   Returns a pointer to the Tree this node is in.
1208  */
tree() const1209 Tree *Node::tree() const
1210 {
1211     return root()->tree();
1212 }
1213 
1214 /*!
1215   Sets the node's declaration location, its definition
1216   location, or both, depending on the suffix of the file
1217   name from the file path in location \a t.
1218  */
setLocation(const Location & t)1219 void Node::setLocation(const Location &t)
1220 {
1221     QString suffix = t.fileSuffix();
1222     if (suffix == "h")
1223         declLocation_ = t;
1224     else if (suffix == "cpp")
1225         defLocation_ = t;
1226     else {
1227         declLocation_ = t;
1228         defLocation_ = t;
1229     }
1230 }
1231 
1232 /*!
1233   Returns true if this node is sharing a comment and the
1234   shared comment is not empty.
1235  */
hasSharedDoc() const1236 bool Node::hasSharedDoc() const
1237 {
1238     return (sharedCommentNode_ && sharedCommentNode_->hasDoc());
1239 }
1240 
1241 /*!
1242   Returns the CPP node's qualified name by prepending the
1243   namespaces name + "::" if there isw a namespace.
1244  */
qualifyCppName()1245 QString Node::qualifyCppName()
1246 {
1247     if (parent_ && parent_->isNamespace() && !parent_->name().isEmpty())
1248         return parent_->name() + "::" + name_;
1249     return name_;
1250 }
1251 
1252 /*!
1253   Return the name of this node qualified with the parent name
1254   and "::" if there is a parent name.
1255  */
qualifyWithParentName()1256 QString Node::qualifyWithParentName()
1257 {
1258     if (parent_ && !parent_->name().isEmpty())
1259         return parent_->name() + "::" + name_;
1260     return name_;
1261 }
1262 
1263 /*!
1264   Returns the QML node's qualified name by stripping off the
1265   "QML:" if present and prepending the logical module name.
1266  */
qualifyQmlName()1267 QString Node::qualifyQmlName()
1268 {
1269     QString qualifiedName = name_;
1270     if (name_.startsWith(QLatin1String("QML:")))
1271         qualifiedName = name_.mid(4);
1272     qualifiedName = logicalModuleName() + "::" + name_;
1273     return qualifiedName;
1274 }
1275 
1276 /*!
1277   Returns the QML node's name after stripping off the
1278   "QML:" if present.
1279  */
unqualifyQmlName()1280 QString Node::unqualifyQmlName()
1281 {
1282     QString qmlTypeName = name_.toLower();
1283     if (qmlTypeName.startsWith(QLatin1String("qml:")))
1284         qmlTypeName = qmlTypeName.mid(4);
1285     return qmlTypeName;
1286 }
1287 
1288 /*!
1289   Returns \c true if the node is a class node or a QML type node
1290   that is marked as being a wrapper class or wrapper QML type,
1291   or if it is a member of a wrapper class or type.
1292  */
isWrapper() const1293 bool Node::isWrapper() const
1294 {
1295     return (parent_ ? parent_->isWrapper() : false);
1296 }
1297 
1298 /*!
1299   Construct the full document name for this node and return it.
1300  */
fullDocumentName() const1301 QString Node::fullDocumentName() const
1302 {
1303     QStringList pieces;
1304     const Node *n = this;
1305 
1306     do {
1307         if (!n->name().isEmpty())
1308             pieces.insert(0, n->name());
1309 
1310         if ((n->isQmlType() || n->isJsType()) && !n->logicalModuleName().isEmpty()) {
1311             pieces.insert(0, n->logicalModuleName());
1312             break;
1313         }
1314 
1315         if (n->isTextPageNode())
1316             break;
1317 
1318         // Examine the parent if the node is a member
1319         if (!n->parent() || n->isRelatedNonmember())
1320             break;
1321 
1322         n = n->parent();
1323     } while (true);
1324 
1325     // Create a name based on the type of the ancestor node.
1326     QString concatenator = "::";
1327     if (n->isQmlType() || n->isJsType())
1328         concatenator = QLatin1Char('.');
1329 
1330     if (n->isTextPageNode())
1331         concatenator = QLatin1Char('#');
1332 
1333     return pieces.join(concatenator);
1334 }
1335 
1336 /*!
1337   Returns the \a str as an NCName, which means the name can
1338   be used as the value of an \e id attribute. Search for NCName
1339   on the internet for details of what can be an NCName.
1340  */
cleanId(const QString & str)1341 QString Node::cleanId(const QString &str)
1342 {
1343     QString clean;
1344     QString name = str.simplified();
1345 
1346     if (name.isEmpty())
1347         return clean;
1348 
1349     name = name.replace("::", "-");
1350     name = name.replace(QLatin1Char(' '), QLatin1Char('-'));
1351     name = name.replace("()", "-call");
1352 
1353     clean.reserve(name.size() + 20);
1354     if (!str.startsWith("id-"))
1355         clean = "id-";
1356     const QChar c = name[0];
1357     const uint u = c.unicode();
1358 
1359     if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9')) {
1360         clean += c;
1361     } else if (u == '~') {
1362         clean += "dtor.";
1363     } else if (u == '_') {
1364         clean += "underscore.";
1365     } else {
1366         clean += QLatin1Char('a');
1367     }
1368 
1369     for (int i = 1; i < name.length(); i++) {
1370         const QChar c = name[i];
1371         const uint u = c.unicode();
1372         if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9') || u == '-'
1373             || u == '_' || u == '.') {
1374             clean += c;
1375         } else if (c.isSpace() || u == ':') {
1376             clean += QLatin1Char('-');
1377         } else if (u == '!') {
1378             clean += "-not";
1379         } else if (u == '&') {
1380             clean += "-and";
1381         } else if (u == '<') {
1382             clean += "-lt";
1383         } else if (u == '=') {
1384             clean += "-eq";
1385         } else if (u == '>') {
1386             clean += "-gt";
1387         } else if (u == '#') {
1388             clean += "-hash";
1389         } else if (u == '(') {
1390             clean += QLatin1Char('-');
1391         } else if (u == ')') {
1392             clean += QLatin1Char('-');
1393         } else {
1394             clean += QLatin1Char('-');
1395             clean += QString::number((int)u, 16);
1396         }
1397     }
1398     return clean;
1399 }
1400 
1401 /*!
1402   Find the module (Qt Core, Qt GUI, etc.) to which the class belongs.
1403   We do this by obtaining the full path to the header file's location
1404   and examine everything between "src/" and the filename. This is
1405   semi-dirty because we are assuming a particular directory structure.
1406 
1407   This function is only really useful if the class's module has not
1408   been defined in the header file with a QT_MODULE macro or with an
1409   \inmodule command in the documentation.
1410  */
physicalModuleName() const1411 QString Node::physicalModuleName() const
1412 {
1413     if (!physicalModuleName_.isEmpty())
1414         return physicalModuleName_;
1415 
1416     QString path = location().filePath();
1417     QString pattern = QString("src") + QDir::separator();
1418     int start = path.lastIndexOf(pattern);
1419 
1420     if (start == -1)
1421         return QString();
1422 
1423     QString moduleDir = path.mid(start + pattern.size());
1424     int finish = moduleDir.indexOf(QDir::separator());
1425 
1426     if (finish == -1)
1427         return QString();
1428 
1429     QString physicalModuleName = moduleDir.left(finish);
1430 
1431     if (physicalModuleName == QLatin1String("corelib"))
1432         return QLatin1String("QtCore");
1433     else if (physicalModuleName == QLatin1String("uitools"))
1434         return QLatin1String("QtUiTools");
1435     else if (physicalModuleName == QLatin1String("gui"))
1436         return QLatin1String("QtGui");
1437     else if (physicalModuleName == QLatin1String("network"))
1438         return QLatin1String("QtNetwork");
1439     else if (physicalModuleName == QLatin1String("opengl"))
1440         return QLatin1String("QtOpenGL");
1441     else if (physicalModuleName == QLatin1String("svg"))
1442         return QLatin1String("QtSvg");
1443     else if (physicalModuleName == QLatin1String("sql"))
1444         return QLatin1String("QtSql");
1445     else if (physicalModuleName == QLatin1String("qtestlib"))
1446         return QLatin1String("QtTest");
1447     else if (moduleDir.contains("webkit"))
1448         return QLatin1String("QtWebKit");
1449     else if (physicalModuleName == QLatin1String("xml"))
1450         return QLatin1String("QtXml");
1451     else
1452         return QString();
1453 }
1454 
1455 /*! \fn Node *Node::clone(Aggregate *parent)
1456 
1457   When reimplemented in a subclass, this function creates a
1458   clone of this node on the heap and makes the clone a child
1459   of \a parent. A pointer to the clone is returned.
1460 
1461   Here in the base class, this function does nothing and returns
1462   nullptr.
1463  */
1464 
1465 /*! \fn NodeType Node::nodeType() const
1466   Returns this node's type.
1467 
1468   \sa NodeType
1469 */
1470 
1471 /*! \fn Genus Node::genus() const
1472   Returns this node's Genus.
1473 
1474   \sa Genus
1475 */
1476 
1477 /*! void Node::setGenus(Genus t)
1478   Sets this node's Genus to \a t.
1479 */
1480 
1481 /*! \fn PageType Node::pageType() const
1482   Returns this node's page type.
1483 
1484   \sa PageType
1485 */
1486 
1487 /*! \fn void Node::setPageType(PageType t)
1488   Sets this node's page type to \a t.
1489 
1490   \sa PageType
1491 */
1492 
1493 /*! \fn  QString Node::signature(bool values, bool noReturnType, bool templateParams) const
1494 
1495   If this node is a FunctionNode, this function returns the function's
1496   signature, including default values if \a values is \c true,
1497   function's return type if \a noReturnType is \c false, and
1498   prefixed with 'template <parameter_list>' for function templates
1499   if templateParams is \true.
1500 
1501   If this node is not a FunctionNode, this function returns plainName().
1502 */
1503 
1504 /*! \fn const QString &Node::fileNameBase() const
1505   Returns the node's file name base string, which is built once, when
1506   Generator::fileBase() is called and stored in the Node.
1507 */
1508 
1509 /*! \fn bool Node::hasFileNameBase() const
1510   Returns true if the node's file name base has been set.
1511 
1512   \sa Node::fileNameBase()
1513 */
1514 
1515 /*! \fn void Node::setFileNameBase(const QString &t)
1516   Sets the node's file name base to \a t. Only called by
1517   Generator::fileBase().
1518 */
1519 
1520 /*! \fn void Node::setAccess(Access t)
1521   Sets the node's access type to \a t.
1522 
1523   \sa Access
1524 */
1525 
1526 /*! \fn void Node::setStatus(Status t)
1527   Sets the node's status to \a t, except that once
1528   the node's status has been set to \c Obsolete, it
1529   can't be reset to \c Deprecated.
1530 
1531   \sa Status
1532 */
1533 
1534 /*! \fn void Node::setThreadSafeness(ThreadSafeness t)
1535   Sets the node's thread safeness to \a t.
1536 
1537   \sa ThreadSafeness
1538 */
1539 
1540 /*! \fn void Node::setPhysicalModuleName(const QString &name)
1541   Sets the node's physical module \a name.
1542 */
1543 
1544 /*! \fn void Node::setTemplateStuff(const QString &t)
1545   If the node represents a template class or member, this function
1546   is called to save the text \a t of the template clause so it can
1547   be reconstructed for the generated documentation.
1548 */
1549 
1550 /*! \fn void Node::setReconstitutedBrief(const QString &t)
1551   When reading an index file, this function is called with the
1552   reconstituted brief clause \a t to set the node's brief clause.
1553   I think this is needed for linking to something in the brief clause.
1554 */
1555 
1556 /*! \fn void Node::setParent(Aggregate *n)
1557   Sets the node's parent pointer to \a n. Such a thing
1558   is not lightly done. All the calls to this function
1559   are in other member functions of Node subclasses. See
1560   the code in node.cpp to understand when this function
1561   can be called safely and why it is called.
1562 */
1563 
1564 /*! \fn void Node::setIndexNodeFlag(bool isIndexNode = true)
1565   Sets a flag in this Node that indicates the node was created
1566   for something in an index file. This is important to know
1567   because an index node is not to be documented in the current
1568   module. When the index flag is set, it means the Node
1569   represents something in another module, and it will be
1570   documented in that module's documentation.
1571 */
1572 
1573 /*! \fn void Node::setRelatedNonmember(bool b)
1574   Sets a flag in the node indicating whether this node is a related nonmember
1575   of something. This function is called when the \c relates command is seen.
1576  */
1577 
1578 /*! \fn void Node::setOutputFileName(const QString &f)
1579   In a PageNode, this function sets the node's output file name to \a f.
1580   In a non-PageNode, this function does nothing.
1581  */
1582 
1583 /*! \fn void Node::addMember(Node *node)
1584   In a CollectionNode, this function adds \a node to the collection
1585   node's members list. It does nothing if this node is not a CollectionNode.
1586  */
1587 
1588 /*! \fn bool Node::hasMembers() const
1589   Returns \c true if this is a CollectionNode and its members list
1590   is not empty. Otherwise it returns \c false.
1591  */
1592 
1593 /*! \fn bool Node::hasNamespaces() const
1594   Returns \c true if this is a CollectionNode and its members list
1595   contains namespace nodes. Otherwise it returns \c false.
1596  */
1597 
1598 /*! \fn bool Node::hasClasses() const
1599   Returns \c true if this is a CollectionNode and its members list
1600   contains class nodes. Otherwise it returns \c false.
1601  */
1602 
1603 /*! \fn void Node::setAbstract(bool b)
1604   If this node is a ClassNode or a QmlTypeNode, the node's abstract flag
1605   data member is set to \a b.
1606  */
1607 
1608 /*! \fn void Node::setWrapper()
1609   If this node is a ClassNode or a QmlTypeNode, the node's wrapper flag
1610   data member is set to \c true.
1611  */
1612 
1613 /*! \fn void Node::getMemberNamespaces(NodeMap& out)
1614   If this is a CollectionNode, \a out is loaded with all the collection
1615   members that are namespaces.
1616  */
1617 
1618 /*! \fn void getMemberClasses(NodeMap& out) const { }
1619   If this is a CollectionNode, \a out is loaded with all the collection
1620   members that are classes.
1621  */
1622 
1623 /*! \fn void Node::setDataType(const QString &dataType)
1624   If this node is a PropertyNode or a QmlPropertyNode, its
1625   data type data member is set to \a dataType. Otherwise,
1626   this function does nothing.
1627  */
1628 
1629 /*! \fn bool Node::wasSeen() const
1630   Returns the \c seen flag data member of this node if it is a NamespaceNode
1631   or a CollectionNode. Otherwise it returns \c false. If \c true is returned,
1632   it means that the location where the namespace or collection is to be
1633   documented has been found.
1634  */
1635 
1636 /*! \fn void appendGroupName(const QString &t)
1637   If this node is a PageNode, the group name \a t is appended to the node's
1638   list of group names. It is not clear to me what this list of group names
1639   is used for, but it is written to the index file, and it is used in the
1640   navigation bar.
1641  */
1642 
1643 /*! \fn QString Node::element() const
1644   If this node is a QmlPropertyNode or a FunctionNode, this function
1645   returns the name of the parent node. Otherwise it returns an empty
1646   string.
1647  */
1648 
1649 /*! \fn void Node::setNoAutoList(bool b)
1650   If this node is a PageNode, the node's \c {no autolist} flag is set to \a b.
1651   Otherwise the function does nothing.
1652  */
1653 
1654 /*! \fn bool Node::docMustBeGenerated() const
1655   This function is called to perform a test to decide if the node must have
1656   documentation generated. In the Node base class, it always returns \c false.
1657 
1658   In the ProxyNode class it always returns \c true. There aren't many proxy
1659   nodes, but when one appears, it must generate documentation. In the overrides
1660   in NamespaceNode and ClassNode, a meaningful test is performed to decide if
1661   documentation must be generated.
1662  */
1663 
1664 /*! \fn QString Node::title() const
1665   Returns a string that can be used to print a title in the documentation for
1666   whatever this Node is. In the Node base class, the node's name() is returned.
1667   In a PageNode, the function returns the title data member. In a HeaderNode,
1668   if the title() is empty, the name() is returned.
1669  */
1670 
1671 /*! \fn QString Node::subtitle() const { return QString(); }
1672   Returns a string that can be used to print a subtitle in the documentation for
1673   whatever this Node is. In the Node base class, the empty string is returned.
1674   In a PageNode, the function returns the subtitle data member. In a HeaderNode,
1675   the subtitle data member is returned.
1676  */
1677 
1678 /*! \fn QString Node::fullTitle() const
1679   Returns a string that can be used as the full title for the documentation of
1680   this node. In this base class, the name() is returned. In a PageNode, title()
1681   is returned. In a HeaderNode, if the title() is empty, the name() is returned.
1682   If the title() is not empty then name-title is returned. In a CollectionNode,
1683   the title() is returned.
1684  */
1685 
1686 /*! \fn bool Node::setTitle(const QString &title)
1687   Sets the node's \a title, which is used for the title of
1688   the documentation page, if one is generated for this node.
1689   Returns \c true if the title is set. In this base class,
1690   there is no title string stored, so in the base class,
1691   nothing happens and \c false is returned. The override in
1692   the PageNode class is where the title is set.
1693  */
1694 
1695 /*! \fn bool Node::setSubtitle(const QString &subtitle)
1696   Sets the node's \a subtitle, which is used for the subtitle
1697   of the documentation page, if one is generated for this node.
1698   Returns \c true if the subtitle is set. In this base class,
1699   there is no subtitle string stored, so in the base class,
1700   nothing happens and \c false is returned. The override in
1701   the PageNode and HeaderNode classes is where the subtitle is
1702   set.
1703  */
1704 
1705 /*! \fn void Node::markDefault()
1706   If this node is a QmlPropertyNode, it is marked as the default property.
1707   Otherwise the function does nothing.
1708  */
1709 
1710 /*! \fn void Node::markReadOnly(bool flag)
1711   If this node is a QmlPropertyNode, then the property's read-only
1712   flag is set to \a flag.
1713  */
1714 
1715 /*! \fn Aggregate *Node::parent() const
1716   Returns the node's paprent pointer.
1717 */
1718 
1719 /*! \fn const QString &Node::name() const
1720   Returns the node's name data member.
1721 */
1722 
1723 /*! \fn QString Node::nameForLists() const
1724   If this node is a PageNode or a HeaderNode, title() is returned.
1725   Otherwise name() is returned.
1726  */
1727 
1728 /*! \fn QString Node::outputFileName() const
1729   If this node is a PageNode, the name of the output file that will be
1730   generated for the node is returned. Otherwise an empty string is returned.
1731  */
1732 
1733 /*! \fn QString Node::obsoleteLink() const
1734   If this node is a ClassNode or a QmlTypeNode, the link to the obsolete members
1735   page is returned. Otherwise an empty string is returned.
1736  */
1737 
1738 /*! \fn void Node::setObsoleteLink(const QString &t)
1739   If this node is a ClassNode or a QmlTypeNode, the link to the obsolete members
1740   page is set to \a t. Otherwise the function does nothing.
1741  */
1742 
1743 /*! \fn void Node::setQtVariable(const QString &v)
1744   If this node is a CollectionNode, its QT variable is set to \a v.
1745   Otherwise the function does nothing. I don't know what the QT variable
1746   is used for.
1747  */
1748 
1749 /*! \fn QString Node::qtVariable() const
1750   If this node is a CollectionNode, its QT variable is returned.
1751   Otherwise an empty string is returned. I don't know what the QT
1752   variable is used for.
1753  */
1754 
1755 /*! \fn bool Node::hasTag(const QString &t) const
1756   If this node is a FunctionNode, the function returns \c true if
1757   the function has the tag \a t. Otherwise the function returns
1758   \c false. I don't know what the tag is used for.
1759  */
1760 
1761 /*! \fn const QMap<LinkType, QPair<QString, QString> > &Node::links() const
1762   Returns a reference to this node's link map. The link map should
1763   probably be moved to the PageNode, because it contains links to the
1764   start page, next page, previous page, and contents page, and these
1765   are only used in PageNode, I think.
1766  */
1767 
1768 /*! \fn Access Node::access() const
1769   Returns the node's Access setting, which can be \c Public,
1770   \c Protected, or \c Private.
1771  */
1772 
1773 /*! \fn const Location& Node::declLocation() const
1774   Returns the Location where this node's declaration was seen.
1775   Normally the declaration location is in an \e include file.
1776   The declaration location is used in qdoc error/warning messages
1777   about the declaration.
1778  */
1779 
1780 /*! \fn const Location& Node::defLocation() const
1781   Returns the Location where this node's dedefinition was seen.
1782   Normally the definition location is in a \e .cpp file.
1783   The definition location is used in qdoc error/warning messages
1784   when the error is discovered at the location of the definition,
1785   although the way to correct the problem often requires changing
1786   the declaration.
1787  */
1788 
1789 /*! \fn const Location& Node::location() const
1790   If this node's definition location is empty, this function
1791   returns this node's declaration location. Otherwise it
1792   returns the definition location.
1793 
1794   \sa Location
1795  */
1796 
1797 /*! \fn const Doc &Node::doc() const
1798   Returns a reference to the node's Doc data member.
1799 
1800   \sa Doc
1801  */
1802 
1803 /*! \fn bool Node::hasDoc() const
1804   Returns \c true if the node has documentation, i.e. if its Doc
1805   data member is not empty.
1806 
1807   \sa Doc
1808  */
1809 
1810 /*! \fn Status Node::status() const
1811   Returns the node's status value.
1812 
1813   \sa Status
1814  */
1815 
1816 /*! \fn QString Node::since() const
1817   Returns the node's since string, which can be empty.
1818  */
1819 
1820 /*! \fn QString Node::templateStuff() const
1821   Returns the node's template parameters string, if this node
1822   represents a templated element.
1823  */
1824 
1825 /*! \fn const QString &Node::reconstitutedBrief() const
1826   Returns the node's reconstituted brief data member.
1827  */
1828 
1829 /*! \fn bool Node::isSharingComment() const
1830   This function returns \c true if the node is sharing a comment
1831   with other nodes. For example, multiple functions can be documented
1832   with a single qdoc comment by listing the \c {\\fn} signatures for
1833   all the functions in the single qdoc comment.
1834  */
1835 
1836 /*! \fn QString Node::qmlTypeName() const
1837   If this is a QmlPropertyNode or a FunctionNode representing a QML
1838   or javascript methos, this function returns the qmlTypeName() of
1839   the parent() node. Otherwise it returns the name data member.
1840  */
1841 
1842 /*! \fn QString Node::qmlFullBaseName() const
1843   If this is a QmlTypeNode, this function returns the QML full
1844   base name. Otherwise it returns an empty string.
1845  */
1846 
1847 /*! \fn QString Node::logicalModuleName() const
1848   If this is a CollectionNode, this function returns the logical
1849   module name. Otherwise it returns an empty string.
1850  */
1851 
1852 /*! \fn QString Node::logicalModuleVersion() const
1853   If this is a CollectionNode, this function returns the logical
1854   module version number. Otherwise it returns an empty string.
1855  */
1856 
1857 /*! \fn QString Node::logicalModuleIdentifier() const
1858   If this is a CollectionNode, this function returns the logical
1859   module identifier. Otherwise it returns an empty string.
1860  */
1861 
1862 /*! \fn void Node::setLogicalModuleInfo(const QString &arg)
1863   If this node is a CollectionNode, this function splits \a arg
1864   on the blank character to get a logical module name and version
1865   number. If the version number is present, it splits the version
1866   number on the '.' character to get a major version number and a
1867   minor version number. If the version number is present, both the
1868   major and minor version numbers should be there, but the minor
1869   version number is not absolutely necessary.
1870 
1871   The strings are stored in the appropriate data members for use
1872   when the QML or javascript module page is generated.
1873  */
1874 
1875 /*! \fn void Node::setLogicalModuleInfo(const QStringList &info)
1876   If this node is a CollectionNode, this function accepts the
1877   logical module \a info as a string list. If the logical module
1878   info contains the version number, it splits the version number
1879   on the '.' character to get the major and minor version numbers.
1880   Both major and minor version numbers should be provided, but
1881   the minor version number is not strictly necessary.
1882 
1883   The strings are stored in the appropriate data members for use
1884   when the QML or javascript module page is generated. This overload
1885   of the function is called when qdoc is reading an index file.
1886  */
1887 
1888 /*! \fn CollectionNode *Node::logicalModule() const
1889   If this is a QmlTypeNode, a pointer to its QML module is returned,
1890   which is a pointer to a CollectionNode. Otherwise the \c nullptr
1891   is returned.
1892  */
1893 
1894 /*! \fn void Node::setQmlModule(CollectionNode *t)
1895   If this is a QmlTypeNode, this function sets the QML type's QML module
1896   pointer to the CollectionNode \a t. Otherwise the function does nothing.
1897  */
1898 
1899 /*! \fn ClassNode *Node::classNode()
1900   If this is a QmlTypeNode, this function returns the pointer to
1901   the C++ ClassNode that this QML type represents. Otherwise the
1902   \c nullptr is returned.
1903  */
1904 
1905 /*! \fn void Node::setClassNode(ClassNode *cn)
1906   If this is a QmlTypeNode, this function sets the C++ class node
1907   to \a cn. The C++ ClassNode is the C++ implementation of the QML
1908   type.
1909  */
1910 
1911 /*! \fn const QString &Node::outputSubdirectory() const
1912   Returns the node's output subdirector, which is the subdirectory
1913   of the output directory where the node's documentation file is
1914   written.
1915  */
1916 
1917 /*! \fn void Node::setOutputSubdirectory(const QString &t)
1918   Sets the node's output subdirectory to \a t. This is the subdirector
1919   of the output directory where the node's documentation file will be
1920   written.
1921  */
1922 
1923 /*! \fn NodeType Node::goal(const QString &t)
1924   When a square-bracket parameter is used in a qdoc command, this
1925   function might be called to convert the text string \a t obtained
1926   from inside the square brackets to be a Goal value, which is returned.
1927 
1928   \sa Goal
1929  */
1930 
1931 /*!
1932   \class Aggregate
1933  */
1934 
1935 /*! \fn Aggregate::Aggregate(NodeType type, Aggregate *parent, const QString &name)
1936   The constructor should never be called directly. It is only called
1937   by the constructors of subclasses of Aggregate. Those constructors
1938   pass the node \a type they want to create, the \a parent of the new
1939   node, and its \a name.
1940  */
1941 
1942 /*!
1943   The destructor calls delete for each child of this Aggregate
1944   that has this Aggregate as its parent. A child node that has
1945   some other Aggregate as its parent is deleted by that
1946   Aggregate's destructor. This is a fail-safe test.
1947 
1948   The destructor no longer deletes the collection of children
1949   by calling qDeleteAll() because the child list can contain
1950   pointers to children that have some other Aggregate as their
1951   parent. This is because of how the \e{\\relates} command is
1952   processed. An Aggregate can have a pointer to, for example,
1953   a FunctionNode in its child list, but that FunctionNode has
1954   a differen Aggregate as its parent because a \e{\\relates}
1955   command was used to relate it to that parent. In that case,
1956   the other Aggregate's destructor must delete that node.
1957 
1958   \note This function is the \b only place where delete is
1959   called to delete any subclass of Node.
1960 
1961   \note This strategy depends on the node tree being destroyed
1962   by calling delete on the root node of the tree. This happens
1963   in the destructor of class Tree.
1964  */
~Aggregate()1965 Aggregate::~Aggregate()
1966 {
1967     enumChildren_.clear();
1968     nonfunctionMap_.clear();
1969     functionMap_.clear();
1970     for (int i = 0; i < children_.size(); ++i) {
1971         if ((children_[i] != nullptr) && (children_[i]->parent() == this))
1972             delete children_[i];
1973         children_[i] = nullptr;
1974     }
1975     children_.clear();
1976 }
1977 
1978 /*!
1979   If \a genus is \c{Node::DontCare}, find the first node in
1980   this node's child list that has the given \a name. If this
1981   node is a QML type, be sure to also look in the children
1982   of its property group nodes. Return the matching node or 0.
1983 
1984   If \a genus is either \c{Node::CPP} or \c {Node::QML}, then
1985   find all this node's children that have the given \a name,
1986   and return the one that satisfies the \a genus requirement.
1987  */
findChildNode(const QString & name,Node::Genus genus,int findFlags) const1988 Node *Aggregate::findChildNode(const QString &name, Node::Genus genus, int findFlags) const
1989 {
1990     if (genus == Node::DontCare) {
1991         Node *node = nonfunctionMap_.value(name);
1992         if (node)
1993             return node;
1994     } else {
1995         NodeList nodes = nonfunctionMap_.values(name);
1996         if (!nodes.isEmpty()) {
1997             for (int i = 0; i < nodes.size(); ++i) {
1998                 Node *node = nodes.at(i);
1999                 if (genus == node->genus()) {
2000                     if (findFlags & TypesOnly) {
2001                         if (!node->isTypedef() && !node->isClassNode() && !node->isQmlType()
2002                             && !node->isQmlBasicType() && !node->isJsType()
2003                             && !node->isJsBasicType() && !node->isEnumType())
2004                             continue;
2005                     } else if (findFlags & IgnoreModules && node->isModule())
2006                         continue;
2007                     return node;
2008                 }
2009             }
2010         }
2011     }
2012     if (genus != Node::DontCare && this->genus() != genus)
2013         return nullptr;
2014     return functionMap_.value(name);
2015 }
2016 
2017 /*!
2018   Find all the child nodes of this node that are named
2019   \a name and return them in \a nodes.
2020  */
findChildren(const QString & name,NodeVector & nodes) const2021 void Aggregate::findChildren(const QString &name, NodeVector &nodes) const
2022 {
2023     nodes.clear();
2024     int nonfunctionCount = nonfunctionMap_.count(name);
2025     auto it = functionMap_.find(name);
2026     if (it != functionMap_.end()) {
2027         int functionCount = 0;
2028         FunctionNode *fn = it.value();
2029         while (fn != nullptr) {
2030             ++functionCount;
2031             fn = fn->nextOverload();
2032         }
2033         nodes.reserve(nonfunctionCount + functionCount);
2034         fn = it.value();
2035         while (fn != nullptr) {
2036             nodes.append(fn);
2037             fn = fn->nextOverload();
2038         }
2039     } else {
2040         nodes.reserve(nonfunctionCount);
2041     }
2042     if (nonfunctionCount > 0) {
2043         for (auto it = nonfunctionMap_.find(name); it != nonfunctionMap_.end() && it.key() == name;
2044              ++it) {
2045             nodes.append(it.value());
2046         }
2047     }
2048 }
2049 
2050 /*!
2051   This function searches for a child node of this Aggregate,
2052   such that the child node has the spacified \a name and the
2053   function \a isMatch returns true for the node. The function
2054   passed must be one of the isXxx() functions in class Node
2055   that tests the node type.
2056  */
findNonfunctionChild(const QString & name,bool (Node::* isMatch)()const)2057 Node *Aggregate::findNonfunctionChild(const QString &name, bool (Node::*isMatch)() const)
2058 {
2059     NodeList nodes = nonfunctionMap_.values(name);
2060     for (int i = 0; i < nodes.size(); ++i) {
2061         Node *node = nodes.at(i);
2062         if ((node->*(isMatch))())
2063             return node;
2064     }
2065     return nullptr;
2066 }
2067 
2068 /*!
2069   Find a function node that is a child of this node, such that
2070   the function node has the specified \a name and \a parameters.
2071   If \a parameters is empty but no matching function is found
2072   that has no parameters, return the first non-internal primary
2073   function or overload, whether it has parameters or not.
2074  */
findFunctionChild(const QString & name,const Parameters & parameters)2075 FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters &parameters)
2076 {
2077     auto it = functionMap_.find(name);
2078     if (it == functionMap_.end())
2079         return nullptr;
2080     FunctionNode *fn = it.value();
2081 
2082     if (parameters.isEmpty() && fn->parameters().isEmpty() && !fn->isInternal())
2083         return fn;
2084 
2085     while (fn != nullptr) {
2086         if (parameters.count() == fn->parameters().count() && !fn->isInternal()) {
2087             if (parameters.isEmpty())
2088                 return fn;
2089             bool matched = true;
2090             for (int i = 0; i < parameters.count(); i++) {
2091                 if (parameters.at(i).type() != fn->parameters().at(i).type()) {
2092                     matched = false;
2093                     break;
2094                 }
2095             }
2096             if (matched)
2097                 return fn;
2098         }
2099         fn = fn->nextOverload();
2100     }
2101 
2102     if (parameters.isEmpty()) {
2103         for (fn = it.value(); fn != nullptr; fn = fn->nextOverload())
2104             if (!fn->isInternal())
2105                 return fn;
2106         return it.value();
2107     }
2108     return nullptr;
2109 }
2110 
2111 /*!
2112   Find the function node that is a child of this node, such
2113   that the function described has the same name and signature
2114   as the function described by the function node \a clone.
2115  */
findFunctionChild(const FunctionNode * clone)2116 FunctionNode *Aggregate::findFunctionChild(const FunctionNode *clone)
2117 {
2118     FunctionNode *fn = functionMap_.value(clone->name());
2119     while (fn != nullptr) {
2120         if (isSameSignature(clone, fn))
2121             return fn;
2122         fn = fn->nextOverload();
2123     }
2124     return nullptr;
2125 }
2126 
2127 /*!
2128   Returns the list of keys from the primary function map.
2129  */
primaryKeys()2130 QStringList Aggregate::primaryKeys()
2131 {
2132     return functionMap_.keys();
2133 }
2134 
2135 /*!
2136   Mark all child nodes that have no documentation as having
2137   private access and internal status. qdoc will then ignore
2138   them for documentation purposes.
2139  */
markUndocumentedChildrenInternal()2140 void Aggregate::markUndocumentedChildrenInternal()
2141 {
2142     for (auto *child : qAsConst(children_)) {
2143         if (!child->isSharingComment() && !child->hasDoc() && !child->isDontDocument()) {
2144             if (!child->docMustBeGenerated()) {
2145                 if (child->isFunction()) {
2146                     if (static_cast<FunctionNode *>(child)->hasAssociatedProperties())
2147                         continue;
2148                 } else if (child->isTypedef()) {
2149                     if (static_cast<TypedefNode *>(child)->hasAssociatedEnum())
2150                         continue;
2151                 }
2152                 child->setAccess(Node::Private);
2153                 child->setStatus(Node::Internal);
2154             }
2155         }
2156         if (child->isAggregate()) {
2157             static_cast<Aggregate *>(child)->markUndocumentedChildrenInternal();
2158         }
2159     }
2160 }
2161 
2162 /*!
2163   This is where we set the overload numbers for function nodes.
2164   \note Overload numbers for related non-members are handled
2165   separately.
2166  */
normalizeOverloads()2167 void Aggregate::normalizeOverloads()
2168 {
2169     /*
2170       Ensure that none of the primary functions is inactive, private,
2171       or marked \e {overload}.
2172     */
2173     for (auto it = functionMap_.begin(); it != functionMap_.end(); ++it) {
2174         FunctionNode *fn = it.value();
2175         if (fn->isOverload()) {
2176             FunctionNode *primary = fn->findPrimaryFunction();
2177             if (primary) {
2178                 primary->setNextOverload(fn);
2179                 it.value() = primary;
2180                 fn = primary;
2181             } else {
2182                 fn->clearOverloadFlag();
2183             }
2184         }
2185         int count = 0;
2186         fn->setOverloadNumber(0);
2187         FunctionNode *internalFn = nullptr;
2188         while (fn != nullptr) {
2189             FunctionNode *next = fn->nextOverload();
2190             if (next) {
2191                 if (next->isInternal()) {
2192                     // internal overloads are moved to a separate list
2193                     // and processed last
2194                     fn->setNextOverload(next->nextOverload());
2195                     next->setNextOverload(internalFn);
2196                     internalFn = next;
2197                 } else {
2198                     next->setOverloadNumber(++count);
2199                 }
2200                 fn = fn->nextOverload();
2201             } else {
2202                 fn->setNextOverload(internalFn);
2203                 break;
2204             }
2205         }
2206         while (internalFn) {
2207             internalFn->setOverloadNumber(++count);
2208             internalFn = internalFn->nextOverload();
2209         }
2210         // process next function in function map.
2211     }
2212     /*
2213       Recursive part.
2214      */
2215     for (auto *node : qAsConst(children_)) {
2216         if (node->isAggregate())
2217             static_cast<Aggregate *>(node)->normalizeOverloads();
2218     }
2219 }
2220 
2221 /*!
2222   Returns a const reference to the list of child nodes of this
2223   aggregate that are not function nodes. Duplicate nodes are
2224   removed from the list.
2225  */
nonfunctionList()2226 const NodeList &Aggregate::nonfunctionList()
2227 {
2228     nonfunctionList_ = nonfunctionMap_.values();
2229     std::sort(nonfunctionList_.begin(), nonfunctionList_.end(), Node::nodeNameLessThan);
2230     nonfunctionList_.erase(std::unique(nonfunctionList_.begin(), nonfunctionList_.end()),
2231                            nonfunctionList_.end());
2232     return nonfunctionList_;
2233 }
2234 
2235 /*! \fn bool Aggregate::isAggregate() const
2236   Returns \c true because this node is an instance of Aggregate,
2237   which means it can have children.
2238  */
2239 
2240 /*!
2241   Finds the enum type node that has \a enumValue as one of
2242   its enum values and returns a pointer to it. Returns 0 if
2243   no enum type node is found that has \a enumValue as one
2244   of its values.
2245  */
findEnumNodeForValue(const QString & enumValue) const2246 const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const
2247 {
2248     for (const auto *node : enumChildren_) {
2249         const EnumNode *en = static_cast<const EnumNode *>(node);
2250         if (en->hasItem(enumValue))
2251             return en;
2252     }
2253     return nullptr;
2254 }
2255 
2256 /*!
2257   Appends \a includeFile file to the list of include files.
2258  */
addIncludeFile(const QString & includeFile)2259 void Aggregate::addIncludeFile(const QString &includeFile)
2260 {
2261     includeFiles_.append(includeFile);
2262 }
2263 
2264 /*!
2265   Sets the list of include files to \a includeFiles.
2266  */
setIncludeFiles(const QStringList & includeFiles)2267 void Aggregate::setIncludeFiles(const QStringList &includeFiles)
2268 {
2269     includeFiles_ = includeFiles;
2270 }
2271 
2272 /*!
2273   Compare \a f1 to \a f2 and return \c true if they have the same
2274   signature. Otherwise return \c false. They must have the same
2275   number of parameters, and all the parameter types must be the
2276   same. The functions must have the same constness and refness.
2277   This is a private function.
2278  */
isSameSignature(const FunctionNode * f1,const FunctionNode * f2)2279 bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
2280 {
2281     if (f1->parameters().count() != f2->parameters().count())
2282         return false;
2283     if (f1->isConst() != f2->isConst())
2284         return false;
2285     if (f1->isRef() != f2->isRef())
2286         return false;
2287     if (f1->isRefRef() != f2->isRefRef())
2288         return false;
2289 
2290     const Parameters &p1 = f1->parameters();
2291     const Parameters &p2 = f2->parameters();
2292     for (int i = 0; i < p1.count(); i++) {
2293         if (p1.at(i).hasType() && p2.at(i).hasType()) {
2294             QString t1 = p1.at(i).type();
2295             QString t2 = p2.at(i).type();
2296 
2297             if (t1.length() < t2.length())
2298                 qSwap(t1, t2);
2299 
2300             /*
2301               ### hack for C++ to handle superfluous
2302               "Foo::" prefixes gracefully
2303              */
2304             if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2)) {
2305                 // Accept a difference in the template parametters of the type if one
2306                 // is omited (eg. "QAtomicInteger" == "QAtomicInteger<T>")
2307                 auto ltLoc = t1.indexOf('<');
2308                 auto gtLoc = t1.indexOf('>', ltLoc);
2309                 if (ltLoc < 0 || gtLoc < ltLoc)
2310                     return false;
2311                 t1.remove(ltLoc, gtLoc - ltLoc + 1);
2312                 if (t1 != t2)
2313                     return false;
2314             }
2315         }
2316     }
2317     return true;
2318 }
2319 
2320 /*!
2321   This function is only called by addChild(), when the child is a
2322   FunctionNode. If the function map does not contain a function with
2323   the name in \a fn, \a fn is inserted into the function map. If the
2324   map already contains a function by that name, \a fn is appended to
2325   that function's linked list of overloads.
2326 
2327   \note A function's overloads appear in the linked list in the same
2328   order they were created. The first overload in the list is the first
2329   overload created. This order is maintained in the numbering of
2330   overloads. In other words, the first overload in the linked list has
2331   overload number 1, and the last overload in the list has overload
2332   number n, where n is the number of overloads not including the
2333   function in the function map.
2334 
2335   \not Adding a function increments the aggregate's function count,
2336   which is the total number of function nodes in the function map,
2337   including the overloads. The overloads are not inserted into the map
2338   but are in a linked list using the FunctionNode's nextOverload_
2339   pointer.
2340 
2341   \note The function's overload number and overload flag are set in
2342   normalizeOverloads().
2343 
2344   \note This is a private function.
2345 
2346   \sa normalizeOverloads()
2347  */
addFunction(FunctionNode * fn)2348 void Aggregate::addFunction(FunctionNode *fn)
2349 {
2350     auto it = functionMap_.find(fn->name());
2351     if (it == functionMap_.end())
2352         functionMap_.insert(fn->name(), fn);
2353     else
2354         it.value()->appendOverload(fn);
2355     functionCount_++;
2356 }
2357 
2358 /*!
2359   When an Aggregate adopts a function that is a child of
2360   another Aggregate, the function is inserted into this
2361   Aggregate's function map, if the function's name is not
2362   already in the function map. If the function's name is
2363   already in the function map, do nothing. The overload
2364   link is already set correctly.
2365 
2366   \note This is a private function.
2367  */
adoptFunction(FunctionNode * fn)2368 void Aggregate::adoptFunction(FunctionNode *fn)
2369 {
2370     auto it = functionMap_.find(fn->name());
2371     if (it == functionMap_.end())
2372         functionMap_.insert(fn->name(), fn);
2373     ++functionCount_;
2374 }
2375 
2376 /*!
2377   Adds the \a child to this node's child map using \a title
2378   as the key. The \a child is not added to the child list
2379   again, because it is presumed to already be there. We just
2380   want to be able to find the child by its \a title.
2381  */
addChildByTitle(Node * child,const QString & title)2382 void Aggregate::addChildByTitle(Node *child, const QString &title)
2383 {
2384     nonfunctionMap_.insert(title, child);
2385 }
2386 
2387 /*!
2388   Adds the \a child to this node's child list and sets the child's
2389   parent pointer to this Aggregate. It then mounts the child with
2390   mountChild().
2391 
2392   The \a child is then added to this Aggregate's searchable maps
2393   and lists.
2394 
2395   \note This function does not test the child's parent pointer
2396   for null before changing it. If the child's parent pointer
2397   is not null, then it is being reparented. The child becomes
2398   a child of this Aggregate, but it also remains a child of
2399   the Aggregate that is it's old parent. But the child will
2400   only have one parent, and it will be this Aggregate. The is
2401   because of the \c relates command.
2402 
2403   \sa mountChild(), dismountChild()
2404  */
addChild(Node * child)2405 void Aggregate::addChild(Node *child)
2406 {
2407     children_.append(child);
2408     child->setParent(this);
2409     child->setOutputSubdirectory(this->outputSubdirectory());
2410     child->setUrl(QString());
2411     child->setIndexNodeFlag(isIndexNode());
2412 
2413     if (child->isFunction()) {
2414         addFunction(static_cast<FunctionNode *>(child));
2415     } else if (!child->name().isEmpty()) {
2416         nonfunctionMap_.insert(child->name(), child);
2417         if (child->isEnumType())
2418             enumChildren_.append(child);
2419     }
2420 }
2421 
2422 /*!
2423   This Aggregate becomes the adoptive parent of \a child. The
2424   \a child knows this Aggregate as its parent, but its former
2425   parent continues to have pointers to the child in its child
2426   list and in its searchable data structures. But the child is
2427   also added to the child list and searchable data structures
2428   of this Aggregate.
2429 
2430   The one caveat is that if the child being adopted is a function
2431   node, it's next overload pointer is not altered.
2432  */
adoptChild(Node * child)2433 void Aggregate::adoptChild(Node *child)
2434 {
2435     if (child->parent() != this) {
2436         children_.append(child);
2437         child->setParent(this);
2438         if (child->isFunction()) {
2439             adoptFunction(static_cast<FunctionNode *>(child));
2440         } else if (!child->name().isEmpty()) {
2441             nonfunctionMap_.insert(child->name(), child);
2442             if (child->isEnumType())
2443                 enumChildren_.append(child);
2444         }
2445         if (child->isSharedCommentNode()) {
2446             SharedCommentNode *scn = static_cast<SharedCommentNode *>(child);
2447             for (Node *n : scn->collective())
2448                 adoptChild(n);
2449         }
2450     }
2451 }
2452 
2453 /*!
2454   Recursively sets the output subdirectory for children
2455  */
setOutputSubdirectory(const QString & t)2456 void Aggregate::setOutputSubdirectory(const QString &t)
2457 {
2458     Node::setOutputSubdirectory(t);
2459     for (auto *node : qAsConst(children_))
2460         node->setOutputSubdirectory(t);
2461 }
2462 
2463 /*!
2464   If this node has a child that is a QML property or JS property
2465   named \a n, return a pointer to that child. Otherwise, return \nullptr.
2466  */
hasQmlProperty(const QString & n) const2467 QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n) const
2468 {
2469     NodeType goal = Node::QmlProperty;
2470     if (isJsNode())
2471         goal = Node::JsProperty;
2472     for (auto *child : qAsConst(children_)) {
2473         if (child->nodeType() == goal) {
2474             if (child->name() == n)
2475                 return static_cast<QmlPropertyNode *>(child);
2476         }
2477     }
2478     return nullptr;
2479 }
2480 
2481 /*!
2482   If this node has a child that is a QML property or JS property
2483   named \a n and that also matches \a attached, return a pointer
2484   to that child.
2485  */
hasQmlProperty(const QString & n,bool attached) const2486 QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n, bool attached) const
2487 {
2488     NodeType goal = Node::QmlProperty;
2489     if (isJsNode())
2490         goal = Node::JsProperty;
2491     for (auto *child : qAsConst(children_)) {
2492         if (child->nodeType() == goal) {
2493             if (child->name() == n && child->isAttached() == attached)
2494                 return static_cast<QmlPropertyNode *>(child);
2495         }
2496     }
2497     return nullptr;
2498 }
2499 
2500 /*!
2501   The FunctionNode \a fn is assumed to be a member function
2502   of this Aggregate. The function's name is looked up in the
2503   Aggregate's function map. It should be found because it is
2504   assumed that \a fn is in this Aggregate's function map. But
2505   in case it is not found, \c false is returned.
2506 
2507   Normally, the name will be found in the function map, and
2508   the value of the iterator is used to get the value, which
2509   is a pointer to another FunctionNode, which is not itself
2510   an overload. If that function has a non-null overload
2511   pointer, true is returned. Otherwise false is returned.
2512 
2513   This is a convenience function that you should not need to
2514   use.
2515  */
hasOverloads(const FunctionNode * fn) const2516 bool Aggregate::hasOverloads(const FunctionNode *fn) const
2517 {
2518     auto it = functionMap_.find(fn->name());
2519     return (it == functionMap_.end() ? false : (it.value()->nextOverload() != nullptr));
2520 }
2521 
2522 /*!
2523   Prints the inner node's list of children.
2524   For debugging only.
2525  */
printChildren(const QString & title)2526 void Aggregate::printChildren(const QString &title)
2527 {
2528     qDebug() << title << name() << children_.size();
2529     if (children_.size() > 0) {
2530         for (int i = 0; i < children_.size(); ++i) {
2531             Node *n = children_.at(i);
2532             qDebug() << "  CHILD:" << n->name() << n->nodeTypeString();
2533         }
2534     }
2535 }
2536 
2537 /*!
2538   Removes \a fn from this aggregate's function map. That's
2539   all it does. If \a fn is in the function map index and it
2540   has an overload, the value pointer in the function map
2541   index is set to the the overload pointer. If the function
2542   has no overload pointer, the function map entry is erased.
2543 
2544   \note When removing a function node from the function map,
2545   it is important to set the removed function node's next
2546   overload pointer to null because the function node might
2547   be added as a child to some other aggregate.
2548 
2549   \note This is a protected function.
2550  */
removeFunctionNode(FunctionNode * fn)2551 void Aggregate::removeFunctionNode(FunctionNode *fn)
2552 {
2553     auto it = functionMap_.find(fn->name());
2554     if (it != functionMap_.end()) {
2555         if (it.value() == fn) {
2556             if (fn->nextOverload() != nullptr) {
2557                 it.value() = fn->nextOverload();
2558                 fn->setNextOverload(nullptr);
2559                 fn->setOverloadNumber(0);
2560             } else {
2561                 functionMap_.erase(it);
2562             }
2563         } else {
2564             FunctionNode *current = it.value();
2565             while (current != nullptr) {
2566                 if (current->nextOverload() == fn) {
2567                     current->setNextOverload(fn->nextOverload());
2568                     fn->setNextOverload(nullptr);
2569                     fn->setOverloadNumber(0);
2570                     break;
2571                 }
2572                 current = current->nextOverload();
2573             }
2574         }
2575     }
2576 }
2577 
2578 /*
2579   When deciding whether to include a function in the function
2580   index, if the function is marked private, don't include it.
2581   If the function is marked obsolete, don't include it. If the
2582   function is marked internal, don't include it. Or if the
2583   function is a destructor or any kind of constructor, don't
2584   include it. Otherwise include it.
2585  */
keep(FunctionNode * fn)2586 static bool keep(FunctionNode *fn)
2587 {
2588     if (fn->isPrivate() || fn->isObsolete() || fn->isInternal() || fn->isSomeCtor() || fn->isDtor())
2589         return false;
2590     return true;
2591 }
2592 
2593 /*!
2594   Insert all functions declared in this aggregate into the
2595   \a functionIndex. Call the function recursively for each
2596   child that is an aggregate.
2597 
2598   Only include functions that are in the public API and
2599   that are not constructors or destructors.
2600  */
findAllFunctions(NodeMapMap & functionIndex)2601 void Aggregate::findAllFunctions(NodeMapMap &functionIndex)
2602 {
2603     for (auto it = functionMap_.constBegin(); it != functionMap_.constEnd(); ++it) {
2604         FunctionNode *fn = it.value();
2605         if (keep(fn))
2606             functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
2607         fn = fn->nextOverload();
2608         while (fn != nullptr) {
2609             if (keep(fn))
2610                 functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn);
2611             fn = fn->nextOverload();
2612         }
2613     }
2614     for (Node *node : qAsConst(children_)) {
2615         if (node->isAggregate() && !node->isPrivate())
2616             static_cast<Aggregate *>(node)->findAllFunctions(functionIndex);
2617     }
2618 }
2619 
2620 /*!
2621   For each child of this node, if the child is a namespace node,
2622   insert the child into the \a namespaces multimap. If the child
2623   is an aggregate, call this function recursively for that child.
2624 
2625   When the function called with the root node of a tree, it finds
2626   all the namespace nodes in that tree and inserts them into the
2627   \a namespaces multimap.
2628 
2629   The root node of a tree is a namespace, but it has no name, so
2630   it is not inserted into the map. So, if this function is called
2631   for each tree in the qdoc database, it finds all the namespace
2632   nodes in the database.
2633   */
findAllNamespaces(NodeMultiMap & namespaces)2634 void Aggregate::findAllNamespaces(NodeMultiMap &namespaces)
2635 {
2636     for (auto *node : qAsConst(children_)) {
2637         if (node->isAggregate() && !node->isPrivate()) {
2638             if (node->isNamespace() && !node->name().isEmpty())
2639                 namespaces.insert(node->name(), node);
2640             static_cast<Aggregate *>(node)->findAllNamespaces(namespaces);
2641         }
2642     }
2643 }
2644 
2645 /*!
2646   Returns true if this aggregate contains at least one child
2647   that is marked obsolete. Otherwise returns false.
2648  */
hasObsoleteMembers() const2649 bool Aggregate::hasObsoleteMembers() const
2650 {
2651     for (const auto *node : children_) {
2652         if (!node->isPrivate() && node->isObsolete()) {
2653             if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef()
2654                 || node->isTypeAlias() || node->isVariable() || node->isQmlProperty()
2655                 || node->isJsProperty())
2656                 return true;
2657         }
2658     }
2659     return false;
2660 }
2661 
2662 /*!
2663   Finds all the obsolete C++ classes and QML types in this
2664   aggregate and all the C++ classes and QML types with obsolete
2665   members, and inserts them into maps used elsewhere for
2666   generating documentation.
2667  */
findAllObsoleteThings()2668 void Aggregate::findAllObsoleteThings()
2669 {
2670     for (auto *node : qAsConst(children_)) {
2671         if (!node->isPrivate()) {
2672             QString name = node->name();
2673             if (node->isObsolete()) {
2674                 if (node->isClassNode())
2675                     QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node);
2676                 else if (node->isQmlType() || node->isJsType())
2677                     QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node);
2678             } else if (node->isClassNode()) {
2679                 Aggregate *a = static_cast<Aggregate *>(node);
2680                 if (a->hasObsoleteMembers())
2681                     QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node);
2682             } else if (node->isQmlType() || node->isJsType()) {
2683                 Aggregate *a = static_cast<Aggregate *>(node);
2684                 if (a->hasObsoleteMembers())
2685                     QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(),
2686                                                                        node);
2687             } else if (node->isAggregate()) {
2688                 static_cast<Aggregate *>(node)->findAllObsoleteThings();
2689             }
2690         }
2691     }
2692 }
2693 
2694 /*!
2695   Finds all the C++ classes, QML types, JS types, QML and JS
2696   basic types, and examples in this aggregate and inserts them
2697   into appropriate maps for later use in generating documentation.
2698  */
findAllClasses()2699 void Aggregate::findAllClasses()
2700 {
2701     for (auto *node : qAsConst(children_)) {
2702         if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument()
2703             && node->tree()->camelCaseModuleName() != QString("QDoc")) {
2704             if (node->isClassNode()) {
2705                 QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node);
2706             } else if (node->isQmlType() || node->isQmlBasicType() || node->isJsType()
2707                        || node->isJsBasicType()) {
2708                 QString name = node->unqualifyQmlName();
2709                 QDocDatabase::qmlTypes().insert(name, node);
2710                 // also add to the QML basic type map
2711                 if (node->isQmlBasicType() || node->isJsBasicType())
2712                     QDocDatabase::qmlBasicTypes().insert(name, node);
2713             } else if (node->isExample()) {
2714                 // use the module index title as key for the example map
2715                 QString title = node->tree()->indexTitle();
2716                 if (!QDocDatabase::examples().contains(title, node))
2717                     QDocDatabase::examples().insert(title, node);
2718             } else if (node->isAggregate()) {
2719                 static_cast<Aggregate *>(node)->findAllClasses();
2720             }
2721         }
2722     }
2723 }
2724 
2725 /*!
2726   Find all the attribution pages in this node and insert them
2727   into \a attributions.
2728  */
findAllAttributions(NodeMultiMap & attributions)2729 void Aggregate::findAllAttributions(NodeMultiMap &attributions)
2730 {
2731     for (auto *node : qAsConst(children_)) {
2732         if (!node->isPrivate()) {
2733             if (node->pageType() == Node::AttributionPage)
2734                 attributions.insert(node->tree()->indexTitle(), node);
2735             else if (node->isAggregate())
2736                 static_cast<Aggregate *>(node)->findAllAttributions(attributions);
2737         }
2738     }
2739 }
2740 
2741 /*!
2742   Finds all the nodes in this node where a \e{since} command appeared
2743   in the qdoc comment and sorts them into maps according to the kind
2744   of node.
2745 
2746   This function is used for generating the "New Classes... in x.y"
2747   section on the \e{What's New in Qt x.y} page.
2748  */
findAllSince()2749 void Aggregate::findAllSince()
2750 {
2751     for (auto *node : qAsConst(children_)) {
2752         if (node->isRelatedNonmember() && node->parent() != this)
2753             continue;
2754         QString sinceString = node->since();
2755         // Insert a new entry into each map for each new since string found.
2756         if (!node->isPrivate() && !sinceString.isEmpty()) {
2757             auto nsmap = QDocDatabase::newSinceMaps().find(sinceString);
2758             if (nsmap == QDocDatabase::newSinceMaps().end())
2759                 nsmap = QDocDatabase::newSinceMaps().insert(sinceString, NodeMultiMap());
2760 
2761             auto ncmap = QDocDatabase::newClassMaps().find(sinceString);
2762             if (ncmap == QDocDatabase::newClassMaps().end())
2763                 ncmap = QDocDatabase::newClassMaps().insert(sinceString, NodeMap());
2764 
2765             auto nqcmap = QDocDatabase::newQmlTypeMaps().find(sinceString);
2766             if (nqcmap == QDocDatabase::newQmlTypeMaps().end())
2767                 nqcmap = QDocDatabase::newQmlTypeMaps().insert(sinceString, NodeMap());
2768 
2769             if (node->isFunction()) {
2770                 // Insert functions into the general since map.
2771                 FunctionNode *fn = static_cast<FunctionNode *>(node);
2772                 if (!fn->isObsolete() && !fn->isSomeCtor() && !fn->isDtor())
2773                     nsmap.value().insert(fn->name(), fn);
2774             } else if (node->isClassNode()) {
2775                 // Insert classes into the since and class maps.
2776                 QString name = node->qualifyWithParentName();
2777                 nsmap.value().insert(name, node);
2778                 ncmap.value().insert(name, node);
2779             } else if (node->isQmlType() || node->isJsType()) {
2780                 // Insert QML elements into the since and element maps.
2781                 QString name = node->qualifyWithParentName();
2782                 nsmap.value().insert(name, node);
2783                 nqcmap.value().insert(name, node);
2784             } else if (node->isQmlProperty() || node->isJsProperty()) {
2785                 // Insert QML properties into the since map.
2786                 nsmap.value().insert(node->name(), node);
2787             } else {
2788                 // Insert external documents into the general since map.
2789                 QString name = node->qualifyWithParentName();
2790                 nsmap.value().insert(name, node);
2791             }
2792         }
2793         // Recursively find child nodes with since commands.
2794         if (node->isAggregate())
2795             static_cast<Aggregate *>(node)->findAllSince();
2796     }
2797 }
2798 
2799 /*!
2800   For each QML Type node in this aggregate's children, if the
2801   QML type has a QML base type name but its QML base type node
2802   pointer is nullptr, use the QML base type name to look up the
2803   base type node. If the node is found, set the node's QML base
2804   type node pointer to that node.
2805  */
resolveQmlInheritance()2806 void Aggregate::resolveQmlInheritance()
2807 {
2808     NodeMap previousSearches;
2809     // Do we need recursion?
2810     for (auto *child : qAsConst(children_)) {
2811         if (!child->isQmlType() && !child->isJsType())
2812             continue;
2813         QmlTypeNode *type = static_cast<QmlTypeNode *>(child);
2814         if (type->qmlBaseNode() != nullptr)
2815             continue;
2816         if (type->qmlBaseName().isEmpty())
2817             continue;
2818         QmlTypeNode *base = static_cast<QmlTypeNode *>(previousSearches.value(type->qmlBaseName()));
2819         if (base && (base != type)) {
2820             type->setQmlBaseNode(base);
2821             QmlTypeNode::addInheritedBy(base, type);
2822         } else {
2823             if (!type->importList().isEmpty()) {
2824                 const ImportList &imports = type->importList();
2825                 for (int i = 0; i < imports.size(); ++i) {
2826                     base = QDocDatabase::qdocDB()->findQmlType(imports[i], type->qmlBaseName());
2827                     if (base && (base != type)) {
2828                         if (base->logicalModuleVersion()[0] != imports[i].version_[0])
2829                             base = nullptr; // Safeguard for QTBUG-53529
2830                         break;
2831                     }
2832                 }
2833             }
2834             if (base == nullptr) {
2835                 base = QDocDatabase::qdocDB()->findQmlType(QString(), type->qmlBaseName());
2836             }
2837             if (base && (base != type)) {
2838                 type->setQmlBaseNode(base);
2839                 QmlTypeNode::addInheritedBy(base, type);
2840                 previousSearches.insert(type->qmlBaseName(), base);
2841             }
2842         }
2843     }
2844 }
2845 
2846 /*!
2847   Returns a word representing the kind of Aggregate this node is.
2848   Currently only works for class, struct, and union, but it can
2849   easily be extended. If \a cap is true, the word is capitalised.
2850  */
typeWord(bool cap) const2851 QString Aggregate::typeWord(bool cap) const
2852 {
2853     if (cap) {
2854         switch (nodeType()) {
2855         case Node::Class:
2856             return QLatin1String("Class");
2857         case Node::Struct:
2858             return QLatin1String("Struct");
2859         case Node::Union:
2860             return QLatin1String("Union");
2861         default:
2862             break;
2863         }
2864     } else {
2865         switch (nodeType()) {
2866         case Node::Class:
2867             return QLatin1String("class");
2868         case Node::Struct:
2869             return QLatin1String("struct");
2870         case Node::Union:
2871             return QLatin1String("union");
2872         default:
2873             break;
2874         }
2875     }
2876     return QString();
2877 }
2878 
2879 /*! \fn int Aggregate::count() const
2880   Returns the number of children in the child list.
2881  */
2882 
2883 /*! \fn const NodeList &Aggregate::childNodes() const
2884   Returns a const reference to the child list.
2885  */
2886 
2887 /*! \fn NodeList::ConstIterator Aggregate::constBegin() const
2888   Returns a const iterator pointing at the beginning of the child list.
2889  */
2890 
2891 /*! \fn NodeList::ConstIterator Aggregate::constEnd() const
2892   Returns a const iterator pointing at the end of the child list.
2893  */
2894 
2895 /*! \fn const QStringList &Aggregate::includeFiles() const
2896   This function returns a const reference to a list of strings, but
2897   I no longer know what they are.
2898  */
2899 
2900 /*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const
2901   If this Aggregate is a QmlTypeNode, this function returns a pointer to
2902   the QmlTypeNode that is its base type. Otherwise it returns \c nullptr.
2903   A QmlTypeNode doesn't always have a base type, so even when this Aggregate
2904   is aQmlTypeNode, the pointer returned can be \c nullptr.
2905  */
2906 
2907 /*!
2908   A base class of this class node was private or internal.
2909   That node's list of \a bases is traversed in this function.
2910   Each of its public base classes is promoted to be a base
2911   class of this node for documentation purposes. For each
2912   private or internal class node in \a bases, this function
2913   is called recursively with the list of base classes from
2914   that private or internal class node.
2915  */
promotePublicBases(const QVector<RelatedClass> & bases)2916 void ClassNode::promotePublicBases(const QVector<RelatedClass> &bases)
2917 {
2918     if (!bases.isEmpty()) {
2919         for (int i = bases.size() - 1; i >= 0; --i) {
2920             ClassNode *bc = bases.at(i).node_;
2921             if (bc == nullptr)
2922                 bc = QDocDatabase::qdocDB()->findClassNode(bases.at(i).path_);
2923             if (bc != nullptr) {
2924                 if (bc->isPrivate() || bc->isInternal())
2925                     promotePublicBases(bc->baseClasses());
2926                 else
2927                     bases_.append(bases.at(i));
2928             }
2929         }
2930     }
2931 }
2932 
2933 /*!
2934   Remove private and internal bases classes from this class's list
2935   of base classes. When a base class is removed from the list, add
2936   its base classes to this class's list of base classes.
2937  */
removePrivateAndInternalBases()2938 void ClassNode::removePrivateAndInternalBases()
2939 {
2940     int i;
2941     i = 0;
2942     QSet<ClassNode *> found;
2943 
2944     // Remove private and duplicate base classes.
2945     while (i < bases_.size()) {
2946         ClassNode *bc = bases_.at(i).node_;
2947         if (bc == nullptr)
2948             bc = QDocDatabase::qdocDB()->findClassNode(bases_.at(i).path_);
2949         if (bc != nullptr
2950             && (bc->isPrivate() || bc->isInternal() || bc->isDontDocument()
2951                 || found.contains(bc))) {
2952             RelatedClass rc = bases_.at(i);
2953             bases_.removeAt(i);
2954             ignoredBases_.append(rc);
2955             promotePublicBases(bc->baseClasses());
2956         } else {
2957             ++i;
2958         }
2959         found.insert(bc);
2960     }
2961 
2962     i = 0;
2963     while (i < derived_.size()) {
2964         ClassNode *dc = derived_.at(i).node_;
2965         if (dc != nullptr && (dc->isPrivate() || dc->isInternal() || dc->isDontDocument())) {
2966             derived_.removeAt(i);
2967             const QVector<RelatedClass> &dd = dc->derivedClasses();
2968             for (int j = dd.size() - 1; j >= 0; --j)
2969                 derived_.insert(i, dd.at(j));
2970         } else {
2971             ++i;
2972         }
2973     }
2974 }
2975 
2976 /*!
2977  */
resolvePropertyOverriddenFromPtrs(PropertyNode * pn)2978 void ClassNode::resolvePropertyOverriddenFromPtrs(PropertyNode *pn)
2979 {
2980     for (const auto &baseClass : qAsConst(baseClasses())) {
2981         ClassNode *cn = baseClass.node_;
2982         if (cn) {
2983             Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
2984             if (n) {
2985                 PropertyNode *baseProperty = static_cast<PropertyNode *>(n);
2986                 cn->resolvePropertyOverriddenFromPtrs(baseProperty);
2987                 pn->setOverriddenFrom(baseProperty);
2988             } else
2989                 cn->resolvePropertyOverriddenFromPtrs(pn);
2990         }
2991     }
2992 }
2993 
2994 /*! \fn FunctionMap &Aggregate::functionMap()
2995   Returns a reference to this Aggregate's function map, which
2996   is a map of all the children of this Aggregate that are
2997   FunctionNodes.
2998  */
2999 
3000 /*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t)
3001   Appends the list of node pointers to the list of elements that are
3002   related to this Aggregate but are documented in a different module.
3003 
3004   \sa relatedByProxy()
3005  */
3006 
3007 /*! \fn NodeList &Aggregate::relatedByProxy()
3008   Returns a reference to a list of node pointers where each element
3009   points to a node in an index file for some other module, such that
3010   whatever the node represents was documented in that other module,
3011   but it is related to this Aggregate, so when the documentation for
3012   this Aggregate is written, it will contain links to elements in the
3013   other module.
3014  */
3015 
3016 /*!
3017   \class NamespaceNode
3018   \brief This class represents a C++ namespace.
3019 
3020   A namespace can be used in multiple C++ modules, so there
3021   can be a NamespaceNode for namespace Xxx in more than one
3022   Node tree.
3023  */
3024 
3025 /*! \fn NamespaceNode(Aggregate *parent, const QString &name)
3026   Constructs a NamespaceNode with the specified \a parent and \a name.
3027   The node type is Node::Namespace.
3028  */
3029 
3030 /*!
3031   The destructor removes all children from the child list that
3032   have a parent() that is not this NamespaceNode. This situation
3033   can arise because of elements that are related to this namespace
3034   using the \c {\\relates} command.
3035 
3036   \note The child nodes remaining in the child list after the ones
3037   with a different parent() have been removed are deleted in the
3038   destructor of the Aggregate base class.
3039  */
~NamespaceNode()3040 NamespaceNode::~NamespaceNode()
3041 {
3042     for (int i = 0; i < children_.size(); ++i) {
3043         if (children_[i]->parent() != this)
3044             children_[i] = nullptr;
3045     }
3046 }
3047 
3048 /*!
3049   Returns true if this namespace is to be documented in the
3050   current module. There can be elements declared in this
3051   namespace spread over multiple modules. Those elements are
3052   documented in the modules where they are declared, but they
3053   are linked to from the namespace page in the module where
3054   the namespace itself is documented.
3055  */
isDocumentedHere() const3056 bool NamespaceNode::isDocumentedHere() const
3057 {
3058     return whereDocumented_ == tree()->camelCaseModuleName();
3059 }
3060 
3061 /*!
3062   Returns true if this namespace node contains at least one
3063   child that has documentation and is not private or internal.
3064  */
hasDocumentedChildren() const3065 bool NamespaceNode::hasDocumentedChildren() const
3066 {
3067     for (const auto *node : qAsConst(children_)) {
3068         if (node->isInAPI())
3069             return true;
3070     }
3071     return false;
3072 }
3073 
3074 /*!
3075   Report qdoc warning for each documented child in a namespace
3076   that is not documented. This function should only be called
3077   when the namespace is not documented.
3078  */
reportDocumentedChildrenInUndocumentedNamespace() const3079 void NamespaceNode::reportDocumentedChildrenInUndocumentedNamespace() const
3080 {
3081     for (const auto *node : qAsConst(children_)) {
3082         if (node->isInAPI()) {
3083             QString msg1 = node->name();
3084             if (node->isFunction())
3085                 msg1 += "()";
3086             msg1 += tr(" is documented, but namespace %1 is not documented in any module.")
3087                             .arg(name());
3088             QString msg2 = tr("Add /*! '\\%1 %2' ... */ or remove the qdoc comment marker (!) at "
3089                               "that line number.")
3090                                    .arg(COMMAND_NAMESPACE)
3091                                    .arg(name());
3092 
3093             node->doc().location().warning(msg1, msg2);
3094         }
3095     }
3096 }
3097 
3098 /*!
3099   Returns true if this namespace node is not private and
3100   contains at least one public child node with documentation.
3101  */
docMustBeGenerated() const3102 bool NamespaceNode::docMustBeGenerated() const
3103 {
3104     if (isInAPI())
3105         return true;
3106     return (hasDocumentedChildren() ? true : false);
3107 }
3108 
3109 /*!
3110   Returns a const reference to the namespace node's list of
3111   included children, which contains pointers to all the child
3112   nodes of other namespace nodes that have the same name as
3113   this namespace node. The list is built after the prepare
3114   phase has been run but just before the generate phase. It
3115   is buils by QDocDatabase::resolveNamespaces().
3116 
3117   \sa QDocDatabase::resolveNamespaces()
3118  */
includedChildren() const3119 const NodeList &NamespaceNode::includedChildren() const
3120 {
3121     return includedChildren_;
3122 }
3123 
3124 /*!
3125   This function is only called from QDocDatabase::resolveNamesapces().
3126 
3127   \sa includedChildren(), QDocDatabase::resolveNamespaces()
3128  */
includeChild(Node * child)3129 void NamespaceNode::includeChild(Node *child)
3130 {
3131     includedChildren_.append(child);
3132 }
3133 
3134 /*! \fn Tree* NamespaceNode::tree() const
3135   Returns a pointer to the Tree that contains this NamespaceNode.
3136   This requires traversing the parent() pointers to the root of
3137   the Tree, which is the unnamed NamespaceNode.
3138  */
3139 
3140 /*! \fn bool NamespaceNode::isFirstClassAggregate() const
3141   Returns \c true.
3142  */
3143 
3144 /*! \fn bool NamespaceNode::isRelatableType() const
3145   Returns \c true.
3146  */
3147 
3148 /*! \fn bool NamespaceNode::wasSeen() const
3149   Returns \c true if the \c {\\namespace} command that this NamespaceNode
3150   represents has been parsed by qdoc. When \c false is returned, it means
3151   that only \c {\\relates} commands have been seen that relate elements to
3152   this namespace.
3153  */
3154 
3155 /*! \fn void NamespaceNode::markSeen()
3156   Sets the data member that indicates that the \c {\\namespace} command this
3157   NamespaceNode represents has been parsed by qdoc.
3158  */
3159 
3160 /*! \fn void NamespaceNode::markNotSeen()
3161   Clears the data member that indicates that the \c {\\namespace} command this
3162   NamespaceNode represents has been parsed by qdoc.
3163  */
3164 
3165 /*! \fn void NamespaceNode::setTree(Tree* t)
3166   Sets the Tree pointer to \a t, which means this NamespaceNode is in the Tree \a t.
3167  */
3168 
3169 /*! \fn QString NamespaceNode::whereDocumented() const
3170   Returns the camel case name of the module where this namespace is documented.
3171 
3172   \sa setWhereDocumented()
3173  */
3174 
3175 /*! \fn void NamespaceNode::setWhereDocumented(const QString &t)
3176   Sets the camel case name of the module where this namespace is documented to
3177   the module named \a t.
3178 
3179   This function is called when the \c {\\namespace} command is processed to let
3180   qdoc know that this namespace is documented in the current module, so that
3181   when something in another module is marked as related to this namespace, it
3182   can be documented there with a ProxyNode for this namespace.
3183 
3184   \sa whereDocumented()
3185  */
3186 
3187 /*! \fn void NamespaceNode::setDocumented()
3188   Sets the flag indicating that the \c {\\namespace} command for this
3189   namespace was seen.
3190  */
3191 
3192 /*! \fn bool NamespaceNode::wasDocumented() const
3193   Returns \c true if a \c {\\namespace} command for this namespace was seen.
3194   Otherwise returns \c false.
3195  */
3196 
3197 /*! \fn void NamespaceNode::setDocNode(NamespaceNode *ns) { docNode_ = ns; }
3198   Called in QDocDatabase::resolveNamespaces() to set the pointer to the
3199   NamespaceNode in which this namespace is documented.
3200 
3201   \sa QDocDatabase::resolveNamespaces()
3202  */
3203 
3204 /*! \fn NamespaceNode *NamespaceNode::docNode() const
3205   Returns a pointer to the NamespaceNode that represents where the namespace
3206   documentation is actually generated. API elements in many different modules
3207   can be included in a single namespace. That namespace is only documented in
3208   one module. The namespace is documented in the module where the \c {\\namespace}
3209   command for the namespace appears.
3210 
3211   \sa QDocDatabase::resolveNamespaces()
3212  */
3213 
3214 /*!
3215   \struct RelatedClass
3216   \brief A struct for indicating that a ClassNode is related in some way to another ClassNode.
3217 
3218   This struct has nothing to do with the \c {\\relates} command. This struct
3219   is used for indicating that a ClassNode is a base class of another ClassNode,
3220   is a derived class of another ClassNode, or is an ignored base class of
3221   another ClassNode. This struct is only used in ClassNode.
3222 */
3223 
3224 /*! \fn RelatedClass::RelatedClass()
3225   The default constructor does nothing. It is only used for allocating empty
3226   instances of RelatedClass in containers.
3227  */
3228 
3229 /*! \fn RelatedClass::RelatedClass(Node::Access access, ClassNode *node)
3230   This is the constructor used when the related class has been resolved.
3231   In other words, when the ClassNode has been created so that \a node is
3232   not \c nullptr.
3233 */
3234 
3235 /*! \fn RelatedClass::RelatedClass(Node::Access access, const QStringList &path, const QString &signature)
3236   This is the constructor used when the related class has not bee resolved,
3237   because it hasn't been created yet. In that case, we store the qualified
3238   \a path name of the class and the \a signature of the class, which I think
3239   is just the name of the class.
3240 
3241   \note We might be able to simplify the whole RelatedClass concept. Maybe we
3242   can get rid of it completely.
3243 */
3244 
3245 /*! \fn bool RelatedClass::isPrivate() const
3246   Returns \c true if this RelatedClass is marked as Node::Private.
3247 */
3248 
3249 /*!
3250   Returns a string representing the access specifier.
3251  */
accessString() const3252 QString RelatedClass::accessString() const
3253 {
3254     switch (access_) {
3255     case Node::Protected:
3256         return QLatin1String("protected");
3257     case Node::Private:
3258         return QLatin1String("private");
3259     case Node::Public:
3260     default:
3261         break;
3262     }
3263     return QLatin1String("public");
3264 }
3265 
3266 /*!
3267   \struct UsingClause
3268   \brief This is supposed to describe a using clause, but I think it is not used.
3269 
3270   This struct is only used in ClassNode. It describes a \c using clause that
3271   was parsed. But now it looks like it is not actually used at all.
3272 
3273   Maybe we can get rid of it?
3274 */
3275 
3276 /*! \fn UsingClause::UsingClause()
3277   The default constructor does nothing. It is only used for allocating empty
3278   instances of UsingClause in containers.
3279  */
3280 
3281 /*! \fn UsingClause::UsingClause(const QString &signature)
3282   We assume the node that the using clause refers to has not yet been
3283   created, so this constructor provides its \a signature, which is the
3284   qualified path name of whatever it is.
3285  */
3286 
3287 /*! \fn const QString &UsingClause::signature() const
3288   This function returns a const reference to the signature, which is the qualified
3289   path name of whatever the using clause refers to.
3290  */
3291 
3292 /*! \fn const Node *UsingClause::node()
3293   This function returns a pointer to the node which has been resolved by looking
3294   up the signature in the qdoc database. If it wasn't resolved, \c nullptr is returned.
3295  */
3296 
3297 /*! \fn void UsingClause::setNode(const Node *n)
3298   This function is called when the signature can be resolved. The node pointer
3299   is set to \a n.
3300  */
3301 
3302 /*!
3303   \class ClassNode
3304   \brief The ClassNode represents a C++ class.
3305 
3306   It is also used to represent a C++ struct or union. There are some
3307   actual uses for structs, but I don't think any unions have been
3308   documented yet.
3309  */
3310 
3311 /*!
3312   Adds the base class \a node to this class's list of base
3313   classes. The base class has the specified \a access. This
3314   is a resolved base class.
3315  */
addResolvedBaseClass(Access access,ClassNode * node)3316 void ClassNode::addResolvedBaseClass(Access access, ClassNode *node)
3317 {
3318     bases_.append(RelatedClass(access, node));
3319     node->derived_.append(RelatedClass(access, this));
3320 }
3321 
3322 /*!
3323   Adds the derived class \a node to this class's list of derived
3324   classes. The derived class inherits this class with \a access.
3325  */
addDerivedClass(Access access,ClassNode * node)3326 void ClassNode::addDerivedClass(Access access, ClassNode *node)
3327 {
3328     derived_.append(RelatedClass(access, node));
3329 }
3330 
3331 /*!
3332   Add an unresolved base class to this class node's list of
3333   base classes. The unresolved base class will be resolved
3334   before the generate phase of qdoc. In an unresolved base
3335   class, the pointer to the base class node is 0.
3336  */
addUnresolvedBaseClass(Access access,const QStringList & path,const QString & signature)3337 void ClassNode::addUnresolvedBaseClass(Access access, const QStringList &path,
3338                                        const QString &signature)
3339 {
3340     bases_.append(RelatedClass(access, path, signature));
3341 }
3342 
3343 /*!
3344   Add an unresolved \c using clause to this class node's list
3345   of \c using clauses. The unresolved \c using clause will be
3346   resolved before the generate phase of qdoc. In an unresolved
3347   \c using clause, the pointer to the function node is 0.
3348  */
addUnresolvedUsingClause(const QString & signature)3349 void ClassNode::addUnresolvedUsingClause(const QString &signature)
3350 {
3351     usingClauses_.append(UsingClause(signature));
3352 }
3353 
3354 /*!
3355   Search the child list to find the property node with the
3356   specified \a name.
3357  */
findPropertyNode(const QString & name)3358 PropertyNode *ClassNode::findPropertyNode(const QString &name)
3359 {
3360     Node *n = findNonfunctionChild(name, &Node::isProperty);
3361 
3362     if (n)
3363         return static_cast<PropertyNode *>(n);
3364 
3365     PropertyNode *pn = nullptr;
3366 
3367     const QVector<RelatedClass> &bases = baseClasses();
3368     if (!bases.isEmpty()) {
3369         for (int i = 0; i < bases.size(); ++i) {
3370             ClassNode *cn = bases[i].node_;
3371             if (cn) {
3372                 pn = cn->findPropertyNode(name);
3373                 if (pn)
3374                     break;
3375             }
3376         }
3377     }
3378     const QVector<RelatedClass> &ignoredBases = ignoredBaseClasses();
3379     if (!ignoredBases.isEmpty()) {
3380         for (int i = 0; i < ignoredBases.size(); ++i) {
3381             ClassNode *cn = ignoredBases[i].node_;
3382             if (cn) {
3383                 pn = cn->findPropertyNode(name);
3384                 if (pn)
3385                     break;
3386             }
3387         }
3388     }
3389 
3390     return pn;
3391 }
3392 
3393 /*!
3394   This function does a recursive search of this class node's
3395   base classes looking for one that has a QML element. If it
3396   finds one, it returns the pointer to that QML element. If
3397   it doesn't find one, it returns null.
3398  */
findQmlBaseNode()3399 QmlTypeNode *ClassNode::findQmlBaseNode()
3400 {
3401     QmlTypeNode *result = nullptr;
3402     const QVector<RelatedClass> &bases = baseClasses();
3403 
3404     if (!bases.isEmpty()) {
3405         for (int i = 0; i < bases.size(); ++i) {
3406             ClassNode *cn = bases[i].node_;
3407             if (cn && cn->qmlElement()) {
3408                 return cn->qmlElement();
3409             }
3410         }
3411         for (int i = 0; i < bases.size(); ++i) {
3412             ClassNode *cn = bases[i].node_;
3413             if (cn) {
3414                 result = cn->findQmlBaseNode();
3415                 if (result != nullptr) {
3416                     return result;
3417                 }
3418             }
3419         }
3420     }
3421     return result;
3422 }
3423 
3424 /*!
3425   \a fn is an overriding function in this class or in a class
3426   derived from this class. Find the node for the function that
3427   \a fn overrides in this class's children or in one of this
3428   class's base classes. Return a pointer to the overridden
3429   function or return 0.
3430 
3431   This should be revised because clang provides the path to the
3432   overridden function. mws 15/12/2018
3433  */
findOverriddenFunction(const FunctionNode * fn)3434 FunctionNode *ClassNode::findOverriddenFunction(const FunctionNode *fn)
3435 {
3436     for (auto &bc : bases_) {
3437         ClassNode *cn = bc.node_;
3438         if (cn == nullptr) {
3439             cn = QDocDatabase::qdocDB()->findClassNode(bc.path_);
3440             bc.node_ = cn;
3441         }
3442         if (cn != nullptr) {
3443             FunctionNode *result = cn->findFunctionChild(fn);
3444             if (result != nullptr && !result->isInternal() && !result->isNonvirtual()
3445                 && result->hasDoc())
3446                 return result;
3447             result = cn->findOverriddenFunction(fn);
3448             if (result != nullptr && !result->isNonvirtual())
3449                 return result;
3450         }
3451     }
3452     return nullptr;
3453 }
3454 
3455 /*!
3456   \a fn is an overriding function in this class or in a class
3457   derived from this class. Find the node for the property that
3458   \a fn overrides in this class's children or in one of this
3459   class's base classes. Return a pointer to the overridden
3460   property or return 0.
3461  */
findOverriddenProperty(const FunctionNode * fn)3462 PropertyNode *ClassNode::findOverriddenProperty(const FunctionNode *fn)
3463 {
3464     for (auto &baseClass : bases_) {
3465         ClassNode *cn = baseClass.node_;
3466         if (cn == nullptr) {
3467             cn = QDocDatabase::qdocDB()->findClassNode(baseClass.path_);
3468             baseClass.node_ = cn;
3469         }
3470         if (cn != nullptr) {
3471             const NodeList &children = cn->childNodes();
3472             for (const auto &child : children) {
3473                 if (child->isProperty()) {
3474                     PropertyNode *pn = static_cast<PropertyNode *>(child);
3475                     if (pn->name() == fn->name() || pn->hasAccessFunction(fn->name())) {
3476                         if (pn->hasDoc())
3477                             return pn;
3478                     }
3479                 }
3480             }
3481             PropertyNode *result = cn->findOverriddenProperty(fn);
3482             if (result != nullptr)
3483                 return result;
3484         }
3485     }
3486     return nullptr;
3487 }
3488 
3489 /*!
3490   Returns true if the class or struct represented by this class
3491   node must be documented. If this function returns true, then
3492   qdoc must find a qdoc comment for this class. If it returns
3493   false, then the class need not be documented.
3494  */
docMustBeGenerated() const3495 bool ClassNode::docMustBeGenerated() const
3496 {
3497     if (!hasDoc() || isPrivate() || isInternal() || isDontDocument())
3498         return false;
3499     if (declLocation().fileName().endsWith(QLatin1String("_p.h")) && !hasDoc())
3500         return false;
3501 
3502     return true;
3503 }
3504 
3505 /*!
3506   \class Headerode
3507   \brief This class represents a C++ header file.
3508  */
3509 
HeaderNode(Aggregate * parent,const QString & name)3510 HeaderNode::HeaderNode(Aggregate *parent, const QString &name) : Aggregate(HeaderFile, parent, name)
3511 {
3512     // Add the include file with enclosing angle brackets removed
3513     if (name.startsWith(QChar('<')) && name.length() > 2)
3514         Aggregate::addIncludeFile(name.mid(1).chopped(1));
3515     else
3516         Aggregate::addIncludeFile(name);
3517 }
3518 
3519 /*!
3520   Returns true if this header file node is not private and
3521   contains at least one public child node with documentation.
3522  */
docMustBeGenerated() const3523 bool HeaderNode::docMustBeGenerated() const
3524 {
3525     if (isInAPI())
3526         return true;
3527     return (hasDocumentedChildren() ? true : false);
3528 }
3529 
3530 /*!
3531   Returns true if this header file node contains at least one
3532   child that has documentation and is not private or internal.
3533  */
hasDocumentedChildren() const3534 bool HeaderNode::hasDocumentedChildren() const
3535 {
3536     for (const auto *node : qAsConst(children_)) {
3537         if (node->isInAPI())
3538             return true;
3539     }
3540     return false;
3541 }
3542 
3543 /*!
3544   \class PageNode
3545   \brief A PageNode is a Node that generates a documentation page.
3546 
3547   Not all subclasses of Node produce documentation pages. FunctionNode,
3548   PropertyNode, and EnumNode are all examples of subclasses of Node that
3549   don't produce documentation pages but add documentation to a page.
3550   They are always child nodes of an Aggregate, and Aggregate inherits
3551   PageNode.
3552 
3553   Not every subclass of PageNode inherits Aggregate. ExternalPageNode,
3554   ExampleNode, and CollectionNode are subclasses of PageNode that are
3555   not subclasses of Aggregate. Because they are not subclasses of
3556   Aggregate, they can't have children. But they still generate, or
3557   link to, a documentation page.
3558  */
3559 
3560 /*! \fn QString PageNode::title() const
3561   Returns the node's title, which is used for the page title.
3562  */
3563 
3564 /*! \fn QString PageNode::subtitle() const
3565   Returns the node's subtitle, which may be empty.
3566  */
3567 
3568 /*!
3569   Returns the node's full title.
3570  */
fullTitle() const3571 QString PageNode::fullTitle() const
3572 {
3573     return title();
3574 }
3575 
3576 /*!
3577   Sets the node's \a title, which is used for the page title.
3578   Returns true. Adds the node to the parent() nonfunction map
3579   using the \a title as the key.
3580  */
setTitle(const QString & title)3581 bool PageNode::setTitle(const QString &title)
3582 {
3583     title_ = title;
3584     parent()->addChildByTitle(this, title);
3585     return true;
3586 }
3587 
3588 /*!
3589   \fn bool PageNode::setSubtitle(const QString &subtitle)
3590   Sets the node's \a subtitle. Returns true;
3591  */
3592 
3593 /*! \fn PageNode::PageNode(Aggregate *parent, const QString &name)
3594   This constructor sets the PageNode's \a parent and the \a name is the
3595   argument of the \c {\\page} command. The node type is set to Node::Page.
3596  */
3597 
3598 /*! \fn PageNode::PageNode(NodeType type, Aggregate *parent, const QString &name)
3599   This constructor is not called directly. It is called by the constructors of
3600   subclasses of PageNode, usually Aggregate. The node type is set to \a type,
3601   and the parent pointer is set to \a parent. \a name is the argument of the topic
3602   command that resulted in the PageNode being created. This could be \c {\\class}
3603   or \c {\\namespace}, for example.
3604  */
3605 
3606 /*! \fn PageNode::PageNode(Aggregate *parent, const QString &name, PageType ptype)
3607   This constructor is called when the argument to the \c {\\page} command
3608   contains a space, which means the second word of the argument is the page type.
3609   It creates a PageNode that has node type Node::Page, with the specified
3610   \a parent and \name, and the \a ptype is that second word of the argument to
3611   the \c {\\page} command.
3612 
3613   \sa Node::PageType
3614  */
3615 
3616 /*! \fn PageNode::~PageNode()
3617   The destructor is virtual, and it does nothing.
3618  */
3619 
3620 /*! \fn bool PageNode::isPageNode() const
3621   Always returns \c true because this is a PageNode.
3622  */
3623 
3624 /*! \fn bool PageNode::isTextPageNode() const
3625   Returns \c true if this instance of PageNode is not an Aggregate.
3626   The significance of a \c true return value is that this PageNode
3627   doesn't have children, because it is not an Aggregate.
3628 
3629   \sa Aggregate.
3630  */
3631 
3632 /*! \fn QString PageNode::nameForLists() const
3633   Returns the title().
3634  */
3635 
3636 /*! \fn QString PageNode::imageFileName() const
3637   If this PageNode is an ExampleNode, the image file name
3638   data member is returned. Otherwise an empty string is
3639   returned.
3640  */
3641 
3642 /*! \fn void PageNode::setImageFileName(const QString &ifn)
3643   If this PageNode is an ExampleNode, the image file name
3644   data member is set to \a ifn. Otherwise the function does
3645   nothing.
3646  */
3647 
3648 /*! \fn bool PageNode::noAutoList() const
3649   Returns the value of the no auto-list flag.
3650  */
3651 
3652 /*! \fn void PageNode::setNoAutoList(bool b)
3653   Sets the no auto-list flag to \a b.
3654  */
3655 
3656 /*! \fn const QStringList &PageNode::groupNames() const
3657   Returns a const reference to the string list containing all the group names.
3658  */
3659 
3660 /*! \fn void PageNode::appendGroupName(const QString &t)
3661   Appends \a t to the list of group names.
3662  */
3663 
3664 /*! \fn void PageNode::setOutputFileName(const QString &f)
3665   Sets this PageNode's output file name to \a f.
3666  */
3667 
3668 /*! \fn QString PageNode::outputFileName() const
3669   Returns this PageNode's output file name.
3670  */
3671 
3672 /*!
3673   \class ExternalPageNode
3674 
3675   \brief The ExternalPageNode represents an external documentation page.
3676 
3677   Qdoc can generate links to pages that are not part of the documentation
3678   being generated. 3rd party software pages are often referenced by links
3679   from the QT documentation. Qdoc creates an ExternalPageNode when it sees
3680   an \c {\\externalpage} command. The HTML generator can then use the node
3681   when it needs to create links to the external page.
3682 
3683   ExternalPageNode inherits PageNode.
3684 */
3685 
3686 /*! \fn ExternalPageNode::ExternalPageNode(Aggregate *parent, const QString &name)
3687   The constructor creates an ExternalPageNode as a child node of \a parent.
3688   It's \a name is the argument from the \c {\\externalpage} command. The node
3689   type is Node::ExternalPage, and the page type is Node::ArticlePage.
3690  */
3691 
3692 /*!
3693   \class EnumNode
3694  */
3695 
3696 /*!
3697   Add \a item to the enum type's item list.
3698  */
addItem(const EnumItem & item)3699 void EnumNode::addItem(const EnumItem &item)
3700 {
3701     items_.append(item);
3702     names_.insert(item.name());
3703 }
3704 
3705 /*!
3706   Returns the access level of the enumeration item named \a name.
3707   Apparently it is private if it has been omitted by qdoc's
3708   omitvalue command. Otherwise it is public.
3709  */
itemAccess(const QString & name) const3710 Node::Access EnumNode::itemAccess(const QString &name) const
3711 {
3712     if (doc().omitEnumItemNames().contains(name))
3713         return Private;
3714     return Public;
3715 }
3716 
3717 /*!
3718   Returns the enum value associated with the enum \a name.
3719  */
itemValue(const QString & name) const3720 QString EnumNode::itemValue(const QString &name) const
3721 {
3722     for (const auto &item : qAsConst(items_)) {
3723         if (item.name() == name)
3724             return item.value();
3725     }
3726     return QString();
3727 }
3728 
3729 /*!
3730   Clone this node on the heap and make the clone a child of
3731   \a parent. Return the pointer to the clone.
3732  */
clone(Aggregate * parent)3733 Node *EnumNode::clone(Aggregate *parent)
3734 {
3735     EnumNode *en = new EnumNode(*this); // shallow copy
3736     en->setParent(nullptr);
3737     parent->addChild(en);
3738     return en;
3739 }
3740 
3741 /*!
3742   \class TypedefNode
3743  */
3744 
3745 /*!
3746  */
setAssociatedEnum(const EnumNode * enume)3747 void TypedefNode::setAssociatedEnum(const EnumNode *enume)
3748 {
3749     associatedEnum_ = enume;
3750 }
3751 
3752 /*!
3753   Clone this node on the heap and make the clone a child of
3754   \a parent. Return the pointer to the clone.
3755  */
clone(Aggregate * parent)3756 Node *TypedefNode::clone(Aggregate *parent)
3757 {
3758     TypedefNode *tn = new TypedefNode(*this); // shallow copy
3759     tn->setParent(nullptr);
3760     parent->addChild(tn);
3761     return tn;
3762 }
3763 
3764 /*!
3765   \class TypeAliasNode
3766  */
3767 
3768 /*!
3769   Clone this node on the heap and make the clone a child of
3770   \a parent. Return the pointer to the clone.
3771  */
clone(Aggregate * parent)3772 Node *TypeAliasNode::clone(Aggregate *parent)
3773 {
3774     TypeAliasNode *tan = new TypeAliasNode(*this); // shallow copy
3775     tan->setParent(nullptr);
3776     parent->addChild(tan);
3777     return tan;
3778 }
3779 
3780 /*!
3781   \class FunctionNode
3782 
3783   This node is used to represent any kind of function being
3784   documented. It can represent a C++ class member function,
3785   a C++ global function, a QML method, a javascript method,
3786   or a macro, with or without parameters.
3787 
3788   A C++ function can be a signal a slot, a constructor of any
3789   kind, a destructor, a copy or move assignment operator, or
3790   just a plain old member function or global function.
3791 
3792   A QML or javascript method can be a plain old method, or a
3793   signal or signal handler.
3794 
3795   If the function is not an overload, its overload flag is
3796   false. If it is an overload, its overload flag is true.
3797   If it is not an overload but it has overloads, its next
3798   overload pointer will point to an overload function. If it
3799   is an overload function, its overload flag is true, and it
3800   may or may not have a non-null next overload pointer.
3801 
3802   So all the overloads of a function are in a linked list
3803   using the next overload pointer. If a function has no
3804   overloads, its overload flag is false and its overload
3805   pointer is null.
3806 
3807   The function node also has an overload number. If the
3808   node's overload flag is set, this overload number is
3809   positive; otherwise, the overload number is 0.
3810  */
3811 
3812 /*!
3813   Construct a function node for a C++ function. It's parent
3814   is \a parent, and it's name is \a name.
3815 
3816   \note The function node's overload flag is set to false, and
3817   its overload number is set to 0. These data members are set
3818   in normalizeOverloads(), when all the overloads are known.
3819  */
FunctionNode(Aggregate * parent,const QString & name)3820 FunctionNode::FunctionNode(Aggregate *parent, const QString &name)
3821     : Node(Function, parent, name),
3822       const_(false),
3823       static_(false),
3824       reimpFlag_(false),
3825       attached_(false),
3826       overloadFlag_(false),
3827       isFinal_(false),
3828       isOverride_(false),
3829       isRef_(false),
3830       isRefRef_(false),
3831       isInvokable_(false),
3832       metaness_(Plain),
3833       virtualness_(NonVirtual),
3834       overloadNumber_(0),
3835       nextOverload_(nullptr)
3836 {
3837     // nothing
3838 }
3839 
3840 /*!
3841   Construct a function node for a QML method or signal, specified
3842   by ther Metaness value \a type. It's parent is \a parent, and
3843   it's name is \a name. If \a attached is true, it is an attached
3844   method or signal.
3845 
3846   \note The function node's overload flag is set to false, and
3847   its overload number is set to 0. These data members are set
3848   in normalizeOverloads(), when all the overloads are known.
3849  */
FunctionNode(Metaness kind,Aggregate * parent,const QString & name,bool attached)3850 FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString &name, bool attached)
3851     : Node(Function, parent, name),
3852       const_(false),
3853       static_(false),
3854       reimpFlag_(false),
3855       attached_(attached),
3856       overloadFlag_(false),
3857       isFinal_(false),
3858       isOverride_(false),
3859       isRef_(false),
3860       isRefRef_(false),
3861       isInvokable_(false),
3862       metaness_(kind),
3863       virtualness_(NonVirtual),
3864       overloadNumber_(0),
3865       nextOverload_(nullptr)
3866 {
3867     setGenus(getGenus(metaness_));
3868     if (!isCppNode() && name.startsWith("__"))
3869         setStatus(Internal);
3870 }
3871 
3872 /*!
3873   Clone this node on the heap and make the clone a child of
3874   \a parent. Return the pointer to the clone.
3875  */
clone(Aggregate * parent)3876 Node *FunctionNode::clone(Aggregate *parent)
3877 {
3878     FunctionNode *fn = new FunctionNode(*this); // shallow copy
3879     fn->setParent(nullptr);
3880     fn->setNextOverload(nullptr);
3881     parent->addChild(fn);
3882     return fn;
3883 }
3884 
3885 /*!
3886   Returns this function's virtualness value as a string
3887   for use as an attribute value in index files.
3888  */
virtualness() const3889 QString FunctionNode::virtualness() const
3890 {
3891     switch (virtualness_) {
3892     case FunctionNode::NormalVirtual:
3893         return QLatin1String("virtual");
3894     case FunctionNode::PureVirtual:
3895         return QLatin1String("pure");
3896     case FunctionNode::NonVirtual:
3897     default:
3898         break;
3899     }
3900     return QLatin1String("non");
3901 }
3902 
3903 /*!
3904   Sets the function node's virtualness value based on the value
3905   of string \a t, which is the value of the function's \e{virtual}
3906   attribute in an index file. If \a t is \e{pure}, and if the
3907   parent() is a C++ class, set the parent's \e abstract flag to
3908   \c {true}.
3909  */
setVirtualness(const QString & t)3910 void FunctionNode::setVirtualness(const QString &t)
3911 {
3912     if (t == QLatin1String("non"))
3913         virtualness_ = NonVirtual;
3914     else if (t == QLatin1String("virtual"))
3915         virtualness_ = NormalVirtual;
3916     else if (t == QLatin1String("pure")) {
3917         virtualness_ = PureVirtual;
3918         if (parent() && parent()->isClassNode())
3919             parent()->setAbstract(true);
3920     }
3921 }
3922 
3923 static QMap<QString, FunctionNode::Metaness> metanessMap_;
buildMetanessMap()3924 static void buildMetanessMap()
3925 {
3926     metanessMap_["plain"] = FunctionNode::Plain;
3927     metanessMap_["signal"] = FunctionNode::Signal;
3928     metanessMap_["slot"] = FunctionNode::Slot;
3929     metanessMap_["constructor"] = FunctionNode::Ctor;
3930     metanessMap_["copy-constructor"] = FunctionNode::CCtor;
3931     metanessMap_["move-constructor"] = FunctionNode::MCtor;
3932     metanessMap_["destructor"] = FunctionNode::Dtor;
3933     metanessMap_["macro"] = FunctionNode::MacroWithParams;
3934     metanessMap_["macrowithparams"] = FunctionNode::MacroWithParams;
3935     metanessMap_["macrowithoutparams"] = FunctionNode::MacroWithoutParams;
3936     metanessMap_["copy-assign"] = FunctionNode::CAssign;
3937     metanessMap_["move-assign"] = FunctionNode::MAssign;
3938     metanessMap_["native"] = FunctionNode::Native;
3939     metanessMap_["qmlsignal"] = FunctionNode::QmlSignal;
3940     metanessMap_["qmlsignalhandler"] = FunctionNode::QmlSignalHandler;
3941     metanessMap_["qmlmethod"] = FunctionNode::QmlMethod;
3942     metanessMap_["jssignal"] = FunctionNode::JsSignal;
3943     metanessMap_["jssignalhandler"] = FunctionNode::JsSignalHandler;
3944     metanessMap_["jsmethos"] = FunctionNode::JsMethod;
3945 }
3946 
3947 static QMap<QString, FunctionNode::Metaness> topicMetanessMap_;
buildTopicMetanessMap()3948 static void buildTopicMetanessMap()
3949 {
3950     topicMetanessMap_["fn"] = FunctionNode::Plain;
3951     topicMetanessMap_["qmlsignal"] = FunctionNode::QmlSignal;
3952     topicMetanessMap_["qmlattachedsignal"] = FunctionNode::QmlSignal;
3953     topicMetanessMap_["qmlmethod"] = FunctionNode::QmlMethod;
3954     topicMetanessMap_["qmlattachedmethod"] = FunctionNode::QmlMethod;
3955     topicMetanessMap_["jssignal"] = FunctionNode::JsSignal;
3956     topicMetanessMap_["jsattachedsignal"] = FunctionNode::JsSignal;
3957     topicMetanessMap_["jsmethod"] = FunctionNode::JsMethod;
3958     topicMetanessMap_["jsattachedmethod"] = FunctionNode::JsMethod;
3959 }
3960 
3961 /*!
3962   Determines the Genus value for this FunctionNode given the
3963   Metaness value \a t. Returns the Genus value. \a t must be
3964   one of the values of Metaness. If not, Node::DontCare is
3965   returned.
3966  */
getGenus(FunctionNode::Metaness t)3967 Node::Genus FunctionNode::getGenus(FunctionNode::Metaness t)
3968 {
3969     switch (t) {
3970     case FunctionNode::Plain:
3971     case FunctionNode::Signal:
3972     case FunctionNode::Slot:
3973     case FunctionNode::Ctor:
3974     case FunctionNode::Dtor:
3975     case FunctionNode::CCtor:
3976     case FunctionNode::MCtor:
3977     case FunctionNode::MacroWithParams:
3978     case FunctionNode::MacroWithoutParams:
3979     case FunctionNode::Native:
3980     case FunctionNode::CAssign:
3981     case FunctionNode::MAssign:
3982         return Node::CPP;
3983     case FunctionNode::QmlSignal:
3984     case FunctionNode::QmlSignalHandler:
3985     case FunctionNode::QmlMethod:
3986         return Node::QML;
3987     case FunctionNode::JsSignal:
3988     case FunctionNode::JsSignalHandler:
3989     case FunctionNode::JsMethod:
3990         return Node::JS;
3991     }
3992     return Node::DontCare;
3993 }
3994 
3995 /*!
3996   This static function converts the string \a t to an enum
3997   value for the kind of function named by \a t.
3998  */
getMetaness(const QString & t)3999 FunctionNode::Metaness FunctionNode::getMetaness(const QString &t)
4000 {
4001     if (metanessMap_.isEmpty())
4002         buildMetanessMap();
4003     return metanessMap_[t];
4004 }
4005 
4006 /*!
4007   This static function converts the topic string \a t to an enum
4008   value for the kind of function this FunctionNode represents.
4009  */
getMetanessFromTopic(const QString & t)4010 FunctionNode::Metaness FunctionNode::getMetanessFromTopic(const QString &t)
4011 {
4012     if (topicMetanessMap_.isEmpty())
4013         buildTopicMetanessMap();
4014     return topicMetanessMap_[t];
4015 }
4016 
4017 /*!
4018   Sets the function node's Metaness value based on the value
4019   of string \a t, which is the value of the function's "meta"
4020   attribute in an index file. Returns the Metaness value
4021  */
setMetaness(const QString & t)4022 FunctionNode::Metaness FunctionNode::setMetaness(const QString &t)
4023 {
4024     metaness_ = getMetaness(t);
4025     return metaness_;
4026 }
4027 
4028 /*!
4029   If this function node's metaness is \a from, change the
4030   metaness to \a to and return \c true. Otherwise return
4031   false. This function is used to change Qml function node
4032   metaness values to Javascript function node metaness,
4033   values because these nodes are created as Qml function
4034   nodes before it is discovered that what the function node
4035   represents is not a Qml function but a javascript function.
4036 
4037   Note that if the function returns true, which means the node
4038   type was indeed changed, then the node's Genus is also changed
4039   from QML to JS.
4040 
4041   The function also works in the other direction, but there is
4042   no use case for that.
4043  */
changeMetaness(Metaness from,Metaness to)4044 bool FunctionNode::changeMetaness(Metaness from, Metaness to)
4045 {
4046     if (metaness_ == from) {
4047         metaness_ = to;
4048         switch (to) {
4049         case QmlSignal:
4050         case QmlSignalHandler:
4051         case QmlMethod:
4052             setGenus(Node::QML);
4053             break;
4054         case JsSignal:
4055         case JsSignalHandler:
4056         case JsMethod:
4057             setGenus(Node::JS);
4058             break;
4059         default:
4060             setGenus(Node::CPP);
4061             break;
4062         }
4063         return true;
4064     }
4065     return false;
4066 }
4067 
4068 /*! \fn void FunctionNode::setOverloadNumber(unsigned char n)
4069   Sets the function node's overload number to \a n. If \a n
4070   is 0, the function node's overload flag is set to false. If
4071   \a n is greater than 0, the overload flag is set to true.
4072  */
setOverloadNumber(signed short n)4073 void FunctionNode::setOverloadNumber(signed short n)
4074 {
4075     overloadNumber_ = n;
4076     overloadFlag_ = (n > 0) ? true : false;
4077 }
4078 
4079 /*!
4080   If this function's next overload pointer is null, set it to
4081   \a fn. Otherwise continue down the overload list by calling
4082   this function recursively for the next overload.
4083 
4084   Although this function appends an overload function to the list of
4085   overloads for this function's name, it does not set the function's
4086   overload number or it's overload flag. If the function has the
4087   \c{\\overload} in its qdoc comment, that will set the overload
4088   flag. But qdoc treats the \c{\\overload} command as a hint that the
4089   function should be documented as an overload. The hint is almost
4090   always correct, but qdoc reserves the right to decide which function
4091   should be the primary function and which functions are the overloads.
4092   These decisions are made in Aggregate::normalizeOverloads().
4093  */
appendOverload(FunctionNode * fn)4094 void FunctionNode::appendOverload(FunctionNode *fn)
4095 {
4096     if (nextOverload_ == nullptr)
4097         nextOverload_ = fn;
4098     else
4099         nextOverload_->appendOverload(fn);
4100 }
4101 
4102 /*!
4103   This function assumes that this FunctionNode is marked as an
4104   overload function. It asks if the next overload is marked as
4105   an overload. If not, then remove that FunctionNode from the
4106   overload list and return it. Otherwise call this function
4107   recursively for the next overload.
4108  */
findPrimaryFunction()4109 FunctionNode *FunctionNode::findPrimaryFunction()
4110 {
4111     if (nextOverload_ != nullptr) {
4112         if (!nextOverload_->isOverload()) {
4113             FunctionNode *t = nextOverload_;
4114             nextOverload_ = t->nextOverload();
4115             t->setNextOverload(nullptr);
4116             return t;
4117         }
4118         return nextOverload_->findPrimaryFunction();
4119     }
4120     return nullptr;
4121 }
4122 
4123 /*!
4124   \fn void FunctionNode::setReimpFlag()
4125 
4126   Sets the function node's reimp flag to \c true, which means
4127   the \e {\\reimp} command was used in the qdoc comment. It is
4128   supposed to mean that the function reimplements a virtual
4129   function in a base class.
4130  */
4131 
4132 /*!
4133   Returns a string representing the kind of function this
4134   Function node represents, which depends on the Metaness
4135   value.
4136  */
kindString() const4137 QString FunctionNode::kindString() const
4138 {
4139     switch (metaness_) {
4140     case FunctionNode::QmlSignal:
4141         return "QML signal";
4142     case FunctionNode::QmlSignalHandler:
4143         return "QML signal handler";
4144     case FunctionNode::QmlMethod:
4145         return "QML method";
4146     case FunctionNode::JsSignal:
4147         return "JS signal";
4148     case FunctionNode::JsSignalHandler:
4149         return "JS signal handler";
4150     case FunctionNode::JsMethod:
4151         return "JS method";
4152     default:
4153         return "function";
4154     }
4155 }
4156 
4157 /*!
4158   Returns a string representing the Metaness enum value for
4159   this function. It is used in index files.
4160  */
metanessString() const4161 QString FunctionNode::metanessString() const
4162 {
4163     switch (metaness_) {
4164     case FunctionNode::Plain:
4165         return "plain";
4166     case FunctionNode::Signal:
4167         return "signal";
4168     case FunctionNode::Slot:
4169         return "slot";
4170     case FunctionNode::Ctor:
4171         return "constructor";
4172     case FunctionNode::CCtor:
4173         return "copy-constructor";
4174     case FunctionNode::MCtor:
4175         return "move-constructor";
4176     case FunctionNode::Dtor:
4177         return "destructor";
4178     case FunctionNode::MacroWithParams:
4179         return "macrowithparams";
4180     case FunctionNode::MacroWithoutParams:
4181         return "macrowithoutparams";
4182     case FunctionNode::Native:
4183         return "native";
4184     case FunctionNode::CAssign:
4185         return "copy-assign";
4186     case FunctionNode::MAssign:
4187         return "move-assign";
4188     case FunctionNode::QmlSignal:
4189         return "qmlsignal";
4190     case FunctionNode::QmlSignalHandler:
4191         return "qmlsignalhandler";
4192     case FunctionNode::QmlMethod:
4193         return "qmlmethod";
4194     case FunctionNode::JsSignal:
4195         return "jssignal";
4196     case FunctionNode::JsSignalHandler:
4197         return "jssignalhandler";
4198     case FunctionNode::JsMethod:
4199         return "jsmethod";
4200     default:
4201         return "plain";
4202     }
4203 }
4204 
4205 /*!
4206   Adds the "associated" property \a p to this function node.
4207   The function might be the setter or getter for a property,
4208   for example.
4209  */
addAssociatedProperty(PropertyNode * p)4210 void FunctionNode::addAssociatedProperty(PropertyNode *p)
4211 {
4212     associatedProperties_.append(p);
4213 }
4214 
4215 /*!
4216     \reimp
4217 
4218     Returns \c true if this is an access function for an obsolete property,
4219     otherwise calls the base implementation of isObsolete().
4220 */
isObsolete() const4221 bool FunctionNode::isObsolete() const
4222 {
4223     auto it = std::find_if_not(associatedProperties_.begin(),
4224                                associatedProperties_.end(),
4225                                [](const Node *p)->bool {
4226                                     return p->isObsolete();
4227                                });
4228 
4229     if (!associatedProperties_.isEmpty() && it == associatedProperties_.end())
4230         return true;
4231 
4232     return Node::isObsolete();
4233 }
4234 
4235 /*! \fn unsigned char FunctionNode::overloadNumber() const
4236   Returns the overload number for this function.
4237  */
4238 
4239 /*!
4240   Reconstructs and returns the function's signature. If \a values
4241   is \c true, the default values of the parameters are included.
4242   The return type is included unless \a noReturnType is \c true.
4243   Function templates are prefixed with \c {template <parameter_list>}
4244   if \a templateParams is \c true.
4245  */
signature(bool values,bool noReturnType,bool templateParams) const4246 QString FunctionNode::signature(bool values, bool noReturnType, bool templateParams) const
4247 {
4248     QStringList elements;
4249 
4250     if (templateParams)
4251         elements << templateDecl();
4252     if (!noReturnType)
4253         elements << returnType_;
4254     elements.removeAll({});
4255 
4256     if (!isMacroWithoutParams()) {
4257         elements << name() + QLatin1Char('(') + parameters_.signature(values) + QLatin1Char(')');
4258         if (!isMacro()) {
4259             if (isConst())
4260                 elements << QStringLiteral("const");
4261             if (isRef())
4262                 elements << QStringLiteral("&");
4263             else if (isRefRef())
4264                 elements << QStringLiteral("&&");
4265         }
4266     } else {
4267         elements << name();
4268     }
4269     return elements.join(QLatin1Char(' '));
4270 }
4271 
4272 /*!
4273   Returns true if function \a fn has role \a r for this
4274   property.
4275  */
role(const FunctionNode * fn) const4276 PropertyNode::FunctionRole PropertyNode::role(const FunctionNode *fn) const
4277 {
4278     for (int i = 0; i < 4; i++) {
4279         if (functions_[i].contains(const_cast<FunctionNode *>(fn)))
4280             return (FunctionRole)i;
4281     }
4282     return Notifier;
4283 }
4284 
4285 /*!
4286   Clone this node on the heap and make the clone a child of
4287   \a parent. Return the pointer to the clone.
4288  */
clone(Aggregate * parent)4289 Node *VariableNode::clone(Aggregate *parent)
4290 {
4291     VariableNode *vn = new VariableNode(*this); // shallow copy
4292     vn->setParent(nullptr);
4293     parent->addChild(vn);
4294     return vn;
4295 }
4296 
4297 /*!
4298   Print some information used for debugging qdoc. Only used when debugging.
4299  */
debug() const4300 void FunctionNode::debug() const
4301 {
4302     qDebug("QML METHOD %s returnType_ %s parentPath_ %s", qPrintable(name()),
4303            qPrintable(returnType_), qPrintable(parentPath_.join(' ')));
4304 }
4305 
4306 /*!
4307   Compares this FunctionNode to the FunctionNode pointed to
4308   by \a fn. Returns true if they describe the same function.
4309  */
compare(const FunctionNode * fn) const4310 bool FunctionNode::compare(const FunctionNode *fn) const
4311 {
4312     if (fn == nullptr)
4313         return false;
4314     if (metaness() != fn->metaness())
4315         return false;
4316     if (parent() != fn->parent())
4317         return false;
4318     if (returnType_ != fn->returnType())
4319         return false;
4320     if (isConst() != fn->isConst())
4321         return false;
4322     if (isAttached() != fn->isAttached())
4323         return false;
4324     const Parameters &p = fn->parameters();
4325     if (parameters_.count() != p.count())
4326         return false;
4327     if (!p.isEmpty()) {
4328         for (int i = 0; i < p.count(); ++i) {
4329             if (parameters_.at(i).type() != p.at(i).type())
4330                 return false;
4331         }
4332     }
4333     return true;
4334 }
4335 
4336 /*!
4337   In some cases, it is ok for a public function to be not documented.
4338   For example, the macro Q_OBJECT adds several functions to the API of
4339   a class, but these functions are normally not meant to be documented.
4340   So if a function node doesn't have documentation, then if its name is
4341   in the list of functions that it is ok not to document, this function
4342   returns true. Otherwise, it returns false.
4343 
4344   These are the member function names added by macros.  Usually they
4345   are not documented, but they can be documented, so this test avoids
4346   reporting an error if they are not documented.
4347 
4348   But maybe we should generate a standard text for each of them?
4349  */
isIgnored() const4350 bool FunctionNode::isIgnored() const
4351 {
4352     if (!hasDoc() && !hasSharedDoc()) {
4353         if (name().startsWith(QLatin1String("qt_")) || name() == QLatin1String("metaObject")
4354             || name() == QLatin1String("tr") || name() == QLatin1String("trUtf8")
4355             || name() == QLatin1String("d_func")) {
4356             return true;
4357         }
4358         QString s = signature(false, false);
4359         if (s.contains(QLatin1String("enum_type")) && s.contains(QLatin1String("operator|")))
4360             return true;
4361     }
4362     return false;
4363 }
4364 
4365 /*!
4366   Returns true if this function has overloads. Otherwise false.
4367   First, if this function node's overload pointer is not nullptr,
4368   return true. Next, if this function node's overload flag is true
4369   return true. Finally, if this function's parent Aggregate has a
4370   function by the same name as this one in its function map and
4371   that function has overloads, return true. Otherwise return false.
4372 
4373   There is a failsafe way to test it under any circumstances.
4374  */
hasOverloads() const4375 bool FunctionNode::hasOverloads() const
4376 {
4377     if (nextOverload_ != nullptr)
4378         return true;
4379     if (overloadFlag_)
4380         return true;
4381     if (parent())
4382         return parent()->hasOverloads(this);
4383     return false;
4384 }
4385 
4386 /*!
4387   \class PropertyNode
4388 
4389   This class describes one instance of using the Q_PROPERTY macro.
4390  */
4391 
4392 /*!
4393   The constructor sets the \a parent and the \a name, but
4394   everything else is set to default values.
4395  */
PropertyNode(Aggregate * parent,const QString & name)4396 PropertyNode::PropertyNode(Aggregate *parent, const QString &name)
4397     : Node(Property, parent, name),
4398       stored_(FlagValueDefault),
4399       designable_(FlagValueDefault),
4400       scriptable_(FlagValueDefault),
4401       writable_(FlagValueDefault),
4402       user_(FlagValueDefault),
4403       const_(false),
4404       final_(false),
4405       revision_(-1),
4406       overrides_(nullptr)
4407 {
4408     // nothing
4409 }
4410 
4411 /*!
4412   Sets this property's \e {overridden from} property to
4413   \a baseProperty, which indicates that this property
4414   overrides \a baseProperty. To begin with, all the values
4415   in this property are set to the corresponding values in
4416   \a baseProperty.
4417 
4418   We probably should ensure that the constant and final
4419   attributes are not being overridden improperly.
4420  */
setOverriddenFrom(const PropertyNode * baseProperty)4421 void PropertyNode::setOverriddenFrom(const PropertyNode *baseProperty)
4422 {
4423     for (int i = 0; i < NumFunctionRoles; ++i) {
4424         if (functions_[i].isEmpty())
4425             functions_[i] = baseProperty->functions_[i];
4426     }
4427     if (stored_ == FlagValueDefault)
4428         stored_ = baseProperty->stored_;
4429     if (designable_ == FlagValueDefault)
4430         designable_ = baseProperty->designable_;
4431     if (scriptable_ == FlagValueDefault)
4432         scriptable_ = baseProperty->scriptable_;
4433     if (writable_ == FlagValueDefault)
4434         writable_ = baseProperty->writable_;
4435     if (user_ == FlagValueDefault)
4436         user_ = baseProperty->user_;
4437     overrides_ = baseProperty;
4438 }
4439 
4440 /*!
4441   Returns a string containing the data type qualified with "const" either
4442   prepended to the data type or appended to it, or without the const
4443   qualification, depending circumstances in the PropertyNode internal state.
4444  */
qualifiedDataType() const4445 QString PropertyNode::qualifiedDataType() const
4446 {
4447     if (setters().isEmpty() && resetters().isEmpty()) {
4448         if (type_.contains(QLatin1Char('*')) || type_.contains(QLatin1Char('&'))) {
4449             // 'QWidget *' becomes 'QWidget *' const
4450             return type_ + " const";
4451         } else {
4452             /*
4453               'int' becomes 'const int' ('int const' is
4454               correct C++, but looks wrong)
4455              */
4456             return "const " + type_;
4457         }
4458     } else {
4459         return type_;
4460     }
4461 }
4462 
4463 /*!
4464   Returns true if this property has an access function named \a name.
4465  */
hasAccessFunction(const QString & name) const4466 bool PropertyNode::hasAccessFunction(const QString &name) const
4467 {
4468     for (const auto &getter : getters()) {
4469         if (getter->name() == name)
4470             return true;
4471     }
4472     for (const auto &setter : setters()) {
4473         if (setter->name() == name)
4474             return true;
4475     }
4476     for (const auto &resetter : resetters()) {
4477         if (resetter->name() == name)
4478             return true;
4479     }
4480     for (const auto &notifier : notifiers()) {
4481         if (notifier->name() == name)
4482             return true;
4483     }
4484     return false;
4485 }
4486 
4487 bool QmlTypeNode::qmlOnly = false;
4488 QMultiMap<const Node *, Node *> QmlTypeNode::inheritedBy;
4489 
4490 /*!
4491   Constructs a Qml type node or a Js type node depending on
4492   the value of \a type, which is Node::QmlType by default,
4493   but which can also be Node::JsType. The new node has the
4494   given \a parent and \a name.
4495  */
QmlTypeNode(Aggregate * parent,const QString & name,NodeType type)4496 QmlTypeNode::QmlTypeNode(Aggregate *parent, const QString &name, NodeType type)
4497     : Aggregate(type, parent, name),
4498       abstract_(false),
4499       cnodeRequired_(false),
4500       wrapper_(false),
4501       cnode_(nullptr),
4502       logicalModule_(nullptr),
4503       qmlBaseNode_(nullptr)
4504 {
4505     int i = 0;
4506     if (name.startsWith("QML:")) {
4507         qDebug() << "BOGUS QML qualifier:" << name;
4508         i = 4;
4509     }
4510     setTitle(name.mid(i));
4511 }
4512 
4513 /*!
4514   Clear the static maps so that subsequent runs don't try to use
4515   contents from a previous run.
4516  */
terminate()4517 void QmlTypeNode::terminate()
4518 {
4519     inheritedBy.clear();
4520 }
4521 
4522 /*!
4523   Record the fact that QML class \a base is inherited by
4524   QML class \a sub.
4525  */
addInheritedBy(const Node * base,Node * sub)4526 void QmlTypeNode::addInheritedBy(const Node *base, Node *sub)
4527 {
4528     if (sub->isInternal())
4529         return;
4530     if (!inheritedBy.contains(base, sub))
4531         inheritedBy.insert(base, sub);
4532 }
4533 
4534 /*!
4535   Loads the list \a subs with the nodes of all the subclasses of \a base.
4536  */
subclasses(const Node * base,NodeList & subs)4537 void QmlTypeNode::subclasses(const Node *base, NodeList &subs)
4538 {
4539     subs.clear();
4540     if (inheritedBy.count(base) > 0) {
4541         subs = inheritedBy.values(base);
4542     }
4543 }
4544 
4545 /*!
4546   If this QML type node has a base type node,
4547   return the fully qualified name of that QML
4548   type, i.e. <QML-module-name>::<QML-type-name>.
4549  */
qmlFullBaseName() const4550 QString QmlTypeNode::qmlFullBaseName() const
4551 {
4552     QString result;
4553     if (qmlBaseNode_) {
4554         result = qmlBaseNode_->logicalModuleName() + "::" + qmlBaseNode_->name();
4555     }
4556     return result;
4557 }
4558 
4559 /*!
4560   If the QML type's QML module pointer is set, return the QML
4561   module name from the QML module node. Otherwise, return the
4562   empty string.
4563  */
logicalModuleName() const4564 QString QmlTypeNode::logicalModuleName() const
4565 {
4566     return (logicalModule_ ? logicalModule_->logicalModuleName() : QString());
4567 }
4568 
4569 /*!
4570   If the QML type's QML module pointer is set, return the QML
4571   module version from the QML module node. Otherwise, return
4572   the empty string.
4573  */
logicalModuleVersion() const4574 QString QmlTypeNode::logicalModuleVersion() const
4575 {
4576     return (logicalModule_ ? logicalModule_->logicalModuleVersion() : QString());
4577 }
4578 
4579 /*!
4580   If the QML type's QML module pointer is set, return the QML
4581   module identifier from the QML module node. Otherwise, return
4582   the empty string.
4583  */
logicalModuleIdentifier() const4584 QString QmlTypeNode::logicalModuleIdentifier() const
4585 {
4586     return (logicalModule_ ? logicalModule_->logicalModuleIdentifier() : QString());
4587 }
4588 
4589 /*!
4590   Returns true if this QML type inherits \a type.
4591  */
inherits(Aggregate * type)4592 bool QmlTypeNode::inherits(Aggregate *type)
4593 {
4594     QmlTypeNode *qtn = qmlBaseNode();
4595     while (qtn != nullptr) {
4596         if (qtn == type)
4597             return true;
4598         qtn = qtn->qmlBaseNode();
4599     }
4600     return false;
4601 }
4602 
4603 /*!
4604   Constructs either a Qml basic type node or a Javascript
4605   basic type node, depending on the value pf \a type, which
4606   must be either Node::QmlBasicType or Node::JsBasicType.
4607   The new node has the given \a parent and \a name.
4608  */
QmlBasicTypeNode(Aggregate * parent,const QString & name,Node::NodeType type)4609 QmlBasicTypeNode::QmlBasicTypeNode(Aggregate *parent, const QString &name, Node::NodeType type)
4610     : Aggregate(type, parent, name)
4611 {
4612     setTitle(name);
4613 }
4614 
4615 /*!
4616   Constructor for the QML property node.
4617  */
QmlPropertyNode(Aggregate * parent,const QString & name,const QString & type,bool attached)4618 QmlPropertyNode::QmlPropertyNode(Aggregate *parent, const QString &name, const QString &type,
4619                                  bool attached)
4620     : Node(parent->isJsType() ? JsProperty : QmlProperty, parent, name),
4621       type_(type),
4622       stored_(FlagValueDefault),
4623       designable_(FlagValueDefault),
4624       isAlias_(false),
4625       isdefault_(false),
4626       attached_(attached),
4627       readOnly_(FlagValueDefault)
4628 {
4629     if (type_ == QString("alias"))
4630         isAlias_ = true;
4631     if (name.startsWith("__"))
4632         setStatus(Internal);
4633 }
4634 
4635 /*!
4636   Returns \c true if a QML property or attached property is
4637   not read-only. The algorithm for figuring this out is long
4638   amd tedious and almost certainly will break. It currently
4639   doesn't work for the qmlproperty:
4640 
4641   \code
4642       bool PropertyChanges::explicit,
4643   \endcode
4644 
4645   ...because the tokenizer gets confused on \e{explicit}.
4646  */
isWritable()4647 bool QmlPropertyNode::isWritable()
4648 {
4649     if (readOnly_ != FlagValueDefault)
4650         return !fromFlagValue(readOnly_, false);
4651 
4652     QmlTypeNode *qcn = qmlTypeNode();
4653     if (qcn) {
4654         if (qcn->cppClassRequired()) {
4655             if (qcn->classNode()) {
4656                 PropertyNode *pn = findCorrespondingCppProperty();
4657                 if (pn)
4658                     return pn->isWritable();
4659                 else
4660                     defLocation().warning(
4661                             tr("No Q_PROPERTY for QML property %1::%2::%3 "
4662                                "in C++ class documented as QML type: "
4663                                "(property not found in the C++ class or its base classes)")
4664                                     .arg(logicalModuleName())
4665                                     .arg(qmlTypeName())
4666                                     .arg(name()));
4667             } else
4668                 defLocation().warning(tr("No Q_PROPERTY for QML property %1::%2::%3 "
4669                                          "in C++ class documented as QML type: "
4670                                          "(C++ class not specified or not found).")
4671                                               .arg(logicalModuleName())
4672                                               .arg(qmlTypeName())
4673                                               .arg(name()));
4674         }
4675     }
4676     return true;
4677 }
4678 
4679 /*!
4680   Returns a pointer this QML property's corresponding C++
4681   property, if it has one.
4682  */
findCorrespondingCppProperty()4683 PropertyNode *QmlPropertyNode::findCorrespondingCppProperty()
4684 {
4685     PropertyNode *pn;
4686     Node *n = parent();
4687     while (n && !(n->isQmlType() || n->isJsType()))
4688         n = n->parent();
4689     if (n) {
4690         QmlTypeNode *qcn = static_cast<QmlTypeNode *>(n);
4691         ClassNode *cn = qcn->classNode();
4692         if (cn) {
4693             /*
4694               If there is a dot in the property name, first
4695               find the C++ property corresponding to the QML
4696               property group.
4697              */
4698             QStringList dotSplit = name().split(QChar('.'));
4699             pn = cn->findPropertyNode(dotSplit[0]);
4700             if (pn) {
4701                 /*
4702                   Now find the C++ property corresponding to
4703                   the QML property in the QML property group,
4704                   <group>.<property>.
4705                  */
4706                 if (dotSplit.size() > 1) {
4707                     QStringList path(extractClassName(pn->qualifiedDataType()));
4708                     Node *nn = QDocDatabase::qdocDB()->findClassNode(path);
4709                     if (nn) {
4710                         ClassNode *cn = static_cast<ClassNode *>(nn);
4711                         PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
4712                         /*
4713                           If found, return the C++ property
4714                           corresponding to the QML property.
4715                           Otherwise, return the C++ property
4716                           corresponding to the QML property
4717                           group.
4718                          */
4719                         return (pn2 ? pn2 : pn);
4720                     }
4721                 } else
4722                     return pn;
4723             }
4724         }
4725     }
4726     return nullptr;
4727 }
4728 
4729 /*!
4730   \class ProxyNode
4731   \brief A class for representing an Aggregate that is documented in a different module.
4732 
4733   This class is used to represent an Aggregate (usually a class)
4734   that is located and documented in a different module. In the
4735   current module, a ProxyNode holds child nodes that are related
4736   to the class in the other module.
4737 
4738   For example, class QHash is located and documented in QtCore.
4739   There are many global functions named qHash() in QtCore that
4740   are all related to class QHash using the \c relates command.
4741   There are also a few qHash() function in QtNetwork that are
4742   related to QHash. These functions must be documented when the
4743   documentation for QtNetwork is generated, but the reference
4744   page for QHash must link to that documentation in its related
4745   nonmembers list.
4746 
4747   The ProxyNode allows qdoc to construct links to the related
4748   functions (or other things?) in QtNetwork from the reference
4749   page in QtCore.
4750  */
4751 
4752 /*!
4753   Constructs the ProxyNode, which at this point looks like any
4754   other Aggregate, and then finds the Tree this node is in and
4755   appends this node to that Tree's proxy list so it will be
4756   easy to find later.
4757  */
ProxyNode(Aggregate * parent,const QString & name)4758 ProxyNode::ProxyNode(Aggregate *parent, const QString &name) : Aggregate(Node::Proxy, parent, name)
4759 {
4760     tree()->appendProxy(this);
4761 }
4762 
4763 /*! \fn bool ProxyNode::docMustBeGenerated() const
4764   Returns true because a ProxyNode always means some documentation
4765   must be generated.
4766 */
4767 
4768 /*! \fn bool ProxyNode::isRelatableType() const
4769   Returns true because the ProxyNode exists so that elements
4770   can be related to it with the \c {\\relates} command.
4771 */
4772 
4773 /*!
4774   \class CollectionNode
4775   \brief A class for holding the members of a collection of doc pages.
4776  */
4777 
4778 /*!
4779   Returns \c true if the collection node's member list is
4780   not empty.
4781  */
hasMembers() const4782 bool CollectionNode::hasMembers() const
4783 {
4784     return !members_.isEmpty();
4785 }
4786 
4787 /*!
4788   Appends \a node to the collection node's member list, if
4789   and only if it isn't already in the member list.
4790  */
addMember(Node * node)4791 void CollectionNode::addMember(Node *node)
4792 {
4793     if (!members_.contains(node))
4794         members_.append(node);
4795 }
4796 
4797 /*!
4798   Returns \c true if this collection node contains at least
4799   one namespace node.
4800  */
hasNamespaces() const4801 bool CollectionNode::hasNamespaces() const
4802 {
4803     if (!members_.isEmpty()) {
4804         for (const auto &member : qAsConst(members_)) {
4805             if (member->isNamespace())
4806                 return true;
4807         }
4808     }
4809     return false;
4810 }
4811 
4812 /*!
4813   Returns \c true if this collection node contains at least
4814   one class node.
4815  */
hasClasses() const4816 bool CollectionNode::hasClasses() const
4817 {
4818     if (!members_.isEmpty()) {
4819         for (const auto &member : qAsConst(members_)) {
4820             if (member->isClassNode())
4821                 return true;
4822         }
4823     }
4824     return false;
4825 }
4826 
4827 /*!
4828   Loads \a out with all this collection node's members that
4829   are namespace nodes.
4830  */
getMemberNamespaces(NodeMap & out)4831 void CollectionNode::getMemberNamespaces(NodeMap &out)
4832 {
4833     out.clear();
4834     for (const auto &member : qAsConst(members_)) {
4835         if (member->isNamespace())
4836             out.insert(member->name(), member);
4837     }
4838 }
4839 
4840 /*!
4841   Loads \a out with all this collection node's members that
4842   are class nodes.
4843  */
getMemberClasses(NodeMap & out) const4844 void CollectionNode::getMemberClasses(NodeMap &out) const
4845 {
4846     out.clear();
4847     for (const auto &i : qAsConst(members_)) {
4848         if (i->isClassNode())
4849             out.insert(i->name(), i);
4850     }
4851 }
4852 
4853 /*!
4854   Prints the collection node's list of members.
4855   For debugging only.
4856  */
printMembers(const QString & title)4857 void CollectionNode::printMembers(const QString &title)
4858 {
4859     qDebug() << title << name() << members_.size();
4860     if (members_.size() > 0) {
4861         for (const auto &member : qAsConst(members_))
4862             qDebug() << "  MEMBER:" << member->name() << member->nodeTypeString();
4863     }
4864 }
4865 
4866 /*!
4867   This function splits \a arg on the blank character to get a
4868   logical module name and version number. If the version number
4869   is present, it splits the version number on the '.' character
4870   to get a major version number and a minor version number. If
4871   the version number is present, both the major and minor version
4872   numbers should be there, but the minor version number is not
4873   absolutely necessary.
4874  */
setLogicalModuleInfo(const QString & arg)4875 void CollectionNode::setLogicalModuleInfo(const QString &arg)
4876 {
4877     QStringList blankSplit = arg.split(QLatin1Char(' '));
4878     logicalModuleName_ = blankSplit[0];
4879     if (blankSplit.size() > 1) {
4880         QStringList dotSplit = blankSplit[1].split(QLatin1Char('.'));
4881         logicalModuleVersionMajor_ = dotSplit[0];
4882         if (dotSplit.size() > 1)
4883             logicalModuleVersionMinor_ = dotSplit[1];
4884         else
4885             logicalModuleVersionMinor_ = "0";
4886     }
4887 }
4888 
4889 /*!
4890   This function accepts the logical module \a info as a string
4891   list. If the logical module info contains the version number,
4892   it splits the version number on the '.' character to get the
4893   major and minor version numbers. Both major and minor version
4894   numbers should be provided, but the minor version number is
4895   not strictly necessary.
4896  */
setLogicalModuleInfo(const QStringList & info)4897 void CollectionNode::setLogicalModuleInfo(const QStringList &info)
4898 {
4899     logicalModuleName_ = info[0];
4900     if (info.size() > 1) {
4901         QStringList dotSplit = info[1].split(QLatin1Char('.'));
4902         logicalModuleVersionMajor_ = dotSplit[0];
4903         if (dotSplit.size() > 1)
4904             logicalModuleVersionMinor_ = dotSplit[1];
4905         else
4906             logicalModuleVersionMinor_ = "0";
4907     }
4908 }
4909 
4910 /*!
4911   Searches the shared comment node's member nodes for function
4912   nodes. Each function node's overload flag is set.
4913  */
setOverloadFlags()4914 void SharedCommentNode::setOverloadFlags()
4915 {
4916     for (Node *n : collective_) {
4917         if (n->isFunction())
4918             static_cast<FunctionNode *>(n)->setOverloadFlag();
4919     }
4920 }
4921 
4922 /*!
4923   Clone this node on the heap and make the clone a child of
4924   \a parent. Return the pointer to the clone.
4925  */
clone(Aggregate * parent)4926 Node *SharedCommentNode::clone(Aggregate *parent)
4927 {
4928     SharedCommentNode *scn = new SharedCommentNode(*this); // shallow copy
4929     scn->setParent(nullptr);
4930     parent->addChild(scn);
4931     return scn;
4932 }
4933 
4934 /*!
4935   Sets the related nonmember flag in this node and in each
4936   node in the shared comment's collective.
4937  */
setRelatedNonmember(bool b)4938 void SharedCommentNode::setRelatedNonmember(bool b)
4939 {
4940     Node::setRelatedNonmember(b);
4941     for (Node *n : collective_)
4942         n->setRelatedNonmember(b);
4943 }
4944 
4945 QT_END_NAMESPACE
4946