7#include <private/qqmlengine_p.h>
8#include <private/qqmlbinding_p.h>
9#include <private/qqmlvmemetaobject_p.h>
11#include <private/qmetaobject_p.h>
12#include <private/qmetaobjectbuilder_p.h>
13#include <private/qqmlpropertycachemethodarguments_p.h>
14#include <private/qqmlsignalnames_p.h>
16#include <private/qv4codegen_p.h>
17#include <private/qv4value_p.h>
19#include <QtCore/qdebug.h>
20#include <QtCore/QCryptographicHash>
21#include <QtCore/private/qtools_p.h>
28# pragma warning( disable : 4200
)
33#define Q_INT16_MAX 32767
40 return (overridingProperty.isVirtual() && overridingProperty.isFinal())
41 || (overridingProperty.doesOverride() && overridingProperty.isFinal())
42 || (overridingProperty.isVirtual() && overridingProperty.doesOverride());
46
47
48
49
50
51
52
53
54
55
56
59 if (!existingProperty)
62 if (existingProperty->isFinal()) {
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
98 const QQmlPropertyData *
const existingProperty)
100 const auto overrideKeyword = overridingProperty.doesOverride();
101 if (overrideKeyword && !existingProperty) {
105 const auto minimalCheckRes = checkMinimal(existingProperty);
107 return minimalCheckRes;
111 Q_ASSERT(existingProperty);
112 if (overridingProperty.isFunction() != existingProperty->isFunction()) {
116 if (!existingProperty->isVirtual()) {
121 const auto overrideOrFinal = overrideKeyword || overridingProperty.isFinal();
122 if (!overrideOrFinal) {
129static inline Status check(
const QQmlPropertyData &overridingProperty,
130 const QQmlPropertyData *
const existingProperty,
CheckMode mode)
132 Q_ASSERT(!hasInvalidModifierCombintation(overridingProperty));
136 return detail::checkMinimal(existingProperty);
138 return detail::checkFull(overridingProperty, existingProperty);
148 const auto status = detail::check(overridingProperty, existingProperty, mode);
150 if (isValidOverride(status)) {
151 overridingProperty.markAsOverrideOf(existingProperty);
161 for (
const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
162 signalCount += QMetaObjectPrivate::get(obj)->signalCount;
166QQmlPropertyData::Flags
167QQmlPropertyData::flagsForProperty(
const QMetaProperty &p)
169 QQmlPropertyData::Flags flags;
171 flags.setIsConstant(p.isConstant());
172 flags.setIsWritable(p.isWritable());
173 flags.setIsResettable(p.isResettable());
174 flags.setIsFinal(p.isFinal());
175 flags.setIsVirtual(p.isVirtual());
176 flags.setDoesOverride(p.isOverride());
177 flags.setIsRequired(p.isRequired());
178 flags.setIsBindable(p.isBindable());
181 const QMetaType metaType = p.metaType();
182 int propType = metaType.id();
183 if (p.isEnumType()) {
184 flags.setType(QQmlPropertyData::Flags::EnumType);
185 }
else if (metaType.flags() & QMetaType::PointerToQObject) {
186 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
187 }
else if (propType == QMetaType::QVariant) {
188 flags.setType(QQmlPropertyData::Flags::QVariantType);
189 }
else if (metaType.flags() & QMetaType::IsQmlList) {
190 flags.setType(QQmlPropertyData::Flags::QListType);
196void QQmlPropertyData::load(
const QMetaProperty &p)
198 Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max());
199 setCoreIndex(p.propertyIndex());
200 setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
201 setFlags(flagsForProperty(p));
202 setRevision(QTypeRevision::fromEncodedVersion(p.revision()));
203 QMetaType type = p.metaType();
207void QQmlPropertyData::load(
const QMetaMethod &m)
209 setCoreIndex(m.methodIndex());
210 m_flags.setType(Flags::FunctionType);
216 switch (m.methodType()) {
217 case QMetaMethod::Signal:
218 m_flags.setIsSignal(
true);
219 m_flags.setIsConstructor(
false);
220 setPropType(m.returnMetaType());
222 case QMetaMethod::Constructor:
223 m_flags.setIsSignal(
false);
224 m_flags.setIsConstructor(
true);
227 m_flags.setIsSignal(
false);
228 m_flags.setIsConstructor(
false);
229 setPropType(m.returnMetaType());
233 m_flags.setIsConstant(m.isConst());
235 const int paramCount = m.parameterCount();
237 m_flags.setHasArguments(
true);
238 m_flags.setIsV4Function(
240 m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
242 m_flags.setHasArguments(
false);
243 m_flags.setIsV4Function(
false);
246 m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
248 Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
249 setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
252Q_LOGGING_CATEGORY(qqmlPropertyCacheAppend,
"qt.qml.propertyCache.append", QtWarningMsg)
255
256
257
258
259
260QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
261 const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
263 Q_ASSERT(metaObject);
266 if (
const QMetaObject *super = metaObject->superClass()) {
267 result = createStandalone(
268 super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
270 result.adopt(
new QQmlPropertyCache(metaObject));
271 result->update(metaObject);
274 if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
280 for (
int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
281 ++metaObjectOffset) {
282 result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
289QQmlPropertyCache::~QQmlPropertyCache()
291 QQmlPropertyCacheMethodArguments *args = argumentsCache;
293 QQmlPropertyCacheMethodArguments *next = args->next;
304QQmlPropertyCache::Ptr QQmlPropertyCache::copy(
const QQmlMetaObjectPointer &mo,
int reserve)
const
306 QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
307 new QQmlPropertyCache(mo, _handleOverride), QQmlPropertyCache::Ptr::Adopt);
308 cache->_parent.reset(
this);
309 cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart;
310 cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart;
311 cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart;
312 cache->stringCache.linkAndReserve(stringCache, reserve);
313 cache->allowedRevisionCache = allowedRevisionCache;
314 cache->_defaultPropertyName = _defaultPropertyName;
315 cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
320QQmlPropertyCache::Ptr QQmlPropertyCache::copy()
const
322 return copy(_metaObject, 0);
325QQmlPropertyCache::Ptr QQmlPropertyCache::rebased(
const ConstPtr &parent)
const
327 QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
328 new QQmlPropertyCache(parent->_metaObject, _handleOverride),
329 QQmlPropertyCache::Ptr::Adopt);
331 cache->_parent = parent;
333 cache->propertyIndexCacheStart = propertyIndexCacheStart;
334 cache->propertyIndexCache = propertyIndexCache;
336 cache->methodIndexCacheStart = methodIndexCacheStart;
337 cache->methodIndexCache = methodIndexCache;
339 cache->signalHandlerIndexCacheStart = signalHandlerIndexCacheStart;
340 cache->signalHandlerIndexCache = signalHandlerIndexCache;
342 cache->enumCache = enumCache;
344 cache->stringCache.linkAndReserve(
345 parent->stringCache, ownPropertyCount() + ownMethodCount() + ownSignalCount());
347 for (
auto it = stringCache.begin(), end = stringCache.end(); it != end; ++it) {
348 const QQmlPropertyData *myData = it.value().second;
349 const int index = it.value().first;
351 QQmlPropertyData *copyData =
nullptr;
352 if (myData->isSignalHandler())
353 copyData = cache->signalHandlerIndexCache.data() + (index - signalOffset());
354 else if (myData->isFunction())
355 copyData = cache->methodIndexCache.data() + (index - methodOffset());
357 copyData = cache->propertyIndexCache.data() + (index - propertyOffset());
359 cache->stringCache.insert(it.key(), std::make_pair(index, copyData));
362 cache->allowedRevisionCache = allowedRevisionCache;
363 cache->_dynamicStringData = _dynamicStringData;
364 cache->_dynamicClassName = _dynamicClassName;
365 cache->_defaultPropertyName = _defaultPropertyName;
366 cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
370QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
371 int propertyCount,
int methodCount,
int signalCount,
int enumCount)
const
373 QQmlPropertyCache::Ptr rv = copy(
374 QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount);
375 rv->propertyIndexCache.reserve(propertyCount);
376 rv->methodIndexCache.reserve(methodCount);
377 rv->signalHandlerIndexCache.reserve(signalCount);
378 rv->enumCache.reserve(enumCount);
382QQmlPropertyCache::AppendResult
383QQmlPropertyCache::appendAlias(
const QString &name, QQmlPropertyData::Flags flags,
int coreIndex,
384 QMetaType propType, QTypeRevision version,
int notifyIndex,
385 int encodedTargetIndex,
int targetObjectId)
387 QQmlPropertyData data;
388 data.setPropType(propType);
389 data.setCoreIndex(coreIndex);
390 data.setNotifyIndex(notifyIndex);
391 flags.setIsAlias(
true);
392 data.setFlags(flags);
393 data.setAliasTarget(encodedTargetIndex);
394 data.setAliasTargetObjectId(targetObjectId);
395 data.setTypeVersion(version);
397 return appendPropertyAttr(name, std::move(data));
400QQmlPropertyCache::AppendResult
401QQmlPropertyCache::appendComponentWrapper(
int coreIndex,
int wrappedObjectIndex)
403 QQmlPropertyData data;
404 data.setCoreIndex(coreIndex);
405 QQmlPropertyData::Flags flags;
406 flags.setType(QQmlPropertyData::Flags::ComponentWrapperType);
407 data.setFlags(flags);
408 data.setWrappedObjectIndex(wrappedObjectIndex);
413 _defaultPropertyName = QStringLiteral(
".qt_component_wrapper__");
414 return appendPropertyAttr(_defaultPropertyName, std::move(data));
417void QQmlPropertyCache::appendSignal(
const QString &name, QQmlPropertyData::Flags flags,
418 int coreIndex,
const QMetaType *types,
419 const QList<QByteArray> &names)
421 QQmlPropertyData data;
422 data.setPropType(QMetaType());
423 data.setCoreIndex(coreIndex);
424 data.setFlags(flags);
425 data.setArguments(
nullptr);
427 QQmlPropertyData handler = data;
428 handler.m_flags.setIsSignalHandler(
true);
431 const auto argumentCount = names.size();
432 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
433 new (args->types) QMetaType;
434 ::memcpy(args->types + 1, types, argumentCount *
sizeof(QMetaType));
435 data.setArguments(args);
438 QQmlPropertyData *old = findNamedProperty(name);
439 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Minimal);
440 maybeLog(overrideStatus, name);
444 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
445 || overrideStatus == OverrideSemantics::Status::Valid
446 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
447 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
450 methodIndexCache.append(*old);
452 handler.m_flags.setIsSignalHandler(
true);
453 signalHandlerIndexCache.append(handler);
457 int methodIndex = methodIndexCache.size();
458 methodIndexCache.append(data);
460 int signalHandlerIndex = signalHandlerIndexCache.size();
461 signalHandlerIndexCache.append(handler);
463 const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
465 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
466 setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
467 signalHandlerIndexCache.data() + signalHandlerIndex);
470void QQmlPropertyCache::appendMethod(
const QString &name, QQmlPropertyData::Flags flags,
471 int coreIndex, QMetaType returnType,
472 const QList<QByteArray> &names,
473 const QList<QMetaType> ¶meterTypes)
475 int argumentCount = names.size();
477 QQmlPropertyData data;
478 data.setPropType(returnType);
479 data.setCoreIndex(coreIndex);
480 data.setFlags(flags);
481 QQmlPropertyData *old = findNamedProperty(name);
482 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Minimal);
483 maybeLog(overrideStatus, name);
487 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
488 || overrideStatus == OverrideSemantics::Status::Valid
489 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
490 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
493 methodIndexCache.append(*old);
497 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
498 new (args->types) QMetaType(returnType);
499 for (
int ii = 0; ii < argumentCount; ++ii)
500 new (args->types + ii + 1) QMetaType(parameterTypes.at(ii));
501 data.setArguments(args);
503 int methodIndex = methodIndexCache.size();
504 methodIndexCache.append(data);
506 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
509void QQmlPropertyCache::appendEnum(
const QString &name,
const QList<QQmlEnumValue> &values)
513 data.values = values;
514 enumCache.append(data);
518const QMetaObject *QQmlPropertyCache::createMetaObject()
const
520 if (_metaObject.isNull()) {
521 QMetaObjectBuilder builder;
522 toMetaObjectBuilder(builder);
523 builder.setSuperClass(_parent->createMetaObject());
524 _metaObject.setSharedOnce(builder.toMetaObject());
527 return _metaObject.metaObject();
530const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(
int index)
const
532 if (index < 0 || index >= propertyCount())
535 const QQmlPropertyData *rv =
nullptr;
536 if (index < propertyIndexCacheStart)
537 return _parent->maybeUnresolvedProperty(index);
539 rv =
const_cast<
const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
543const QQmlPropertyData *QQmlPropertyCache::defaultProperty()
const
545 return property(defaultPropertyName(),
nullptr,
nullptr);
548void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
550 if (_parent != newParent)
551 _parent = std::move(newParent);
554QQmlPropertyCache::Ptr
555QQmlPropertyCache::copyAndAppend(
const QMetaObject *metaObject,
556 QTypeRevision typeVersion,
557 QQmlPropertyData::Flags propertyFlags,
558 QQmlPropertyData::Flags methodFlags,
559 QQmlPropertyData::Flags signalFlags)
const
561 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
566 QQmlPropertyCache::Ptr rv = copy(
568 QMetaObjectPrivate::get(metaObject)->methodCount
569 + QMetaObjectPrivate::get(metaObject)->signalCount
570 + QMetaObjectPrivate::get(metaObject)->propertyCount);
572 rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
579 return QQmlSignalNames::signalNameToHandlerName(methodName);
584 return QQmlSignalNames::signalNameToHandlerName(
585 QLatin1StringView{ methodName.constData(), methodName.length() });
591 const char *cptr = str;
593 utf8 |= *cptr & 0x80;
596 return std::make_pair(utf8, cptr - str);
599void QQmlPropertyCache::append(
const QMetaObject *metaObject,
600 QTypeRevision typeVersion,
601 QQmlPropertyData::Flags propertyFlags,
602 QQmlPropertyData::Flags methodFlags,
603 QQmlPropertyData::Flags signalFlags)
605 allowedRevisionCache.append(QTypeRevision::zero());
607 int methodCount = metaObject->methodCount();
608 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
609 int signalCount = metaObjectSignalCount(metaObject);
610 int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
612 if (classInfoCount) {
613 int classInfoOffset = metaObject->classInfoOffset();
614 for (
int ii = 0; ii < classInfoCount; ++ii) {
615 int idx = ii + classInfoOffset;
616 QMetaClassInfo mci = metaObject->classInfo(idx);
617 const char *name = mci.name();
618 if (0 == qstrcmp(name,
"DefaultProperty")) {
619 _defaultPropertyName = QString::fromUtf8(mci.value());
620 }
else if (0 == qstrcmp(name,
"qt_QmlJSWrapperFactoryMethod")) {
621 const char *
const factoryMethod = mci.value();
622 _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
623 if (_jsFactoryMethodIndex != -1)
624 _jsFactoryMethodIndex -= metaObject->methodOffset();
625 }
else if (0 == qstrcmp(name,
"QML.ListPropertyAssignBehavior")) {
626 _listPropertyAssignBehavior = mci.value();
632 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
633 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
634 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
638 const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
640 int methodOffset = metaObject->methodOffset();
641 int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
645 methodIndexCache.resize(methodCount - methodIndexCacheStart);
646 signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
647 int signalHandlerIndex = signalOffset;
648 for (
int ii = methodOffset; ii < methodCount; ++ii) {
649 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
651 const QMetaMethod &m = metaObject->method(ii);
652 if (m.access() == QMetaMethod::Private)
657 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
659 QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
660 QQmlPropertyData *sigdata =
nullptr;
662 if (m.methodType() == QMetaMethod::Signal)
663 data->setFlags(signalFlags);
665 data->setFlags(methodFlags);
669 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
670 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
672 if (data->isSignal()) {
673 sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
675 sigdata->m_flags.setIsSignalHandler(
true);
678 const auto doSetNamedProperty = [&](
const auto &methodName) {
679 QQmlPropertyData *old =
nullptr;
680 if (StringCache::mapped_type *it = stringCache.value(methodName)) {
681 const auto overrideStatus = _handleOverride(*data, (old = it->second),
682 OverrideSemantics::CheckMode::Minimal);
683 maybeLog(overrideStatus, methodName);
687 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
688 || overrideStatus == OverrideSemantics::Status::Valid
689 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
690 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
697 sigdata->m_flags.setIsSignalHandler(
true);
698 ++signalHandlerIndex;
704 setNamedProperty(methodName, ii, data);
706 if (data->isSignal()) {
709 if constexpr (std::is_same_v<std::decay_t<
decltype(methodName)>, QHashedCStringRef>)
710 data->m_flags.setIsOverridableSignal(
true);
712 setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
713 ++signalHandlerIndex;
717 const char *str = m.nameView().constData();
718 const auto [isUtf8, len] = deriveEncodingAndLength(str);
720 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)));
722 doSetNamedProperty(QHashedCStringRef(str, len));
725 int propCount = metaObject->propertyCount();
726 int propOffset = metaObject->propertyOffset();
730 propertyIndexCache.resize(propCount - propertyIndexCacheStart);
731 for (
int ii = propOffset; ii < propCount; ++ii) {
732 QMetaProperty p = metaObject->property(ii);
733 if (!p.isScriptable())
737 QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
739 data->setFlags(propertyFlags);
741 data->setTypeVersion(typeVersion);
743 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
744 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
746 const auto doSetNamedProperty = [
this](
const auto &propName,
int index,
auto *propData) {
747 QQmlPropertyData *existingPropData = findNamedProperty(propName);
748 const auto overrideStatus = _handleOverride(*propData, existingPropData,
749 OverrideSemantics::CheckMode::Full);
750 maybeLog(overrideStatus, propName);
751 if (!OverrideSemantics::isValidOverride(overrideStatus)) {
752 if (existingPropData) {
754 *propData = *existingPropData;
759 setNamedProperty(propName, index, propData);
762 const char *str = p.name();
763 const auto [isUtf8, len] = deriveEncodingAndLength(str);
765 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)), ii, data);
767 doSetNamedProperty(QHashedCStringRef(str, len), ii, data);
769 bool isGadget =
true;
770 for (
const QMetaObject *it = metaObject; it !=
nullptr; it = it->superClass()) {
771 if (it == &QObject::staticMetaObject)
776 if (!isGadget && !data->isAlias())
777 data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
781void QQmlPropertyCache::update(
const QMetaObject *metaObject)
783 Q_ASSERT(metaObject);
789 int pc = metaObject->propertyCount();
790 int mc = metaObject->methodCount();
791 int sc = metaObjectSignalCount(metaObject);
792 propertyIndexCache.reserve(pc - propertyIndexCacheStart);
793 methodIndexCache.reserve(mc - methodIndexCacheStart);
794 signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
798 stringCache.reserve(pc + mc + sc);
801 append(metaObject, QTypeRevision());
805
806
807
808void QQmlPropertyCache::invalidate(
const QMetaObject *metaObject)
810 propertyIndexCache.clear();
811 methodIndexCache.clear();
812 signalHandlerIndexCache.clear();
814 argumentsCache =
nullptr;
816 int pc = metaObject->propertyCount();
817 int mc = metaObject->methodCount();
818 int sc = metaObjectSignalCount(metaObject);
819 int reserve = pc + mc + sc;
822 propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart;
823 methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart;
824 signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart;
825 stringCache.linkAndReserve(parent()->stringCache, reserve);
826 append(metaObject, QTypeRevision());
828 propertyIndexCacheStart = 0;
829 methodIndexCacheStart = 0;
830 signalHandlerIndexCacheStart = 0;
835const QQmlPropertyData *QQmlPropertyCache::findProperty(
836 StringCache::ConstIterator it, QObject *object,
837 const QQmlRefPointer<QQmlContextData> &context)
const
839 QQmlData *data = (object ? QQmlData::get(object) :
nullptr);
840 const QQmlVMEMetaObject *vmemo =
nullptr;
841 if (data && data->hasVMEMetaObject) {
842 QObjectPrivate *op = QObjectPrivate::get(object);
843 vmemo =
static_cast<
const QQmlVMEMetaObject *>(op->metaObject);
845 return findProperty(it, vmemo, context);
850inline bool contextHasNoExtensions(
const QQmlRefPointer<QQmlContextData> &context)
854 const QQmlRefPointer<QQmlContextData> parent = context->parent();
855 return (!parent || !parent->imports());
858inline int maximumIndexForProperty(
const QQmlPropertyData *prop,
const int methodCount,
const int signalCount,
const int propertyCount)
860 return prop->isFunction() ? methodCount
861 : prop->isSignalHandler() ? signalCount
867const QQmlPropertyData *QQmlPropertyCache::findProperty(
868 StringCache::ConstIterator it,
const QQmlVMEMetaObject *vmemo,
869 const QQmlRefPointer<QQmlContextData> &context)
const
871 StringCache::ConstIterator end = stringCache.end();
874 const QQmlPropertyData *result = it.value().second;
880 if (vmemo && context && !contextHasNoExtensions(context)) {
883 if (vmemo->contextData() == context)
886 vmemo = vmemo->parentVMEMetaObject();
891 const int methodCount = vmemo->cache->methodCount();
892 const int signalCount = vmemo->cache->signalCount();
893 const int propertyCount = vmemo->cache->propertyCount();
897 const StringCache::mapped_type &property(it.value());
899 if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
901 if (property.second->isFunction() || property.second->isSignalHandler()) {
905 result = property.second;
911 it = stringCache.findNext(it);
922QQmlPropertyCache::AppendResult QQmlPropertyCache::appendPropertyAttr(
const QString &name,
923 QQmlPropertyData &&data)
925 QQmlPropertyData *old = findNamedProperty(name);
926 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Full);
927 maybeLog(overrideStatus, name);
928 if (!OverrideSemantics::isValidOverride(overrideStatus)) {
931 propertyIndexCache.append(old ? *old : data);
932 return q23::make_unexpected(overrideStatus);
935 const int index = propertyIndexCache.size();
936 propertyIndexCache.append(std::move(data));
938 setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index);
942void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
944 Q_ASSERT(predecessor !=
this);
950 setOverrideIndexIsProperty(!predecessor->isFunction());
951 setOverrideIndex(predecessor->coreIndex());
953 m_flags.setIsVirtual(predecessor->isVirtual());
954 predecessor->m_flags.setIsOverridden(
true);
955 Q_ASSERT(predecessor->isOverridden());
959QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
960 int argc,
const QList<QByteArray> &names)
962 typedef QQmlPropertyCacheMethodArguments A;
963 A *args =
static_cast<A *>(malloc(
sizeof(A) + argc *
sizeof(QMetaType)));
964 args->names = argc ?
new QList<QByteArray>(names) :
nullptr;
965 args->next = argumentsCache;
966 argumentsCache = args;
970QString QQmlPropertyCache::signalParameterStringForJS(
971 const QList<QByteArray> ¶meterNameList, QString *errorString)
973 bool unnamedParameter =
false;
976 const qsizetype count = parameterNameList.size();
977 if (count > std::numeric_limits<quint16>::max())
978 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal has an excessive number of parameters: %1").arg(count);
980 for (qsizetype i = 0; i < count; ++i) {
982 parameters += QLatin1Char(
',');
983 const QByteArray ¶m = parameterNameList.at(i);
984 if (param.isEmpty()) {
985 unnamedParameter =
true;
986 }
else if (unnamedParameter) {
988 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal uses unnamed parameter followed by named parameter.");
990 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
992 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
995 parameters += QString::fromUtf8(param);
1001int QQmlPropertyCache::originalClone(
int index)
const
1003 while (signal(index)->isCloned())
1008int QQmlPropertyCache::originalClone(
const QObject *object,
int index)
1010 QQmlData *data = QQmlData::get(object);
1011 if (data && data->propertyCache) {
1012 const QQmlPropertyCache *cache = data->propertyCache.data();
1013 const QQmlPropertyData *sig = cache->signal(index);
1014 while (sig && sig->isCloned()) {
1016 sig = cache->signal(index);
1019 while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
1028 Q_ASSERT(metaObject);
1029 static_assert(std::is_same_v<T, QByteArray>);
1031 QQmlPropertyData rv;
1034
1035
1038 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
1039 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
1040 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
1042 const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
1044 int methodCount = metaObject->methodCount();
1045 for (
int ii = methodCount - 1; ii >= 0; --ii) {
1046 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
1048 QMetaMethod m = metaObject->method(ii);
1049 if (m.access() == QMetaMethod::Private)
1052 if (m.name() == propertyName) {
1059 const QMetaObject *cmo = metaObject;
1061 int idx = cmo->indexOfProperty(propertyName.data());
1063 QMetaProperty p = cmo->property(idx);
1064 if (p.isScriptable()) {
1068 bool changed =
false;
1069 while (cmo && cmo->propertyOffset() >= idx) {
1070 cmo = cmo->superClass();
1074
1075 if (!changed) cmo =
nullptr;
1087 return string.toUtf8();
1092 return string.toUtf8();
1097 return string->toQString().toUtf8();
1103 QQmlPropertyData *local)
1105 const QQmlPropertyCache *cache =
nullptr;
1107 QQmlData *ddata = QQmlData::get(obj,
false);
1109 if (ddata && ddata->propertyCache) {
1110 cache = ddata->propertyCache.data();
1111 }
else if (
auto newCache = QQmlMetaType::propertyCache(obj)) {
1112 cache = newCache.data();
1113 ddata = QQmlData::get(obj,
true);
1114 ddata->propertyCache =
std::move(newCache);
1117 const QQmlPropertyData *rv =
nullptr;
1120 rv = cache->property(name, obj, context);
1122 *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1123 if (local->isValid())
1130const QQmlPropertyData *QQmlPropertyCache::property(
1131 QObject *obj,
const QV4::String *name,
const QQmlRefPointer<QQmlContextData> &context,
1132 QQmlPropertyData *local)
1134 return qQmlPropertyCacheProperty<
const QV4::String *>(obj, name, context, local);
1137const QQmlPropertyData *QQmlPropertyCache::property(
1138 QObject *obj, QStringView name,
const QQmlRefPointer<QQmlContextData> &context,
1139 QQmlPropertyData *local)
1141 return qQmlPropertyCacheProperty<
const QStringView &>(obj, name, context, local);
1144const QQmlPropertyData *QQmlPropertyCache::property(
1145 QObject *obj,
const QLatin1String &name,
const QQmlRefPointer<QQmlContextData> &context,
1146 QQmlPropertyData *local)
1148 return qQmlPropertyCacheProperty<
const QLatin1String &>(obj, name, context, local);
1154 uint offset = mo->d.stringdata[2*index];
1155 uint length = mo->d.stringdata[2*index + 1];
1156 const char *string =
reinterpret_cast<
const char *>(mo->d.stringdata) + offset;
1157 return QByteArray::fromRawData(string, length);
1160const char *QQmlPropertyCache::className()
const
1162 if (
const QMetaObject *mo = _metaObject.metaObject())
1163 return mo->className();
1165 return _dynamicClassName.constData();
1168void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
const
1170 struct Sort {
static bool lt(
const std::pair<QString,
const QQmlPropertyData *> &lhs,
1171 const std::pair<QString,
const QQmlPropertyData *> &rhs) {
1172 return lhs.second->coreIndex() < rhs.second->coreIndex();
1175 struct Insert {
static void in(
const QQmlPropertyCache *This,
1176 QList<std::pair<QString,
const QQmlPropertyData *> > &properties,
1177 QList<std::pair<QString,
const QQmlPropertyData *> > &methods,
1178 StringCache::ConstIterator iter,
const QQmlPropertyData *data) {
1179 if (data->isSignalHandler())
1182 if (data->isFunction()) {
1183 if (data->coreIndex() < This->methodIndexCacheStart)
1186 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
1188 if (!methods.contains(entry)) methods.append(entry);
1190 data = This->overrideData(data);
1191 if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1193 if (data->coreIndex() < This->propertyIndexCacheStart)
1196 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
1198 if (!properties.contains(entry)) properties.append(entry);
1200 data = This->overrideData(data);
1201 if (data) Insert::in(This, properties, methods, iter, data);
1206 builder.setClassName(_dynamicClassName);
1208 QList<std::pair<QString,
const QQmlPropertyData *> > properties;
1209 QList<std::pair<QString,
const QQmlPropertyData *> > methods;
1211 for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
1212 Insert::in(
this, properties, methods, iter, iter.value().second);
1216 Q_ASSERT(properties.size() <= propertyIndexCache.size());
1217 Q_ASSERT(methods.size() <= methodIndexCache.size());
1219 std::sort(properties.begin(), properties.end(), Sort::lt);
1220 std::sort(methods.begin(), methods.end(), Sort::lt);
1222 for (
int ii = 0; ii < properties.size(); ++ii) {
1223 const QQmlPropertyData *data = properties.at(ii).second;
1225 int notifierId = -1;
1226 if (data->notifyIndex() != -1)
1227 notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
1229 QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1230 data->propType().name(),
1234 property.setReadable(
true);
1235 property.setWritable(data->isWritable());
1236 property.setResettable(data->isResettable());
1237 property.setBindable(data->notifiesViaBindable());
1238 property.setAlias(data->isAlias());
1241 for (
int ii = 0; ii < methods.size(); ++ii) {
1242 const QQmlPropertyData *data = methods.at(ii).second;
1244 QByteArray returnType;
1245 if (data->propType().isValid())
1246 returnType = data->propType().name();
1248 QByteArray signature;
1250 signature += methods.at(ii).first.toUtf8() +
'(';
1252 QQmlPropertyCacheMethodArguments *arguments =
nullptr;
1253 if (data->hasArguments()) {
1254 arguments = data->arguments();
1255 for (
int ii = 0, end = arguments->names ? arguments->names->size() : 0;
1258 signature.append(
',');
1259 signature.append(arguments->types[1 + ii].name());
1263 signature.append(
')');
1265 QMetaMethodBuilder method;
1266 if (data->isSignal()) {
1267 method = builder.addSignal(signature);
1269 method = builder.addSlot(signature);
1271 method.setAccess(QMetaMethod::Public);
1273 if (arguments && arguments->names)
1274 method.setParameterNames(*arguments->names);
1276 if (!returnType.isEmpty())
1277 method.setReturnType(returnType);
1280 for (
int ii = 0; ii < enumCache.size(); ++ii) {
1281 const QQmlEnumData &enumData = enumCache.at(ii);
1282 QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
1283 enumeration.setIsScoped(
true);
1284 for (
int jj = 0; jj < enumData.values.size(); ++jj) {
1285 const QQmlEnumValue &value = enumData.values.at(jj);
1286 enumeration.addKey(value.namedValue.toUtf8(), value.value);
1290 if (!_defaultPropertyName.isEmpty()) {
1291 const QQmlPropertyData *dp = property(_defaultPropertyName,
nullptr,
nullptr);
1292 if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
1293 Q_ASSERT(!dp->isFunction());
1294 builder.addClassInfo(
"DefaultProperty", _defaultPropertyName.toUtf8());
1298 if (!_listPropertyAssignBehavior.isEmpty())
1299 builder.addClassInfo(
"QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
1303template <
typename StringVisitor,
typename TypeInfoVisitor>
1304int visitMethods(
const QMetaObject &mo,
int methodOffset,
int methodCount,
1305 StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1307 int fieldsForParameterData = 0;
1309 bool hasOldStyleRevisionedMethods =
false;
1311 for (
int i = 0; i < methodCount; ++i) {
1312 const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
1314 const uint flags = mo.d.data[handle + 4];
1315 if (flags & MethodRevisioned) {
1316 if (mo.d.data[0] < 13)
1317 hasOldStyleRevisionedMethods =
true;
1319 fieldsForParameterData += 1;
1322 visitString(mo.d.data[handle + 0]);
1323 visitString(mo.d.data[handle + 3]);
1325 const int argc = mo.d.data[handle + 1];
1326 const int paramIndex = mo.d.data[handle + 2];
1328 fieldsForParameterData += argc * 2;
1329 fieldsForParameterData += 1;
1332 for (
int i = 0; i < 1 + argc; ++i) {
1334 visitTypeInfo(mo.d.data[paramIndex + i]);
1338 visitString(mo.d.data[paramIndex + argc + i]);
1342 int fieldsForRevisions = 0;
1343 if (hasOldStyleRevisionedMethods)
1344 fieldsForRevisions = methodCount;
1346 return methodCount * QMetaObjectPrivate::IntsPerMethod
1347 + fieldsForRevisions + fieldsForParameterData;
1350template <
typename StringVisitor,
typename TypeInfoVisitor>
1351int visitProperties(
const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1353 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1355 for (
int i = 0; i < priv->propertyCount; ++i) {
1356 const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
1358 visitString(mo.d.data[handle]);
1359 visitTypeInfo(mo.d.data[handle + 1]);
1362 return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
1365template <
typename StringVisitor>
1366int visitClassInfo(
const QMetaObject &mo, StringVisitor visitString)
1368 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1369 const int intsPerClassInfo = 2;
1371 for (
int i = 0; i < priv->classInfoCount; ++i) {
1372 const int handle = priv->classInfoData + i * intsPerClassInfo;
1374 visitString(mo.d.data[handle]);
1375 visitString(mo.d.data[handle + 1]);
1378 return priv->classInfoCount * intsPerClassInfo;
1381template <
typename StringVisitor>
1382int visitEnumerations(
const QMetaObject &mo, StringVisitor visitString)
1384 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1386 int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
1388 for (
int i = 0; i < priv->enumeratorCount; ++i) {
1389 const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
1391 const uint keyCount = enumeratorData[3];
1392 fieldCount += keyCount * 2;
1394 visitString(enumeratorData[0]);
1395 visitString(enumeratorData[1]);
1397 const uint keyOffset = enumeratorData[4];
1399 for (uint j = 0; j < keyCount; ++j) {
1400 visitString(mo.d.data[keyOffset + 2 * j]);
1407template <
typename StringVisitor>
1408int countMetaObjectFields(
const QMetaObject &mo, StringVisitor stringVisitor)
1410 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1412 const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
1413 if (typeInfo & IsUnresolvedType)
1414 stringVisitor(typeInfo & TypeNameIndexMask);
1417 int fieldCount = MetaObjectPrivateFieldCount;
1419 fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
1421 fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
1424 fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
1425 fieldCount += visitClassInfo(mo, stringVisitor);
1426 fieldCount += visitEnumerations(mo, stringVisitor);
1433static_assert(QMetaObjectPrivate::OutputRevision == 13,
"Check and adjust determineMetaObjectSizes");
1435bool QQmlPropertyCache::determineMetaObjectSizes(
const QMetaObject &mo,
int *fieldCount,
1438 const QMetaObjectPrivate *priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1439 if (priv->revision != QMetaObjectPrivate::OutputRevision)
1442 uint highestStringIndex = 0;
1443 const auto stringIndexVisitor = [&highestStringIndex](uint index) {
1444 highestStringIndex = qMax(highestStringIndex, index);
1447 *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
1448 *stringCount = highestStringIndex + 1;
1453bool QQmlPropertyCache::addToHash(QCryptographicHash &hash,
const QMetaObject &mo)
1456 int stringCount = 0;
1457 if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
1461 hash.addData({
reinterpret_cast<
const char *>(mo.d.data), qsizetype(fieldCount *
sizeof(uint))});
1462 for (
int i = 0; i < stringCount; ++i) {
1463 hash.addData(stringData(&mo, i));
1469QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums,
bool *ok)
const
1471 auto it = checksums->constFind(quintptr(
this));
1472 if (it != checksums->constEnd()) {
1478 if (isComposite()) {
1480 return QByteArray();
1483 QCryptographicHash hash(QCryptographicHash::Md5);
1486 hash.addData(_parent->checksum(checksums, ok));
1488 return QByteArray();
1491 if (!addToHash(hash, *_metaObject.metaObject())) {
1493 return QByteArray();
1496 const QByteArray result = hash.result();
1497 if (result.isEmpty()) {
1501 checksums->insert(quintptr(
this), result);
1507
1508
1509
1510QList<QByteArray> QQmlPropertyCache::signalParameterNames(
int index)
const
1512 const QQmlPropertyData *signalData = signal(index);
1513 if (signalData && signalData->hasArguments()) {
1514 QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
1515 if (args && args->names)
1516 return *args->names;
1517 const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
1518 return method.parameterNames();
1520 return QList<QByteArray>();
static Status checkMinimal(const QQmlPropertyData *const existingProperty)
static Status check(const QQmlPropertyData &overridingProperty, const QQmlPropertyData *const existingProperty, CheckMode mode)
static bool hasInvalidModifierCombintation(const QQmlPropertyData &overridingProperty)
static Status checkFull(const QQmlPropertyData &overridingProperty, const QQmlPropertyData *const existingProperty)
Status handleOverride(QQmlPropertyData &overridingProperty, QQmlPropertyData *existingProperty, CheckMode mode)
@ MissingOverrideOrFinalSpecifier
@ OverridingNonVirtualError
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
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 QByteArray 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)