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 ¶meters)
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 ¬ifier : 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