Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmltypenode.cpp
Go to the documentation of this file.
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 "qmltypenode.h"
6#include "qdocdatabase.h"
7
8#include <QtCore/qdebug.h>
9
11
12QMultiMap<const Node *, Node *> QmlTypeNode::s_inheritedBy;
13
14/*!
15 Constructs a Qml type.
16
17 The new node has the given \a parent, name \a name, and a specific node
18 \a type. Valid types are NodeType::QmlType and NodeType::QmlValueType.
19 */
20QmlTypeNode::QmlTypeNode(Aggregate *parent, const QString &name, NodeType type)
21 : Aggregate(type, parent, name)
22{
23 Q_ASSERT(type == NodeType::QmlType || type == NodeType::QmlValueType);
24}
25
26/*!
27 Clear the static maps so that subsequent runs don't try to use
28 contents from a previous run.
29 */
31{
32 s_inheritedBy.clear();
33}
34
35/*!
36 Record the fact that QML class \a base is inherited by
37 QML class \a sub.
38 */
39void QmlTypeNode::addInheritedBy(const Node *base, Node *sub)
40{
41 if (sub->isInternal())
42 return;
43 if (!s_inheritedBy.contains(base, sub))
44 s_inheritedBy.insert(base, sub);
45}
46
47/*!
48 Loads the list \a subs with the nodes of all the subclasses of \a base.
49 */
50void QmlTypeNode::subclasses(const Node *base, NodeList &subs, bool recurse)
51{
52 if (s_inheritedBy.count(base) > 0) {
53 if (recurse) {
54 for (auto *sub : s_inheritedBy.values(base)) {
55 if (!subs.contains(sub)) {
56 subs.append(sub);
57 QmlTypeNode::subclasses(sub, subs, recurse);
58 }
59 }
60 } else
61 subs = s_inheritedBy.values(base);
62 }
63}
64
65/*!
66 If this QML type node has a base type node,
67 return the fully qualified name of that QML
68 type, i.e. <QML-module-name>::<QML-type-name>.
69 */
71{
72 QString result;
73 if (m_qmlBaseNode) {
74 result = m_qmlBaseNode->logicalModuleName() + "::" + m_qmlBaseNode->name();
75 }
76 return result;
77}
78
79/*!
80 If the QML type's QML module pointer is set, return the QML
81 module name from the QML module node. Otherwise, return the
82 empty string.
83 */
85{
86 return (m_logicalModule ? m_logicalModule->logicalModuleName() : QString());
87}
88
89/*!
90 If the QML type's QML module pointer is set, return the QML
91 module version from the QML module node. Otherwise, return
92 the empty string.
93 */
95{
96 return (m_logicalModule ? m_logicalModule->logicalModuleVersion() : QString());
97}
98
99/*!
100 If the QML type's QML module pointer is set, return the QML
101 module identifier from the QML module node. Otherwise, return
102 the empty string.
103 */
105{
106 return (m_logicalModule ? m_logicalModule->logicalModuleIdentifier() : QString());
107}
108
109/*!
110 Returns true if this QML type inherits \a type.
111 */
113{
115 while (qtn != nullptr) {
116 if (qtn == type)
117 return true;
118 qtn = qtn->qmlBaseNode();
119 }
120 return false;
121}
122
123/*!
124 Recursively resolves the base node for this QML type when only the name of
125 the base type is known.
126
127 \a previousSearches is used for speeding up the process.
128*/
129void QmlTypeNode::resolveInheritance(NodeMap &previousSearches)
130{
131 if (m_qmlBaseNode || m_qmlBaseName.isEmpty())
132 return;
133
134 auto *base = static_cast<QmlTypeNode *>(previousSearches.value(m_qmlBaseName));
135
136 // If the cached base is from a different module, we need to search again
137 // to respect module context for disambiguation
138 bool needsSearch = !previousSearches.contains(m_qmlBaseName);
139 if (!needsSearch && base && logicalModule() && base->logicalModule() != logicalModule())
140 needsSearch = true;
141
142 if (needsSearch) {
143 for (const auto &imp : std::as_const(m_importList)) {
144 base = QDocDatabase::qdocDB()->findQmlType(imp, m_qmlBaseName, this);
145 if (base)
146 break;
147 }
148 if (!base) {
149 if (m_qmlBaseName.contains(':'))
150 base = QDocDatabase::qdocDB()->findQmlType(m_qmlBaseName, this);
151 else
152 base = QDocDatabase::qdocDB()->findQmlType(QString(), m_qmlBaseName, this);
153 }
154 // Only cache if we don't have a module (to avoid polluting cache with module-specific results)
155 if (!logicalModule())
156 previousSearches.insert(m_qmlBaseName, base);
157 }
158
159 if (base) {
160 if (base != this) {
161 m_qmlBaseNode = base;
163 // Base types read from the index need resolving as they only have the name set
164 if (base->isIndexNode())
165 base->resolveInheritance(previousSearches);
166 } else
167 location().warning(QStringLiteral("Type is its own base type: '%1'").arg(name()));
168 }
169
170 if (!base)
171 location().report(QStringLiteral("Unknown base '%1' for QML type '%2'").arg(qmlBaseName(), name()));
172}
173
174/*!
175 Checks and warns about problems with the inheritance of this QML type.
176*/
178{
179 /* Use Floyd's cycle-finding algorithm (tortoise and hare) to detect base
180 types that inherit from their descendants. */
181 const QmlTypeNode *qtn = this;
182 const QmlTypeNode *hare = qtn;
183
184 // Record the previous type found by the hare for reporting.
185 QmlTypeNode *previous = nullptr;
186
187 while (qtn && hare) {
188 // Examine the base node.
189 qtn = qtn->qmlBaseNode();
190
191 /* The hare node moves two nodes up the inheritance tree to increase
192 the cycle detection distance, recording the previous type in case
193 it needs to be reported. */
194 for (int i = 0; i < 2; i++)
195 if (hare) {
196 previous = const_cast<QmlTypeNode *>(hare);
197 hare = hare->qmlBaseNode();
198 }
199
200 // Only report a cycle if both nodes are non-null and identical.
201 if (previous && qtn && hare && qtn == hare) {
202 location().warning(QStringLiteral("Cyclic type inheritance: '%1'").arg(previous->name()));
203 previous->m_qmlBaseNode = nullptr;
204 break;
205 }
206 }
207}
208
209QT_END_NAMESPACE
static void terminate()
Clear the static maps so that subsequent runs don't try to use contents from a previous run.
QmlTypeNode(Aggregate *parent, const QString &name, NodeType type)
Constructs a Qml type.
QString qmlFullBaseName() const override
If this QML type node has a base type node, return the fully qualified name of that QML type,...
QString logicalModuleIdentifier() const override
If the QML type's QML module pointer is set, return the QML module identifier from the QML module nod...
static void subclasses(const Node *base, NodeList &subs, bool recurse=false)
Loads the list subs with the nodes of all the subclasses of base.
bool inherits(Aggregate *type)
Returns true if this QML type inherits type.
QString logicalModuleVersion() const override
If the QML type's QML module pointer is set, return the QML module version from the QML module node.
void resolveInheritance(NodeMap &previousSearches)
Recursively resolves the base node for this QML type when only the name of the base type is known.
static void addInheritedBy(const Node *base, Node *sub)
Record the fact that QML class base is inherited by QML class sub.
void checkInheritance()
Checks and warns about problems with the inheritance of this QML type.
QString logicalModuleName() const override
If the QML type's QML module pointer is set, return the QML module name from the QML module node.
QmlTypeNode * qmlBaseNode() const override
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
Definition qmltypenode.h:47
CollectionNode * logicalModule() const override
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
Definition qmltypenode.h:40
NodeType
Definition genustypes.h:150
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:44
QMap< QString, Node * > NodeMap
Definition node.h:47
The Node class is the base class for all the nodes in QDoc's parse tree.
virtual bool isInternal() const
Returns true if the node's status is Internal, or if its parent is a class with Internal status.
Definition node.cpp:848
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
Definition node.h:238