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);
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
172 if (declLocation().fileName().endsWith(
"_p.h"_L1) && !hasDoc())
179
180
181
182
183
184
185
186
187
188
189
190
191
193 QStringList *cyclePath)
const
195 QMap<
const ClassNode*, Color> colors;
196 QList<
const ClassNode*> path;
198 bool cycleFound = detectCycleRecursive(direction, colors, path);
200 if (cycleFound && cyclePath) {
203 if (!path.isEmpty()) {
204 const ClassNode *repeatedNode = path.last();
205 auto first = path.indexOf(repeatedNode);
206 if (first != -1 && first < path.size() - 1)
207 path = path.mid(first);
210 for (
const ClassNode *node : path)
211 cyclePath->append(node->name());
218
219
220
221
222
223
224
225
226
227
228
229
230
231
233 QMap<
const ClassNode*, Color> &colors,
234 QList<
const ClassNode*> &path)
const
236 colors[
this] = Color::Gray;
239 const QList<RelatedClass> &related = (direction == HierarchyDirection::Base)
243 for (
const auto &relatedClass : related) {
244 const ClassNode *rc = relatedClass.m_node;
246 rc = QDocDatabase::qdocDB()->findClassNode(relatedClass.m_path);
248 if (rc !=
nullptr && (rc->isPrivate() || rc->isInternal() || rc->isDontDocument())) {
250 qCDebug(lcQdoc) <<
"Skipping self-reference (CRTP-like) in" <<
this->name();
254 Color rcColor = colors.value(rc, Color::White);
256 if (rcColor == Color::Gray) {
261 if (rcColor == Color::White) {
262 if (rc->detectCycleRecursive(direction, colors, path))
268 colors[
this] = Color::Black;
275
276
277
278
279
280
281
282
283
284
285
286
289 return hasCircularRelationship(HierarchyDirection::Base, cyclePath);
293
294
295
296
297
298
299
300
301
302
303
306 return hasCircularRelationship(HierarchyDirection::Derived, cyclePath);
310
311
312
313
314
315
316
317
318void ClassNode::promotePublicBases(
const QList<RelatedClass> &bases)
320 if (!bases.isEmpty()) {
321 for (qsizetype i = bases.size() - 1; i >= 0; --i) {
326 if (bc->isPrivate() || bc->isInternal())
327 promotePublicBases(bc->baseClasses());
329 m_bases.append(bases.at(i));
336
337
338
339
344 QSet<ClassNode *> found;
347 while (i < m_bases.size()) {
350 bc = QDocDatabase::qdocDB()->findClassNode(m_bases.at(i).m_path);
353 || found.contains(bc))) {
356 m_ignoredBases.append(rc);
357 QStringList cyclePath;
358 if (bc->hasCircularInheritance(&cyclePath))
359 bc->location().warning(
"Circular inheritance detected: %1"_L1.arg(cyclePath.join(
" -> ")));
361 promotePublicBases(bc->baseClasses());
369 while (i < m_derived.size()) {
372 QStringList derivedCyclePath;
373 if (dc->hasCircularDerivedClasses(&derivedCyclePath)) {
374 dc
->location().warning(QStringLiteral(
"Circular derived class relationship detected: %1").arg(derivedCyclePath.join(
" -> ")));
375 m_derived.removeAt(i);
377 m_derived.removeAt(i);
378 const QList<RelatedClass> &dd = dc->derivedClasses();
379 for (qsizetype j = dd.size() - 1; j >= 0; --j) {
381 if (dd.at(j).m_node != dc) {
382 m_derived.insert(i, dd.at(j));
384 qCDebug(lcQdoc) <<
"Skipping CRTP self-reference in derived class promotion for"
396
399 for (
const auto &baseClass : std::as_const(baseClasses())) {
400 ClassNode *cn = baseClass.m_node;
402 Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
404 auto *baseProperty =
static_cast<PropertyNode *>(n);
405 cn->resolvePropertyOverriddenFromPtrs(baseProperty);
406 pn->setOverriddenFrom(baseProperty);
408 cn->resolvePropertyOverriddenFromPtrs(pn);
414
415
416
421 case NodeType::Struct:
422 return "(unnamed struct)"_L1;
423 case NodeType::Union:
424 return "(unnamed union)"_L1;
425 case NodeType::Class:
426 return "(unnamed class)"_L1;
431 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.
bool docMustBeGenerated() const override
Returns true if the class or struct represented by this class node must be documented.
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.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...