1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QQMLPROPERTYDATA_P_H
41 #define QQMLPROPERTYDATA_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <private/qobject_p.h>
55 #include <QtCore/qglobal.h>
56 
57 QT_BEGIN_NAMESPACE
58 
59 class QQmlPropertyCacheMethodArguments;
60 class QQmlPropertyData
61 {
62 public:
63     enum WriteFlag {
64         BypassInterceptor = 0x01,
65         DontRemoveBinding = 0x02,
66         RemoveBindingOnAliasWrite = 0x04
67     };
68     Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
69 
70     typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
71 
72     struct Flags {
73         friend class QQmlPropertyData;
74         enum Types {
75             OtherType            = 0,
76             FunctionType         = 1, // Is an invokable
77             QObjectDerivedType   = 2, // Property type is a QObject* derived type
78             EnumType             = 3, // Property type is an enum
79             QListType            = 4, // Property type is a QML list
80             QmlBindingType       = 5, // Property type is a QQmlBinding*
81             QJSValueType         = 6, // Property type is a QScriptValue
82                                       // Gap, used to be V4HandleType
83             VarPropertyType      = 8, // Property type is a "var" property of VMEMO
84             QVariantType         = 9  // Property is a QVariant
85         };
86 
87         // The _otherBits (which "pad" the Flags struct to align it nicely) are used
88         // to store the relative property index. It will only get used when said index fits. See
89         // trySetStaticMetaCallFunction for details.
90         // (Note: this padding is done here, because certain compilers have surprising behavior
91         // when an enum is declared in-between two bit fields.)
92         enum { BitsLeftInFlags = 15 };
93         unsigned otherBits       : BitsLeftInFlags; // align to 32 bits
94 
95         // Members of the form aORb can only be a when type is not FunctionType, and only be
96         // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
97         // overloaded, and the accessor functions are used to get the correct value
98         //
99         // Moreover, isSignalHandler, isOverload and isCloned and isConstructor make only sense
100         // for functions, too (and could at a later point be reused for flags that only make sense
101         // for non-functions)
102         //
103         // Lastly, isDirect and isOverridden apply to both functions and non-functions
104     private:
105         unsigned isConstantORisVMEFunction     : 1; // Has CONST flag OR Function was added by QML
106         unsigned isWritableORhasArguments      : 1; // Has WRITE function OR Function takes arguments
107         unsigned isResettableORisSignal        : 1; // Has RESET function OR Function is a signal
108         unsigned isAliasORisVMESignal          : 1; // Is a QML alias to another property OR Signal was added by QML
109         unsigned isFinalORisV4Function         : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
110         unsigned isSignalHandler               : 1; // Function is a signal handler
111         unsigned isOverload                    : 1; // Function is an overload of another function
112         unsigned isRequiredORisCloned          : 1; // Has REQUIRED flag OR The function was marked as cloned
113         unsigned isConstructor                 : 1; // The function was marked is a constructor
114         unsigned isDirect                      : 1; // Exists on a C++ QMetaObject
115         unsigned isOverridden                  : 1; // Is overridden by a extension property
116     public:
117         unsigned type             : 4; // stores an entry of Types
118 
119         // Apply only to IsFunctions
120 
121         // Internal QQmlPropertyCache flags
122         unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
123         unsigned overrideIndexIsProperty: 1;
124 
125         inline Flags();
126         inline bool operator==(const Flags &other) const;
127         inline void copyPropertyTypeFlags(Flags from);
128 
setIsConstantFlags129         void setIsConstant(bool b) {
130             Q_ASSERT(type != FunctionType);
131             isConstantORisVMEFunction = b;
132         }
133 
setIsWritableFlags134         void setIsWritable(bool b) {
135             Q_ASSERT(type != FunctionType);
136             isWritableORhasArguments = b;
137         }
138 
setIsResettableFlags139         void setIsResettable(bool b) {
140             Q_ASSERT(type != FunctionType);
141             isResettableORisSignal = b;
142         }
143 
setIsAliasFlags144         void setIsAlias(bool b) {
145             Q_ASSERT(type != FunctionType);
146             isAliasORisVMESignal = b;
147         }
148 
setIsFinalFlags149         void setIsFinal(bool b) {
150             Q_ASSERT(type != FunctionType);
151             isFinalORisV4Function = b;
152         }
153 
setIsOverriddenFlags154         void setIsOverridden(bool b) {
155             isOverridden = b;
156         }
157 
setIsDirectFlags158         void setIsDirect(bool b) {
159             isDirect = b;
160         }
161 
setIsRequiredFlags162         void setIsRequired(bool b) {
163             Q_ASSERT(type != FunctionType);
164             isRequiredORisCloned = b;
165         }
166 
setIsVMEFunctionFlags167         void setIsVMEFunction(bool b) {
168             Q_ASSERT(type == FunctionType);
169             isConstantORisVMEFunction = b;
170         }
setHasArgumentsFlags171         void setHasArguments(bool b) {
172             Q_ASSERT(type == FunctionType);
173             isWritableORhasArguments = b;
174         }
setIsSignalFlags175         void setIsSignal(bool b) {
176             Q_ASSERT(type == FunctionType);
177             isResettableORisSignal = b;
178         }
setIsVMESignalFlags179         void setIsVMESignal(bool b) {
180             Q_ASSERT(type == FunctionType);
181             isAliasORisVMESignal = b;
182         }
183 
setIsV4FunctionFlags184         void setIsV4Function(bool b) {
185             Q_ASSERT(type == FunctionType);
186             isFinalORisV4Function = b;
187         }
188 
setIsSignalHandlerFlags189         void setIsSignalHandler(bool b) {
190             Q_ASSERT(type == FunctionType);
191             isSignalHandler = b;
192         }
193 
setIsOverloadFlags194         void setIsOverload(bool b) {
195             Q_ASSERT(type == FunctionType);
196             isOverload = b;
197         }
198 
setIsClonedFlags199         void setIsCloned(bool b) {
200             Q_ASSERT(type == FunctionType);
201             isRequiredORisCloned = b;
202         }
203 
setIsConstructorFlags204         void setIsConstructor(bool b) {
205             Q_ASSERT(type == FunctionType);
206             isConstructor = b;
207         }
208 
209     };
210 
211 
212     inline bool operator==(const QQmlPropertyData &) const;
213 
flags()214     Flags flags() const { return m_flags; }
setFlags(Flags f)215     void setFlags(Flags f)
216     {
217         unsigned otherBits = m_flags.otherBits;
218         m_flags = f;
219         m_flags.otherBits = otherBits;
220     }
221 
isValid()222     bool isValid() const { return coreIndex() != -1; }
223 
isConstant()224     bool isConstant() const { return !isFunction() && m_flags.isConstantORisVMEFunction; }
isWritable()225     bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
setWritable(bool onoff)226     void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
isResettable()227     bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
isAlias()228     bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
isFinal()229     bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
isOverridden()230     bool isOverridden() const { return m_flags.isOverridden; }
isDirect()231     bool isDirect() const { return m_flags.isDirect; }
isRequired()232     bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
hasStaticMetaCallFunction()233     bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
isFunction()234     bool isFunction() const { return m_flags.type == Flags::FunctionType; }
isQObject()235     bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
isEnum()236     bool isEnum() const { return m_flags.type == Flags::EnumType; }
isQList()237     bool isQList() const { return m_flags.type == Flags::QListType; }
isQmlBinding()238     bool isQmlBinding() const { return m_flags.type == Flags::QmlBindingType; }
isQJSValue()239     bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
isVarProperty()240     bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
isQVariant()241     bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
isVMEFunction()242     bool isVMEFunction() const { return isFunction() && m_flags.isConstantORisVMEFunction; }
hasArguments()243     bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
isSignal()244     bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
isVMESignal()245     bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
isV4Function()246     bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
isSignalHandler()247     bool isSignalHandler() const { return m_flags.isSignalHandler; }
isOverload()248     bool isOverload() const { return m_flags.isOverload; }
setOverload(bool onoff)249     void setOverload(bool onoff) { m_flags.isOverload = onoff; }
isCloned()250     bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
isConstructor()251     bool isConstructor() const { return m_flags.isConstructor; }
252 
hasOverride()253     bool hasOverride() const { return overrideIndex() >= 0; }
hasRevision()254     bool hasRevision() const { return revision() != 0; }
255 
isFullyResolved()256     bool isFullyResolved() const { return !m_flags.notFullyResolved; }
257 
propType()258     int propType() const { Q_ASSERT(isFullyResolved()); return m_propType; }
setPropType(int pt)259     void setPropType(int pt)
260     {
261         Q_ASSERT(pt >= 0);
262         Q_ASSERT(pt <= std::numeric_limits<qint16>::max());
263         m_propType = quint16(pt);
264     }
265 
notifyIndex()266     int notifyIndex() const { return m_notifyIndex; }
setNotifyIndex(int idx)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 
overrideIndexIsProperty()274     bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
setOverrideIndexIsProperty(bool onoff)275     void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
276 
overrideIndex()277     int overrideIndex() const { return m_overrideIndex; }
setOverrideIndex(int idx)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 
coreIndex()285     int coreIndex() const { return m_coreIndex; }
setCoreIndex(int idx)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 
revision()293     quint8 revision() const { return m_revision; }
setRevision(quint8 rev)294     void setRevision(quint8 rev)
295     {
296         Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
297         m_revision = quint8(rev);
298     }
299 
300     /* If a property is a C++ type, then we store the minor
301      * version of this type.
302      * This is required to resolve property or signal revisions
303      * if this property is used as a grouped property.
304      *
305      * Test.qml
306      * property TextEdit someTextEdit: TextEdit {}
307      *
308      * Test {
309      *   someTextEdit.preeditText: "test" //revision 7
310      *   someTextEdit.onEditingFinished: console.log("test") //revision 6
311      * }
312      *
313      * To determine if these properties with revisions are available we need
314      * the minor version of TextEdit as imported in Test.qml.
315      *
316      */
317 
typeMinorVersion()318     quint8 typeMinorVersion() const { return m_typeMinorVersion; }
setTypeMinorVersion(quint8 rev)319     void setTypeMinorVersion(quint8 rev)
320     {
321         Q_ASSERT(rev <= std::numeric_limits<quint8>::max());
322         m_typeMinorVersion = quint8(rev);
323     }
324 
arguments()325     QQmlPropertyCacheMethodArguments *arguments() const { return m_arguments; }
setArguments(QQmlPropertyCacheMethodArguments * args)326     void setArguments(QQmlPropertyCacheMethodArguments *args) { m_arguments = args; }
327 
metaObjectOffset()328     int metaObjectOffset() const { return m_metaObjectOffset; }
setMetaObjectOffset(int off)329     void setMetaObjectOffset(int off)
330     {
331         Q_ASSERT(off >= std::numeric_limits<qint16>::min());
332         Q_ASSERT(off <= std::numeric_limits<qint16>::max());
333         m_metaObjectOffset = qint16(off);
334     }
335 
staticMetaCallFunction()336     StaticMetaCallFunction staticMetaCallFunction() const { return m_staticMetaCallFunction; }
trySetStaticMetaCallFunction(StaticMetaCallFunction f,unsigned relativePropertyIndex)337     void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
338     {
339         if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
340             m_flags.otherBits = relativePropertyIndex;
341             m_staticMetaCallFunction = f;
342         }
343     }
relativePropertyIndex()344     quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
345 
346     static Flags flagsForProperty(const QMetaProperty &);
347     void load(const QMetaProperty &);
348     void load(const QMetaMethod &);
349     QString name(QObject *) const;
350     QString name(const QMetaObject *) const;
351 
352     void markAsOverrideOf(QQmlPropertyData *predecessor);
353 
readProperty(QObject * target,void * property)354     inline void readProperty(QObject *target, void *property) const
355     {
356         void *args[] = { property, nullptr };
357         readPropertyWithArgs(target, args);
358     }
359 
readPropertyWithArgs(QObject * target,void * args[])360     inline void readPropertyWithArgs(QObject *target, void *args[]) const
361     {
362         if (hasStaticMetaCallFunction())
363             staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
364         else if (isDirect())
365             target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args);
366         else
367             QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args);
368     }
369 
writeProperty(QObject * target,void * value,WriteFlags flags)370     bool writeProperty(QObject *target, void *value, WriteFlags flags) const
371     {
372         int status = -1;
373         void *argv[] = { value, nullptr, &status, &flags };
374         if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
375             staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
376         else if (flags.testFlag(BypassInterceptor) && isDirect())
377             target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv);
378         else
379             QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv);
380         return true;
381     }
382 
defaultSignalFlags()383     static Flags defaultSignalFlags()
384     {
385         Flags f;
386         f.type = Flags::FunctionType;
387         f.setIsSignal(true);
388         f.setIsVMESignal(true);
389         return f;
390     }
391 
defaultSlotFlags()392     static Flags defaultSlotFlags()
393     {
394         Flags f;
395         f.type = Flags::FunctionType;
396         f.setIsVMEFunction(true);
397         return f;
398     }
399 
400 private:
401     friend class QQmlPropertyCache;
402     void lazyLoad(const QMetaProperty &);
403     void lazyLoad(const QMetaMethod &);
notFullyResolved()404     bool notFullyResolved() const { return m_flags.notFullyResolved; }
405 
406     Flags m_flags;
407     qint16 m_coreIndex = -1;
408     quint16 m_propType = 0;
409 
410     // The notify index is in the range returned by QObjectPrivate::signalIndex().
411     // This is different from QMetaMethod::methodIndex().
412     qint16 m_notifyIndex = -1;
413     qint16 m_overrideIndex = -1;
414 
415     quint8 m_revision = 0;
416     quint8 m_typeMinorVersion = 0;
417     qint16 m_metaObjectOffset = -1;
418 
419     QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
420     StaticMetaCallFunction m_staticMetaCallFunction = nullptr;
421 };
422 
423 #if QT_POINTER_SIZE == 4
424     Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
425 #else // QT_POINTER_SIZE == 8
426     Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
427 #endif
428 
429 bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
430 {
431     return flags() == other.flags() &&
432             propType() == other.propType() &&
433             coreIndex() == other.coreIndex() &&
434             notifyIndex() == other.notifyIndex() &&
435             revision() == other.revision();
436 }
437 
Flags()438 QQmlPropertyData::Flags::Flags()
439     : otherBits(0)
440     , isConstantORisVMEFunction(false)
441     , isWritableORhasArguments(false)
442     , isResettableORisSignal(false)
443     , isAliasORisVMESignal(false)
444     , isFinalORisV4Function(false)
445     , isSignalHandler(false)
446     , isOverload(false)
447     , isRequiredORisCloned(false)
448     , isConstructor(false)
449     , isDirect(false)
450     , isOverridden(false)
451     , type(OtherType)
452     , notFullyResolved(false)
453     , overrideIndexIsProperty(false)
454 {}
455 
456 bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
457 {
458     return isConstantORisVMEFunction == other.isConstantORisVMEFunction &&
459             isWritableORhasArguments == other.isWritableORhasArguments &&
460             isResettableORisSignal == other.isResettableORisSignal &&
461             isAliasORisVMESignal == other.isAliasORisVMESignal &&
462             isFinalORisV4Function == other.isFinalORisV4Function &&
463             isOverridden == other.isOverridden &&
464             isSignalHandler == other.isSignalHandler &&
465             isRequiredORisCloned == other.isRequiredORisCloned &&
466             type == other.type &&
467             isConstructor == other.isConstructor &&
468             notFullyResolved == other.notFullyResolved &&
469             overrideIndexIsProperty == other.overrideIndexIsProperty;
470 }
471 
copyPropertyTypeFlags(QQmlPropertyData::Flags from)472 void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
473 {
474     switch (from.type) {
475     case QObjectDerivedType:
476     case EnumType:
477     case QListType:
478     case QmlBindingType:
479     case QJSValueType:
480     case QVariantType:
481         type = from.type;
482     }
483 }
484 
485 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
486 
487 QT_END_NAMESPACE
488 
489 #endif // QQMLPROPERTYDATA_P_H
490