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