Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlpropertycache.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <private/qqmlengine_p.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlvmemetaobject_p.h>
9
10#include <private/qmetaobject_p.h>
11#include <private/qmetaobjectbuilder_p.h>
12#include <private/qqmlpropertycachemethodarguments_p.h>
13#include <private/qqmlsignalnames_p.h>
14
15#include <private/qv4codegen_p.h>
16#include <private/qv4value_p.h>
17
18#include <QtCore/qdebug.h>
19#include <QtCore/QCryptographicHash>
20#include <QtCore/private/qtools_p.h>
21
22#include <limits.h>
23#include <algorithm>
24
25#ifdef Q_CC_MSVC
26// nonstandard extension used : zero-sized array in struct/union.
27# pragma warning( disable : 4200 )
28#endif
29
31
32#define Q_INT16_MAX 32767
33
34static int metaObjectSignalCount(const QMetaObject *metaObject)
35{
36 int signalCount = 0;
37 for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
38 signalCount += QMetaObjectPrivate::get(obj)->signalCount;
39 return signalCount;
40}
41
42QQmlPropertyData::Flags
43QQmlPropertyData::flagsForProperty(const QMetaProperty &p)
44{
45 QQmlPropertyData::Flags flags;
46
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());
53
54
55 const QMetaType metaType = p.metaType();
56 int propType = metaType.id();
57 if (p.isEnumType()) {
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);
65 }
66
67 return flags;
68}
69
70void QQmlPropertyData::load(const QMetaProperty &p)
71{
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();
78 setPropType(type);
79}
80
81void QQmlPropertyData::load(const QMetaMethod &m)
82{
83 setCoreIndex(m.methodIndex());
84 m_flags.setType(Flags::FunctionType);
85
86 // We need to set the constructor, signal, constant, arguments, V4Function, cloned flags.
87 // These are specific to methods and change with each method.
88 // The same QQmlPropertyData may be loaded with multiple methods in sequence.
89
90 switch (m.methodType()) {
91 case QMetaMethod::Signal:
92 m_flags.setIsSignal(true);
93 m_flags.setIsConstructor(false);
94 setPropType(m.returnMetaType());
95 break;
96 case QMetaMethod::Constructor:
97 m_flags.setIsSignal(false);
98 m_flags.setIsConstructor(true);
99 break;
100 default:
101 m_flags.setIsSignal(false);
102 m_flags.setIsConstructor(false);
103 setPropType(m.returnMetaType());
104 break;
105 }
106
107 m_flags.setIsConstant(m.isConst());
108
109 const int paramCount = m.parameterCount();
110 if (paramCount) {
111 m_flags.setHasArguments(true);
112 m_flags.setIsV4Function(
113 paramCount == 1 &&
114 m.parameterMetaType(0) == QMetaType::fromType<QQmlV4FunctionPtr>());
115 } else {
116 m_flags.setHasArguments(false);
117 m_flags.setIsV4Function(false);
118 }
119
120 m_flags.setIsCloned(m.attributes() & QMetaMethod::Cloned);
121
122 Q_ASSERT(m.revision() <= std::numeric_limits<quint16>::max());
123 setRevision(QTypeRevision::fromEncodedVersion(m.revision()));
124}
125
126/*!
127 Creates a standalone QQmlPropertyCache of \a metaObject. It is separate from the usual
128 QQmlPropertyCache hierarchy. It's parent is not equal to any other QQmlPropertyCache
129 created from QObject::staticMetaObject, for example.
130*/
131QQmlPropertyCache::Ptr QQmlPropertyCache::createStandalone(
132 const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
133{
134 Q_ASSERT(metaObject);
135
136 Ptr result;
137 if (const QMetaObject *super = metaObject->superClass()) {
138 result = createStandalone(
139 super, metaObjectRevision)->copyAndAppend(metaObject, metaObjectRevision);
140 } else {
141 result.adopt(new QQmlPropertyCache(metaObject));
142 result->update(metaObject);
143 }
144
145 if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
146 // Set the revision of the meta object that this cache describes to be
147 // 'metaObjectRevision'. This is useful when constructing a property cache
148 // from a type that was created directly in C++, and not through QML. For such
149 // types, the revision for each recorded QMetaObject would normally be zero, which
150 // would exclude any revisioned properties.
151 for (int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
152 ++metaObjectOffset) {
153 result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
154 }
155 }
156
157 return result;
158}
159
160QQmlPropertyCache::~QQmlPropertyCache()
161{
162 QQmlPropertyCacheMethodArguments *args = argumentsCache;
163 while (args) {
164 QQmlPropertyCacheMethodArguments *next = args->next;
165 delete args->names;
166 free(args);
167 args = next;
168 }
169
170 // We must clear this prior to releasing the parent incase it is a
171 // linked hash
172 stringCache.clear();
173}
174
175QQmlPropertyCache::Ptr QQmlPropertyCache::copy(const QQmlMetaObjectPointer &mo, int reserve) const
176{
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;
187
188 return cache;
189}
190
191QQmlPropertyCache::Ptr QQmlPropertyCache::copy() const
192{
193 return copy(_metaObject, 0);
194}
195
196QQmlPropertyCache::Ptr QQmlPropertyCache::copyAndReserve(
197 int propertyCount, int methodCount, int signalCount, int enumCount) const
198{
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);
205 return rv;
206}
207
208QQmlPropertyCache::OverrideResult
209QQmlPropertyCache::appendAlias(const QString &name, QQmlPropertyData::Flags flags, int coreIndex,
210 QMetaType propType, QTypeRevision version, int notifyIndex,
211 int encodedTargetIndex)
212{
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);
221
222 return doAppendPropertyData(name, std::move(data));
223}
224
225void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags,
226 int coreIndex, const QMetaType *types,
227 const QList<QByteArray> &names)
228{
229 QQmlPropertyData data;
230 data.setPropType(QMetaType());
231 data.setCoreIndex(coreIndex);
232 data.setFlags(flags);
233 data.setArguments(nullptr);
234
235 QQmlPropertyData handler = data;
236 handler.m_flags.setIsSignalHandler(true);
237
238 if (types) {
239 const auto argumentCount = names.size();
240 QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names);
241 new (args->types) QMetaType; // Invalid return type
242 ::memcpy(args->types + 1, types, argumentCount * sizeof(QMetaType));
243 data.setArguments(args);
244 }
245
246 QQmlPropertyData *old = findNamedProperty(name);
247 const OverrideResult overrideResult = handleOverride(name, &data, old);
248 if (overrideResult == InvalidOverride) {
249 // Insert the overridden member and its signal once more, to keep the counts in sync
250 methodIndexCache.append(*old);
251 handler = *old;
252 handler.m_flags.setIsSignalHandler(true);
253 signalHandlerIndexCache.append(handler);
254 return;
255 }
256
257 int methodIndex = methodIndexCache.size();
258 methodIndexCache.append(data);
259
260 int signalHandlerIndex = signalHandlerIndexCache.size();
261 signalHandlerIndexCache.append(handler);
262
263 const QString handlerName = QQmlSignalNames::signalNameToHandlerName(name);
264
265 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
266 setNamedProperty(handlerName, signalHandlerIndex + signalOffset(),
267 signalHandlerIndexCache.data() + signalHandlerIndex);
268}
269
270void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags,
271 int coreIndex, QMetaType returnType,
272 const QList<QByteArray> &names,
273 const QVector<QMetaType> &parameterTypes)
274{
275 int argumentCount = names.size();
276
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) {
284 // Insert the overridden member once more, to keep the counts in sync
285 methodIndexCache.append(*old);
286 return;
287 }
288
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);
294
295 int methodIndex = methodIndexCache.size();
296 methodIndexCache.append(data);
297
298 setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex);
299}
300
301void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values)
302{
303 QQmlEnumData data;
304 data.name = name;
305 data.values = values;
306 enumCache.append(data);
307}
308
309// Returns this property cache's metaObject, creating it if necessary.
310const QMetaObject *QQmlPropertyCache::createMetaObject() const
311{
312 if (_metaObject.isNull()) {
313 QMetaObjectBuilder builder;
314 toMetaObjectBuilder(builder);
315 builder.setSuperClass(_parent->createMetaObject());
316 _metaObject.setSharedOnce(builder.toMetaObject());
317 }
318
319 return _metaObject.metaObject();
320}
321
322const QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
323{
324 if (index < 0 || index >= propertyCount())
325 return nullptr;
326
327 const QQmlPropertyData *rv = nullptr;
328 if (index < propertyIndexCacheStart)
329 return _parent->maybeUnresolvedProperty(index);
330 else
331 rv = const_cast<const QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
332 return rv;
333}
334
335const QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
336{
337 return property(defaultPropertyName(), nullptr, nullptr);
338}
339
340void QQmlPropertyCache::setParent(QQmlPropertyCache::ConstPtr newParent)
341{
342 if (_parent != newParent)
343 _parent = std::move(newParent);
344}
345
346QQmlPropertyCache::Ptr
347QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject,
348 QTypeRevision typeVersion,
349 QQmlPropertyData::Flags propertyFlags,
350 QQmlPropertyData::Flags methodFlags,
351 QQmlPropertyData::Flags signalFlags) const
352{
353 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
354
355 // Reserve enough space in the name hash for all the methods (including signals), all the
356 // signal handlers and all the properties. This assumes no name clashes, but this is the
357 // common case.
358 QQmlPropertyCache::Ptr rv = copy(
359 metaObject,
360 QMetaObjectPrivate::get(metaObject)->methodCount
361 + QMetaObjectPrivate::get(metaObject)->signalCount
362 + QMetaObjectPrivate::get(metaObject)->propertyCount);
363
364 rv->append(metaObject, typeVersion, propertyFlags, methodFlags, signalFlags);
365
366 return rv;
367}
368
369static QHashedString signalNameToHandlerName(const QHashedString &methodName)
370{
371 return QQmlSignalNames::signalNameToHandlerName(methodName);
372}
373
374static QHashedString signalNameToHandlerName(const QHashedCStringRef &methodName)
375{
376 return QQmlSignalNames::signalNameToHandlerName(
377 QLatin1StringView{ methodName.constData(), methodName.length() });
378}
379
380static inline std::pair<bool, int> deriveEncodingAndLength(const char *str)
381{
382 char utf8 = 0;
383 const char *cptr = str;
384 while (*cptr != 0) {
385 utf8 |= *cptr & 0x80;
386 ++cptr;
387 }
388 return std::make_pair(utf8, cptr - str);
389}
390
391void QQmlPropertyCache::append(const QMetaObject *metaObject,
392 QTypeRevision typeVersion,
393 QQmlPropertyData::Flags propertyFlags,
394 QQmlPropertyData::Flags methodFlags,
395 QQmlPropertyData::Flags signalFlags)
396{
397 allowedRevisionCache.append(QTypeRevision::zero());
398
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;
403
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();
419 }
420 }
421 }
422
423 //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
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()");
427 // These indices don't apply to gadgets, so don't block them.
428 // It is enough to check for QObject::staticMetaObject here because the loop below excludes
429 // methods of parent classes: It starts at metaObject->methodOffset()
430 const bool preventDestruction = (metaObject == &QObject::staticMetaObject);
431
432 int methodOffset = metaObject->methodOffset();
433 int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
434
435 // update() should have reserved enough space in the vector that this doesn't cause a realloc
436 // and invalidate the stringCache.
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))
442 continue;
443 const QMetaMethod &m = metaObject->method(ii);
444 if (m.access() == QMetaMethod::Private)
445 continue;
446
447 // Extract method name
448 // It's safe to keep the raw name pointer
449 Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
450
451 QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
452 QQmlPropertyData *sigdata = nullptr;
453
454 if (m.methodType() == QMetaMethod::Signal)
455 data->setFlags(signalFlags);
456 else
457 data->setFlags(methodFlags);
458
459 data->load(m);
460
461 Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
462 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
463
464 if (data->isSignal()) {
465 sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
466 *sigdata = *data;
467 sigdata->m_flags.setIsSignalHandler(true);
468 }
469
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) {
474 *data = *old;
475 if (sigdata) {
476 // Keep the signal counts in sync,
477 // even if the "old" data has no real signal.
478 *sigdata = *old;
479 sigdata->m_flags.setIsSignalHandler(true);
480 ++signalHandlerIndex;
481 }
482 return;
483 }
484 }
485
486 setNamedProperty(methodName, ii, data);
487
488 if (data->isSignal()) {
489
490 // TODO: Remove this once we can. Signals should not be overridable.
491 if constexpr (std::is_same_v<std::decay_t<decltype(methodName)>, QHashedCStringRef>)
492 data->m_flags.setIsOverridableSignal(true);
493
494 setNamedProperty(signalNameToHandlerName(methodName), ii, sigdata);
495 ++signalHandlerIndex;
496 }
497 };
498
499 const char *str = m.nameView().constData();
500 const auto [isUtf8, len] = deriveEncodingAndLength(str);
501 if (isUtf8)
502 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)));
503 else
504 doSetNamedProperty(QHashedCStringRef(str, len));
505 }
506
507 int propCount = metaObject->propertyCount();
508 int propOffset = metaObject->propertyOffset();
509
510 // update() should have reserved enough space in the vector that this doesn't cause a realloc
511 // and invalidate the stringCache.
512 propertyIndexCache.resize(propCount - propertyIndexCacheStart);
513 for (int ii = propOffset; ii < propCount; ++ii) {
514 QMetaProperty p = metaObject->property(ii);
515 if (!p.isScriptable())
516 continue;
517
518 QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
519
520 data->setFlags(propertyFlags);
521 data->load(p);
522 data->setTypeVersion(typeVersion);
523
524 Q_ASSERT((allowedRevisionCache.size() - 1) < Q_INT16_MAX);
525 data->setMetaObjectOffset(allowedRevisionCache.size() - 1);
526
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;
533 return;
534 }
535 }
536 setNamedProperty(propName, index, propData);
537 };
538
539 const char *str = p.name();
540 const auto [isUtf8, len] = deriveEncodingAndLength(str);
541 if (isUtf8)
542 doSetNamedProperty(QHashedString(QString::fromUtf8(str, len)), ii, data);
543 else
544 doSetNamedProperty(QHashedCStringRef(str, len), ii, data);
545
546 bool isGadget = true;
547 for (const QMetaObject *it = metaObject; it != nullptr; it = it->superClass()) {
548 if (it == &QObject::staticMetaObject)
549 isGadget = false;
550 }
551
552 // otherwise always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
553 if (!isGadget && !data->isAlias())
554 data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
555 }
556}
557
558void QQmlPropertyCache::update(const QMetaObject *metaObject)
559{
560 Q_ASSERT(metaObject);
561 stringCache.clear();
562
563 // Preallocate enough space in the index caches for all the properties/methods/signals that
564 // are not cached in a parent cache so that the caches never need to be reallocated as this
565 // would invalidate pointers stored in the stringCache.
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);
572
573 // Reserve enough space in the stringCache for all properties/methods/signals including those
574 // cached in a parent cache.
575 stringCache.reserve(pc + mc + sc);
576
577 if (metaObject)
578 append(metaObject, QTypeRevision());
579}
580
581/*! \internal
582 invalidates and updates the PropertyCache if the QMetaObject has changed.
583 This function is used in the tooling to update dynamic properties.
584*/
585void QQmlPropertyCache::invalidate(const QMetaObject *metaObject)
586{
587 propertyIndexCache.clear();
588 methodIndexCache.clear();
589 signalHandlerIndexCache.clear();
590
591 argumentsCache = nullptr;
592
593 int pc = metaObject->propertyCount();
594 int mc = metaObject->methodCount();
595 int sc = metaObjectSignalCount(metaObject);
596 int reserve = pc + mc + sc;
597
598 if (parent()) {
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());
604 } else {
605 propertyIndexCacheStart = 0;
606 methodIndexCacheStart = 0;
607 signalHandlerIndexCacheStart = 0;
608 update(metaObject);
609 }
610}
611
612const QQmlPropertyData *QQmlPropertyCache::findProperty(
613 StringCache::ConstIterator it, QObject *object,
614 const QQmlRefPointer<QQmlContextData> &context) const
615{
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);
621 }
622 return findProperty(it, vmemo, context);
623}
624
625namespace {
626
627inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &context)
628{
629 // This context has no extension if its parent is the engine's rootContext,
630 // which has children but no imports
631 const QQmlRefPointer<QQmlContextData> parent = context->parent();
632 return (!parent || !parent->imports());
633}
634
635inline int maximumIndexForProperty(const QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
636{
637 return prop->isFunction() ? methodCount
638 : prop->isSignalHandler() ? signalCount
639 : propertyCount;
640}
641
642}
643
644const QQmlPropertyData *QQmlPropertyCache::findProperty(
645 StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo,
646 const QQmlRefPointer<QQmlContextData> &context) const
647{
648 StringCache::ConstIterator end = stringCache.end();
649
650 if (it != end) {
651 const QQmlPropertyData *result = it.value().second;
652
653 // If there exists a typed property (not a function or signal handler), of the
654 // right name available to the specified context, we need to return that
655 // property rather than any subsequent override
656
657 if (vmemo && context && !contextHasNoExtensions(context)) {
658 // Find the meta-object that corresponds to the supplied context
659 do {
660 if (vmemo->ctxt.contextData().data() == context.data())
661 break;
662
663 vmemo = vmemo->parentVMEMetaObject();
664 } while (vmemo);
665 }
666
667 if (vmemo) {
668 const int methodCount = vmemo->cache->methodCount();
669 const int signalCount = vmemo->cache->signalCount();
670 const int propertyCount = vmemo->cache->propertyCount();
671
672 // Ensure that the property we resolve to is accessible from this meta-object
673 do {
674 const StringCache::mapped_type &property(it.value());
675
676 if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) {
677 // This property is available in the specified context
678 if (property.second->isFunction() || property.second->isSignalHandler()) {
679 // Prefer the earlier resolution
680 } else {
681 // Prefer the typed property to any previous property found
682 result = property.second;
683 }
684 break;
685 }
686
687 // See if there is a better candidate
688 it = stringCache.findNext(it);
689 } while (it != end);
690 }
691
692 return result;
693 }
694
695 return nullptr;
696}
697
698void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
699{
700 Q_ASSERT(predecessor != this);
701
702 setOverrideIndexIsProperty(!predecessor->isFunction());
703 setOverrideIndex(predecessor->coreIndex());
704 predecessor->m_flags.setIsOverridden(true);
705 Q_ASSERT(predecessor->isOverridden());
706 return;
707}
708
709QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(
710 int argc, const QList<QByteArray> &names)
711{
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;
717 return args;
718}
719
720QString QQmlPropertyCache::signalParameterStringForJS(
721 const QList<QByteArray> &parameterNameList, QString *errorString)
722{
723 bool unnamedParameter = false;
724 QString parameters;
725
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);
729
730 for (qsizetype i = 0; i < count; ++i) {
731 if (i > 0)
732 parameters += QLatin1Char(',');
733 const QByteArray &param = parameterNameList.at(i);
734 if (param.isEmpty()) {
735 unnamedParameter = true;
736 } else if (unnamedParameter) {
737 if (errorString)
738 *errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
739 return QString();
740 } else if (QV4::Compiler::Codegen::isNameGlobal(param)) {
741 if (errorString)
742 *errorString = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
743 return QString();
744 }
745 parameters += QString::fromUtf8(param);
746 }
747
748 return parameters;
749}
750
751int QQmlPropertyCache::originalClone(int index) const
752{
753 while (signal(index)->isCloned())
754 --index;
755 return index;
756}
757
758int QQmlPropertyCache::originalClone(const QObject *object, int index)
759{
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()) {
765 --index;
766 sig = cache->signal(index);
767 }
768 } else {
769 while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
770 --index;
771 }
772 return index;
773}
774
775template<typename T>
776static QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const T& propertyName)
777{
778 Q_ASSERT(metaObject);
779
780 QQmlPropertyData rv;
781
782 /* It's important to check the method list before checking for properties;
783 * otherwise, if the meta object is dynamic, a property will be created even
784 * if not found and it might obscure a method having the same name. */
785
786 //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
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()");
790 // These indices don't apply to gadgets, so don't block them.
791 const bool preventDestruction = metaObject->superClass() || metaObject == &QObject::staticMetaObject;
792
793 int methodCount = metaObject->methodCount();
794 for (int ii = methodCount - 1; ii >= 0; --ii) {
795 if (preventDestruction && (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx))
796 continue;
797 QMetaMethod m = metaObject->method(ii);
798 if (m.access() == QMetaMethod::Private)
799 continue;
800
801 if (m.name() == propertyName) {
802 rv.load(m);
803 return rv;
804 }
805 }
806
807 {
808 const QMetaObject *cmo = metaObject;
809 while (cmo) {
810 int idx = cmo->indexOfProperty(propertyName);
811 if (idx != -1) {
812 QMetaProperty p = cmo->property(idx);
813 if (p.isScriptable()) {
814 rv.load(p);
815 return rv;
816 } else {
817 bool changed = false;
818 while (cmo && cmo->propertyOffset() >= idx) {
819 cmo = cmo->superClass();
820 changed = true;
821 }
822 /* If the "cmo" variable didn't change, set it to 0 to
823 * avoid running into an infinite loop */
824 if (!changed) cmo = nullptr;
825 }
826 } else {
827 cmo = nullptr;
828 }
829 }
830 }
831 return rv;
832}
833
834static inline const char *qQmlPropertyCacheToString(QLatin1String string)
835{
836 return string.data();
837}
838
839static inline QByteArray qQmlPropertyCacheToString(QStringView string)
840{
841 return string.toUtf8();
842}
843
844static inline QByteArray qQmlPropertyCacheToString(const QV4::String *string)
845{
846 return string->toQString().toUtf8();
847}
848
849template<typename T>
850const QQmlPropertyData *
851qQmlPropertyCacheProperty(QObject *obj, T name, const QQmlRefPointer<QQmlContextData> &context,
852 QQmlPropertyData *local)
853{
854 const QQmlPropertyCache *cache = nullptr;
855
856 QQmlData *ddata = QQmlData::get(obj, false);
857
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);
864 }
865
866 const QQmlPropertyData *rv = nullptr;
867
868 if (cache) {
869 rv = cache->property(name, obj, context);
870 } else if (local) {
871 *local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
872 if (local->isValid())
873 rv = local;
874 }
875
876 return rv;
877}
878
879const QQmlPropertyData *QQmlPropertyCache::property(
880 QObject *obj, const QV4::String *name, const QQmlRefPointer<QQmlContextData> &context,
881 QQmlPropertyData *local)
882{
883 return qQmlPropertyCacheProperty<const QV4::String *>(obj, name, context, local);
884}
885
886const QQmlPropertyData *QQmlPropertyCache::property(
887 QObject *obj, QStringView name, const QQmlRefPointer<QQmlContextData> &context,
888 QQmlPropertyData *local)
889{
890 return qQmlPropertyCacheProperty<const QStringView &>(obj, name, context, local);
891}
892
893const QQmlPropertyData *QQmlPropertyCache::property(
894 QObject *obj, const QLatin1String &name, const QQmlRefPointer<QQmlContextData> &context,
895 QQmlPropertyData *local)
896{
897 return qQmlPropertyCacheProperty<const QLatin1String &>(obj, name, context, local);
898}
899
900// this function is copied from qmetaobject.cpp
901static inline const QByteArray stringData(const QMetaObject *mo, int index)
902{
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);
907}
908
909const char *QQmlPropertyCache::className() const
910{
911 if (const QMetaObject *mo = _metaObject.metaObject())
912 return mo->className();
913 else
914 return _dynamicClassName.constData();
915}
916
917void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) const
918{
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();
922 } };
923
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())
929 return;
930
931 if (data->isFunction()) {
932 if (data->coreIndex() < This->methodIndexCacheStart)
933 return;
934
935 std::pair<QString, const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
936 // Overrides can cause the entry to already exist
937 if (!methods.contains(entry)) methods.append(entry);
938
939 data = This->overrideData(data);
940 if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
941 } else {
942 if (data->coreIndex() < This->propertyIndexCacheStart)
943 return;
944
945 std::pair<QString, const QQmlPropertyData *> entry = std::make_pair((QString)iter.key(), data);
946 // Overrides can cause the entry to already exist
947 if (!properties.contains(entry)) properties.append(entry);
948
949 data = This->overrideData(data);
950 if (data) Insert::in(This, properties, methods, iter, data);
951 }
952
953 } };
954
955 builder.setClassName(_dynamicClassName);
956
957 QList<std::pair<QString, const QQmlPropertyData *> > properties;
958 QList<std::pair<QString, const QQmlPropertyData *> > methods;
959
960 for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter)
961 Insert::in(this, properties, methods, iter, iter.value().second);
962
963 // Any invalid overrides are not linked by name into the properties and methods hashes.
964 // Therefore there can be more properties and methods than present in the hashes.
965 Q_ASSERT(properties.size() <= propertyIndexCache.size());
966 Q_ASSERT(methods.size() <= methodIndexCache.size());
967
968 std::sort(properties.begin(), properties.end(), Sort::lt);
969 std::sort(methods.begin(), methods.end(), Sort::lt);
970
971 for (int ii = 0; ii < properties.size(); ++ii) {
972 const QQmlPropertyData *data = properties.at(ii).second;
973
974 int notifierId = -1;
975 if (data->notifyIndex() != -1)
976 notifierId = data->notifyIndex() - signalHandlerIndexCacheStart;
977
978 QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
979 data->propType().name(),
980 data->propType(),
981 notifierId);
982
983 property.setReadable(true);
984 property.setWritable(data->isWritable());
985 property.setResettable(data->isResettable());
986 property.setBindable(data->notifiesViaBindable());
987 property.setAlias(data->isAlias());
988 }
989
990 for (int ii = 0; ii < methods.size(); ++ii) {
991 const QQmlPropertyData *data = methods.at(ii).second;
992
993 QByteArray returnType;
994 if (data->propType().isValid())
995 returnType = data->propType().name();
996
997 QByteArray signature;
998 // '+=' reserves extra capacity. Follow-up appending will be probably free.
999 signature += methods.at(ii).first.toUtf8() + '(';
1000
1001 QQmlPropertyCacheMethodArguments *arguments = nullptr;
1002 if (data->hasArguments()) {
1003 arguments = data->arguments();
1004 for (int ii = 0, end = arguments->names ? arguments->names->size() : 0;
1005 ii < end; ++ii) {
1006 if (ii != 0)
1007 signature.append(',');
1008 signature.append(arguments->types[1 + ii].name());
1009 }
1010 }
1011
1012 signature.append(')');
1013
1014 QMetaMethodBuilder method;
1015 if (data->isSignal()) {
1016 method = builder.addSignal(signature);
1017 } else {
1018 method = builder.addSlot(signature);
1019 }
1020 method.setAccess(QMetaMethod::Public);
1021
1022 if (arguments && arguments->names)
1023 method.setParameterNames(*arguments->names);
1024
1025 if (!returnType.isEmpty())
1026 method.setReturnType(returnType);
1027 }
1028
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);
1036 }
1037 }
1038
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());
1044 }
1045 }
1046
1047 if (!_listPropertyAssignBehavior.isEmpty())
1048 builder.addClassInfo("QML.ListPropertyAssignBehavior", _listPropertyAssignBehavior);
1049}
1050
1051namespace {
1052template <typename StringVisitor, typename TypeInfoVisitor>
1053int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount,
1054 StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1055{
1056 int fieldsForParameterData = 0;
1057
1058 bool hasOldStyleRevisionedMethods = false;
1059
1060 for (int i = 0; i < methodCount; ++i) {
1061 const int handle = methodOffset + i * QMetaObjectPrivate::IntsPerMethod;
1062
1063 const uint flags = mo.d.data[handle + 4];
1064 if (flags & MethodRevisioned) {
1065 if (mo.d.data[0] < 13)
1066 hasOldStyleRevisionedMethods = true;
1067 else
1068 fieldsForParameterData += 1; // revision
1069 }
1070
1071 visitString(mo.d.data[handle + 0]); // name
1072 visitString(mo.d.data[handle + 3]); // tag
1073
1074 const int argc = mo.d.data[handle + 1];
1075 const int paramIndex = mo.d.data[handle + 2];
1076
1077 fieldsForParameterData += argc * 2; // type and name
1078 fieldsForParameterData += 1; // + return type
1079
1080 // return type + args
1081 for (int i = 0; i < 1 + argc; ++i) {
1082 // type name (maybe)
1083 visitTypeInfo(mo.d.data[paramIndex + i]);
1084
1085 // parameter name
1086 if (i > 0)
1087 visitString(mo.d.data[paramIndex + argc + i]);
1088 }
1089 }
1090
1091 int fieldsForRevisions = 0;
1092 if (hasOldStyleRevisionedMethods)
1093 fieldsForRevisions = methodCount;
1094
1095 return methodCount * QMetaObjectPrivate::IntsPerMethod
1096 + fieldsForRevisions + fieldsForParameterData;
1097}
1098
1099template <typename StringVisitor, typename TypeInfoVisitor>
1100int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo)
1101{
1102 const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
1103
1104 for (int i = 0; i < priv->propertyCount; ++i) {
1105 const int handle = priv->propertyData + i * QMetaObjectPrivate::IntsPerProperty;
1106
1107 visitString(mo.d.data[handle]); // name
1108 visitTypeInfo(mo.d.data[handle + 1]);
1109 }
1110
1111 return priv->propertyCount * QMetaObjectPrivate::IntsPerProperty;
1112}
1113
1114template <typename StringVisitor>
1115int visitClassInfo(const QMetaObject &mo, StringVisitor visitString)
1116{
1117 const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
1118 const int intsPerClassInfo = 2;
1119
1120 for (int i = 0; i < priv->classInfoCount; ++i) {
1121 const int handle = priv->classInfoData + i * intsPerClassInfo;
1122
1123 visitString(mo.d.data[handle]); // key
1124 visitString(mo.d.data[handle + 1]); // value
1125 }
1126
1127 return priv->classInfoCount * intsPerClassInfo;
1128}
1129
1130template <typename StringVisitor>
1131int visitEnumerations(const QMetaObject &mo, StringVisitor visitString)
1132{
1133 const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
1134
1135 int fieldCount = priv->enumeratorCount * QMetaObjectPrivate::IntsPerEnum;
1136
1137 for (int i = 0; i < priv->enumeratorCount; ++i) {
1138 const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * QMetaObjectPrivate::IntsPerEnum;
1139
1140 const uint keyCount = enumeratorData[3];
1141 fieldCount += keyCount * 2;
1142
1143 visitString(enumeratorData[0]); // name
1144 visitString(enumeratorData[1]); // enum name
1145
1146 const uint keyOffset = enumeratorData[4];
1147
1148 for (uint j = 0; j < keyCount; ++j) {
1149 visitString(mo.d.data[keyOffset + 2 * j]);
1150 }
1151 }
1152
1153 return fieldCount;
1154}
1155
1156template <typename StringVisitor>
1157int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor)
1158{
1159 const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
1160
1161 const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) {
1162 if (typeInfo & IsUnresolvedType)
1163 stringVisitor(typeInfo & TypeNameIndexMask);
1164 };
1165
1166 int fieldCount = MetaObjectPrivateFieldCount;
1167
1168 fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor,
1169 typeInfoVisitor);
1170 fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor,
1171 typeInfoVisitor);
1172
1173 fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor);
1174 fieldCount += visitClassInfo(mo, stringVisitor);
1175 fieldCount += visitEnumerations(mo, stringVisitor);
1176
1177 return fieldCount;
1178}
1179
1180} // anonymous namespace
1181
1182static_assert(QMetaObjectPrivate::OutputRevision == 13, "Check and adjust determineMetaObjectSizes");
1183
1184bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount,
1185 int *stringCount)
1186{
1187 const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data);
1188 if (priv->revision != QMetaObjectPrivate::OutputRevision)
1189 return false;
1190
1191 uint highestStringIndex = 0;
1192 const auto stringIndexVisitor = [&highestStringIndex](uint index) {
1193 highestStringIndex = qMax(highestStringIndex, index);
1194 };
1195
1196 *fieldCount = countMetaObjectFields(mo, stringIndexVisitor);
1197 *stringCount = highestStringIndex + 1;
1198
1199 return true;
1200}
1201
1202bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo)
1203{
1204 int fieldCount = 0;
1205 int stringCount = 0;
1206 if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) {
1207 return false;
1208 }
1209
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));
1213 }
1214
1215 return true;
1216}
1217
1218QByteArray QQmlPropertyCache::checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const
1219{
1220 auto it = checksums->constFind(quintptr(this));
1221 if (it != checksums->constEnd()) {
1222 *ok = true;
1223 return *it;
1224 }
1225
1226 // Generate a checksum on the meta-object data only on C++ types.
1227 if (_metaObject.isShared()) {
1228 *ok = false;
1229 return QByteArray();
1230 }
1231
1232 QCryptographicHash hash(QCryptographicHash::Md5);
1233
1234 if (_parent) {
1235 hash.addData(_parent->checksum(checksums, ok));
1236 if (!*ok)
1237 return QByteArray();
1238 }
1239
1240 if (!addToHash(hash, *_metaObject.metaObject())) {
1241 *ok = false;
1242 return QByteArray();
1243 }
1244
1245 const QByteArray result = hash.result();
1246 if (result.isEmpty()) {
1247 *ok = false;
1248 } else {
1249 *ok = true;
1250 checksums->insert(quintptr(this), result);
1251 }
1252 return result;
1253}
1254
1255/*! \internal
1256 \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
1257 This is different from QMetaMethod::methodIndex().
1258*/
1259QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
1260{
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();
1268 }
1269 return QList<QByteArray>();
1270}
1271
1272QT_END_NAMESPACE
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)
#define Q_INT16_MAX
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)