12#include <QtCore/qlatin1stringview.h>
16using namespace Qt::StringLiterals;
19
20
21
22
23
24
25
28
29
30
31
34 m_bases.append(RelatedClass(access, node));
39
40
41
44 m_derived.append(RelatedClass(access, node));
48
49
50
51
52
55 m_bases.append(RelatedClass(access, path));
59
60
61
64 Node *n = findNonfunctionChild(name, &Node::isProperty);
67 return static_cast<PropertyNode *>(n);
71 const QList<RelatedClass> &bases = baseClasses();
72 if (!bases.isEmpty()) {
73 for (
const RelatedClass &base : bases) {
74 ClassNode *cn = base.m_node;
76 pn = cn->findPropertyNode(name);
82 const QList<RelatedClass> &ignoredBases = ignoredBaseClasses();
83 if (!ignoredBases.isEmpty()) {
84 for (
const RelatedClass &base : ignoredBases) {
85 ClassNode *cn = base.m_node;
87 pn = cn->findPropertyNode(name);
98
99
100
101
102
103
104
105
106
109 for (
auto &bc : m_bases) {
110 ClassNode *cn = bc.m_node;
112 cn = QDocDatabase::qdocDB()->findClassNode(bc.m_path);
116 FunctionNode *result = cn->findFunctionChild(fn);
117 if (result !=
nullptr && !result->isInternal() && !result->isNonvirtual()
120 result = cn->findOverriddenFunction(fn);
121 if (result !=
nullptr && !result->isNonvirtual())
129
130
131
132
133
134
137 for (
auto &baseClass : m_bases) {
138 ClassNode *cn = baseClass.m_node;
140 cn = QDocDatabase::qdocDB()->findClassNode(baseClass.m_path);
141 baseClass.m_node = cn;
144 const NodeList &children = cn->childNodes();
145 for (
const auto &child : children) {
146 if (child->isProperty()) {
147 auto *pn =
static_cast<PropertyNode *>(child);
148 if (pn->name() == fn->name() || pn->hasAccessFunction(fn->name())) {
154 PropertyNode *result = cn->findOverriddenProperty(fn);
155 if (result !=
nullptr)
163
164
165
166
167
168
169
172
173
174
175
176
177
178
179
180
181
182
183
184
186 QStringList *cyclePath)
const
188 QMap<
const ClassNode*, Color> colors;
189 QList<
const ClassNode*> path;
191 bool cycleFound = detectCycleRecursive(direction, colors, path);
193 if (cycleFound && cyclePath) {
196 if (!path.isEmpty()) {
197 const ClassNode *repeatedNode = path.last();
198 auto first = path.indexOf(repeatedNode);
199 if (first != -1 && first < path.size() - 1)
200 path = path.mid(first);
203 for (
const ClassNode *node : path)
204 cyclePath->append(node->name());
211
212
213
214
215
216
217
218
219
220
221
222
223
224
226 QMap<
const ClassNode*, Color> &colors,
227 QList<
const ClassNode*> &path)
const
229 colors[
this] = Color::Gray;
232 const QList<RelatedClass> &related = (direction == HierarchyDirection::Base)
236 for (
const auto &relatedClass : related) {
237 const ClassNode *rc = relatedClass.m_node;
239 rc = QDocDatabase::qdocDB()->findClassNode(relatedClass.m_path);
241 if (rc !=
nullptr && (rc->isPrivate() || rc->isInternal() || rc->isDontDocument())) {
243 qCDebug(lcQdoc) <<
"Skipping self-reference (CRTP-like) in" <<
this->name();
247 Color rcColor = colors.value(rc, Color::White);
249 if (rcColor == Color::Gray) {
254 if (rcColor == Color::White) {
255 if (rc->detectCycleRecursive(direction, colors, path))
261 colors[
this] = Color::Black;
268
269
270
271
272
273
274
275
276
277
278
279
282 return hasCircularRelationship(HierarchyDirection::Base, cyclePath);
286
287
288
289
290
291
292
293
294
295
296
299 return hasCircularRelationship(HierarchyDirection::Derived, cyclePath);
303
304
305
306
307
308
309
310
311void ClassNode::promotePublicBases(
const QList<RelatedClass> &bases)
313 if (!bases.isEmpty()) {
314 for (qsizetype i = bases.size() - 1; i >= 0; --i) {
319 if (bc->isPrivate() || bc->isInternal())
320 promotePublicBases(bc->baseClasses());
322 m_bases.append(bases.at(i));
329
330
331
332
337 QSet<ClassNode *> found;
340 while (i < m_bases.size()) {
344 if (bc !=
nullptr && !found.contains(bc)
348 m_ignoredBases.append(rc);
349 QStringList cyclePath;
350 if (bc->hasCircularInheritance(&cyclePath))
351 bc
->location().warning(
"Circular inheritance detected: %1"_L1.arg(cyclePath.join(
" -> ")));
353 promotePublicBases(bc->baseClasses());
361 while (i < m_derived.size()) {
364 QStringList derivedCyclePath;
365 if (dc->hasCircularDerivedClasses(&derivedCyclePath)) {
366 dc
->location().warning(QStringLiteral(
"Circular derived class relationship detected: %1").arg(derivedCyclePath.join(
" -> ")));
367 m_derived.removeAt(i);
369 m_derived.removeAt(i);
370 const QList<RelatedClass> &dd = dc->derivedClasses();
371 for (qsizetype j = dd.size() - 1; j >= 0; --j) {
373 if (dd.at(j).m_node != dc) {
374 m_derived.insert(i, dd.at(j));
376 qCDebug(lcQdoc) <<
"Skipping CRTP self-reference in derived class promotion for"
388
391 for (
const auto &baseClass : std::as_const(baseClasses())) {
392 ClassNode *cn = baseClass.m_node;
394 Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
396 auto *baseProperty =
static_cast<PropertyNode *>(n);
397 cn->resolvePropertyOverriddenFromPtrs(baseProperty);
398 pn->setOverriddenFrom(baseProperty);
400 cn->resolvePropertyOverriddenFromPtrs(pn);
406
407
408
413 case NodeType::Struct:
414 return "(unnamed struct)"_L1;
415 case NodeType::Union:
416 return "(unnamed union)"_L1;
417 case NodeType::Class:
418 return "(unnamed class)"_L1;
423 return Node::plainName();
The ClassNode represents a C++ class.
PropertyNode * findPropertyNode(const QString &name)
Search the child list to find the property node with the specified name.
void addResolvedBaseClass(Access access, ClassNode *node)
Adds the base class node to this class's list of base classes.
PropertyNode * findOverriddenProperty(const FunctionNode *fn)
fn is an overriding function in this class or in a class derived from this class.
bool hasCircularDerivedClasses(QStringList *cyclePath=nullptr) const
Checks if this class has circular derived class relationships by traversing its derived class hierarc...
FunctionNode * findOverriddenFunction(const FunctionNode *fn)
fn is an overriding function in this class or in a class derived from this class.
QString plainName() const override
Returns the display name for this class node.
bool hasCircularInheritance(QStringList *cyclePath=nullptr) const
Checks if this class has circular inheritance by traversing its base class hierarchy.
void removePrivateAndInternalBases()
Remove private and internal bases classes from this class's list of base classes.
void resolvePropertyOverriddenFromPtrs(PropertyNode *pn)
void addDerivedClass(Access access, ClassNode *node)
Adds the derived class node to this class's list of derived classes.
void addUnresolvedBaseClass(Access access, const QStringList &path)
Add an unresolved base class to this class node's list of base classes.
This node is used to represent any kind of function being documented.
This class describes one instance of using the Q_PROPERTY macro.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isDontDocument() const
Returns true if this node's status is DontDocument.
bool isPrivate() const
Returns true if this node's access is Private.
virtual bool isInternal() const
Returns true if the node's status is Internal, or if its parent is a class with Internal status.
NodeType nodeType() const override
Returns this node's type.
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.