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 // One spot left for an extra type in the 3 bits used to store this.
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 isVMEFunction() const { return isFunction() && m_flags.isDeepAliasORisVMEFunction; }
235 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
236 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
237 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
238 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
239 bool isSignalHandler() const { return m_flags.isSignalHandler; }
240 bool hasMetaObject() const { return m_flags.hasMetaObject; }
241
243 {
244 return !isAlias() && staticMetaCallFunction() != nullptr;
245 }
246
247 // TODO: Remove this once we can. Signals should not be overridable.
248 bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
249
250 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
251 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
252
253 bool notifiesViaBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
254 bool acceptsQBinding() const { return notifiesViaBindable() && !m_flags.isDeepAliasORisVMEFunction; }
255
256 bool hasOverride() const { return overrideIndex() >= 0; }
257 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
258
259 QMetaType propType() const { return m_propType; }
260 void setPropType(QMetaType pt)
261 {
262 m_propType = pt;
263 }
264
265 int notifyIndex() const { return m_notifyIndex; }
266 void setNotifyIndex(int idx)
267 {
268 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
269 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
270 m_notifyIndex = qint16(idx);
271 }
272
273 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
274 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
275
276 int overrideIndex() const { return m_overrideIndex; }
277 void setOverrideIndex(int idx)
278 {
279 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
280 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
281 m_overrideIndex = qint16(idx);
282 }
283
284 int coreIndex() const { return m_coreIndex; }
285 void setCoreIndex(int idx)
286 {
287 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
288 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
289 m_coreIndex = qint16(idx);
290 }
291
292 int aliasTarget() const
293 {
294 Q_ASSERT(isAlias());
295 return m_encodedAliasTargetIndex;
296 }
297 void setAliasTarget(int target)
298 {
299 Q_ASSERT(isAlias());
300 m_encodedAliasTargetIndex = target;
301 }
302
304 {
305 Q_ASSERT(isAlias());
306 return m_metaObjectOffsetOrAliasTargetObjectId;
307 }
308
310 {
311 Q_ASSERT(isAlias());
312 Q_ASSERT(id >= std::numeric_limits<qint16>::min());
313 Q_ASSERT(id <= std::numeric_limits<qint16>::max());
314 m_metaObjectOffsetOrAliasTargetObjectId = id;
315 }
316
317 QTypeRevision revision() const { return m_revision; }
318 void setRevision(QTypeRevision revision) { m_revision = revision; }
319
320 /* If a property is a C++ type, then we store the minor
321 * version of this type.
322 * This is required to resolve property or signal revisions
323 * if this property is used as a grouped property.
324 *
325 * Test.qml
326 * property TextEdit someTextEdit: TextEdit {}
327 *
328 * Test {
329 * someTextEdit.preeditText: "test" //revision 7
330 * someTextEdit.onEditingFinished: console.log("test") //revision 6
331 * }
332 *
333 * To determine if these properties with revisions are available we need
334 * the minor version of TextEdit as imported in Test.qml.
335 *
336 */
337
338 QTypeRevision typeVersion() const { return m_typeVersion; }
339 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
340
342 {
343 Q_ASSERT(!hasMetaObject());
344 return m_arguments;
345 }
347 {
348 Q_ASSERT(!hasMetaObject());
349 m_arguments = args;
350 }
351
352 const QMetaObject *metaObject() const
353 {
354 Q_ASSERT(hasMetaObject());
355 return m_metaObject;
356 }
357
358 void setMetaObject(const QMetaObject *metaObject)
359 {
360 Q_ASSERT(!hasArguments() || !m_arguments);
361 m_flags.setHasMetaObject(true);
362 m_metaObject = metaObject;
363 }
364
366 {
367 Q_ASSERT(hasMetaObject());
368 Q_ASSERT(isFunction());
369 return m_metaObject->method(m_coreIndex);
370 }
371
373 {
374 Q_ASSERT(!isAlias());
375 return m_metaObjectOffsetOrAliasTargetObjectId;
376 }
377
379 {
380 Q_ASSERT(!isAlias());
381 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
382 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
383 m_metaObjectOffsetOrAliasTargetObjectId = qint16(off);
384 }
385
387 {
388 Q_ASSERT(!isFunction() && !isAlias());
389 return m_staticMetaCallFunction;
390 }
391
392 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
393 {
394 Q_ASSERT(!isFunction() && !isAlias());
395 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
396 m_flags.otherBits = relativePropertyIndex;
397 m_staticMetaCallFunction = f;
398 }
399 }
400 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
401
402 static Flags flagsForProperty(const QMetaProperty &);
403 void load(const QMetaProperty &);
404 void load(const QMetaMethod &);
405
406 QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
407 QString name(const QMetaObject *metaObject) const
408 {
409 if (!metaObject || m_coreIndex == -1)
410 return QString();
411
412 return QString::fromUtf8(isFunction()
413 ? metaObject->method(m_coreIndex).name().constData()
414 : metaObject->property(m_coreIndex).name());
415 }
416
417 void markAsOverrideOf(QQmlPropertyData *predecessor);
418
419 inline void readProperty(QObject *target, void *property) const
420 {
421 void *args[] = { property, nullptr };
422 readPropertyWithArgs(target, args);
423 }
424
425 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
426 // And we ignore the return value.
427 template<QMetaObject::Call call>
428 void doMetacall(QObject *object, int idx, void **argv) const
429 {
430 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
431 dynamicMetaObject->metaCall(object, call, idx, argv);
432 else
433 object->qt_metacall(call, idx, argv);
434 }
435
436 void readPropertyWithArgs(QObject *target, void *args[]) const
437 {
438 if (hasStaticMetaCallFunction())
439 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
440 else
441 doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
442 }
443
444 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
445 {
446 int status = -1;
447 void *argv[] = { value, nullptr, &status, &flags };
448 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
449 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
450 else
451 doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
452 return true;
453 }
454
455 bool resetProperty(QObject *target, WriteFlags flags) const
456 {
457 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
458 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
459 else
460 doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
461 return true;
462 }
463
464 QUntypedBindable propertyBindable(QObject *target) const
465 {
466 QUntypedBindable result;
467 void *argv[] = { &result };
468 if (hasStaticMetaCallFunction())
469 staticMetaCallFunction()(target, QMetaObject::BindableProperty, relativePropertyIndex(), argv);
470 else
471 doMetacall<QMetaObject::BindableProperty>(target, coreIndex(), argv);
472 return result;
473 }
474
476 {
477 Flags f;
479 f.setIsSignal(true);
481 return f;
482 }
483
485 {
486 Flags f;
489 return f;
490 }
491
492private:
493 friend class QQmlPropertyCache;
494
495 Flags m_flags;
496 qint16 m_coreIndex = -1;
497
498 // The notify index is in the range returned by QObjectPrivate::signalIndex().
499 // This is different from QMetaMethod::methodIndex().
500 qint16 m_notifyIndex = -1;
501 qint16 m_overrideIndex = -1;
502
503 qint16 m_metaObjectOffsetOrAliasTargetObjectId = -1;
504
505 QTypeRevision m_revision = QTypeRevision::zero();
506 QTypeRevision m_typeVersion = QTypeRevision::zero();
507
508 QMetaType m_propType = {};
509
510 union {
511 // only for methods (if stored in property cache)
513
514 // only for C++-declared properties
516
517 // only for methods (if stored in lookups)
519
520 // only for aliases
522 };
523};
524
525#if QT_POINTER_SIZE == 4
526 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
527#else // QT_POINTER_SIZE == 8
529#endif
530
531static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
532
533bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
534{
535 return flags() == other.flags() &&
536 propType() == other.propType() &&
537 coreIndex() == other.coreIndex() &&
538 notifyIndex() == other.notifyIndex() &&
539 revision() == other.revision();
540}
541
543 : otherBits(0),
544 isConst(false),
545 isDeepAliasORisVMEFunction(false),
546 isWritableORhasArguments(false),
547 isResettableORisSignal(false),
548 isAliasORisVMESignal(false),
549 isFinalORisV4Function(false),
550 isSignalHandler(false),
551 isOverridableSignal(false),
552 isRequiredORisCloned(false),
553 isConstructorORisBindable(false),
554 isVirtual(false),
555 doesOverride(false),
556 isOverridden(false),
557 hasMetaObject(false),
558 type(OtherType),
559 overrideIndexIsProperty(false)
560{
561}
562
564{
565 return isConst == other.isConst
566 && isDeepAliasORisVMEFunction == other.isDeepAliasORisVMEFunction
567 && isWritableORhasArguments == other.isWritableORhasArguments
568 && isResettableORisSignal == other.isResettableORisSignal
569 && isAliasORisVMESignal == other.isAliasORisVMESignal
570 && isFinalORisV4Function == other.isFinalORisV4Function && isVirtual == other.isVirtual
571 && doesOverride == other.doesOverride && isOverridden == other.isOverridden
572 && isSignalHandler == other.isSignalHandler
573 && isRequiredORisCloned == other.isRequiredORisCloned
574 && hasMetaObject == other.hasMetaObject && type == other.type
575 && isConstructorORisBindable == other.isConstructorORisBindable
576 && overrideIndexIsProperty == other.overrideIndexIsProperty;
577}
578
580{
581 switch (from.type) {
583 case EnumType:
584 case QListType:
585 case QVariantType:
586 type = from.type;
587 }
588}
589
590Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
591
592QT_END_NAMESPACE
593
594#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)
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 setWritable(bool onoff)
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