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()) {
346 || found.contains(bc))) {
349 m_ignoredBases.append(rc);
350 QStringList cyclePath;
351 if (bc->hasCircularInheritance(&cyclePath))
352 bc
->location().warning(
"Circular inheritance detected: %1"_L1.arg(cyclePath.join(
" -> ")));
354 promotePublicBases(bc->baseClasses());
362 while (i < m_derived.size()) {
365 QStringList derivedCyclePath;
366 if (dc->hasCircularDerivedClasses(&derivedCyclePath)) {
367 dc
->location().warning(QStringLiteral(
"Circular derived class relationship detected: %1").arg(derivedCyclePath.join(
" -> ")));
368 m_derived.removeAt(i);
370 m_derived.removeAt(i);
371 const QList<RelatedClass> &dd = dc->derivedClasses();
372 for (qsizetype j = dd.size() - 1; j >= 0; --j) {
374 if (dd.at(j).m_node != dc) {
375 m_derived.insert(i, dd.at(j));
377 qCDebug(lcQdoc) <<
"Skipping CRTP self-reference in derived class promotion for"
389
392 for (
const auto &baseClass : std::as_const(baseClasses())) {
393 ClassNode *cn = baseClass.m_node;
395 Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
397 auto *baseProperty =
static_cast<PropertyNode *>(n);
398 cn->resolvePropertyOverriddenFromPtrs(baseProperty);
399 pn->setOverriddenFrom(baseProperty);
401 cn->resolvePropertyOverriddenFromPtrs(pn);
407
408
409
414 case NodeType::Struct:
415 return "(unnamed struct)"_L1;
416 case NodeType::Union:
417 return "(unnamed union)"_L1;
418 case NodeType::Class:
419 return "(unnamed class)"_L1;
424 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.
Combined button and popup list for selecting options.
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.