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
39 return (overridingProperty.isVirtual() && overridingProperty.isFinal())
40 || (overridingProperty.doesOverride() && overridingProperty.isFinal())
41 || (overridingProperty.isVirtual() && overridingProperty.doesOverride());
45
46
47
48
49
50
51
52
53
54
55
58 if (!existingProperty)
61 if (existingProperty->isFinal()) {
69
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
97 const QQmlPropertyData *
const existingProperty)
99 const auto overrideKeyword = overridingProperty.doesOverride();
100 if (overrideKeyword && !existingProperty) {
104 const auto minimalCheckRes = checkMinimal(existingProperty);
106 return minimalCheckRes;
110 Q_ASSERT(existingProperty);
111 if (overridingProperty.isFunction() != existingProperty->isFunction()) {
115 if (!existingProperty->isVirtual()) {
120 const auto overrideOrFinal = overrideKeyword || overridingProperty.isFinal();
121 if (!overrideOrFinal) {
128static inline Status check(
const QQmlPropertyData &overridingProperty,
129 const QQmlPropertyData *
const existingProperty,
CheckMode mode)
131 Q_ASSERT(!hasInvalidModifierCombintation(overridingProperty));
135 return detail::checkMinimal(existingProperty);
137 return detail::checkFull(overridingProperty, existingProperty);
147 const auto status = detail::check(overridingProperty, existingProperty, mode);
149 if (isValidOverride(status)) {
150 overridingProperty.markAsOverrideOf(existingProperty);
160 for (
const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
161 signalCount += QMetaObjectPrivate::get(obj)->signalCount;
165QQmlPropertyData::Flags
166QQmlPropertyData::flagsForProperty(
const QMetaProperty &p)
168 QQmlPropertyData::Flags flags;
170 flags.setIsConstant(p.isConstant());
171 flags.setIsWritable(p.isWritable());
172 flags.setIsResettable(p.isResettable());
173 flags.setIsFinal(p.isFinal());
174 flags.setIsVirtual(p.isVirtual());
175 flags.setDoesOverride(p.isOverride());
176 flags.setIsRequired(p.isRequired());
177 flags.setIsBindable(p.isBindable());
180 const QMetaType metaType = p.metaType();
181 int propType = metaType.id();
182 if (p.isEnumType()) {
183 flags.setType(QQmlPropertyData::Flags::EnumType);
184 }
else if (metaType.flags() & QMetaType::PointerToQObject) {
185 flags.setType(QQmlPropertyData::Flags::QObjectDerivedType);
186 }
else if (propType == QMetaType::QVariant) {
187 flags.setType(QQmlPropertyData::Flags::QVariantType);
188 }
else if (metaType.flags() & QMetaType::IsQmlList) {
189 flags.setType(QQmlPropertyData::Flags::QListType);
195void QQmlPropertyData::load(
const QMetaProperty &p)
197 Q_ASSERT(p.revision() <= std::numeric_limits<quint16>::max());
198 setCoreIndex(p.propertyIndex());
199 setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal()));
200 setFlags(flagsForProperty(p));
201 setRevision(QTypeRevision::fromEncodedVersion(p.revision()));
202 QMetaType type = p.metaType();
206void QQmlPropertyData::load(
const QMetaMethod &m)
208 setCoreIndex(m.methodIndex());
209 m_flags.setType(Flags::FunctionType);
215 switch (m.methodType()) {
216 case QMetaMethod::Signal:
217 m_flags.setIsSignal(
true);
218 m_flags.setIsConstructor(
false);
219 setPropType(m.returnMetaType());
221 case QMetaMethod::Constructor:
222 m_flags.setIsSignal(
false);
223 m_flags.setIsConstructor(
true);
226 m_flags.setIsSignal(
false);
227 m_flags.setIsConstructor(
false);
228 setPropType(m.returnMetaType());
232 m_flags.setIsConstant(m.isConst());
234 const int paramCount = m.parameterCount();
236 m_flags.setHasArguments(
true);
237 m_flags.setIsV4Function(
239 m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
241 m_flags.setHasArguments(
false);
242 m_flags.setIsV4Function(
false);
245 m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
247 Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
248 setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
254
255
256
257
258
259QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
260 const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
262 Q_ASSERT(metaObject);
265 if (
const QMetaObject *super = metaObject->superClass()) {
266 result = createStandalone(
267 super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
269 result.adopt(
new QQmlPropertyCache(metaObject));
270 result->update(metaObject);
273 if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
279 for (
int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
280 ++metaObjectOffset) {
281 result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
288QQmlPropertyCache::~QQmlPropertyCache()
290 QQmlPropertyCacheMethodArguments *args = argumentsCache;
292 QQmlPropertyCacheMethodArguments *next = args->next;
303QQmlPropertyCache::Ptr QQmlPropertyCache::copy(
const QQmlMetaObjectPointer &mo,
int reserve)
const
305 QQmlPropertyCache::Ptr cache = QQmlPropertyCache::Ptr(
306 new QQmlPropertyCache(mo, _handleOverride), QQmlPropertyCache::Ptr::Adopt);
307 cache->_parent.reset(
this);
308 cache->propertyIndexCacheStart = propertyIndexCache.size() + propertyIndexCacheStart;
309 cache->methodIndexCacheStart = methodIndexCache.size() + methodIndexCacheStart;
310 cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.size() + signalHandlerIndexCacheStart;
311 cache->stringCache.linkAndReserve(stringCache, reserve);
312 cache->allowedRevisionCache = allowedRevisionCache;
313 cache->_defaultPropertyName = _defaultPropertyName;
314 cache->_listPropertyAssignBehavior = _listPropertyAssignBehavior;
319QQmlPropertyCache::Ptr QQmlPropertyCache::copy()
const
321 return copy(_metaObject, 0);
324QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
325 int propertyCount,
int methodCount,
int signalCount,
int enumCount)
const
327 QQmlPropertyCache::Ptr rv = copy(
328 QQmlMetaObjectPointer(), propertyCount + methodCount + signalCount);
329 rv->propertyIndexCache.reserve(propertyCount);
330 rv->methodIndexCache.reserve(methodCount);
331 rv->signalHandlerIndexCache.reserve(signalCount);
332 rv->enumCache.reserve(enumCount);
336QQmlPropertyCache::AppendResult
337QQmlPropertyCache::appendAlias(
const QString &name, QQmlPropertyData::Flags flags,
int coreIndex,
338 QMetaType propType, QTypeRevision version,
int notifyIndex,
339 int encodedTargetIndex)
341 QQmlPropertyData data;
342 data.setPropType(propType);
343 data.setCoreIndex(coreIndex);
344 data.setNotifyIndex(notifyIndex);
345 flags.setIsAlias(
true);
346 data.setFlags(flags);
347 data.setAliasTarget(encodedTargetIndex);
348 data.setTypeVersion(version);
350 return appendPropertyAttr(name, std::move(data));
353void QQmlPropertyCache::appendSignal(
const QString &name, QQmlPropertyData::Flags flags,
354 int coreIndex,
const QMetaType *types,
355 const QList<QByteArray> &names)
357 QQmlPropertyData data;
358 data.setPropType(QMetaType());
359 data.setCoreIndex(coreIndex);
360 data.setFlags(flags);
361 data.setArguments(
nullptr);
363 QQmlPropertyData handler = data;
364 handler.m_flags.setIsSignalHandler(
true);
367 const auto argumentCount = names.size();
368 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
369 new (args->types) QMetaType;
370 ::memcpy(args->types + 1, types, argumentCount *
sizeof(QMetaType));
371 data.setArguments(args);
374 QQmlPropertyData *old = findNamedProperty(name);
375 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Minimal);
376 maybeLog(overrideStatus, name);
380 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
381 || overrideStatus == OverrideSemantics::Status::Valid
382 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
383 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
386 methodIndexCache.append(*old);
388 handler.m_flags.setIsSignalHandler(
true);
389 signalHandlerIndexCache.append(handler);
393 int methodIndex = methodIndexCache.size();
394 methodIndexCache.append(data);
396 int signalHandlerIndex = signalHandlerIndexCache.size();
397 signalHandlerIndexCache.append(handler);
399 const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
401 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
402 setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
403 signalHandlerIndexCache.data() + signalHandlerIndex);
406void QQmlPropertyCache::appendMethod(
const QString &name, QQmlPropertyData::Flags flags,
407 int coreIndex, QMetaType returnType,
408 const QList<QByteArray> &names,
409 const QList<QMetaType> ¶meterTypes)
411 int argumentCount = names.size();
413 QQmlPropertyData data;
414 data.setPropType(returnType);
415 data.setCoreIndex(coreIndex);
416 data.setFlags(flags);
417 QQmlPropertyData *old = findNamedProperty(name);
418 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Minimal);
419 maybeLog(overrideStatus, name);
423 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
424 || overrideStatus == OverrideSemantics::Status::Valid
425 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
426 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
429 methodIndexCache.append(*old);
433 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
434 new (args->types) QMetaType(returnType);
435 for (
int ii = 0; ii < argumentCount; ++ii)
436 new (args->types + ii + 1) QMetaType(parameterTypes.at(ii));
437 data.setArguments(args);
439 int methodIndex = methodIndexCache.size();
440 methodIndexCache.append(data);
442 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
445void QQmlPropertyCache::appendEnum(
const QString &name,
const QList<QQmlEnumValue> &values)
449 data.values = values;
450 enumCache.append(data);
454const QMetaObject *QQmlPropertyCache::createMetaObject()
const
456 if (_metaObject.isNull()) {
457 QMetaObjectBuilder builder;
458 toMetaObjectBuilder(builder);
459 builder.setSuperClass(_parent->createMetaObject());
460 _metaObject.setSharedOnce(builder.toMetaObject());
463 return _metaObject.metaObject();
466const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(
int index)
const
468 if (index < 0 || index >= propertyCount())
471 const QQmlPropertyData *rv =
nullptr;
472 if (index < propertyIndexCacheStart)
473 return _parent->maybeUnresolvedProperty(index);
475 rv =
const_cast<
const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
479const QQmlPropertyData *QQmlPropertyCache::defaultProperty()
const
481 return property(defaultPropertyName(),
nullptr,
nullptr);
484void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
486 if (_parent != newParent)
487 _parent = std::move(newParent);
490QQmlPropertyCache::Ptr
491QQmlPropertyCache::copyAndAppend(
const QMetaObject *metaObject,
492 QTypeRevision typeVersion,
493 QQmlPropertyData::Flags propertyFlags,
494 QQmlPropertyData::Flags methodFlags,
495 QQmlPropertyData::Flags signalFlags)
const
497 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
502 QQmlPropertyCache::Ptr rv = copy(
504 QMetaObjectPrivate::get(metaObject)->methodCount
505 + QMetaObjectPrivate::get(metaObject)->signalCount
506 + QMetaObjectPrivate::get(metaObject)->propertyCount);
508 rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
515 return QQmlSignalNames::signalNameToHandlerName(methodName);
520 return QQmlSignalNames::signalNameToHandlerName(
521 QLatin1StringView{ methodName.constData(), methodName.length() });
527 const char *cptr = str;
529 utf8 |= *cptr & 0x80;
532 return std::make_pair(utf8, cptr - str);
535void QQmlPropertyCache::append(
const QMetaObject *metaObject,
536 QTypeRevision typeVersion,
537 QQmlPropertyData::Flags propertyFlags,
538 QQmlPropertyData::Flags methodFlags,
539 QQmlPropertyData::Flags signalFlags)
541 allowedRevisionCache.append(QTypeRevision::zero());
543 int methodCount = metaObject->methodCount();
544 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
545 int signalCount = metaObjectSignalCount(metaObject);
546 int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
548 if (classInfoCount) {
549 int classInfoOffset = metaObject->classInfoOffset();
550 for (
int ii = 0; ii < classInfoCount; ++ii) {
551 int idx = ii + classInfoOffset;
552 QMetaClassInfo mci = metaObject->classInfo(idx);
553 const char *name = mci.name();
554 if (0 == qstrcmp(name,
"DefaultProperty")) {
555 _defaultPropertyName = QString::fromUtf8(mci.value());
556 }
else if (0 == qstrcmp(name,
"qt_QmlJSWrapperFactoryMethod")) {
557 const char *
const factoryMethod = mci.value();
558 _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod);
559 if (_jsFactoryMethodIndex != -1)
560 _jsFactoryMethodIndex -= metaObject->methodOffset();
561 }
else if (0 == qstrcmp(name,
"QML.ListPropertyAssignBehavior")) {
562 _listPropertyAssignBehavior = mci.value();
568 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
569 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
570 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
574 const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
576 int methodOffset = metaObject->methodOffset();
577 int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
581 methodIndexCache.resize(methodCount - methodIndexCacheStart);
582 signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
583 int signalHandlerIndex = signalOffset;
584 for (
int ii = methodOffset; ii < methodCount; ++ii) {
585 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
587 const QMetaMethod &m = metaObject->method(ii);
588 if (m.access() == QMetaMethod::Private)
593 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
595 QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
596 QQmlPropertyData *sigdata =
nullptr;
598 if (m.methodType() == QMetaMethod::Signal)
599 data->setFlags(signalFlags);
601 data->setFlags(methodFlags);
605 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
606 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
608 if (data->isSignal()) {
609 sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
611 sigdata->m_flags.setIsSignalHandler(
true);
614 const auto doSetNamedProperty = [&](
const auto &methodName) {
615 QQmlPropertyData *old =
nullptr;
616 if (StringCache::mapped_type *it = stringCache.value(methodName)) {
617 const auto overrideStatus = _handleOverride(*data, (old = it->second),
618 OverrideSemantics::CheckMode::Minimal);
619 maybeLog(overrideStatus, methodName);
623 Q_ASSERT(overrideStatus == OverrideSemantics::Status::NoOverride
624 || overrideStatus == OverrideSemantics::Status::Valid
625 || overrideStatus == OverrideSemantics::Status::OverridingFinal);
626 if (overrideStatus == OverrideSemantics::Status::OverridingFinal) {
633 sigdata->m_flags.setIsSignalHandler(
true);
634 ++signalHandlerIndex;
640 setNamedProperty(methodName, ii, data);
642 if (data->isSignal()) {
645 if constexpr (std::is_same_v<std::decay_t<
decltype(methodName)>, QHashedCStringRef>)
646 data->m_flags.setIsOverridableSignal(
true);
648 setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
649 ++signalHandlerIndex;
653 const char *str = m.nameView().constData();
654 const auto [isUtf8, len] = deriveEncodingAndLength(str);
656 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)));
658 doSetNamedProperty(QHashedCStringRef(str, len));
661 int propCount = metaObject->propertyCount();
662 int propOffset = metaObject->propertyOffset();
666 propertyIndexCache.resize(propCount - propertyIndexCacheStart);
667 for (
int ii = propOffset; ii < propCount; ++ii) {
668 QMetaProperty p = metaObject->property(ii);
669 if (!p.isScriptable())
673 QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
675 data->setFlags(propertyFlags);
677 data->setTypeVersion(typeVersion);
679 Q_ASSERT((allowedRevisionCache.size() - 1) <
Q_INT16_MAX);
680 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
682 const auto doSetNamedProperty = [
this](
const auto &propName,
int index,
auto *propData) {
683 QQmlPropertyData *existingPropData = findNamedProperty(propName);
684 const auto overrideStatus = _handleOverride(*propData, existingPropData,
685 OverrideSemantics::CheckMode::Full);
686 maybeLog(overrideStatus, propName);
687 if (!OverrideSemantics::isValidOverride(overrideStatus)) {
688 if (existingPropData) {
690 *propData = *existingPropData;
695 setNamedProperty(propName, index, propData);
698 const char *str = p.name();
699 const auto [isUtf8, len] = deriveEncodingAndLength(str);
701 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)), ii, data);
703 doSetNamedProperty(QHashedCStringRef(str, len), ii, data);
705 bool isGadget =
true;
706 for (
const QMetaObject *it = metaObject; it !=
nullptr; it = it->superClass()) {
707 if (it == &QObject::staticMetaObject)
712 if (!isGadget && !data->isAlias())
713 data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
717void QQmlPropertyCache::update(
const QMetaObject *metaObject)
719 Q_ASSERT(metaObject);
725 int pc = metaObject->propertyCount();
726 int mc = metaObject->methodCount();
727 int sc = metaObjectSignalCount(metaObject);
728 propertyIndexCache.reserve(pc - propertyIndexCacheStart);
729 methodIndexCache.reserve(mc - methodIndexCacheStart);
730 signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
734 stringCache.reserve(pc + mc + sc);
737 append(metaObject, QTypeRevision());
741
742
743
744void QQmlPropertyCache::invalidate(
const QMetaObject *metaObject)
746 propertyIndexCache.clear();
747 methodIndexCache.clear();
748 signalHandlerIndexCache.clear();
750 argumentsCache =
nullptr;
752 int pc = metaObject->propertyCount();
753 int mc = metaObject->methodCount();
754 int sc = metaObjectSignalCount(metaObject);
755 int reserve = pc + mc + sc;
758 propertyIndexCacheStart = parent()->propertyIndexCache.size() + parent()->propertyIndexCacheStart;
759 methodIndexCacheStart = parent()->methodIndexCache.size() + parent()->methodIndexCacheStart;
760 signalHandlerIndexCacheStart = parent()->signalHandlerIndexCache.size() + parent()->signalHandlerIndexCacheStart;
761 stringCache.linkAndReserve(parent()->stringCache, reserve);
762 append(metaObject, QTypeRevision());
764 propertyIndexCacheStart = 0;
765 methodIndexCacheStart = 0;
766 signalHandlerIndexCacheStart = 0;
771const QQmlPropertyData *QQmlPropertyCache::findProperty(
772 StringCache::ConstIterator it, QObject *object,
773 const QQmlRefPointer<QQmlContextData> &context)
const
775 QQmlData *data = (object ? QQmlData::get(object) :
nullptr);
776 const QQmlVMEMetaObject *vmemo =
nullptr;
777 if (data && data->hasVMEMetaObject) {
778 QObjectPrivate *op = QObjectPrivate::get(object);
779 vmemo =
static_cast<
const QQmlVMEMetaObject *>(op->metaObject);
781 return findProperty(it, vmemo, context);
786inline bool contextHasNoExtensions(
const QQmlRefPointer<QQmlContextData> &context)
790 const QQmlRefPointer<QQmlContextData> parent = context->parent();
791 return (!parent || !parent->imports());
794inline int maximumIndexForProperty(
const QQmlPropertyData *prop,
const int methodCount,
const int signalCount,
const int propertyCount)
796 return prop->isFunction() ? methodCount
797 : prop->isSignalHandler() ? signalCount
803const QQmlPropertyData *QQmlPropertyCache::findProperty(
804 StringCache::ConstIterator it,
const QQmlVMEMetaObject *vmemo,
805 const QQmlRefPointer<QQmlContextData> &context)
const
807 StringCache::ConstIterator end = stringCache.end();
810 const QQmlPropertyData *result = it.value().second;
816 if (vmemo && context && !contextHasNoExtensions(context)) {
819 if (vmemo->contextData() == context)
822 vmemo = vmemo->parentVMEMetaObject();
827 const int methodCount = vmemo->cache->methodCount();
828 const int signalCount = vmemo->cache->signalCount();
829 const int propertyCount = vmemo->cache->propertyCount();
833 const StringCache::mapped_type &property(it.value());
835 if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
837 if (property.second->isFunction() || property.second->isSignalHandler()) {
841 result = property.second;
847 it = stringCache.findNext(it);
858QQmlPropertyCache::AppendResult QQmlPropertyCache::appendPropertyAttr(
const QString &name,
859 QQmlPropertyData &&data)
861 QQmlPropertyData *old = findNamedProperty(name);
862 const auto overrideStatus = _handleOverride(data, old, OverrideSemantics::CheckMode::Full);
863 maybeLog(overrideStatus, name);
864 if (!OverrideSemantics::isValidOverride(overrideStatus)) {
867 propertyIndexCache.append(old ? *old : data);
868 return q23::make_unexpected(overrideStatus);
871 const int index = propertyIndexCache.size();
872 propertyIndexCache.append(std::move(data));
874 setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index);
878void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
880 Q_ASSERT(predecessor !=
this);
886 setOverrideIndexIsProperty(!predecessor->isFunction());
887 setOverrideIndex(predecessor->coreIndex());
889 m_flags.setIsVirtual(predecessor->isVirtual());
890 predecessor->m_flags.setIsOverridden(
true);
891 Q_ASSERT(predecessor->isOverridden());
895QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
896 int argc,
const QList<QByteArray> &names)
898 typedef QQmlPropertyCacheMethodArguments A;
899 A *args =
static_cast<A *>(malloc(
sizeof(A) + argc *
sizeof(QMetaType)));
900 args->names = argc ?
new QList<QByteArray>(names) :
nullptr;
901 args->next = argumentsCache;
902 argumentsCache = args;
906QString QQmlPropertyCache::signalParameterStringForJS(
907 const QList<QByteArray> ¶meterNameList, QString *errorString)
909 bool unnamedParameter =
false;
912 const qsizetype count = parameterNameList.size();
913 if (count > std::numeric_limits<quint16>::max())
914 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal has an excessive number of parameters: %1").arg(count);
916 for (qsizetype i = 0; i < count; ++i) {
918 parameters += QLatin1Char(
',');
919 const QByteArray ¶m = parameterNameList.at(i);
920 if (param.isEmpty()) {
921 unnamedParameter =
true;
922 }
else if (unnamedParameter) {
924 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal uses unnamed parameter followed by named parameter.");
926 }
else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
928 *errorString = QCoreApplication::translate(
"QQmlRewrite",
"Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
931 parameters += QString::fromUtf8(param);
937int QQmlPropertyCache::originalClone(
int index)
const
939 while (signal(index)->isCloned())
944int QQmlPropertyCache::originalClone(
const QObject *object,
int index)
946 QQmlData *data = QQmlData::get(object);
947 if (data && data->propertyCache) {
948 const QQmlPropertyCache *cache = data->propertyCache.data();
949 const QQmlPropertyData *sig = cache->signal(index);
950 while (sig && sig->isCloned()) {
952 sig = cache->signal(index);
955 while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
964 Q_ASSERT(metaObject);
969
970
973 static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal(
"destroyed(QObject*)");
974 static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal(
"destroyed()");
975 static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot(
"deleteLater()");
977 const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
979 int methodCount = metaObject->methodCount();
980 for (
int ii = methodCount - 1; ii >= 0; --ii) {
981 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
983 QMetaMethod m = metaObject->method(ii);
984 if (m.access() == QMetaMethod::Private)
987 if (m.name() == propertyName) {
994 const QMetaObject *cmo = metaObject;
996 int idx = cmo->indexOfProperty(propertyName);
998 QMetaProperty p = cmo->property(idx);
999 if (p.isScriptable()) {
1003 bool changed =
false;
1004 while (cmo && cmo->propertyOffset() >= idx) {
1005 cmo = cmo->superClass();
1009
1010 if (!changed) cmo =
nullptr;
1022 return string.data();
1027 return string.toUtf8();
1032 return string->toQString().toUtf8();
1038 QQmlPropertyData *local)
1040 const QQmlPropertyCache *cache =
nullptr;
1042 QQmlData *ddata = QQmlData::get(obj,
false);
1044 if (ddata && ddata->propertyCache) {
1045 cache = ddata->propertyCache.data();
1046 }
else if (
auto newCache = QQmlMetaType::propertyCache(obj)) {
1047 cache = newCache.data();
1048 ddata = QQmlData::get(obj,
true);
1049 ddata->propertyCache =
std::move(newCache);
1052 const QQmlPropertyData *rv =
nullptr;
1055 rv = cache->property(name, obj, context);
1057 *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1058 if (local->isValid())
1065const QQmlPropertyData *QQmlPropertyCache::property(
1066 QObject *obj,
const QV4::String *name,
const QQmlRefPointer<QQmlContextData> &context,
1067 QQmlPropertyData *local)
1069 return qQmlPropertyCacheProperty<
const QV4::String *>(obj, name, context, local);
1072const QQmlPropertyData *QQmlPropertyCache::property(
1073 QObject *obj, QStringView name,
const QQmlRefPointer<QQmlContextData> &context,
1074 QQmlPropertyData *local)
1076 return qQmlPropertyCacheProperty<
const QStringView &>(obj, name, context, local);
1079const QQmlPropertyData *QQmlPropertyCache::property(
1080 QObject *obj,
const QLatin1String &name,
const QQmlRefPointer<QQmlContextData> &context,
1081 QQmlPropertyData *local)
1083 return qQmlPropertyCacheProperty<
const QLatin1String &>(obj, name, context, local);
1089 uint offset = mo->d.stringdata[2*index];
1090 uint length = mo->d.stringdata[2*index + 1];
1091 const char *string =
reinterpret_cast<
const char *>(mo->d.stringdata) + offset;
1092 return QByteArray::fromRawData(string, length);
1095const char *QQmlPropertyCache::className()
const
1097 if (
const QMetaObject *mo = _metaObject.metaObject())
1098 return mo->className();
1100 return _dynamicClassName.constData();
1103void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
const
1105 struct Sort {
static bool lt(
const std::pair<QString,
const QQmlPropertyData *> &lhs,
1106 const std::pair<QString,
const QQmlPropertyData *> &rhs) {
1107 return lhs.second->coreIndex() < rhs.second->coreIndex();
1110 struct Insert {
static void in(
const QQmlPropertyCache *This,
1111 QList<std::pair<QString,
const QQmlPropertyData *> > &properties,
1112 QList<std::pair<QString,
const QQmlPropertyData *> > &methods,
1113 StringCache::ConstIterator iter,
const QQmlPropertyData *data) {
1114 if (data->isSignalHandler())
1117 if (data->isFunction()) {
1118 if (data->coreIndex() < This->methodIndexCacheStart)
1121 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
1123 if (!methods.contains(entry)) methods.append(entry);
1125 data = This->overrideData(data);
1126 if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1128 if (data->coreIndex() < This->propertyIndexCacheStart)
1131 std::pair<QString,
const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
1133 if (!properties.contains(entry)) properties.append(entry);
1135 data = This->overrideData(data);
1136 if (data) Insert::in(This, properties, methods, iter, data);
1141 builder.setClassName(_dynamicClassName);
1143 QList<std::pair<QString,
const QQmlPropertyData *> > properties;
1144 QList<std::pair<QString,
const QQmlPropertyData *> > methods;
1146 for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
1147 Insert::in(
this, properties, methods, iter, iter.value().second);
1151 Q_ASSERT(properties.size() <= propertyIndexCache.size());
1152 Q_ASSERT(methods.size() <= methodIndexCache.size());
1154 std::sort(properties.begin(), properties.end(), Sort::lt);
1155 std::sort(methods.begin(), methods.end(), Sort::lt);
1157 for (
int ii = 0; ii < properties.size(); ++ii) {
1158 const QQmlPropertyData *data = properties.at(ii).second;
1160 int notifierId = -1;
1161 if (data->notifyIndex() != -1)
1162 notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
1164 QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1165 data->propType().name(),
1169 property.setReadable(
true);
1170 property.setWritable(data->isWritable());
1171 property.setResettable(data->isResettable());
1172 property.setBindable(data->notifiesViaBindable());
1173 property.setAlias(data->isAlias());
1176 for (
int ii = 0; ii < methods.size(); ++ii) {
1177 const QQmlPropertyData *data = methods.at(ii).second;
1179 QByteArray returnType;
1180 if (data->propType().isValid())
1181 returnType = data->propType().name();
1183 QByteArray signature;
1185 signature += methods.at(ii).first.toUtf8() +
'(';
1187 QQmlPropertyCacheMethodArguments *arguments =
nullptr;
1188 if (data->hasArguments()) {
1189 arguments = data->arguments();
1190 for (
int ii = 0, end = arguments->names ? arguments->names->size() : 0;
1193 signature.append(
',');
1194 signature.append(arguments->types[1 + ii].name());
1198 signature.append(
')');
1200 QMetaMethodBuilder method;
1201 if (data->isSignal()) {
1202 method = builder.addSignal(signature);
1204 method = builder.addSlot(signature);
1206 method.setAccess(QMetaMethod::Public);
1208 if (arguments && arguments->names)
1209 method.setParameterNames(*arguments->names);
1211 if (!returnType.isEmpty())
1212 method.setReturnType(returnType);
1215 for (
int ii = 0; ii < enumCache.size(); ++ii) {
1216 const QQmlEnumData &enumData = enumCache.at(ii);
1217 QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
1218 enumeration.setIsScoped(
true);
1219 for (
int jj = 0; jj < enumData.values.size(); ++jj) {
1220 const QQmlEnumValue &value = enumData.values.at(jj);
1221 enumeration.addKey(value.namedValue.toUtf8(), value.value);
1225 if (!_defaultPropertyName.isEmpty()) {
1226 const QQmlPropertyData *dp = property(_defaultPropertyName,
nullptr,
nullptr);
1227 if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
1228 Q_ASSERT(!dp->isFunction());
1229 builder.addClassInfo(
"DefaultProperty", _defaultPropertyName.toUtf8());
1233 if (!_listPropertyAssignBehavior.isEmpty())
1234 builder.addClassInfo(
"QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
1238template <
typename StringVisitor,
typename TypeInfoVisitor>
1239int visitMethods(
const QMetaObject &mo,
int methodOffset,
int methodCount,
1240 StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1242 int fieldsForParameterData = 0;
1244 bool hasOldStyleRevisionedMethods =
false;
1246 for (
int i = 0; i < methodCount; ++i) {
1247 const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
1249 const uint flags = mo.d.data[handle + 4];
1250 if (flags & MethodRevisioned) {
1251 if (mo.d.data[0] < 13)
1252 hasOldStyleRevisionedMethods =
true;
1254 fieldsForParameterData += 1;
1257 visitString(mo.d.data[handle + 0]);
1258 visitString(mo.d.data[handle + 3]);
1260 const int argc = mo.d.data[handle + 1];
1261 const int paramIndex = mo.d.data[handle + 2];
1263 fieldsForParameterData += argc * 2;
1264 fieldsForParameterData += 1;
1267 for (
int i = 0; i < 1 + argc; ++i) {
1269 visitTypeInfo(mo.d.data[paramIndex + i]);
1273 visitString(mo.d.data[paramIndex + argc + i]);
1277 int fieldsForRevisions = 0;
1278 if (hasOldStyleRevisionedMethods)
1279 fieldsForRevisions = methodCount;
1281 return methodCount * QMetaObjectPrivate::IntsPerMethod
1282 + fieldsForRevisions + fieldsForParameterData;
1285template <
typename StringVisitor,
typename TypeInfoVisitor>
1286int visitProperties(
const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1288 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1290 for (
int i = 0; i < priv->propertyCount; ++i) {
1291 const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
1293 visitString(mo.d.data[handle]);
1294 visitTypeInfo(mo.d.data[handle + 1]);
1297 return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
1300template <
typename StringVisitor>
1301int visitClassInfo(
const QMetaObject &mo, StringVisitor visitString)
1303 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1304 const int intsPerClassInfo = 2;
1306 for (
int i = 0; i < priv->classInfoCount; ++i) {
1307 const int handle = priv->classInfoData + i * intsPerClassInfo;
1309 visitString(mo.d.data[handle]);
1310 visitString(mo.d.data[handle + 1]);
1313 return priv->classInfoCount * intsPerClassInfo;
1316template <
typename StringVisitor>
1317int visitEnumerations(
const QMetaObject &mo, StringVisitor visitString)
1319 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1321 int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
1323 for (
int i = 0; i < priv->enumeratorCount; ++i) {
1324 const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
1326 const uint keyCount = enumeratorData[3];
1327 fieldCount += keyCount * 2;
1329 visitString(enumeratorData[0]);
1330 visitString(enumeratorData[1]);
1332 const uint keyOffset = enumeratorData[4];
1334 for (uint j = 0; j < keyCount; ++j) {
1335 visitString(mo.d.data[keyOffset + 2 * j]);
1342template <
typename StringVisitor>
1343int countMetaObjectFields(
const QMetaObject &mo, StringVisitor stringVisitor)
1345 const QMetaObjectPrivate *
const priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1347 const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
1348 if (typeInfo & IsUnresolvedType)
1349 stringVisitor(typeInfo & TypeNameIndexMask);
1352 int fieldCount = MetaObjectPrivateFieldCount;
1354 fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
1356 fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
1359 fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
1360 fieldCount += visitClassInfo(mo, stringVisitor);
1361 fieldCount += visitEnumerations(mo, stringVisitor);
1369static_assert(QMetaObjectPrivate::OutputRevision == 13 || QMetaObjectPrivate::OutputRevision == 14,
1370 "Check and adjust determineMetaObjectSizes");
1372bool QQmlPropertyCache::determineMetaObjectSizes(
const QMetaObject &mo,
int *fieldCount,
1375 const QMetaObjectPrivate *priv =
reinterpret_cast<
const QMetaObjectPrivate*>(mo.d.data);
1376 if (priv->revision != QMetaObjectPrivate::OutputRevision)
1379 uint highestStringIndex = 0;
1380 const auto stringIndexVisitor = [&highestStringIndex](uint index) {
1381 highestStringIndex = qMax(highestStringIndex, index);
1384 *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
1385 *stringCount = highestStringIndex + 1;
1390bool QQmlPropertyCache::addToHash(QCryptographicHash &hash,
const QMetaObject &mo)
1393 int stringCount = 0;
1394 if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
1398 hash.addData({
reinterpret_cast<
const char *>(mo.d.data), qsizetype(fieldCount *
sizeof(uint))});
1399 for (
int i = 0; i < stringCount; ++i) {
1400 hash.addData(stringData(&mo, i));
1406QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums,
bool *ok)
const
1408 auto it = checksums->constFind(quintptr(
this));
1409 if (it != checksums->constEnd()) {
1415 if (_metaObject.isShared()) {
1417 return QByteArray();
1420 QCryptographicHash hash(QCryptographicHash::Md5);
1423 hash.addData(_parent->checksum(checksums, ok));
1425 return QByteArray();
1428 if (!addToHash(hash, *_metaObject.metaObject())) {
1430 return QByteArray();
1433 const QByteArray result = hash.result();
1434 if (result.isEmpty()) {
1438 checksums->insert(quintptr(
this), result);
1444
1445
1446
1447QList<QByteArray> QQmlPropertyCache::signalParameterNames(
int index)
const
1449 const QQmlPropertyData *signalData = signal(index);
1450 if (signalData && signalData->hasArguments()) {
1451 QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments();
1452 if (args && args->names)
1453 return *args->names;
1454 const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
1455 return method.parameterNames();
1457 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 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)