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
qqmlpropertydata_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 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// Qt-Security score:significant
4
5#ifndef QQMLPROPERTYDATA_P_H
6#define QQMLPROPERTYDATA_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <private/qobject_p.h>
20#include <QtCore/qglobal.h>
21#include <QtCore/qversionnumber.h>
22
23QT_BEGIN_NAMESPACE
24
25class QQmlPropertyCacheMethodArguments;
27{
28public:
35 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
36
38
39 struct Flags {
40 friend class QQmlPropertyData;
41 enum Type {
43 FunctionType = 1, // Is an invokable
44 QObjectDerivedType = 2, // Property type is a QObject* derived type
45 EnumType = 3, // Property type is an enum
46 QListType = 4, // Property type is a QML list
47 VarPropertyType = 5, // Property type is a "var" property of VMEMO
48 QVariantType = 6, // Property is a QVariant
49 ComponentWrapperType = 7, // Synthetic property wrapping a child object into a Component
50 };
51
52 private:
53 // The _otherBits (which "pad" the Flags struct to align it nicely) are used
54 // to store the relative property index. It will only get used when said index fits. See
55 // trySetStaticMetaCallFunction for details.
56 // (Note: this padding is done here, because certain compilers have surprising behavior
57 // when an enum is declared in-between two bit fields.)
58 enum { BitsLeftInFlags = 14 };
59 unsigned otherBits : BitsLeftInFlags; // align to 32 bits
60
61 // Members of the form aORb can only be a when type is not FunctionType, and only be
62 // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
63 // overloaded, and the accessor functions are used to get the correct value
64 //
65 // Moreover, isSignalHandler, isOverridableSignal and isCloned make only sense
66 // for functions, too (and could at a later point be reused for flags that only make sense
67 // for non-functions)
68 //
69 // Lastly, isDirect and isOverridden apply to both functions and non-functions
70 unsigned isConst : 1; // Property: has CONST flag/Method: is const
71 unsigned isDeepAliasORisVMEFunction : 1; // Alias points into value type OR Function was added by QML
72 unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
73 unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
74 unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
75 unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4FunctionPtr args
76 unsigned isSignalHandler : 1; // Function is a signal handler
77
78 // TODO: Remove this once we can. Signals should not be overridable.
79 unsigned isOverridableSignal : 1; // Function is an overridable signal
80
81 unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
82 unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
83 unsigned isVirtual : 1; // Property: has VIRTUAL specifier
84 // This flag is named doesOverride to avoid potential misspell issues,
85 // that could be caused by naming it isOverriding or isOverride,
86 // since there is alread isOverriden flag
87 unsigned doesOverride : 1; // Property: has OVERRIDE specifier, overrides virtual property
88 unsigned isOverridden : 1; // Is overridden by a extension property
89 unsigned hasMetaObject : 1;
90 unsigned type : 3; // stores an entry of Types
91
92 // Internal QQmlPropertyCache flags
93 unsigned overrideIndexIsProperty : 1;
94
95 public:
96 inline Flags();
97 inline bool operator==(const Flags &other) const;
98 inline void copyPropertyTypeFlags(Flags from);
99
100 void setIsConstant(bool b) {
101 isConst = b;
102 }
103
104 void setIsWritable(bool b) {
105 Q_ASSERT(type != FunctionType);
106 isWritableORhasArguments = b;
107 }
108
109 void setIsResettable(bool b) {
110 Q_ASSERT(type != FunctionType);
111 isResettableORisSignal = b;
112 }
113
114 void setIsAlias(bool b) {
115 Q_ASSERT(type != FunctionType);
116 isAliasORisVMESignal = b;
117 }
118
119 void setIsDeepAlias(bool b) {
120 Q_ASSERT(type != FunctionType);
121 isDeepAliasORisVMEFunction = b;
122 }
123
124 void setIsFinal(bool b) {
125 Q_ASSERT(type != FunctionType);
126 isFinalORisV4Function = b;
127 }
128
129 void setIsVirtual(bool b) {
130 isVirtual = b;
131 }
132
133 void setDoesOverride(bool b) {
134 doesOverride = b;
135 }
136
137 void setIsOverridden(bool b) {
138 isOverridden = b;
139 }
140
141 void setIsBindable(bool b) {
142 Q_ASSERT(type != FunctionType);
143 isConstructorORisBindable = b;
144 }
145
146 void setIsRequired(bool b) {
147 Q_ASSERT(type != FunctionType);
148 isRequiredORisCloned = b;
149 }
150
151 void setIsVMEFunction(bool b) {
152 Q_ASSERT(type == FunctionType);
153 isDeepAliasORisVMEFunction = b;
154 }
155
156 void setHasArguments(bool b) {
157 Q_ASSERT(type == FunctionType);
158 isWritableORhasArguments = b;
159 }
160 void setIsSignal(bool b) {
161 Q_ASSERT(type == FunctionType);
162 isResettableORisSignal = b;
163 }
164 void setIsVMESignal(bool b) {
165 Q_ASSERT(type == FunctionType);
166 isAliasORisVMESignal = b;
167 }
168
169 void setIsV4Function(bool b) {
170 Q_ASSERT(type == FunctionType);
171 isFinalORisV4Function = b;
172 }
173
174 void setIsSignalHandler(bool b) {
175 Q_ASSERT(type == FunctionType);
176 isSignalHandler = b;
177 }
178
179 // TODO: Remove this once we can. Signals should not be overridable.
181 Q_ASSERT(type == FunctionType);
182 Q_ASSERT(isResettableORisSignal);
183 isOverridableSignal = b;
184 }
185
186 void setIsCloned(bool b) {
187 Q_ASSERT(type == FunctionType);
188 isRequiredORisCloned = b;
189 }
190
191 void setIsConstructor(bool b) {
192 Q_ASSERT(type == FunctionType);
193 isConstructorORisBindable = b;
194 }
195
196 void setHasMetaObject(bool b) {
197 hasMetaObject = b;
198 }
199
200 void setType(Type newType) {
201 type = newType;
202 }
203 };
204
205
206 inline bool operator==(const QQmlPropertyData &) const;
207
208 Flags flags() const { return m_flags; }
210 {
211 unsigned otherBits = m_flags.otherBits;
212 m_flags = f;
213 m_flags.otherBits = otherBits;
214 }
215
216 bool isValid() const { return coreIndex() != -1; }
217
218 bool isConstant() const { return m_flags.isConst; }
219 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
220 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
221 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
222 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
223 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
224 bool isVirtual() const { return m_flags.isVirtual; }
225 bool doesOverride() const { return m_flags.doesOverride; }
226 bool isOverridden() const { return m_flags.isOverridden; }
227 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
228 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
229 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
230 bool isEnum() const { return m_flags.type == Flags::EnumType; }
231 bool isQList() const { return m_flags.type == Flags::QListType; }
232 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
233 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
234 bool isComponentWrapper() const { return m_flags.type == Flags::ComponentWrapperType; }
235 bool isVMEFunction() const { return isFunction() && m_flags.isDeepAliasORisVMEFunction; }
236 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
237 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
238 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
239 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
240 bool isSignalHandler() const { return m_flags.isSignalHandler; }
241 bool hasMetaObject() const { return m_flags.hasMetaObject; }
242
244 {
245 return !isAlias() && !isComponentWrapper() && staticMetaCallFunction() != nullptr;
246 }
247
248 // TODO: Remove this once we can. Signals should not be overridable.
249 bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
250
251 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
252 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
253
254 bool notifiesViaBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
255 bool acceptsQBinding() const { return notifiesViaBindable() && !m_flags.isDeepAliasORisVMEFunction; }
256
257 bool hasOverride() const { return overrideIndex() >= 0; }
258 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
259
260 QMetaType propType() const { return m_propType; }
261 void setPropType(QMetaType pt)
262 {
263 m_propType = pt;
264 }
265
266 int notifyIndex() const { return m_notifyIndex; }
267 void setNotifyIndex(int idx)
268 {
269 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
270 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
271 m_notifyIndex = qint16(idx);
272 }
273
274 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
275 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
276
277 int overrideIndex() const { return m_overrideIndex; }
278 void setOverrideIndex(int idx)
279 {
280 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
281 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
282 m_overrideIndex = qint16(idx);
283 }
284
285 int coreIndex() const { return m_coreIndex; }
286 void setCoreIndex(int idx)
287 {
288 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
289 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
290 m_coreIndex = qint16(idx);
291 }
292
293 int aliasTarget() const
294 {
295 Q_ASSERT(isAlias());
296 return m_encodedAliasTargetIndex;
297 }
298 void setAliasTarget(int target)
299 {
300 Q_ASSERT(isAlias());
301 m_encodedAliasTargetIndex = target;
302 }
303
305 {
306 Q_ASSERT(isAlias());
307 return m_metaObjectOffsetOrAliasTargetObjectId;
308 }
309
311 {
312 Q_ASSERT(isAlias());
313 Q_ASSERT(id >= std::numeric_limits<qint16>::min());
314 Q_ASSERT(id <= std::numeric_limits<qint16>::max());
315 m_metaObjectOffsetOrAliasTargetObjectId = id;
316 }
317
319 {
320 Q_ASSERT(isComponentWrapper());
321 return m_wrappedObjectIndex;
322 }
323 void setWrappedObjectIndex(int wrappedObjectIndex)
324 {
325 Q_ASSERT(isComponentWrapper());
326 m_wrappedObjectIndex = wrappedObjectIndex;
327 }
328
329 QTypeRevision revision() const { return m_revision; }
330 void setRevision(QTypeRevision revision) { m_revision = revision; }
331
332 /* If a property is a C++ type, then we store the minor
333 * version of this type.
334 * This is required to resolve property or signal revisions
335 * if this property is used as a grouped property.
336 *
337 * Test.qml
338 * property TextEdit someTextEdit: TextEdit {}
339 *
340 * Test {
341 * someTextEdit.preeditText: "test" //revision 7
342 * someTextEdit.onEditingFinished: console.log("test") //revision 6
343 * }
344 *
345 * To determine if these properties with revisions are available we need
346 * the minor version of TextEdit as imported in Test.qml.
347 *
348 */
349
350 QTypeRevision typeVersion() const { return m_typeVersion; }
351 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
352
354 {
355 Q_ASSERT(!hasMetaObject());
356 return m_arguments;
357 }
359 {
360 Q_ASSERT(!hasMetaObject());
361 m_arguments = args;
362 }
363
364 const QMetaObject *metaObject() const
365 {
366 Q_ASSERT(hasMetaObject());
367 return m_metaObject;
368 }
369
370 void setMetaObject(const QMetaObject *metaObject)
371 {
372 Q_ASSERT(!hasArguments() || !m_arguments);
373 m_flags.setHasMetaObject(true);
374 m_metaObject = metaObject;
375 }
376
378 {
379 Q_ASSERT(hasMetaObject());
380 Q_ASSERT(isFunction());
381 return m_metaObject->method(m_coreIndex);
382 }
383
385 {
386 Q_ASSERT(!isAlias());
387 return m_metaObjectOffsetOrAliasTargetObjectId;
388 }
389
391 {
392 Q_ASSERT(!isAlias());
393 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
394 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
395 m_metaObjectOffsetOrAliasTargetObjectId = qint16(off);
396 }
397
399 {
400 Q_ASSERT(!isFunction() && !isAlias());
401 return m_staticMetaCallFunction;
402 }
403
404 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
405 {
406 Q_ASSERT(!isFunction() && !isAlias());
407 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
408 m_flags.otherBits = relativePropertyIndex;
409 m_staticMetaCallFunction = f;
410 }
411 }
412 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
413
414 static Flags flagsForProperty(const QMetaProperty &);
415 void load(const QMetaProperty &);
416 void load(const QMetaMethod &);
417
418 QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
419 QString name(const QMetaObject *metaObject) const
420 {
421 if (!metaObject || m_coreIndex == -1)
422 return QString();
423
424 return QString::fromUtf8(isFunction()
425 ? metaObject->method(m_coreIndex).name().constData()
426 : metaObject->property(m_coreIndex).name());
427 }
428
429 void markAsOverrideOf(QQmlPropertyData *predecessor);
430
431 inline void readProperty(QObject *target, void *property) const
432 {
433 void *args[] = { property, nullptr };
434 readPropertyWithArgs(target, args);
435 }
436
437 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
438 // And we ignore the return value.
439 template<QMetaObject::Call call>
440 void doMetacall(QObject *object, int idx, void **argv) const
441 {
442 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
443 dynamicMetaObject->metaCall(object, call, idx, argv);
444 else
445 object->qt_metacall(call, idx, argv);
446 }
447
448 void readPropertyWithArgs(QObject *target, void *args[]) const
449 {
450 if (hasStaticMetaCallFunction())
451 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
452 else
453 doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
454 }
455
456 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
457 {
458 int status = -1;
459 void *argv[] = { value, nullptr, &status, &flags };
460 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
461 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
462 else
463 doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
464 return true;
465 }
466
467 bool resetProperty(QObject *target, WriteFlags flags) const
468 {
469 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
470 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
471 else
472 doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
473 return true;
474 }
475
476 QUntypedBindable propertyBindable(QObject *target) const
477 {
478 QUntypedBindable result;
479 void *argv[] = { &result };
480 if (hasStaticMetaCallFunction())
481 staticMetaCallFunction()(target, QMetaObject::BindableProperty, relativePropertyIndex(), argv);
482 else
483 doMetacall<QMetaObject::BindableProperty>(target, coreIndex(), argv);
484 return result;
485 }
486
488 {
489 Flags f;
491 f.setIsSignal(true);
493 return f;
494 }
495
497 {
498 Flags f;
501 return f;
502 }
503
504private:
505 friend class QQmlPropertyCache;
506
507 Flags m_flags;
508 qint16 m_coreIndex = -1;
509
510 // The notify index is in the range returned by QObjectPrivate::signalIndex().
511 // This is different from QMetaMethod::methodIndex().
512 qint16 m_notifyIndex = -1;
513 qint16 m_overrideIndex = -1;
514
515 qint16 m_metaObjectOffsetOrAliasTargetObjectId = -1;
516
517 QTypeRevision m_revision = QTypeRevision::zero();
518 QTypeRevision m_typeVersion = QTypeRevision::zero();
519
520 QMetaType m_propType = {};
521
522 union {
523 // only for methods (if stored in property cache)
525
526 // only for C++-declared properties
528
529 // only for methods (if stored in lookups)
531
532 // only for aliases
534
535 // only for implicit components
537 };
538};
539
540#if QT_POINTER_SIZE == 4
541 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
542#else // QT_POINTER_SIZE == 8
544#endif
545
546static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
547
548bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
549{
550 return flags() == other.flags() &&
551 propType() == other.propType() &&
552 coreIndex() == other.coreIndex() &&
553 notifyIndex() == other.notifyIndex() &&
554 revision() == other.revision();
555}
556
558 : otherBits(0),
559 isConst(false),
560 isDeepAliasORisVMEFunction(false),
561 isWritableORhasArguments(false),
562 isResettableORisSignal(false),
563 isAliasORisVMESignal(false),
564 isFinalORisV4Function(false),
565 isSignalHandler(false),
566 isOverridableSignal(false),
567 isRequiredORisCloned(false),
568 isConstructorORisBindable(false),
569 isVirtual(false),
570 doesOverride(false),
571 isOverridden(false),
572 hasMetaObject(false),
573 type(OtherType),
574 overrideIndexIsProperty(false)
575{
576}
577
579{
580 return isConst == other.isConst
581 && isDeepAliasORisVMEFunction == other.isDeepAliasORisVMEFunction
582 && isWritableORhasArguments == other.isWritableORhasArguments
583 && isResettableORisSignal == other.isResettableORisSignal
584 && isAliasORisVMESignal == other.isAliasORisVMESignal
585 && isFinalORisV4Function == other.isFinalORisV4Function && isVirtual == other.isVirtual
586 && doesOverride == other.doesOverride && isOverridden == other.isOverridden
587 && isSignalHandler == other.isSignalHandler
588 && isRequiredORisCloned == other.isRequiredORisCloned
589 && hasMetaObject == other.hasMetaObject && type == other.type
590 && isConstructorORisBindable == other.isConstructorORisBindable
591 && overrideIndexIsProperty == other.overrideIndexIsProperty;
592}
593
595{
596 switch (from.type) {
598 case EnumType:
599 case QListType:
600 case QVariantType:
601 type = from.type;
602 }
603}
604
605Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
606
607QT_END_NAMESPACE
608
609#endif // QQMLPROPERTYDATA_P_H
bool overrideIndexIsProperty() const
void readProperty(QObject *target, void *property) const
bool isResettable() const
bool isConstructor() const
bool isOverridden() const
int metaObjectOffset() const
bool isVarProperty() const
void readPropertyWithArgs(QObject *target, void *args[]) const
bool notifiesViaBindable() const
QMetaMethod metaMethod() const
QTypeRevision typeVersion() const
void setRevision(QTypeRevision revision)
bool writeProperty(QObject *target, void *value, WriteFlags flags) const
QTypeRevision revision() const
void setAliasTarget(int target)
bool isVMEFunction() const
bool doesOverride() const
void setNotifyIndex(int idx)
StaticMetaCallFunction m_staticMetaCallFunction
StaticMetaCallFunction staticMetaCallFunction() const
bool operator==(const QQmlPropertyData &) const
void setMetaObjectOffset(int off)
int aliasTargetObjectId() const
void setMetaObject(const QMetaObject *metaObject)
void setAliasTargetObjectId(int id)
bool hasArguments() const
QMetaType propType() const
bool isV4Function() const
QString name(const QMetaObject *metaObject) const
void doMetacall(QObject *object, int idx, void **argv) const
void setOverrideIndexIsProperty(bool onoff)
void setCoreIndex(int idx)
bool acceptsQBinding() const
void setArguments(QQmlPropertyCacheMethodArguments *args)
bool isComponentWrapper() const
void setPropType(QMetaType pt)
bool hasMetaObject() const
const QMetaObject * m_metaObject
void setOverrideIndex(int idx)
QUntypedBindable propertyBindable(QObject *target) const
QQmlPropertyCacheMethodArguments * arguments() const
void markAsOverrideOf(QQmlPropertyData *predecessor)
QQmlPropertyCacheMethodArguments * m_arguments
static Flags defaultSlotFlags()
void setWrappedObjectIndex(int wrappedObjectIndex)
void setWritable(bool onoff)
int wrappedObjectIndex() const
bool hasStaticMetaCallFunction() const
void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
static Flags defaultSignalFlags()
static Flags flagsForProperty(const QMetaProperty &)
void load(const QMetaProperty &)
bool resetProperty(QObject *target, WriteFlags flags) const
bool isSignalHandler() const
QString name(QObject *object) const
bool isOverridableSignal() const
void setTypeVersion(QTypeRevision typeVersion)
const QMetaObject * metaObject() const
quint16 relativePropertyIndex() const
Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4==0)
void copyPropertyTypeFlags(Flags from)
bool operator==(const Flags &other) const