1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlmetatypedata_p.h"
41
42#include <private/qqmltype_p_p.h>
43#include <private/qqmltypemodule_p.h>
44#include <private/qqmlpropertycache_p.h>
45
46QT_BEGIN_NAMESPACE
47
48QQmlMetaTypeData::QQmlMetaTypeData()
49{
50}
51
52QQmlMetaTypeData::~QQmlMetaTypeData()
53{
54 for (TypeModules::const_iterator i = uriToModule.constBegin(), cend = uriToModule.constEnd(); i != cend; ++i)
55 delete *i;
56 for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator it = propertyCaches.begin(), end = propertyCaches.end();
57 it != end; ++it)
58 (*it)->release();
59
60 // Do this before the attached properties disappear.
61 types.clear();
62 undeletableTypes.clear();
63}
64
65// This expects a "fresh" QQmlTypePrivate and adopts its reference.
66void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv)
67{
68 for (int i = 0; i < types.count(); ++i) {
69 if (!types.at(i).isValid()) {
70 types[i] = QQmlType(priv);
71 priv->index = i;
72 priv->release();
73 return;
74 }
75 }
76 types.append(t: QQmlType(priv));
77 priv->index = types.count() - 1;
78 priv->release();
79}
80
81bool QQmlMetaTypeData::registerModuleTypes(const QQmlMetaTypeData::VersionedUri &versionedUri)
82{
83 auto function = moduleTypeRegistrationFunctions.constFind(akey: versionedUri);
84 if (function != moduleTypeRegistrationFunctions.constEnd()) {
85 (*function)();
86 return true;
87 }
88 return false;
89}
90
91QQmlPropertyCache *QQmlMetaTypeData::propertyCacheForMinorVersion(int index, int minorVersion) const
92{
93 return (index < typePropertyCaches.length())
94 ? typePropertyCaches.at(i: index).value(akey: minorVersion).data()
95 : nullptr;
96}
97
98void QQmlMetaTypeData::setPropertyCacheForMinorVersion(int index, int minorVersion,
99 QQmlPropertyCache *cache)
100{
101 if (index >= typePropertyCaches.length())
102 typePropertyCaches.resize(asize: index + 1);
103 typePropertyCaches[index][minorVersion] = cache;
104}
105
106void QQmlMetaTypeData::clearPropertyCachesForMinorVersion(int index)
107{
108 if (index < typePropertyCaches.length())
109 typePropertyCaches[index].clear();
110}
111
112QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion)
113{
114 if (QQmlPropertyCache *rv = propertyCaches.value(akey: metaObject))
115 return rv;
116
117 if (!metaObject->superClass()) {
118 QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
119 propertyCaches.insert(akey: metaObject, avalue: rv);
120 return rv;
121 }
122 auto super = propertyCache(metaObject: metaObject->superClass(), minorVersion);
123 QQmlPropertyCache *rv = super->copyAndAppend(metaObject, typeMinorVersion: minorVersion);
124 propertyCaches.insert(akey: metaObject, avalue: rv);
125 return rv;
126}
127
128QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion)
129{
130 Q_ASSERT(type.isValid());
131
132 if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(index: type.index(), minorVersion))
133 return pc;
134
135 QVector<QQmlType> types;
136
137 int maxMinorVersion = 0;
138
139 const QMetaObject *metaObject = type.metaObject();
140
141 while (metaObject) {
142 QQmlType t = QQmlMetaType::qmlType(metaObject, module: type.module(), version_major: type.majorVersion(), version_minor: minorVersion);
143 if (t.isValid()) {
144 maxMinorVersion = qMax(a: maxMinorVersion, b: t.minorVersion());
145 types << t;
146 } else {
147 types << QQmlType();
148 }
149
150 metaObject = metaObject->superClass();
151 }
152
153 if (QQmlPropertyCache *pc = propertyCacheForMinorVersion(index: type.index(), minorVersion: maxMinorVersion)) {
154 setPropertyCacheForMinorVersion(index: type.index(), minorVersion, cache: pc);
155 return pc;
156 }
157
158 QQmlPropertyCache *raw = propertyCache(metaObject: type.metaObject(), minorVersion).data();
159
160 bool hasCopied = false;
161
162 for (int ii = 0; ii < types.count(); ++ii) {
163 const QQmlType &currentType = types.at(i: ii);
164 if (!currentType.isValid())
165 continue;
166
167 int rev = currentType.metaObjectRevision();
168 int moIndex = types.count() - 1 - ii;
169
170 if (raw->allowedRevision(index: moIndex) != rev) {
171 if (!hasCopied) {
172 // TODO: The copy should be mutable, and the original should be const
173 // Considering this, the setAllowedRevision() below does not violate
174 // the immutability of already published property caches.
175 raw = raw->copy();
176 hasCopied = true;
177 }
178 raw->setAllowedRevision(index: moIndex, allowed: rev);
179 }
180 }
181
182 // Test revision compatibility - the basic rule is:
183 // * Anything that is excluded, cannot overload something that is not excluded *
184
185 // Signals override:
186 // * other signals and methods of the same name.
187 // * properties named on<Signal Name>
188 // * automatic <property name>Changed notify signals
189
190 // Methods override:
191 // * other methods of the same name
192
193 // Properties override:
194 // * other elements of the same name
195
196#if 0
197 bool overloadError = false;
198 QString overloadName;
199
200 for (QQmlPropertyCache::StringCache::ConstIterator iter = raw->stringCache.begin();
201 !overloadError && iter != raw->stringCache.end();
202 ++iter) {
203
204 QQmlPropertyData *d = *iter;
205 if (raw->isAllowedInRevision(d))
206 continue; // Not excluded - no problems
207
208 // check that a regular "name" overload isn't happening
209 QQmlPropertyData *current = d;
210 while (!overloadError && current) {
211 current = d->overrideData(current);
212 if (current && raw->isAllowedInRevision(current))
213 overloadError = true;
214 }
215 }
216
217 if (overloadError) {
218 if (hasCopied) raw->release();
219
220 error.setDescription(QLatin1String("Type ") + type.qmlTypeName() + QLatin1Char(' ') + QString::number(type.majorVersion()) + QLatin1Char('.') + QString::number(minorVersion) + QLatin1String(" contains an illegal property \"") + overloadName + QLatin1String("\". This is an error in the type's implementation."));
221 return 0;
222 }
223#endif
224
225 setPropertyCacheForMinorVersion(index: type.index(), minorVersion, cache: raw);
226
227 if (hasCopied)
228 raw->release();
229
230 if (minorVersion != maxMinorVersion)
231 setPropertyCacheForMinorVersion(index: type.index(), minorVersion: maxMinorVersion, cache: raw);
232
233 return raw;
234}
235
236QT_END_NAMESPACE
237

source code of qtdeclarative/src/qml/qml/qqmlmetatypedata.cpp