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
qqmlobjectcreator_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 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 QQMLOBJECTCREATOR_P_H
6#define QQMLOBJECTCREATOR_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/qqmlimport_p.h>
20#include <private/qqmltypenamecache_p.h>
21#include <private/qv4compileddata_p.h>
22#include <private/qrecursionwatcher_p.h>
23#include <private/qqmlprofiler_p.h>
24#include <private/qv4qmlcontext_p.h>
25#include <private/qqmlguardedcontextdata_p.h>
26#include <private/qqmlfinalizer_p.h>
27#include <private/qqmlvmemetaobject_p.h>
28
29#include <qpointer.h>
30#include <deque>
31
32QT_BEGIN_NAMESPACE
33
34class QQmlAbstractBinding;
37
42
43/*!
44\internal
45This struct contains information solely used for displaying error messages
46\variable aliasesToRequired allows us to give the user a way to know which (aliasing) properties
47can be set to set the required property
48\sa QQmlComponentPrivate::unsetRequiredPropertyToQQmlError
49*/
57
59{
61 RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)
62 : object(object)
63 , data(data)
64 {}
65
66 const QObject *object = nullptr;
67 const QQmlPropertyData *data = nullptr;
68
69private:
70 friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0)
71 {
72 return qHashMulti(seed, key.object, key.data);
73 }
74
75 friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
76 {
77 return a.object == b.object && a.data == b.data;
78 }
79};
80
82
93
99
100class Q_AUTOTEST_EXPORT ObjectInCreationGCAnchorList {
101public:
102 // this is a non owning view, rule of zero applies
103 ObjectInCreationGCAnchorList() = default;
104 ObjectInCreationGCAnchorList(const QV4::Scope &scope)
105 {
106 allocationScope = &scope;
107 }
108 void trackObject(QV4::ExecutionEngine *engine, QObject *instance);
109 bool canTrack() const { return allocationScope; }
110private:
111 // pointer to scope to reference JS wrappers during creation phase.
112 const QV4::Scope *allocationScope = nullptr;
113};
114
119
136
137class Q_QML_EXPORT QQmlObjectCreator
138{
139 Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
140public:
141 enum class InitFlag: quint8
142 {
143 None = 0x0,
144 IsDocumentRoot = 0x1,
145 IsContextObject = 0x2,
146 IsImplicitComponent = 0x4,
147 };
149
150 QQmlObjectCreator(const QQmlRefPointer<QQmlContextData> &parentContext,
151 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
152 const QQmlRefPointer<QQmlContextData> &creationContext,
153 const QString &inlineComponentName,
154 QQmlIncubatorPrivate *incubator = nullptr);
155 ~QQmlObjectCreator();
156
158 QObject *create(int subComponentIndex = -1, QObject *parent = nullptr,
159 QQmlInstantiationInterrupt *interrupt = nullptr, int flags = NormalObject);
160
161 bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
162
163 void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
164 void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
165 const QV4::CompiledData::Binding *binding);
166 void populateDeferredInstance(QObject *outerObject, int deferredIndex,
167 int index, QObject *instance, QObject *bindingTarget,
168 const QQmlPropertyData *valueTypeProperty,
169 const QV4::CompiledData::Binding *binding = nullptr);
171
172 bool finalize(QQmlInstantiationInterrupt &interrupt);
173 void clear();
174
176 int objectIndex, QObject *parent,
177 const QQmlRefPointer<QQmlContextData> &existingContext);
178
179 QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
180 QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
181
183
185 {
186 return parentContext.contextData();
187 }
188 std::vector<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
189
190 RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
191 bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
192
193 static QQmlComponent *createComponent(
194 QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index,
195 QObject *parent, const QQmlRefPointer<QQmlContextData> &context);
196
197 void removePendingBinding(QObject *target, int propertyIndex) const
198 {
199 QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
200 pendingBindings.removeIf([&](const DeferredQPropertyBinding &deferred) {
201 return deferred.properyIndex == propertyIndex && deferred.target == target;
202 });
203 }
204
206 int index, QObject *instance,
207 const QQmlRefPointer<QQmlContextData> &instanceContext, InitFlags flags);
208
209private:
210 QQmlObjectCreator(
211 const QQmlRefPointer<QQmlContextData> &contextData,
212 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
213 const QString inlineComponentName,
214 QQmlObjectCreatorSharedState *inheritedSharedState, bool isContextObject);
215
216 void init(const QQmlRefPointer<QQmlContextData> &parentContext);
217
218 void initializeDData(
219 const QV4::CompiledData::Object *obj, QObject *instance, QQmlData *ddata,
220 InitFlags flags);
221 void initializePropertyCache(
222 int index, QQmlData *ddata, const QV4::ResolvedTypeReference *typeRef);
223 void initializeParent(QObject *instance, QObject *parent);
224 QObject *populateInstanceAndAliasBindings(int index, QObject *instance, InitFlags flags);
225
226 QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
227
228 QObject *initializeComponent(
229 int index, const QV4::CompiledData::Object *obj, QObject *instance, InitFlags flags);
230 QObject *initializeComposite(
231 int index, const QV4::CompiledData::Object *obj,
232 const QV4::ResolvedTypeReference *typeRef, QObject *instance, QObject *parent,
233 InitFlags flags);
234 QObject *initializeNonComposite(
235 int index, const QV4::CompiledData::Object *obj,
236 const QV4::ResolvedTypeReference *typeRef, QObject *instance, QObject *parent,
237 InitFlags flags);
238
239 bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
240 const QQmlPropertyData *valueTypeProperty,
241 const QV4::CompiledData::Binding *binding = nullptr);
242
243 // If qmlProperty and binding are null, populate all properties, otherwise only the given one.
244 void populateDeferred(QObject *instance, int deferredIndex);
245 void populateDeferred(QObject *instance, int deferredIndex,
246 const QQmlPropertyPrivate *qmlProperty,
247 const QV4::CompiledData::Binding *binding);
248
249 enum BindingMode {
250 ApplyNone = 0x0,
251 ApplyImmediate = 0x1,
252 ApplyDeferred = 0x2,
253 ApplyAll = ApplyImmediate | ApplyDeferred,
254 };
255 Q_DECLARE_FLAGS(BindingSetupFlags, BindingMode);
256
257 void setupBindings(BindingSetupFlags mode = BindingMode::ApplyImmediate);
258 bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
259 void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding,
260 std::optional<int> foldedNumber = std::nullopt);
261 void setupFunctions();
262
263 QString stringAt(int idx) const { return compilationUnit->stringAt(idx); }
264 void recordError(const QV4::CompiledData::Location &location, const QString &description);
265
266 void registerObjectWithContextById(int objectIndex, QObject *instance) const;
267
268 inline QV4::QmlContext *currentQmlContext();
269 QV4::ResolvedTypeReference *resolvedType(int id) const
270 {
271 return compilationUnit->resolvedType(id);
272 }
273
274 enum Phase {
275 Startup,
276 CreatingObjects,
277 CreatingObjectsPhase2,
278 ObjectsCreated,
279 Finalizing,
280 Done
281 } phase;
282
283 QQmlEngine *engine;
284 QV4::ExecutionEngine *v4;
285 QString m_inlineComponentName;
286 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
287 const QV4::CompiledData::Unit *qmlUnit;
288 QQmlGuardedContextData parentContext;
289 QQmlRefPointer<QQmlContextData> context;
290 const QQmlPropertyCacheVector *propertyCaches;
291 QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
292 bool topLevelCreator;
293 bool isContextObject;
294 QQmlIncubatorPrivate *incubator;
295
296 QObject *_qobject;
297 QObject *_scopeObject;
298 QObject *_bindingTarget;
299
300 const QQmlPropertyData *_valueTypeProperty; // belongs to _qobjectForBindings's property cache
301 int _compiledObjectIndex;
302 const QV4::CompiledData::Object *_compiledObject;
303 QQmlData *_ddata;
304 QQmlPropertyCache::ConstPtr _propertyCache;
305 QQmlVMEMetaObject *_vmeMetaObject;
306 QQmlListProperty<QObject> _currentList;
307 QV4::QmlContext *_qmlContext;
308
310
311 typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
312 std::vector<PendingAliasBinding> pendingAliasBindings;
313
314 template<typename Functor>
315 void doPopulateDeferred(QObject *instance, int deferredIndex, Functor f)
316 {
317 QQmlData *declarativeData = QQmlData::get(instance);
318
319 // We're in the process of creating the object. We sure hope it's still alive.
320 Q_ASSERT(declarativeData && declarativeData->propertyCache);
321
322 QObject *bindingTarget = instance;
323
324 QQmlPropertyCache::ConstPtr cache = declarativeData->propertyCache;
325 QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance, v4);
326
327 QObject *scopeObject = instance;
328 qt_ptr_swap(_scopeObject, scopeObject);
329
330 QV4::Scope valueScope(v4);
331 QScopedValueRollback<ObjectInCreationGCAnchorList> jsObjectGuard(
332 sharedState->allJavaScriptObjects, ObjectInCreationGCAnchorList(valueScope));
333
334 Q_ASSERT(topLevelCreator);
335 QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.constructUndefined(1));
336
337 qt_ptr_swap(_qmlContext, qmlContext);
338
339 _propertyCache.swap(cache);
340 qt_ptr_swap(_qobject, instance);
341
342 int objectIndex = deferredIndex;
343 std::swap(_compiledObjectIndex, objectIndex);
344
345 const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
346 qt_ptr_swap(_compiledObject, obj);
347 qt_ptr_swap(_ddata, declarativeData);
348 qt_ptr_swap(_bindingTarget, bindingTarget);
349 qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
350
351 f();
352
353 qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
354 qt_ptr_swap(_bindingTarget, bindingTarget);
355 qt_ptr_swap(_ddata, declarativeData);
356 qt_ptr_swap(_compiledObject, obj);
357 std::swap(_compiledObjectIndex, objectIndex);
358 qt_ptr_swap(_qobject, instance);
359 _propertyCache.swap(cache);
360
361 qt_ptr_swap(_qmlContext, qmlContext);
362 qt_ptr_swap(_scopeObject, scopeObject);
363 }
364 void registerPostHocRequiredProperties(const QV4::CompiledData::Binding *binding);
365};
366
368{
369 QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator);
370
371 bool hasRecursed() const { return watcher.hasRecursed(); }
372
373private:
374 QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
375 QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
376};
377
378QV4::QmlContext *QQmlObjectCreator::currentQmlContext()
379{
380 if (!_qmlContext->isManaged())
381 _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
382
383 return _qmlContext;
384}
385
386Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlObjectCreator::InitFlags);
387
388QT_END_NAMESPACE
389
390#endif // QQMLOBJECTCREATOR_P_H
friend class QQmlIncubatorPrivate
QQmlComponentAttached ** componentAttachment()
Q_DECLARE_FLAGS(InitFlags, InitFlag)
bool finalize(QQmlInstantiationInterrupt &interrupt)
void repopulateBindings(int index, QObject *instance, const QQmlRefPointer< QQmlContextData > &instanceContext, InitFlags flags)
bool componentHadTopLevelRequiredProperties() const
void beginPopulateDeferred(const QQmlRefPointer< QQmlContextData > &context)
QQmlRefPointer< QQmlContextData > parentContextData() const
static QQmlComponent * createComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, int index, QObject *parent, const QQmlRefPointer< QQmlContextData > &context)
QObject * create(int subComponentIndex=-1, QObject *parent=nullptr, QQmlInstantiationInterrupt *interrupt=nullptr, int flags=NormalObject)
QObject * createObjectInContext(int objectIndex, QObject *parent, const QQmlRefPointer< QQmlContextData > &existingContext)
void removePendingBinding(QObject *target, int propertyIndex) const
std::vector< QQmlGuard< QObject > > & allCreatedObjects()
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex, const QV4::CompiledData::Binding *binding)
RequiredProperties * requiredProperties()
QList< QQmlError > errors
void populateDeferredInstance(QObject *outerObject, int deferredIndex, int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QV4::CompiledData::Binding *binding=nullptr)
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData)
QQmlObjectCreator(const QQmlRefPointer< QQmlContextData > &parentContext, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QQmlRefPointer< QQmlContextData > &creationContext, const QString &inlineComponentName, QQmlIncubatorPrivate *incubator=nullptr)
QQmlRefPointer< QQmlContextData > rootContext() const
void clear()
Clears the entire result set and releases any associated resources.
RequiredPropertiesAndTarget & operator=(RequiredPropertiesAndTarget &&)=default
RequiredPropertiesAndTarget(const RequiredPropertiesAndTarget &)=default
RequiredPropertiesAndTarget(QObject *target)
RequiredPropertiesAndTarget & operator=(const RequiredPropertiesAndTarget &)=default
RequiredPropertiesAndTarget(RequiredPropertiesAndTarget &&)=default
Combined button and popup list for selecting options.
Definition qjsvalue.h:24
QJSEngine engine
[0]
QUntypedPropertyBinding binding
QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator)
QList< DeferredQPropertyBinding > allQPropertyBindings
std::vector< QQmlGuard< QObject > > allCreatedObjects
QQmlRefPointer< QQmlContextData > rootContext
std::vector< ParserStatus > allParserStatusCallbacks
QQmlRefPointer< QQmlContextData > creationContext
QQmlComponentAttached * componentAttached
std::vector< QQmlAbstractBinding::Ptr > allCreatedBindings
QList< QQmlFinalizerHook * > finalizeHooks
ObjectInCreationGCAnchorList allJavaScriptObjects
QString stringAt(int index) const
QV4::CompiledData::Location location
QList< AliasToRequiredInfo > aliasesToRequired
friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
friend size_t qHash(const RequiredPropertyKey &key, size_t seed=0)
RequiredPropertyKey()=default
const QQmlPropertyData * data
RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)