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
4#ifndef QQMLPROPERTYDATA_P_H
5#define QQMLPROPERTYDATA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qobject_p.h>
19#include <QtCore/qglobal.h>
20#include <QtCore/qversionnumber.h>
21
22QT_BEGIN_NAMESPACE
23
24class QQmlPropertyCacheMethodArguments;
25class QQmlPropertyData
26{
27public:
28 enum WriteFlag {
29 BypassInterceptor = 0x01,
30 DontRemoveBinding = 0x02,
31 RemoveBindingOnAliasWrite = 0x04,
32 HasInternalIndex = 0x8,
33 };
34 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
35
36 typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
37
38 struct Flags {
39 friend class QQmlPropertyData;
40 enum Types {
41 OtherType = 0,
42 FunctionType = 1, // Is an invokable
43 QObjectDerivedType = 2, // Property type is a QObject* derived type
44 EnumType = 3, // Property type is an enum
45 QListType = 4, // Property type is a QML list
46 /*QmlBindingType = 5; was: Property type is a QQmlBinding*; now unused */
47 QJSValueType = 6, // Property type is a QScriptValue
48 // Gap, used to be V4HandleType
49 VarPropertyType = 8, // Property type is a "var" property of VMEMO
50 QVariantType = 9, // Property is a QVariant
51 ValueType = 10 // Property type is a custom value type
52 };
53
54 // The _otherBits (which "pad" the Flags struct to align it nicely) are used
55 // to store the relative property index. It will only get used when said index fits. See
56 // trySetStaticMetaCallFunction for details.
57 // (Note: this padding is done here, because certain compilers have surprising behavior
58 // when an enum is declared in-between two bit fields.)
59 enum { BitsLeftInFlags = 16 };
60 unsigned otherBits : BitsLeftInFlags; // align to 32 bits
61
62 // Members of the form aORb can only be a when type is not FunctionType, and only be
63 // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
64 // overloaded, and the accessor functions are used to get the correct value
65 //
66 // Moreover, isSignalHandler, isOverload and isCloned make only sense
67 // for functions, too (and could at a later point be reused for flags that only make sense
68 // for non-functions)
69 //
70 // Lastly, isDirect and isOverridden apply to both functions and non-functions
71 private:
72 unsigned isConst : 1; // Property: has CONST flag/Method: is const
73 unsigned isVMEFunction : 1; // Function was added by QML
74 unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
75 unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
76 unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
77 unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
78 unsigned isSignalHandler : 1; // Function is a signal handler
79 unsigned isOverload : 1; // Function is an overload of another function
80 unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
81 unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
82 unsigned isOverridden : 1; // Is overridden by a extension property
83 public:
84 unsigned type : 4; // stores an entry of Types
85
86 // Apply only to IsFunctions
87
88 // Internal QQmlPropertyCache flags
89 unsigned overrideIndexIsProperty: 1;
90
91 inline Flags();
92 inline bool operator==(const Flags &other) const;
93 inline void copyPropertyTypeFlags(Flags from);
94
95 void setIsConstant(bool b) {
96 isConst = b;
97 }
98
99 void setIsWritable(bool b) {
100 Q_ASSERT(type != FunctionType);
101 isWritableORhasArguments = b;
102 }
103
104 void setIsResettable(bool b) {
105 Q_ASSERT(type != FunctionType);
106 isResettableORisSignal = b;
107 }
108
109 void setIsAlias(bool b) {
110 Q_ASSERT(type != FunctionType);
111 isAliasORisVMESignal = b;
112 }
113
114 void setIsFinal(bool b) {
115 Q_ASSERT(type != FunctionType);
116 isFinalORisV4Function = b;
117 }
118
119 void setIsOverridden(bool b) {
120 isOverridden = b;
121 }
122
123 void setIsBindable(bool b) {
124 Q_ASSERT(type != FunctionType);
125 isConstructorORisBindable = b;
126 }
127
128 void setIsRequired(bool b) {
129 Q_ASSERT(type != FunctionType);
130 isRequiredORisCloned = b;
131 }
132
133 void setIsVMEFunction(bool b) {
134 Q_ASSERT(type == FunctionType);
135 isVMEFunction = b;
136 }
137 void setHasArguments(bool b) {
138 Q_ASSERT(type == FunctionType);
139 isWritableORhasArguments = b;
140 }
141 void setIsSignal(bool b) {
142 Q_ASSERT(type == FunctionType);
143 isResettableORisSignal = b;
144 }
145 void setIsVMESignal(bool b) {
146 Q_ASSERT(type == FunctionType);
147 isAliasORisVMESignal = b;
148 }
149
150 void setIsV4Function(bool b) {
151 Q_ASSERT(type == FunctionType);
152 isFinalORisV4Function = b;
153 }
154
155 void setIsSignalHandler(bool b) {
156 Q_ASSERT(type == FunctionType);
157 isSignalHandler = b;
158 }
159
160 void setIsOverload(bool b) {
161 Q_ASSERT(type == FunctionType);
162 isOverload = b;
163 }
164
165 void setIsCloned(bool b) {
166 Q_ASSERT(type == FunctionType);
167 isRequiredORisCloned = b;
168 }
169
170 void setIsConstructor(bool b) {
171 Q_ASSERT(type == FunctionType);
172 isConstructorORisBindable = b;
173 }
174
175 };
176
177
178 inline bool operator==(const QQmlPropertyData &) const;
179
180 Flags flags() const { return m_flags; }
181 void setFlags(Flags f)
182 {
183 unsigned otherBits = m_flags.otherBits;
184 m_flags = f;
185 m_flags.otherBits = otherBits;
186 }
187
188 bool isValid() const { return coreIndex() != -1; }
189
190 bool isConstant() const { return m_flags.isConst; }
191 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
192 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
193 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
194 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
195 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
196 bool isOverridden() const { return m_flags.isOverridden; }
197 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
198 bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
199 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
200 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
201 bool isEnum() const { return m_flags.type == Flags::EnumType; }
202 bool isQList() const { return m_flags.type == Flags::QListType; }
203 bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
204 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
205 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
206 bool isVMEFunction() const { return isFunction() && m_flags.isVMEFunction; }
207 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
208 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
209 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
210 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
211 bool isSignalHandler() const { return m_flags.isSignalHandler; }
212 bool isOverload() const { return m_flags.isOverload; }
213 void setOverload(bool onoff) { m_flags.isOverload = onoff; }
214 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
215 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
216 bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
217
218 bool hasOverride() const { return overrideIndex() >= 0; }
219 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
220
221 QMetaType propType() const { return m_propType; }
222 void setPropType(QMetaType pt)
223 {
224 m_propType = pt;
225 }
226
227 int notifyIndex() const { return m_notifyIndex; }
228 void setNotifyIndex(int idx)
229 {
230 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
231 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
232 m_notifyIndex = qint16(idx);
233 }
234
235 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
236 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
237
238 int overrideIndex() const { return m_overrideIndex; }
239 void setOverrideIndex(int idx)
240 {
241 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
242 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
243 m_overrideIndex = qint16(idx);
244 }
245
246 int coreIndex() const { return m_coreIndex; }
247 void setCoreIndex(int idx)
248 {
249 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
250 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
251 m_coreIndex = qint16(idx);
252 }
253
254 QTypeRevision revision() const { return m_revision; }
255 void setRevision(QTypeRevision revision) { m_revision = revision; }
256
257 /* If a property is a C++ type, then we store the minor
258 * version of this type.
259 * This is required to resolve property or signal revisions
260 * if this property is used as a grouped property.
261 *
262 * Test.qml
263 * property TextEdit someTextEdit: TextEdit {}
264 *
265 * Test {
266 * someTextEdit.preeditText: "test" //revision 7
267 * someTextEdit.onEditingFinished: console.log("test") //revision 6
268 * }
269 *
270 * To determine if these properties with revisions are available we need
271 * the minor version of TextEdit as imported in Test.qml.
272 *
273 */
274
275 QTypeRevision typeVersion() const { return m_typeVersion; }
276 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
277
278 QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
279 void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
280
281 int metaObjectOffset() const { return m_metaObjectOffset; }
282 void setMetaObjectOffset(int off)
283 {
284 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
285 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
286 m_metaObjectOffset = qint16(off);
287 }
288
289 StaticMetaCallFunction staticMetaCallFunction() const { Q_ASSERT(!isFunction()); return m_staticMetaCallFunction; }
290 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
291 {
292 Q_ASSERT(!isFunction());
293 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
294 m_flags.otherBits = relativePropertyIndex;
295 m_staticMetaCallFunction = f;
296 }
297 }
298 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
299
300 static Flags flagsForProperty(const QMetaProperty &);
301 void load(const QMetaProperty &);
302 void load(const QMetaMethod &);
303 QString name(QObject *) const;
304 QString name(const QMetaObject *) const;
305
306 bool markAsOverrideOf(QQmlPropertyData *predecessor);
307
308 inline void readProperty(QObject *target, void *property) const
309 {
310 void *args[] = { property, nullptr };
311 readPropertyWithArgs(target, args);
312 }
313
314 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
315 // And we ignore the return value.
316 template<QMetaObject::Call call>
317 void doMetacall(QObject *object, int idx, void **argv) const
318 {
319 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(o: object)->metaObject)
320 dynamicMetaObject->metaCall(object, call, id: idx, argv);
321 else
322 object->qt_metacall(call, idx, argv);
323 }
324
325 void readPropertyWithArgs(QObject *target, void *args[]) const
326 {
327 if (hasStaticMetaCallFunction())
328 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
329 else
330 doMetacall<QMetaObject::ReadProperty>(object: target, idx: coreIndex(), argv: args);
331 }
332
333 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
334 {
335 int status = -1;
336 void *argv[] = { value, nullptr, &status, &flags };
337 if (flags.testFlag(flag: BypassInterceptor) && hasStaticMetaCallFunction())
338 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
339 else
340 doMetacall<QMetaObject::WriteProperty>(object: target, idx: coreIndex(), argv);
341 return true;
342 }
343
344 bool resetProperty(QObject *target, WriteFlags flags) const
345 {
346 if (flags.testFlag(flag: BypassInterceptor) && hasStaticMetaCallFunction())
347 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
348 else
349 doMetacall<QMetaObject::ResetProperty>(object: target, idx: coreIndex(), argv: nullptr);
350 return true;
351 }
352
353 static Flags defaultSignalFlags()
354 {
355 Flags f;
356 f.type = Flags::FunctionType;
357 f.setIsSignal(true);
358 f.setIsVMESignal(true);
359 return f;
360 }
361
362 static Flags defaultSlotFlags()
363 {
364 Flags f;
365 f.type = Flags::FunctionType;
366 f.setIsVMEFunction(true);
367 return f;
368 }
369
370private:
371 friend class QQmlPropertyCache;
372
373 Flags m_flags;
374 qint16 m_coreIndex = -1;
375
376 // The notify index is in the range returned by QObjectPrivate::signalIndex().
377 // This is different from QMetaMethod::methodIndex().
378 qint16 m_notifyIndex = -1;
379 qint16 m_overrideIndex = -1;
380
381 qint16 m_metaObjectOffset = -1;
382
383 QTypeRevision m_revision = QTypeRevision::zero();
384 QTypeRevision m_typeVersion = QTypeRevision::zero();
385
386 QMetaType m_propType = {};
387
388 union {
389 QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
390 StaticMetaCallFunction m_staticMetaCallFunction;
391 };
392};
393
394#if QT_POINTER_SIZE == 4
395 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
396#else // QT_POINTER_SIZE == 8
397 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
398#endif
399
400static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
401
402bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
403{
404 return flags() == other.flags() &&
405 propType() == other.propType() &&
406 coreIndex() == other.coreIndex() &&
407 notifyIndex() == other.notifyIndex() &&
408 revision() == other.revision();
409}
410
411QQmlPropertyData::Flags::Flags()
412 : otherBits(0)
413 , isConst(false)
414 , isVMEFunction(false)
415 , isWritableORhasArguments(false)
416 , isResettableORisSignal(false)
417 , isAliasORisVMESignal(false)
418 , isFinalORisV4Function(false)
419 , isSignalHandler(false)
420 , isOverload(false)
421 , isRequiredORisCloned(false)
422 , isConstructorORisBindable(false)
423 , isOverridden(false)
424 , type(OtherType)
425 , overrideIndexIsProperty(false)
426{}
427
428bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
429{
430 return isConst == other.isConst &&
431 isVMEFunction == other.isVMEFunction &&
432 isWritableORhasArguments == other.isWritableORhasArguments &&
433 isResettableORisSignal == other.isResettableORisSignal &&
434 isAliasORisVMESignal == other.isAliasORisVMESignal &&
435 isFinalORisV4Function == other.isFinalORisV4Function &&
436 isOverridden == other.isOverridden &&
437 isSignalHandler == other.isSignalHandler &&
438 isRequiredORisCloned == other.isRequiredORisCloned &&
439 type == other.type &&
440 isConstructorORisBindable == other.isConstructorORisBindable &&
441 overrideIndexIsProperty == other.overrideIndexIsProperty;
442}
443
444void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
445{
446 switch (from.type) {
447 case QObjectDerivedType:
448 case EnumType:
449 case QListType:
450 case QJSValueType:
451 case QVariantType:
452 type = from.type;
453 }
454}
455
456Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
457
458QT_END_NAMESPACE
459
460#endif // QQMLPROPERTYDATA_P_H
461

source code of qtdeclarative/src/qml/qml/qqmlpropertydata_p.h