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 setTitle(name);
25}
26
27/*!
28 Clear the static maps so that subsequent runs don't try to use
29 contents from a previous run.
30 */
32{
33 s_inheritedBy.clear();
34}
35
36/*!
37 Record the fact that QML class \a base is inherited by
38 QML class \a sub.
39 */
40void QmlTypeNode::addInheritedBy(const Node *base, Node *sub)
41{
42 if (sub->isInternal())
43 return;
44 if (!s_inheritedBy.contains(base, sub))
45 s_inheritedBy.insert(base, sub);
46}
47
48/*!
49 Loads the list \a subs with the nodes of all the subclasses of \a base.
50 */
51void QmlTypeNode::subclasses(const Node *base, NodeList &subs)
52{
53 subs.clear();
54 if (s_inheritedBy.count(base) > 0) {
55 subs = s_inheritedBy.values(base);
56 }
57}
58
59/*!
60 If this QML type node has a base type node,
61 return the fully qualified name of that QML
62 type, i.e. <QML-module-name>::<QML-type-name>.
63 */
65{
66 QString result;
67 if (m_qmlBaseNode) {
68 result = m_qmlBaseNode->logicalModuleName() + "::" + m_qmlBaseNode->name();
69 }
70 return result;
71}
72
73/*!
74 If the QML type's QML module pointer is set, return the QML
75 module name from the QML module node. Otherwise, return the
76 empty string.
77 */
79{
80 return (m_logicalModule ? m_logicalModule->logicalModuleName() : QString());
81}
82
83/*!
84 If the QML type's QML module pointer is set, return the QML
85 module version from the QML module node. Otherwise, return
86 the empty string.
87 */
89{
90 return (m_logicalModule ? m_logicalModule->logicalModuleVersion() : QString());
91}
92
93/*!
94 If the QML type's QML module pointer is set, return the QML
95 module identifier from the QML module node. Otherwise, return
96 the empty string.
97 */
99{
100 return (m_logicalModule ? m_logicalModule->logicalModuleIdentifier() : QString());
101}
102
103/*!
104 Returns true if this QML type inherits \a type.
105 */
107{
109 while (qtn != nullptr) {
110 if (qtn == type)
111 return true;
112 qtn = qtn->qmlBaseNode();
113 }
114 return false;
115}
116
117/*!
118 Recursively resolves the base node for this QML type when only the name of
119 the base type is known.
120
121 \a previousSearches is used for speeding up the process.
122*/
123void QmlTypeNode::resolveInheritance(NodeMap &previousSearches)
124{
125 if (m_qmlBaseNode || m_qmlBaseName.isEmpty())
126 return;
127
128 auto *base = static_cast<QmlTypeNode *>(previousSearches.value(m_qmlBaseName));
129 if (!previousSearches.contains(m_qmlBaseName)) {
130 for (const auto &imp : std::as_const(m_importList)) {
131 base = QDocDatabase::qdocDB()->findQmlType(imp, m_qmlBaseName);
132 if (base)
133 break;
134 }
135 if (!base) {
136 if (m_qmlBaseName.contains(':'))
137 base = QDocDatabase::qdocDB()->findQmlType(m_qmlBaseName);
138 else
139 base = QDocDatabase::qdocDB()->findQmlType(QString(), m_qmlBaseName);
140 }
141 previousSearches.insert(m_qmlBaseName, base);
142 }
143
144 if (base) {
145 if (base != this) {
146 m_qmlBaseNode = base;
148 // Base types read from the index need resolving as they only have the name set
149 if (base->isIndexNode())
150 base->resolveInheritance(previousSearches);
151 } else
152 location().warning(QStringLiteral("Type is its own base type: '%1'").arg(name()));
153 }
154
155 if (!base)
156 location().report(QStringLiteral("Unknown base '%1' for QML type '%2'").arg(qmlBaseName(), name()));
157}
158
159/*!
160 Checks and warns about problems with the inheritance of this QML type.
161*/
163{
164 /* Use Floyd's cycle-finding algorithm (tortoise and hare) to detect base
165 types that inherit from their descendants. */
166 const QmlTypeNode *qtn = this;
167 const QmlTypeNode *hare = qtn;
168
169 // Record the previous type found by the hare for reporting.
170 QmlTypeNode *previous = nullptr;
171
172 while (qtn && hare) {
173 // Examine the base node.
174 qtn = qtn->qmlBaseNode();
175
176 /* The hare node moves two nodes up the inheritance tree to increase
177 the cycle detection distance, recording the previous type in case
178 it needs to be reported. */
179 for (int i = 0; i < 2; i++)
180 if (hare) {
181 previous = const_cast<QmlTypeNode *>(hare);
182 hare = hare->qmlBaseNode();
183 }
184
185 // Only report a cycle if both nodes are non-null and identical.
186 if (previous && qtn && hare && qtn == hare) {
187 location().warning(QStringLiteral("Cyclic type inheritance: '%1'").arg(previous->name()));
188 previous->m_qmlBaseNode = nullptr;
189 break;
190 }
191 }
192}
193
194QT_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...
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.
static void subclasses(const Node *base, NodeList &subs)
Loads the list subs with the nodes of all the subclasses of base.
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
NodeType
Definition genustypes.h:150
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:802
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
Definition node.h:238