summaryrefslogtreecommitdiffstats
path: root/src/qdoc/qdoc/src/qdoc/classnode.cpp
blob: f6de10f78db23bbbc5b3c6cf721a4c63ea1c9e8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "classnode.h"

#include "functionnode.h"
#include "propertynode.h"
#include "qdocdatabase.h"
#include "qmltypenode.h"

QT_BEGIN_NAMESPACE

/*!
  \class ClassNode
  \brief The ClassNode represents a C++ class.

  It is also used to represent a C++ struct or union. There are some
  actual uses for structs, but I don't think any unions have been
  documented yet.
 */

/*!
  Adds the base class \a node to this class's list of base
  classes. The base class has the specified \a access. This
  is a resolved base class.
 */
void ClassNode::addResolvedBaseClass(Access access, ClassNode *node)
{
    m_bases.append(RelatedClass(access, node));
    node->m_derived.append(RelatedClass(access, this));
}

/*!
  Adds the derived class \a node to this class's list of derived
  classes. The derived class inherits this class with \a access.
 */
void ClassNode::addDerivedClass(Access access, ClassNode *node)
{
    m_derived.append(RelatedClass(access, node));
}

/*!
  Add an unresolved base class to this class node's list of
  base classes. The unresolved base class will be resolved
  before the generate phase of qdoc. In an unresolved base
  class, the pointer to the base class node is 0.
 */
void ClassNode::addUnresolvedBaseClass(Access access, const QStringList &path)
{
    m_bases.append(RelatedClass(access, path));
}

/*!
  Search the child list to find the property node with the
  specified \a name.
 */
PropertyNode *ClassNode::findPropertyNode(const QString &name)
{
    Node *n = findNonfunctionChild(name, &Node::isProperty);

    if (n)
        return static_cast<PropertyNode *>(n);

    PropertyNode *pn = nullptr;

    const QList<RelatedClass> &bases = baseClasses();
    if (!bases.isEmpty()) {
        for (const RelatedClass &base : bases) {
            ClassNode *cn = base.m_node;
            if (cn) {
                pn = cn->findPropertyNode(name);
                if (pn)
                    break;
            }
        }
    }
    const QList<RelatedClass> &ignoredBases = ignoredBaseClasses();
    if (!ignoredBases.isEmpty()) {
        for (const RelatedClass &base : ignoredBases) {
            ClassNode *cn = base.m_node;
            if (cn) {
                pn = cn->findPropertyNode(name);
                if (pn)
                    break;
            }
        }
    }

    return pn;
}

/*!
  This function does a recursive search of this class node's
  base classes looking for one that has a QML element. If it
  finds one, it returns the pointer to that QML element. If
  it doesn't find one, it returns null.
 */
QmlTypeNode *ClassNode::findQmlBaseNode()
{
    QmlTypeNode *result = nullptr;
    const QList<RelatedClass> &bases = baseClasses();

    if (!bases.isEmpty()) {
        for (const RelatedClass &base : bases) {
            ClassNode *cn = base.m_node;
            if (cn && cn->qmlElement()) {
                return cn->qmlElement();
            }
        }
        for (const RelatedClass &base : bases) {
            ClassNode *cn = base.m_node;
            if (cn) {
                result = cn->findQmlBaseNode();
                if (result != nullptr) {
                    return result;
                }
            }
        }
    }
    return result;
}

/*!
  \a fn is an overriding function in this class or in a class
  derived from this class. Find the node for the function that
  \a fn overrides in this class's children or in one of this
  class's base classes. Return a pointer to the overridden
  function or return 0.

  This should be revised because clang provides the path to the
  overridden function. mws 15/12/2018
 */
FunctionNode *ClassNode::findOverriddenFunction(const FunctionNode *fn)
{
    for (auto &bc : m_bases) {
        ClassNode *cn = bc.m_node;
        if (cn == nullptr) {
            cn = QDocDatabase::qdocDB()->findClassNode(bc.m_path);
            bc.m_node = cn;
        }
        if (cn != nullptr) {
            FunctionNode *result = cn->findFunctionChild(fn);
            if (result != nullptr && !result->isInternal() && !result->isNonvirtual()
                && result->hasDoc())
                return result;
            result = cn->findOverriddenFunction(fn);
            if (result != nullptr && !result->isNonvirtual())
                return result;
        }
    }
    return nullptr;
}

/*!
  \a fn is an overriding function in this class or in a class
  derived from this class. Find the node for the property that
  \a fn overrides in this class's children or in one of this
  class's base classes. Return a pointer to the overridden
  property or return 0.
 */
PropertyNode *ClassNode::findOverriddenProperty(const FunctionNode *fn)
{
    for (auto &baseClass : m_bases) {
        ClassNode *cn = baseClass.m_node;
        if (cn == nullptr) {
            cn = QDocDatabase::qdocDB()->findClassNode(baseClass.m_path);
            baseClass.m_node = cn;
        }
        if (cn != nullptr) {
            const NodeList &children = cn->childNodes();
            for (const auto &child : children) {
                if (child->isProperty()) {
                    auto *pn = static_cast<PropertyNode *>(child);
                    if (pn->name() == fn->name() || pn->hasAccessFunction(fn->name())) {
                        if (pn->hasDoc())
                            return pn;
                    }
                }
            }
            PropertyNode *result = cn->findOverriddenProperty(fn);
            if (result != nullptr)
                return result;
        }
    }
    return nullptr;
}

/*!
  Returns true if the class or struct represented by this class
  node must be documented. If this function returns true, then
  qdoc must find a qdoc comment for this class. If it returns
  false, then the class need not be documented.
 */
bool ClassNode::docMustBeGenerated() const
{
    if (!hasDoc() || isPrivate() || isInternal() || isDontDocument())
        return false;
    if (declLocation().fileName().endsWith(QLatin1String("_p.h")) && !hasDoc())
        return false;

    return true;
}

/*!
  A base class of this class node was private or internal.
  That node's list of \a bases is traversed in this function.
  Each of its public base classes is promoted to be a base
  class of this node for documentation purposes. For each
  private or internal class node in \a bases, this function
  is called recursively with the list of base classes from
  that private or internal class node.
 */
void ClassNode::promotePublicBases(const QList<RelatedClass> &bases)
{
    if (!bases.isEmpty()) {
        for (qsizetype i = bases.size() - 1; i >= 0; --i) {
            ClassNode *bc = bases.at(i).m_node;
            if (bc == nullptr)
                bc = QDocDatabase::qdocDB()->findClassNode(bases.at(i).m_path);
            if (bc != nullptr) {
                if (bc->isPrivate() || bc->isInternal())
                    promotePublicBases(bc->baseClasses());
                else
                    m_bases.append(bases.at(i));
            }
        }
    }
}

/*!
  Remove private and internal bases classes from this class's list
  of base classes. When a base class is removed from the list, add
  its base classes to this class's list of base classes.
 */
void ClassNode::removePrivateAndInternalBases()
{
    int i;
    i = 0;
    QSet<ClassNode *> found;

    // Remove private and duplicate base classes.
    while (i < m_bases.size()) {
        ClassNode *bc = m_bases.at(i).m_node;
        if (bc == nullptr)
            bc = QDocDatabase::qdocDB()->findClassNode(m_bases.at(i).m_path);
        if (bc != nullptr
            && (bc->isPrivate() || bc->isInternal() || bc->isDontDocument()
                || found.contains(bc))) {
            RelatedClass rc = m_bases.at(i);
            m_bases.removeAt(i);
            m_ignoredBases.append(rc);
            promotePublicBases(bc->baseClasses());
        } else {
            ++i;
        }
        found.insert(bc);
    }

    i = 0;
    while (i < m_derived.size()) {
        ClassNode *dc = m_derived.at(i).m_node;
        if (dc != nullptr && (dc->isPrivate() || dc->isInternal() || dc->isDontDocument())) {
            m_derived.removeAt(i);
            const QList<RelatedClass> &dd = dc->derivedClasses();
            for (qsizetype j = dd.size() - 1; j >= 0; --j)
                m_derived.insert(i, dd.at(j));
        } else {
            ++i;
        }
    }
}

/*!
 */
void ClassNode::resolvePropertyOverriddenFromPtrs(PropertyNode *pn)
{
    for (const auto &baseClass : std::as_const(baseClasses())) {
        ClassNode *cn = baseClass.m_node;
        if (cn) {
            Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty);
            if (n) {
                auto *baseProperty = static_cast<PropertyNode *>(n);
                cn->resolvePropertyOverriddenFromPtrs(baseProperty);
                pn->setOverriddenFrom(baseProperty);
            } else
                cn->resolvePropertyOverriddenFromPtrs(pn);
        }
    }
}

QT_END_NAMESPACE