6#include <private/qqmlengine_p.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlvmemetaobject_p.h>
10#include <private/qmetaobject_p.h>
11#include <private/qmetaobjectbuilder_p.h>
12#include <private/qqmlpropertycachemethodarguments_p.h>
13#include <private/qqmlsignalnames_p.h>
15#include <private/qv4codegen_p.h>
16#include <private/qv4value_p.h>
18#include <QtCore/qdebug.h>
19#include <QtCore/QCryptographicHash>
20#include <QtCore/private/qtools_p.h>
27# pragma warning( disable : 4200
)
32#define Q_INT16_MAX 32767
37 for (
const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
38 signalCount += QMetaObjectPrivate::get(obj)->signalCount;
42QQmlPropertyData::Flags
43QQmlPropertyData::flagsForProperty(
const QMetaProperty &p)
45 QQmlPropertyData::Flags flags;
47 flags.setIsConstant(p.isConstant());
48 flags.setIsWritable(p.isWritable());
49 flags.setIsResettable(p.isResettable());
50 flags.setIsFinal(p.isFinal());
51 flags.setIsRequired(p.isRequired());
52 flags.setIsBindable(p.isBindable());
55 const QMetaType metaType = p.metaType();
56 int propType = metaType.id();
58 flags.setType(QQmlPropertyData::Flags::EnumType);
59 }
else if (metaType.flags() & QMetaType::PointerToQObject) {
60 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
61 }
else if (propType == QMetaType::QVariant) {
62 flags.setType(QQmlPropertyData::Flags::QVariantType);
63 }
else if (metaType.flags() & QMetaType::IsQmlList) {
64 flags.setType(QQmlPropertyData::Flags::QListType);
70void QQmlPropertyData::load(
const QMetaProperty &p)
72 Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max());
73 setCoreIndex(p.propertyIndex());
74 setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
75 setFlags(flagsForProperty(p));
76 setRevision(QTypeRevision::fromEncodedVersion(p.revision()));
77 QMetaType type = p.metaType();
81void QQmlPropertyData::load(
const QMetaMethod &m)
83 setCoreIndex(m.methodIndex());
84 m_flags.setType(Flags::FunctionType);
90 switch (m.methodType()) {
91 case QMetaMethod::Signal:
92 m_flags.setIsSignal(
true);
93 m_flags.setIsConstructor(
false);
94 setPropType(m.returnMetaType());
96 case QMetaMethod::Constructor:
97 m_flags.setIsSignal(
false);
98 m_flags.setIsConstructor(
true);
101 m_flags.setIsSignal(
false);
102 m_flags.setIsConstructor(
false);
103 setPropType(m.returnMetaType());
107 m_flags.setIsConstant(m.isConst());
109 const int paramCount = m.parameterCount();
111 m_flags.setHasArguments(
true);
112 m_flags.setIsV4Function(
114 m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
116 m_flags.setHasArguments(
false);
117 m_flags.setIsV4Function(
false);
120 m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
122 Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
123 setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
127
128
129
130
131QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
132 const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
134 Q_ASSERT(metaObject);
137 if (
const QMetaObject *super = metaObject->superClass()) {
138 result = createStandalone(
139 super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
141 result.adopt(
new QQmlPropertyCache(metaObject));
142 result->update(metaObject);
145 if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
151 for (
int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
152 ++metaObjectOffset) {
153 result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
160QQmlPropertyCache::~QQmlPropertyCache()
162 QQmlPropertyCacheMethodArguments *args = argumentsCache;
164 QQmlPropertyCacheMethodArguments *next = args->next;
175QQmlPropertyCache::Ptr QQmlPropertyCache::copy(
const QQmlMetaObjectPointer &mo,
int reserve)
const
177 QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
178 new QQmlPropertyCache(mo), QQmlPropertyCache::Ptr::Adopt);
179 cache->_parent.reset(
this);
180 cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart;
181 cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart;
182 cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart;
183 cache->stringCache.linkAndReserve(stringCache, reserve);
184 cache->allowedRevisionCache = allowedRevisionCache;
185 cache->_defaultPropertyName = _defaultPropertyName;
186 cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
191QQmlPropertyCache::Ptr QQmlPropertyCache::copy()
const
193 return copy(_metaObject, 0);
196QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
197 int propertyCount,
int methodCount,
int signalCount,
int enumCount)
const
199 QQmlPropertyCache::Ptr rv = copy(
200 QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount);
201 rv->propertyIndexCache.reserve(propertyCount);
202 rv->methodIndexCache.reserve(methodCount);
203 rv->signalHandlerIndexCache.reserve(signalCount);
204 rv->enumCache.reserve(enumCount);
208QQmlPropertyCache::OverrideResult
209QQmlPropertyCache::appendAlias(
const QString &name, QQmlPropertyData::Flags flags,
int coreIndex,
210 QMetaType propType, QTypeRevision version,
int notifyIndex,
211 int encodedTargetIndex)
213 QQmlPropertyData data;
214 data.setPropType(propType);
215 data.setCoreIndex(coreIndex);
216 data.setNotifyIndex(notifyIndex);
217 flags.setIsAlias(
true);
218 data.setFlags(flags);
219 data.setAliasTarget(encodedTargetIndex);
220 data.setTypeVersion(version);
222 return doAppendPropertyData(name, std::move(data));
225void QQmlPropertyCache::appendSignal(
const QString &name, QQmlPropertyData::Flags flags,
226 int coreIndex,
const QMetaType *types,
227 const QList<QByteArray> &names)
229 QQmlPropertyData data;
230 data.setPropType(QMetaType());
231 data.setCoreIndex(coreIndex);
232 data.setFlags(flags);
233 data.setArguments(
nullptr);
235 QQmlPropertyData handler = data;
236 handler.m_flags.setIsSignalHandler(
true);
239 const auto argumentCount = names.size();
240 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
241 new (args->types) QMetaType;
242 ::memcpy(args->types + 1, types, argumentCount *
sizeof(QMetaType));
243 data.setArguments(args);
246 QQmlPropertyData *old = findNamedProperty(name);
247 const OverrideResult overrideResult = handleOverride(name, &data, old);
248 if (overrideResult == InvalidOverride) {
250 methodIndexCache.append(*old);
252 handler.m_flags.setIsSignalHandler(
true);
253 signalHandlerIndexCache.append(handler);
257 int methodIndex = methodIndexCache.size();
258 methodIndexCache.append(data);
260 int signalHandlerIndex = signalHandlerIndexCache.size();
261 signalHandlerIndexCache.append(handler);
263 const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
265 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
266 setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
267 signalHandlerIndexCache.data() + signalHandlerIndex);
270void QQmlPropertyCache::appendMethod(
const QString &name, QQmlPropertyData::Flags flags,
271 int coreIndex, QMetaType returnType,
272 const QList<QByteArray> &names,
273 const QVector<QMetaType> ¶meterTypes)
275 int argumentCount = names.size();
277 QQmlPropertyData data;
278 data.setPropType(returnType);
279 data.setCoreIndex(coreIndex);
280 data.setFlags(flags);
281 QQmlPropertyData *old = findNamedProperty(name);
282 const OverrideResult overrideResult = handleOverride(name, &data, old);
283 if (overrideResult == InvalidOverride) {
285 methodIndexCache.append(*old);
289 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
290 new (args->types) QMetaType(returnType);
291 for (
int ii = 0; ii < argumentCount; ++ii)
292 new (args->types + ii + 1) QMetaType(parameterTypes.at(ii));
293 data.setArguments(args);
295 int methodIndex = methodIndexCache.size();
296 methodIndexCache.append(data);
298 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
301void QQmlPropertyCache::appendEnum(
const QString &name,
const QVector<QQmlEnumValue> &values)
305 data.values = values;
306 enumCache.append(data);
310const QMetaObject *QQmlPropertyCache::createMetaObject()
const
312 if (_metaObject.isNull()) {
313 QMetaObjectBuilder builder;
314 toMetaObjectBuilder(builder);
315 builder.setSuperClass(_parent->createMetaObject());
316 _metaObject.setSharedOnce(builder.toMetaObject());
319 return _metaObject.metaObject();
322const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(
int index)
const
324 if (index < 0 || index >= propertyCount())
327 const QQmlPropertyData *rv =
nullptr;
328 if (index < propertyIndexCacheStart)
329 return _parent->maybeUnresolvedProperty(index);
331 rv =
const_cast<
const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
335const QQmlPropertyData *QQmlPropertyCache::defaultProperty()
const
337 return property(defaultPropertyName(),
nullptr,
nullptr);
340void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
342 if (_parent != newParent)
343 _parent = std::move(newParent);
346QQmlPropertyCache::Ptr
347QQmlPropertyCache::copyAndAppend(
const QMetaObject *metaObject,
348 QTypeRevision typeVersion,
349 QQmlPropertyData::Flags propertyFlags,
350 QQmlPropertyData::Flags methodFlags,
351 QQmlPropertyData::Flags signalFlags)
const
353 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
358 QQmlPropertyCache::Ptr rv = copy(
360 QMetaObjectPrivate::get(metaObject)->methodCount
361 + QMetaObjectPrivate::get(metaObject)->signalCount
362 + QMetaObjectPrivate::get(metaObject)->propertyCount);
364 rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
371 return QQmlSignalNames::signalNameToHandlerName(methodName);
376 return QQmlSignalNames::signalNameToHandlerName(
377 QLatin1StringView{ methodName.constData(), methodName.length() });
383 const char *cptr = str;
385 utf8 |= *cptr & 0x80;
388 return std::make_pair(utf8, cptr - str);
391void QQmlPropertyCache::append(
const QMetaObject *metaObject,
392 QTypeRevision typeVersion,
393 QQmlPropertyData::Flags propertyFlags,
394 QQmlPropertyData::Flags methodFlags,
395 QQmlPropertyData::Flags signalFlags)
397 allowedRevisionCache.append(QTypeRevision::zero());
399 int methodCount = metaObject->methodCount();
400 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
401 int signalCount = metaObjectSignalCount(metaObject);
402 int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
404 if (classInfoCount) {
405 int classInfoOffset = metaObject->classInfoOffset();
406 for (
int ii = 0; ii < classInfoCount; ++ii) {
407 int idx = ii + classInfoOffset;
408 QMetaClassInfo mci = metaObject->classInfo(idx);
409 const char *name = mci.name();
410 if (0 == qstrcmp(name,
"DefaultProperty")) {
411 _defaultPropertyName = QString::fromUtf8(mci.value());
412 }
else if (0 == qstrcmp(name,
"qt_QmlJSWrapperFactoryMethod")) {
413 const char *
const factoryMethod = mci.value();
414 _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
415 if (_jsFactoryMethodIndex != -1)
416 _jsFactoryMethodIndex -= metaObject->methodOffset();
417 }
else if (0 == qstrcmp(name,
"QML.ListPropertyAssignBehavior")) {
418 _listPropertyAssignBehavior = mci.value();
424 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
425 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
426 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
430 const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
432 int methodOffset = metaObject->methodOffset();
433 int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
437 methodIndexCache.resize(methodCount - methodIndexCacheStart);
438 signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
439 int signalHandlerIndex = signalOffset;
440 for (
int ii = methodOffset; ii < methodCount; ++ii) {
441 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
443 const QMetaMethod &m = metaObject->method(ii);
444 if (m.access() == QMetaMethod::Private)
449 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
451 QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
452 QQmlPropertyData *sigdata =
nullptr;
454 if (m.methodType() == QMetaMethod::Signal)
455 data->setFlags(signalFlags);
457 data->setFlags(methodFlags);
461 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
462 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
464 if (data->isSignal()) {
465 sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
467 sigdata->m_flags.setIsSignalHandler(
true);
470 const auto doSetNamedProperty = [&](
const auto &methodName) {
471 QQmlPropertyData *old =
nullptr;
472 if (StringCache::mapped_type *it = stringCache.value(methodName)) {
473 if (handleOverride(methodName, data, (old = it->second)) == InvalidOverride) {
479 sigdata->m_flags.setIsSignalHandler(
true);
480 ++signalHandlerIndex;
486 setNamedProperty(methodName, ii, data);
488 if (data->isSignal()) {
491 if constexpr (std::is_same_v<std::decay_t<
decltype(methodName)>, QHashedCStringRef>)
492 data->m_flags.setIsOverridableSignal(
true);
494 setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
495 ++signalHandlerIndex;
499 const char *str = m.nameView().constData();
500 const auto [isUtf8, len] = deriveEncodingAndLength(str);
502 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)));
504 doSetNamedProperty(QHashedCStringRef(str, len));
507 int propCount = metaObject->propertyCount();
508 int propOffset = metaObject->propertyOffset();
512 propertyIndexCache.resize(propCount - propertyIndexCacheStart);
513 for (
int ii = propOffset; ii < propCount; ++ii) {
514 QMetaProperty p = metaObject->property(ii);
515 if (!p.isScriptable())
518 QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
520 data->setFlags(propertyFlags);
522 data->setTypeVersion(typeVersion);
524 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
525 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
527 const auto doSetNamedProperty = [
this](
const auto &propName,
int index,
auto *propData) {
528 QQmlPropertyData *existingPropData =
nullptr;
529 if (StringCache::mapped_type *it = stringCache.value(propName)) {
530 if (handleOverride(propName, propData, (existingPropData = it->second))
531 == InvalidOverride) {
532 *propData = *existingPropData;
536 setNamedProperty(propName, index, propData);
539 const char *str = p.name();
540 const auto [isUtf8, len] = deriveEncodingAndLength(str);
542 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)), ii, data);
544 doSetNamedProperty(QHashedCStringRef(str, len), ii, data);
546 bool isGadget =
true;
547 for (
const QMetaObject *it = metaObject; it !=
nullptr; it = it->superClass()) {
548 if (it == &QObject::staticMetaObject)
553 if (!isGadget && !data->isAlias())
554 data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
558void QQmlPropertyCache::update(
const QMetaObject *metaObject)
560 Q_ASSERT(metaObject);
566 int pc = metaObject->propertyCount();
567 int mc = metaObject->methodCount();
568 int sc = metaObjectSignalCount(metaObject);
569 propertyIndexCache.reserve(pc - propertyIndexCacheStart);
570 methodIndexCache.reserve(mc - methodIndexCacheStart);
571 signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
575 stringCache.reserve(pc + mc + sc);
578 append(metaObject, QTypeRevision());
582
583
584
585void QQmlPropertyCache::invalidate(
const QMetaObject *metaObject)
587 propertyIndexCache.clear();
588 methodIndexCache.clear();
589 signalHandlerIndexCache.clear();
591 argumentsCache =
nullptr;
593 int pc = metaObject->propertyCount();
594 int mc = metaObject->methodCount();
595 int sc = metaObjectSignalCount(metaObject);
596 int reserve = pc + mc + sc;
599 propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart;
600 methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart;
601 signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart;
602 stringCache.linkAndReserve(parent()->stringCache, reserve);
603 append(metaObject, QTypeRevision());
605 propertyIndexCacheStart = 0;
606 methodIndexCacheStart = 0;
607 signalHandlerIndexCacheStart = 0;
612const QQmlPropertyData *QQmlPropertyCache::findProperty(
613 StringCache::ConstIterator it, QObject *object,
614 const QQmlRefPointer<QQmlContextData> &context)
const
616 QQmlData *data = (object ? QQmlData::get(object) :
nullptr);
617 const QQmlVMEMetaObject *vmemo =
nullptr;
618 if (data && data->hasVMEMetaObject) {
619 QObjectPrivate *op = QObjectPrivate::get(object);
620 vmemo =
static_cast<
const QQmlVMEMetaObject *>(op->metaObject);
622 return findProperty(it, vmemo, context);
627inline bool contextHasNoExtensions(
const QQmlRefPointer<QQmlContextData> &context)
631 const QQmlRefPointer<QQmlContextData> parent = context->parent();
632 return (!parent || !parent->imports());
635inline int maximumIndexForProperty(
const QQmlPropertyData *prop,
const int methodCount,
const int signalCount,
const int propertyCount)
637 return prop->isFunction() ? methodCount
638 : prop->isSignalHandler() ? signalCount
644const QQmlPropertyData *QQmlPropertyCache::findProperty(
645 StringCache::ConstIterator it,
const QQmlVMEMetaObject *vmemo,
646 const QQmlRefPointer<QQmlContextData> &context)
const
648 StringCache::ConstIterator end = stringCache.end();
651 const QQmlPropertyData *result = it.value().second;
657 if (vmemo && context && !contextHasNoExtensions(context)) {
660 if (vmemo->ctxt.contextData().data() == context.data())
663 vmemo = vmemo->parentVMEMetaObject();
668 const int methodCount = vmemo->cache->methodCount();
669 const int signalCount = vmemo->cache->signalCount();
670 const int propertyCount = vmemo->cache->propertyCount();
674 const StringCache::mapped_type &property(it.value());
676 if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
678 if (property.second->isFunction() || property.second->isSignalHandler()) {
682 result = property.second;
688 it = stringCache.findNext(it);
698void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
700 Q_ASSERT(predecessor !=
this);
702 setOverrideIndexIsProperty(!predecessor->isFunction());
703 setOverrideIndex(predecessor->coreIndex());
704 predecessor->m_flags.setIsOverridden(
true);
705 Q_ASSERT(predecessor->isOverridden());
709QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
710 int argc,
const QList<QByteArray> &names)
712 typedef QQmlPropertyCacheMethodArguments A;
713 A *args =
static_cast<A *>(malloc(
sizeof(A) + argc *
sizeof(QMetaType)));
714 args->names = argc ?
new QList<QByteArray>(names) :
nullptr;
715 args->next = argumentsCache;
716 argumentsCache = args;
720QString QQmlPropertyCache::signalParameterStringForJS(
721 const QList<QByteArray> ¶meterNameList, QString *errorString)
723 bool unnamedParameter =
false;
726 const qsizetype count = parameterNameList.size();
727 if (count > std::numeric_limits<quint16>::max())
728 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal has an excessive number of parameters: %1").arg(count);
730 for (qsizetype i = 0; i < count; ++i) {
732 parameters += QLatin1Char(
',');
733 const QByteArray ¶m = parameterNameList.at(i);
734 if (param.isEmpty()) {
735 unnamedParameter =
true;
736 }
else if (unnamedParameter) {
738 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal uses unnamed parameter followed by named parameter.");
740 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
742 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
745 parameters += QString::fromUtf8(param);
751int QQmlPropertyCache::originalClone(
int index)
const
753 while (signal(index)->isCloned())
758int QQmlPropertyCache::originalClone(
const QObject *object,
int index)
760 QQmlData *data = QQmlData::get(object);
761 if (data && data->propertyCache) {
762 const QQmlPropertyCache *cache = data->propertyCache.data();
763 const QQmlPropertyData *sig = cache->signal(index);
764 while (sig && sig->isCloned()) {
766 sig = cache->signal(index);
769 while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
778 Q_ASSERT(metaObject);
783
784
787 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
788 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
789 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
791 const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
793 int methodCount = metaObject->methodCount();
794 for (
int ii = methodCount - 1; ii >= 0; --ii) {
795 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
797 QMetaMethod m = metaObject->method(ii);
798 if (m.access() == QMetaMethod::Private)
801 if (m.name() == propertyName) {
808 const QMetaObject *cmo = metaObject;
810 int idx = cmo->indexOfProperty(propertyName);
812 QMetaProperty p = cmo->property(idx);
813 if (p.isScriptable()) {
817 bool changed =
false;
818 while (cmo && cmo->propertyOffset() >= idx) {
819 cmo = cmo->superClass();
823
824 if (!changed) cmo =
nullptr;
836 return string.data();
841 return string.toUtf8();
846 return string->toQString().toUtf8();
852 QQmlPropertyData *local)
854 const QQmlPropertyCache *cache =
nullptr;
856 QQmlData *ddata = QQmlData::get(obj,
false);
858 if (ddata && ddata->propertyCache) {
859 cache = ddata->propertyCache.data();
860 }
else if (
auto newCache = QQmlMetaType::propertyCache(obj)) {
861 cache = newCache.data();
862 ddata = QQmlData::get(obj,
true);
863 ddata->propertyCache =
std::move(newCache);
866 const QQmlPropertyData *rv =
nullptr;
869 rv = cache->property(name, obj, context);
871 *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
872 if (local->isValid())
879const QQmlPropertyData *QQmlPropertyCache::property(
880 QObject *obj,
const QV4::String *name,
const QQmlRefPointer<QQmlContextData> &context,
881 QQmlPropertyData *local)
883 return qQmlPropertyCacheProperty<
const QV4::String *>(obj, name, context, local);
886const QQmlPropertyData *QQmlPropertyCache::property(
887 QObject *obj, QStringView name,
const QQmlRefPointer<QQmlContextData> &context,
888 QQmlPropertyData *local)
890 return qQmlPropertyCacheProperty<
const QStringView &>(obj, name, context, local);
893const QQmlPropertyData *QQmlPropertyCache::property(
894 QObject *obj,
const QLatin1String &name,
const QQmlRefPointer<QQmlContextData> &context,
895 QQmlPropertyData *local)
897 return qQmlPropertyCacheProperty<
const QLatin1String &>(obj, name, context, local);
903 uint offset = mo->d.stringdata[2*index];
904 uint length = mo->d.stringdata[2*index + 1];
905 const char *string =
reinterpret_cast<
const char *>(mo->d.stringdata) + offset;
906 return QByteArray::fromRawData(string, length);
909const char *QQmlPropertyCache::className()
const
911 if (
const QMetaObject *mo = _metaObject.metaObject())
912 return mo->className();
914 return _dynamicClassName.constData();
917void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
const
919 struct Sort {
static bool lt(
const std::pair<QString,
const QQmlPropertyData *> &lhs,
920 const std::pair<QString,
const QQmlPropertyData *> &rhs) {
921 return lhs.second->coreIndex() < rhs.second->coreIndex();
924 struct Insert {
static void in(
const QQmlPropertyCache *This,
925 QList<std::pair<QString,
const QQmlPropertyData *> > &properties,
926 QList<std::pair<QString,
const QQmlPropertyData *> > &methods,
927 StringCache::ConstIterator iter,
const QQmlPropertyData *data) {
928 if (data->isSignalHandler())
931 if (data->isFunction()) {
932 if (data->coreIndex() < This->methodIndexCacheStart)
935 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
937 if (!methods.contains(entry)) methods.append(entry);
939 data = This->overrideData(data);
940 if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
942 if (data->coreIndex() < This->propertyIndexCacheStart)
945 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
947 if (!properties.contains(entry)) properties.append(entry);
949 data = This->overrideData(data);
950 if (data) Insert::in(This, properties, methods, iter, data);
955 builder.setClassName(_dynamicClassName);
957 QList<std::pair<QString,
const QQmlPropertyData *> > properties;
958 QList<std::pair<QString,
const QQmlPropertyData *> > methods;
960 for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
961 Insert::in(
this, properties, methods, iter, iter.value().second);
965 Q_ASSERT(properties.size() <= propertyIndexCache.size());
966 Q_ASSERT(methods.size() <= methodIndexCache.size());
968 std::sort(properties.begin(), properties.end(), Sort::lt);
969 std::sort(methods.begin(), methods.end(), Sort::lt);
971 for (
int ii = 0; ii < properties.size(); ++ii) {
972 const QQmlPropertyData *data = properties.at(ii).second;
975 if (data->notifyIndex() != -1)
976 notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
978 QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
979 data->propType().name(),
983 property.setReadable(
true);
984 property.setWritable(data->isWritable());
985 property.setResettable(data->isResettable());
986 property.setBindable(data->notifiesViaBindable());
987 property.setAlias(data->isAlias());
990 for (
int ii = 0; ii < methods.size(); ++ii) {
991 const QQmlPropertyData *data = methods.at(ii).second;
993 QByteArray returnType;
994 if (data->propType().isValid())
995 returnType = data->propType().name();
997 QByteArray signature;
999 signature += methods.at(ii).first.toUtf8() +
'(';
1001 QQmlPropertyCacheMethodArguments *arguments =
nullptr;
1002 if (data->hasArguments()) {
1003 arguments = data->arguments();
1004 for (
int ii = 0, end = arguments->names ? arguments->names->size() : 0;
1007 signature.append(
',');
1008 signature.append(arguments->types[1 + ii].name());
1012 signature.append(
')');
1014 QMetaMethodBuilder method;
1015 if (data->isSignal()) {
1016 method = builder.addSignal(signature);
1018 method = builder.addSlot(signature);
1020 method.setAccess(QMetaMethod::Public);
1022 if (arguments && arguments->names)
1023 method.setParameterNames(*arguments->names);
1025 if (!returnType.isEmpty())
1026 method.setReturnType(returnType);
1029 for (
int ii = 0; ii < enumCache.size(); ++ii) {
1030 const QQmlEnumData &enumData = enumCache.at(ii);
1031 QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
1032 enumeration.setIsScoped(
true);
1033 for (
int jj = 0; jj < enumData.values.size(); ++jj) {
1034 const QQmlEnumValue &value = enumData.values.at(jj);
1035 enumeration.addKey(value.namedValue.toUtf8(), value.value);
1039 if (!_defaultPropertyName.isEmpty()) {
1040 const QQmlPropertyData *dp = property(_defaultPropertyName,
nullptr,
nullptr);
1041 if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
1042 Q_ASSERT(!dp->isFunction());
1043 builder.addClassInfo(
"DefaultProperty", _defaultPropertyName.toUtf8());
1047 if (!_listPropertyAssignBehavior.isEmpty())
1048 builder.addClassInfo(
"QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
1052template <
typename StringVisitor,
typename TypeInfoVisitor>
1053int visitMethods(
const QMetaObject &mo,
int methodOffset,
int methodCount,
1054 StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1056 int fieldsForParameterData = 0;
1058 bool hasOldStyleRevisionedMethods =
false;
1060 for (
int i = 0; i < methodCount; ++i) {
1061 const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
1063 const uint flags = mo.d.data[handle + 4];
1064 if (flags & MethodRevisioned) {
1065 if (mo.d.data[0] < 13)
1066 hasOldStyleRevisionedMethods =
true;
1068 fieldsForParameterData += 1;
1071 visitString(mo.d.data[handle + 0]);
1072 visitString(mo.d.data[handle + 3]);
1074 const int argc = mo.d.data[handle + 1];
1075 const int paramIndex = mo.d.data[handle + 2];
1077 fieldsForParameterData += argc * 2;
1078 fieldsForParameterData += 1;
1081 for (
int i = 0; i < 1 + argc; ++i) {
1083 visitTypeInfo(mo.d.data[paramIndex + i]);
1087 visitString(mo.d.data[paramIndex + argc + i]);
1091 int fieldsForRevisions = 0;
1092 if (hasOldStyleRevisionedMethods)
1093 fieldsForRevisions = methodCount;
1095 return methodCount * QMetaObjectPrivate::IntsPerMethod
1096 + fieldsForRevisions + fieldsForParameterData;
1099template <
typename StringVisitor,
typename TypeInfoVisitor>
1100int visitProperties(
const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1102 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1104 for (
int i = 0; i < priv->propertyCount; ++i) {
1105 const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
1107 visitString(mo.d.data[handle]);
1108 visitTypeInfo(mo.d.data[handle + 1]);
1111 return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
1114template <
typename StringVisitor>
1115int visitClassInfo(
const QMetaObject &mo, StringVisitor visitString)
1117 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1118 const int intsPerClassInfo = 2;
1120 for (
int i = 0; i < priv->classInfoCount; ++i) {
1121 const int handle = priv->classInfoData + i * intsPerClassInfo;
1123 visitString(mo.d.data[handle]);
1124 visitString(mo.d.data[handle + 1]);
1127 return priv->classInfoCount * intsPerClassInfo;
1130template <
typename StringVisitor>
1131int visitEnumerations(
const QMetaObject &mo, StringVisitor visitString)
1133 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1135 int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
1137 for (
int i = 0; i < priv->enumeratorCount; ++i) {
1138 const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
1140 const uint keyCount = enumeratorData[3];
1141 fieldCount += keyCount * 2;
1143 visitString(enumeratorData[0]);
1144 visitString(enumeratorData[1]);
1146 const uint keyOffset = enumeratorData[4];
1148 for (uint j = 0; j < keyCount; ++j) {
1149 visitString(mo.d.data[keyOffset + 2 * j]);
1156template <
typename StringVisitor>
1157int countMetaObjectFields(
const QMetaObject &mo, StringVisitor stringVisitor)
1159 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1161 const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
1162 if (typeInfo & IsUnresolvedType)
1163 stringVisitor(typeInfo & TypeNameIndexMask);
1166 int fieldCount = MetaObjectPrivateFieldCount;
1168 fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
1170 fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
1173 fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
1174 fieldCount += visitClassInfo(mo, stringVisitor);
1175 fieldCount += visitEnumerations(mo, stringVisitor);
1182static_assert(QMetaObjectPrivate::OutputRevision == 13,
"Check and adjust determineMetaObjectSizes");
1184bool QQmlPropertyCache::determineMetaObjectSizes(
const QMetaObject &mo,
int *fieldCount,
1187 const QMetaObjectPrivate *priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1188 if (priv->revision != QMetaObjectPrivate::OutputRevision)
1191 uint highestStringIndex = 0;
1192 const auto stringIndexVisitor = [&highestStringIndex](uint index) {
1193 highestStringIndex = qMax(highestStringIndex, index);
1196 *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
1197 *stringCount = highestStringIndex + 1;
1202bool QQmlPropertyCache::addToHash(QCryptographicHash &hash,
const QMetaObject &mo)
1205 int stringCount = 0;
1206 if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
1210 hash.addData({
reinterpret_cast<
const char *>(mo.d.data), qsizetype(fieldCount *
sizeof(uint))});
1211 for (
int i = 0; i < stringCount; ++i) {
1212 hash.addData(stringData(&mo, i));
1218QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums,
bool *ok)
const
1220 auto it = checksums->constFind(quintptr(
this));
1221 if (it != checksums->constEnd()) {
1227 if (_metaObject.isShared()) {
1229 return QByteArray();
1232 QCryptographicHash hash(QCryptographicHash::Md5);
1235 hash.addData(_parent->checksum(checksums, ok));
1237 return QByteArray();
1240 if (!addToHash(hash, *_metaObject.metaObject())) {
1242 return QByteArray();
1245 const QByteArray result = hash.result();
1246 if (result.isEmpty()) {
1250 checksums->insert(quintptr(
this), result);
1256
1257
1258
1259QList<QByteArray> QQmlPropertyCache::signalParameterNames(
int index)
const
1261 const QQmlPropertyData *signalData = signal(index);
1262 if (signalData && signalData->hasArguments()) {
1263 QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
1264 if (args && args->names)
1265 return *args->names;
1266 const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
1267 return method.parameterNames();
1269 return QList<QByteArray>();
const QQmlPropertyData * qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer< QQmlContextData > &context, QQmlPropertyData *local)
static const QByteArray stringData(const QMetaObject *mo, int index)
static QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const T &propertyName)
static const char * qQmlPropertyCacheToString(QLatin1String string)
static QByteArray qQmlPropertyCacheToString(const QV4::String *string)
static std::pair< bool, int > deriveEncodingAndLength(const char *str)
static QHashedString signalNameToHandlerName(const QHashedString &methodName)
static int metaObjectSignalCount(const QMetaObject *metaObject)