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 "collectionnode.h" |
6 | #include "qdocdatabase.h" |
7 | |
8 | #include <QtCore/qdebug.h> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | QMultiMap<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 Node::QmlType and Node::QmlValueType. |
19 | */ |
20 | QmlTypeNode::QmlTypeNode(Aggregate *parent, const QString &name, Node::NodeType type) |
21 | : Aggregate(type, parent, name) |
22 | { |
23 | Q_ASSERT(type == Node::QmlType || type == Node::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 | */ |
31 | void QmlTypeNode::terminate() |
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 | */ |
40 | void QmlTypeNode::addInheritedBy(const Node *base, Node *sub) |
41 | { |
42 | if (sub->isInternal()) |
43 | return; |
44 | if (!s_inheritedBy.contains(key: base, value: sub)) |
45 | s_inheritedBy.insert(key: base, value: sub); |
46 | } |
47 | |
48 | /*! |
49 | Loads the list \a subs with the nodes of all the subclasses of \a base. |
50 | */ |
51 | void QmlTypeNode::subclasses(const Node *base, NodeList &subs) |
52 | { |
53 | subs.clear(); |
54 | if (s_inheritedBy.count(key: base) > 0) { |
55 | subs = s_inheritedBy.values(key: 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 | */ |
64 | QString QmlTypeNode::qmlFullBaseName() const |
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 | */ |
78 | QString QmlTypeNode::logicalModuleName() const |
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 | */ |
88 | QString QmlTypeNode::logicalModuleVersion() const |
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 | */ |
98 | QString QmlTypeNode::logicalModuleIdentifier() const |
99 | { |
100 | return (m_logicalModule ? m_logicalModule->logicalModuleIdentifier() : QString()); |
101 | } |
102 | |
103 | /*! |
104 | Returns true if this QML type inherits \a type. |
105 | */ |
106 | bool QmlTypeNode::inherits(Aggregate *type) |
107 | { |
108 | QmlTypeNode *qtn = qmlBaseNode(); |
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 | */ |
123 | void QmlTypeNode::resolveInheritance(NodeMap &previousSearches) |
124 | { |
125 | if (m_qmlBaseNode || m_qmlBaseName.isEmpty()) |
126 | return; |
127 | |
128 | auto *base = static_cast<QmlTypeNode *>(previousSearches.value(key: m_qmlBaseName)); |
129 | if (!previousSearches.contains(key: m_qmlBaseName)) { |
130 | for (const auto &import : std::as_const(t&: m_importList)) { |
131 | base = QDocDatabase::qdocDB()->findQmlType(import, name: m_qmlBaseName); |
132 | if (base) |
133 | break; |
134 | } |
135 | if (!base) { |
136 | if (m_qmlBaseName.contains(c: ':')) |
137 | base = QDocDatabase::qdocDB()->findQmlType(name: m_qmlBaseName); |
138 | else |
139 | base = QDocDatabase::qdocDB()->findQmlType(qmid: QString(), name: m_qmlBaseName); |
140 | } |
141 | previousSearches.insert(key: m_qmlBaseName, value: base); |
142 | } |
143 | |
144 | if (base && base != this) { |
145 | m_qmlBaseNode = base; |
146 | QmlTypeNode::addInheritedBy(base, sub: this); |
147 | // Base types read from the index need resolving as they only have the name set |
148 | if (base->isIndexNode()) |
149 | base->resolveInheritance(previousSearches); |
150 | } |
151 | } |
152 | |
153 | QT_END_NAMESPACE |
154 | |