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
qqmlpreviewbindingpatchcontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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 reason:default
4
6#include <private/qqmlboundsignal_p.h>
7#include <private/qqmlcomponent_p.h>
8#include <private/qqmlobjectcreator_p.h>
9#include <private/qqmlproperty_p.h>
10#include <private/qqmltypeloader_p.h>
11#include <private/qqmlvme_p.h>
12#include <private/qv4functionobject_p.h>
13#include <private/qv4generatorobject_p.h>
14#include <private/qv4qmlcontext_p.h>
15#include <private/qv4resolvedtypereference_p.h>
16
18
19namespace QQmlPreview {
20
22{
23 // Intentionally take an extra refpointer of the CU.
24 // The GC might kick in and remove it from the ddata.
25 if (QQmlRefPointer<QV4::ExecutableCompilationUnit> cu = m_ddata->compilationUnit)
26 resetBindings(m_object->metaObject(), cu, m_ddata->cuObjectIndex);
27
28 for (QQmlVMEMetaObject *vmeMeta = m_ddata->hasVMEMetaObject
29 ? static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(m_object)->metaObject)
30 : nullptr;
31 vmeMeta; vmeMeta = vmeMeta->parentVMEMetaObject()) {
32 resetBindings(vmeMeta->toDynamicMetaObject(m_object), vmeMeta->compilationUnit(),
33 vmeMeta->qmlObjectId());
34 }
35
36 // Remove all composite signal handlers, no matter where they're from.
37 while (QQmlBoundSignal *signalHandler = m_ddata->signalHandlers)
38 delete signalHandler;
39
40 const QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties =
41 m_ddata->hasExtendedData() ? m_ddata->attachedProperties() : nullptr;
42 const auto isAttached = [attachedProperties](QObject *child) {
43 if (!attachedProperties)
44 return false;
45 for (QObject *attached : *attachedProperties) {
46 if (attached == child)
47 return true;
48 }
49 return false;
50 };
51
52 const QObjectList children = m_object->children();
53
54 for (QObject *child : children) {
55 // Objects from the same CU have likely been created as inner scopes and will be replaced.
56 // Unparent the old ones so that the GC can take care of them.
57 // But skip attached property objects — they are reused across rebuilds.
58 if (QQmlData *ddata = QQmlData::get(child);
59 ddata && ddata->compilationUnit == m_ddata->compilationUnit) {
60 if (!isAttached(child))
61 child->setParent(nullptr);
62 }
63 }
64}
65
66void BindingPatchContext::resetBinding(
67 const QMetaObject *metaObject, const QV4::CompiledData::Binding *binding,
68 const QString &defaultPropName,
69 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit)
70{
71 if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
72 return;
73
74 const QString name = binding->propertyNameIndex == 0
75 ? defaultPropName
76 : oldUnit->stringAt(binding->propertyNameIndex);
77 if (name.isEmpty())
78 return;
79
80 const int propIdx = metaObject->indexOfProperty(name.toUtf8().constData());
81 Q_ASSERT(propIdx >= 0);
82
83 if (m_handledProperties.contains(propIdx))
84 return;
85
86 const QMetaProperty property = metaObject->property(propIdx);
87 const QMetaType type = property.metaType();
88
89 const QMetaType::TypeFlags flags = type.flags();
90 if (flags.testFlag(QMetaType::IsQmlList)) {
91 QQmlListReference list(m_object, property.name());
92 if (list.clear()) {
93 (void)m_handledProperties.hasSeen(propIdx);
94 return;
95 }
96 } else if (flags.testFlag(QMetaType::PointerToQObject) && binding->isGroupProperty()) {
97 QObject *groupObject = property.read(m_object).value<QObject *>();
98 if (!groupObject) {
99 (void)m_handledProperties.hasSeen(propIdx);
100 return;
101 }
102
103 // If it's an object used as group property, reset each of the properties assigned here.
104 // This does not reset the whole object, so don't add it to the duplicate tracker
105 BindingPatchContext(groupObject)
106 .resetBindings(groupObject->metaObject(), oldUnit, binding->value.objectIndex);
107 return;
108 }
109
110 if ((property.isResettable() && property.reset(m_object))
111 || (property.isWritable() && property.write(m_object, QVariant(type)))) {
112 (void)m_handledProperties.hasSeen(propIdx);
113 }
114}
115
116void BindingPatchContext::resetBindings(
117 const QMetaObject *metaObject,
118 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit, int cuIndex)
119{
120 const QV4::CompiledData::Object *obj = oldUnit->objectAt(cuIndex);
121 const QQmlPropertyCache::ConstPtr cache = oldUnit->propertyCachesPtr()->at(cuIndex);
122 const QString defaultPropertyName = cache ? cache->defaultPropertyName() : QString();
123
124 const QV4::CompiledData::Binding *binding = obj->bindingTable();
125
126 for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
127 if (binding->isAttachedProperty()) {
128 // Recurse into existing attached objects to reset their bindings.
129 // The object creator will reuse them via qmlAttachedPropertiesObject().
130 if (!m_ddata->hasExtendedData())
131 continue;
132
133 QV4::ResolvedTypeReference *typeRef = oldUnit->resolvedType(binding->propertyNameIndex);
134 Q_ASSERT(typeRef);
135 QQmlAttachedPropertiesFunc func
136 = typeRef->type().attachedPropertiesFunction(oldUnit->engine->typeLoader());
137 Q_ASSERT(func);
138
139 if (QObject *attached = m_ddata->attachedProperties()->value(func)) {
140 BindingPatchContext(attached).resetBindings(
141 attached->metaObject(), oldUnit,
142 binding->value.objectIndex);
143 }
144 continue;
145 }
146
147 // Signal handlers are disconnected centrally.
148 if (binding->isSignalHandler())
149 continue;
150
151 resetBinding(metaObject, binding, defaultPropertyName, oldUnit);
152 }
153}
154
155} // namespace QQmlPreview
156
157QT_END_NAMESPACE
Combined button and popup list for selecting options.