1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "classnode.h"
5
6#include "functionnode.h"
7#include "propertynode.h"
8#include "qdocdatabase.h"
9#include "qmltypenode.h"
10
11QT_BEGIN_NAMESPACE
12
13/*!
14 \class ClassNode
15 \brief The ClassNode represents a C++ class.
16
17 It is also used to represent a C++ struct or union. There are some
18 actual uses for structs, but I don't think any unions have been
19 documented yet.
20 */
21
22/*!
23 Adds the base class \a node to this class's list of base
24 classes. The base class has the specified \a access. This
25 is a resolved base class.
26 */
27void ClassNode::addResolvedBaseClass(Access access, ClassNode *node)
28{
29 m_bases.append(t: RelatedClass(access, node));
30 node->m_derived.append(t: RelatedClass(access, this));
31}
32
33/*!
34 Adds the derived class \a node to this class's list of derived
35 classes. The derived class inherits this class with \a access.
36 */
37void ClassNode::addDerivedClass(Access access, ClassNode *node)
38{
39 m_derived.append(t: RelatedClass(access, node));
40}
41
42/*!
43 Add an unresolved base class to this class node's list of
44 base classes. The unresolved base class will be resolved
45 before the generate phase of qdoc. In an unresolved base
46 class, the pointer to the base class node is 0.
47 */
48void ClassNode::addUnresolvedBaseClass(Access access, const QStringList &path)
49{
50 m_bases.append(t: RelatedClass(access, path));
51}
52
53/*!
54 Search the child list to find the property node with the
55 specified \a name.
56 */
57PropertyNode *ClassNode::findPropertyNode(const QString &name)
58{
59 Node *n = findNonfunctionChild(name, &Node::isProperty);
60
61 if (n)
62 return static_cast<PropertyNode *>(n);
63
64 PropertyNode *pn = nullptr;
65
66 const QList<RelatedClass> &bases = baseClasses();
67 if (!bases.isEmpty()) {
68 for (const RelatedClass &base : bases) {
69 ClassNode *cn = base.m_node;
70 if (cn) {
71 pn = cn->findPropertyNode(name);
72 if (pn)
73 break;
74 }
75 }
76 }
77 const QList<RelatedClass> &ignoredBases = ignoredBaseClasses();
78 if (!ignoredBases.isEmpty()) {
79 for (const RelatedClass &base : ignoredBases) {
80 ClassNode *cn = base.m_node;
81 if (cn) {
82 pn = cn->findPropertyNode(name);
83 if (pn)
84 break;
85 }
86 }
87 }
88
89 return pn;
90}
91
92/*!
93 This function does a recursive search of this class node's
94 base classes looking for one that has a QML element. If it
95 finds one, it returns the pointer to that QML element. If
96 it doesn't find one, it returns null.
97 */
98QmlTypeNode *ClassNode::findQmlBaseNode()
99{
100 QmlTypeNode *result = nullptr;
101 const QList<RelatedClass> &bases = baseClasses();
102
103 if (!bases.isEmpty()) {
104 for (const RelatedClass &base : bases) {
105 ClassNode *cn = base.m_node;
106 if (cn && cn->qmlElement()) {
107 return cn->qmlElement();
108 }
109 }
110 for (const RelatedClass &base : bases) {
111 ClassNode *cn = base.m_node;
112 if (cn) {
113 result = cn->findQmlBaseNode();
114 if (result != nullptr) {
115 return result;
116 }
117 }
118 }
119 }
120 return result;
121}
122
123/*!
124 \a fn is an overriding function in this class or in a class
125 derived from this class. Find the node for the function that
126 \a fn overrides in this class's children or in one of this
127 class's base classes. Return a pointer to the overridden
128 function or return 0.
129
130 This should be revised because clang provides the path to the
131 overridden function. mws 15/12/2018
132 */
133FunctionNode *ClassNode::findOverriddenFunction(const FunctionNode *fn)
134{
135 for (auto &bc : m_bases) {
136 ClassNode *cn = bc.m_node;
137 if (cn == nullptr) {
138 cn = QDocDatabase::qdocDB()->findClassNode(path: bc.m_path);
139 bc.m_node = cn;
140 }
141 if (cn != nullptr) {
142 FunctionNode *result = cn->findFunctionChild(clone: fn);
143 if (result != nullptr && !result->isInternal() && !result->isNonvirtual()
144 && result->hasDoc())
145 return result;
146 result = cn->findOverriddenFunction(fn);
147 if (result != nullptr && !result->isNonvirtual())
148 return result;
149 }
150 }
151 return nullptr;
152}
153
154/*!
155 \a fn is an overriding function in this class or in a class
156 derived from this class. Find the node for the property that
157 \a fn overrides in this class's children or in one of this
158 class's base classes. Return a pointer to the overridden
159 property or return 0.
160 */
161PropertyNode *ClassNode::findOverriddenProperty(const FunctionNode *fn)
162{
163 for (auto &baseClass : m_bases) {
164 ClassNode *cn = baseClass.m_node;
165 if (cn == nullptr) {
166 cn = QDocDatabase::qdocDB()->findClassNode(path: baseClass.m_path);
167 baseClass.m_node = cn;
168 }
169 if (cn != nullptr) {
170 const NodeList &children = cn->childNodes();
171 for (const auto &child : children) {
172 if (child->isProperty()) {
173 auto *pn = static_cast<PropertyNode *>(child);
174 if (pn->name() == fn->name() || pn->hasAccessFunction(name: fn->name())) {
175 if (pn->hasDoc())
176 return pn;
177 }
178 }
179 }
180 PropertyNode *result = cn->findOverriddenProperty(fn);
181 if (result != nullptr)
182 return result;
183 }
184 }
185 return nullptr;
186}
187
188/*!
189 Returns true if the class or struct represented by this class
190 node must be documented. If this function returns true, then
191 qdoc must find a qdoc comment for this class. If it returns
192 false, then the class need not be documented.
193 */
194bool ClassNode::docMustBeGenerated() const
195{
196 if (!hasDoc() || isPrivate() || isInternal() || isDontDocument())
197 return false;
198 if (declLocation().fileName().endsWith(s: QLatin1String("_p.h")) && !hasDoc())
199 return false;
200
201 return true;
202}
203
204/*!
205 A base class of this class node was private or internal.
206 That node's list of \a bases is traversed in this function.
207 Each of its public base classes is promoted to be a base
208 class of this node for documentation purposes. For each
209 private or internal class node in \a bases, this function
210 is called recursively with the list of base classes from
211 that private or internal class node.
212 */
213void ClassNode::promotePublicBases(const QList<RelatedClass> &bases)
214{
215 if (!bases.isEmpty()) {
216 for (qsizetype i = bases.size() - 1; i >= 0; --i) {
217 ClassNode *bc = bases.at(i).m_node;
218 if (bc == nullptr)
219 bc = QDocDatabase::qdocDB()->findClassNode(path: bases.at(i).m_path);
220 if (bc != nullptr) {
221 if (bc->isPrivate() || bc->isInternal())
222 promotePublicBases(bases: bc->baseClasses());
223 else
224 m_bases.append(t: bases.at(i));
225 }
226 }
227 }
228}
229
230/*!
231 Remove private and internal bases classes from this class's list
232 of base classes. When a base class is removed from the list, add
233 its base classes to this class's list of base classes.
234 */
235void ClassNode::removePrivateAndInternalBases()
236{
237 int i;
238 i = 0;
239 QSet<ClassNode *> found;
240
241 // Remove private and duplicate base classes.
242 while (i < m_bases.size()) {
243 ClassNode *bc = m_bases.at(i).m_node;
244 if (bc == nullptr)
245 bc = QDocDatabase::qdocDB()->findClassNode(path: m_bases.at(i).m_path);
246 if (bc != nullptr
247 && (bc->isPrivate() || bc->isInternal() || bc->isDontDocument()
248 || found.contains(value: bc))) {
249 RelatedClass rc = m_bases.at(i);
250 m_bases.removeAt(i);
251 m_ignoredBases.append(t: rc);
252 promotePublicBases(bases: bc->baseClasses());
253 } else {
254 ++i;
255 }
256 found.insert(value: bc);
257 }
258
259 i = 0;
260 while (i < m_derived.size()) {
261 ClassNode *dc = m_derived.at(i).m_node;
262 if (dc != nullptr && (dc->isPrivate() || dc->isInternal() || dc->isDontDocument())) {
263 m_derived.removeAt(i);
264 const QList<RelatedClass> &dd = dc->derivedClasses();
265 for (qsizetype j = dd.size() - 1; j >= 0; --j)
266 m_derived.insert(i, t: dd.at(i: j));
267 } else {
268 ++i;
269 }
270 }
271}
272
273/*!
274 */
275void ClassNode::resolvePropertyOverriddenFromPtrs(PropertyNode *pn)
276{
277 for (const auto &baseClass : std::as_const(t&: baseClasses())) {
278 ClassNode *cn = baseClass.m_node;
279 if (cn) {
280 Node *n = cn->findNonfunctionChild(name: pn->name(), &Node::isProperty);
281 if (n) {
282 auto *baseProperty = static_cast<PropertyNode *>(n);
283 cn->resolvePropertyOverriddenFromPtrs(pn: baseProperty);
284 pn->setOverriddenFrom(baseProperty);
285 } else
286 cn->resolvePropertyOverriddenFromPtrs(pn);
287 }
288 }
289}
290
291QT_END_NAMESPACE
292

source code of qttools/src/qdoc/qdoc/classnode.cpp