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
qqmltccompilerpieces_p.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:critical reason:code-generation
4
5#ifndef QQMLTCCOMPILERPIECES_P_H
6#define QQMLTCCOMPILERPIECES_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 <QtCore/qscopeguard.h>
20#include <QtCore/qstringbuilder.h>
21#include <QtCore/qfileinfo.h>
22
23#include <private/qqmljsutils_p.h>
24#include <private/qqmlglobal_p.h>
25#include <private/qqmltranslation_p.h>
26
27#include <private/qqmltcoutputir_p.h>
28#include <private/qqmltcvisitor_p.h>
29
30QT_BEGIN_NAMESPACE
31
32namespace QQmltc {
33
34/*!
35 \internal
36
37 Helper class that generates code for the output IR. Takes care of
38 complicated, repetitive, nasty logic which is better kept in a single
39 confined place.
40*/
42{
44 static const QString typeCountName;
45
47 Visitor *visitor = nullptr;
48
51
52 [[nodiscard]] inline decltype(auto) generate_initCode(Type &current,
53 const QQmlJSScope::ConstPtr &type) const;
54 inline void generate_initCodeForTopLevelComponent(Type &current,
55 const QQmlJSScope::ConstPtr &type);
56
57 inline void generate_qmltcInstructionCallCode(Method *function,
58 const QQmlJSScope::ConstPtr &type,
59 const QString &baseInstructionArgs,
60 const QString &childInstructionArgs) const;
61 inline void generate_endInitCode(Type &current, const QQmlJSScope::ConstPtr &type) const;
62 inline void generate_setComplexBindingsCode(Type &current,
63 const QQmlJSScope::ConstPtr &type) const;
64
65 inline void generate_interfaceCallCode(Method *function, const QQmlJSScope::ConstPtr &type,
66 const QString &interfaceName,
67 const QString &interfaceCall) const;
68 inline void generate_beginClassCode(Type &current, const QQmlJSScope::ConstPtr &type) const;
69 inline void generate_completeComponentCode(Type &current,
70 const QQmlJSScope::ConstPtr &type) const;
71 inline void generate_finalizeComponentCode(Type &current,
72 const QQmlJSScope::ConstPtr &type) const;
73 inline void generate_handleOnCompletedCode(Type &current,
74 const QQmlJSScope::ConstPtr &type) const;
75
76 static void generate_assignToProperty(QStringList *block, const QQmlJSScope::ConstPtr &type,
77 const QQmlJSMetaProperty &p, const QString &value,
78 const QString &accessor,
79 bool constructFromQObject = false);
80
81 static void generate_assignToListProperty(QStringList *block, const QQmlJSScope::ConstPtr &type,
82 const QQmlJSMetaProperty &p, const QStringList &value,
83 const QString &accessor, QString &qmlListVarName);
84
85 static void generate_setIdValue(QStringList *block, const QString &context, qsizetype index,
86 const QString &accessor, const QString &idString);
87
88 inline QString
89 generate_typeCount(const InlineComponentOrDocumentRootName &inlinedComponent) const
90 {
91 return generate_typeCount([](const QQmlJSScope::ConstPtr &) { return false; },
92 inlinedComponent);
93 }
94
95 /*!
96 * \internal
97 * Generate the constexpr typeCount expression for given inlinedComponent. Leave
98 * inlinedComponent empty to generate the expression for the main component.
99 */
100 template<typename Predicate>
101 inline QString
102 generate_typeCount(Predicate p,
103 const InlineComponentOrDocumentRootName &inlinedComponent) const;
104
105 static void generate_callExecuteRuntimeFunction(QStringList *block, const QString &url,
106 QQmlJSMetaMethod::AbsoluteFunctionIndex index,
107 const QString &accessor,
108 const QString &returnType,
109 const QList<Variable> &parameters = {});
110
111 static void generate_createBindingOnProperty(QStringList *block, const QString &unitVarName,
112 const QString &scope, qsizetype functionIndex,
113 const QString &target,
114 const QQmlJSScope::ConstPtr &targetType,
115 int propertyIndex, const QQmlJSMetaProperty &p,
116 int valueTypeIndex, const QString &subTarget);
117
118 // Used in generate_createTranslationBindingOnProperty to transport its numerous arguments.
120 {
126
128
130 // For the source location of the translation binding
132 // For the source location of the translation binding
134 };
135
136 static void generate_createTranslationBindingOnProperty(QStringList *block,
137 const TranslationBindingInfo &info);
138
140
147
148 static PreparedValue wrap_mismatchingTypeConversion(const QQmlJSMetaProperty &p, QString value);
149 static PreparedValue wrap_extensionType(const QQmlJSScope::ConstPtr &type,
150 const QQmlJSMetaProperty &p, const QString &accessor);
151
152 static QString wrap_privateClass(const QString &accessor, const QQmlJSMetaProperty &p);
153 static QString wrap_addressof(const QString &addressed);
154
156 {
157 using namespace Qt::StringLiterals;
158 QFileInfo fi(documentUrl);
159 return u"q_qmltc_docUrl_" + fi.fileName().replace(u".qml"_s, u""_s).replace(u'.', u'_');
160 }
161};
162
163/*!
164 \internal
165
166 Generates \a{current.init}'s code. The init method sets up a
167 QQmlContext for the object and (in case \a type is a document
168 root) calls other object creation methods, and a user-provided
169 initialization callback, in a well-defined order:
170 1. current.beginClass
171 2. current.endInit
172 3. user-provided initialization function
173 4. current.setComplexBindings
174 5. current.completeComponent
175 6. current.finalizeComponent
176 7. current.handleOnCompleted
177
178 This function returns a QScopeGuard with the final instructions that have to
179 be generated at a later point, once everything else is compiled.
180
181 \sa generate_initCodeForTopLevelComponent
182*/
183inline decltype(auto) CodeGenerator::generate_initCode(Type &current,
184 const QQmlJSScope::ConstPtr &type) const
185{
186 using namespace Qt::StringLiterals;
187
188 // qmltc_init()'s parameters:
189 // * QQmltcObjectCreationHelper* creator
190 // * QQmlEngine* engine
191 // * const QQmlRefPointer<QQmlContextData>& parentContext
192 // * bool canFinalize [optional, when document root]
193 const bool isDocumentRoot = type == visitor->result();
194 const bool isInlineComponent = type->isInlineComponent();
195
196 current.init.body << u"Q_UNUSED(creator)"_s; // can happen sometimes
197
198 current.init.body << u"auto context = parentContext;"_s;
199
200 // if parent scope has a QML base type and is not a (current) document root,
201 // the parentContext we passed as input to this object is a context of
202 // another document. we need to fix it by using parentContext->parent()
203
204 const auto realQmlScope = [](const QQmlJSScope::ConstPtr &scope) {
205 if (scope->isArrayScope())
206 return scope->parentScope();
207 return scope;
208 };
209
210 if (auto parentScope = realQmlScope(type->parentScope());
211 parentScope != visitor->result() && QQmlJSUtils::hasCompositeBase(parentScope)) {
212 current.init.body << u"// NB: context->parent() is the context of this document"_s;
213 current.init.body << u"context = context->parent();"_s;
214 }
215
216 // any object with QML base class has to call base's init method
217 if (auto base = type->baseType(); base->isComposite()) {
218 QString lhs;
219 // init creates new context. for document root, it's going to be a real
220 // parent context, so store it temporarily in `context` variable
221 if (isDocumentRoot || isInlineComponent)
222 lhs = u"context = "_s;
223 current.init.body << u"// 0. call base's init method"_s;
224
225 const auto isCurrentType = [&](const QQmlJSScope::ConstPtr &qmlType) {
226 return qmlType == type;
227 };
228 const QString creationOffset =
229 generate_typeCount(isCurrentType, type->enclosingInlineComponentName());
230
231 current.init.body << u"{"_s;
232 current.init.body << u"QQmltcObjectCreationHelper subCreator(creator, %1);"_s.arg(
233 creationOffset);
234 current.init.body
235 << QStringLiteral("%1%2::%3(&subCreator, engine, context, /* finalize */ false);")
236 .arg(lhs, base->internalName(), current.init.name);
237 // if not document root, set outer context
238 if (!isDocumentRoot && !isInlineComponent) {
239 current.init.body
240 << u"QQmlEnginePrivate::setInternalContext("
241 "this, parentContext, QQmlContextData::OrdinaryObject);"_s;
242 }
243 current.init.body << u"}"_s;
244 }
245
246 current.init.body
247 << QStringLiteral("auto %1 = QQmlEnginePrivate::get(engine);").arg(privateEngineName);
248 current.init.body << QStringLiteral("Q_UNUSED(%1)").arg(privateEngineName); // precaution
249
250 // when generating root or inlineComponents, we need to create a new (document-level) context.
251 // otherwise, just use existing context as is
252 if (isDocumentRoot || isInlineComponent) {
253 current.init.body << u"// 1. create new QML context for this document"_s;
254 current.init.body
255 << QStringLiteral(
256 "context = %1->createComponentRootContext("
257 "%1->compilationUnitFromUrl(%2()), context, %3);")
258 .arg(privateEngineName, urlMethodName())
259 .arg(this->visitor->creationIndex(type));
260 } else {
261 current.init.body << u"// 1. use current context as this object's context"_s;
262 current.init.body << u"// context = context;"_s;
263 }
264
265 if (!type->baseType()->isComposite() || isDocumentRoot || isInlineComponent) {
266 current.init.body << u"// 2. set context for this object"_s;
267 current.init.body << QStringLiteral(
268 "%1->setInternalContext(this, context, QQmlContextData::%2);")
269 .arg(privateEngineName,
270 (isDocumentRoot ? u"DocumentRoot"_s
271 : u"OrdinaryObject"_s));
272 if (isDocumentRoot || isInlineComponent)
273 current.init.body << u"context->setContextObject(this);"_s;
274 }
275
276 // context is this document's context. we must remember it in each type
277 current.variables.emplaceBack(u"QQmlRefPointer<QQmlContextData>"_s, u"q_qmltc_thisContext"_s,
278 u"nullptr"_s);
279
280 const QString relevantContext
281 = (isDocumentRoot || isInlineComponent) ? u"context"_s : u"parentContext"_s;
282 current.init.body
283 << u"%1::q_qmltc_thisContext = %2;"_s.arg(type->internalName(), relevantContext);
284
285 if (int id = visitor->runtimeId(type); id >= 0) {
286 current.init.body << u"// 3. set id since it is provided"_s;
287 QString idString = visitor->addressableScopes().id(type, type);
288 if (idString.isEmpty())
289 idString = u"<unknown>"_s;
290 CodeGenerator::generate_setIdValue(
291 &current.init.body, relevantContext, id, u"this"_s, idString);
292 }
293
294 // if type has an extension, create a dynamic meta object for it
295 bool hasExtension = false;
296 for (auto cppBase = QQmlJSScope::nonCompositeBaseType(type); cppBase;
297 cppBase = cppBase->baseType()) {
298 // QObject is special: we have a pseudo-extension on it due to builtins
299 if (cppBase->internalName() == u"QObject"_s)
300 break;
301 if (cppBase->extensionType().extensionSpecifier != QQmlJSScope::NotExtension) {
302 hasExtension = true;
303 break;
304 }
305 }
306 if (hasExtension) {
307 current.init.body << u"{"_s;
308 current.init.body << u"auto cppData = QmltcTypeData(this);"_s;
309 current.init.body << u"qmltcCreateDynamicMetaObject(this, cppData);"_s;
310 current.init.body << u"}"_s;
311 }
312
313 const auto generateFinalLines = [&current, isDocumentRoot, isInlineComponent]() {
314 if (isDocumentRoot || isInlineComponent) {
315 current.init.body << u"// 4. finish the document root creation"_s;
316 current.init.body << u"if (canFinalize) {"_s;
317 current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
318 .arg(current.beginClass.name);
319 current.init.body << QStringLiteral(" %1(creator, engine);")
320 .arg(current.endInit.name);
321
322 current.init.body << QStringLiteral(" {");
323 current.init.body << QStringLiteral(" PropertyInitializer propertyInitializer(*this);");
324 current.init.body << QStringLiteral(" initializer(propertyInitializer);");
325 current.init.body << QStringLiteral(" %1(creator, engine, propertyInitializer.initializedCache);").arg(current.setComplexBindings.name);
326 current.init.body << QStringLiteral(" }");
327
328
329 current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
330 .arg(current.completeComponent.name);
331 current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
332 .arg(current.finalizeComponent.name);
333 current.init.body << QStringLiteral(" %1(creator);")
334 .arg(current.handleOnCompleted.name);
335 current.init.body << u"}"_s;
336 }
337 current.init.body << u"return context;"_s;
338 };
339
340 return QScopeGuard(generateFinalLines);
341}
342
343/*!
344 \internal
345
346 Generates \a{current.init}'s code in case when \a type is a top-level
347 Component type. The init method in this case mimics
348 QQmlObjectCreator::createComponent() logic.
349
350 \sa generate_initCode
351*/
353 const QQmlJSScope::ConstPtr &type)
354{
355 Q_UNUSED(type);
356
357 using namespace Qt::StringLiterals;
358
359 // since we create a document root as QQmlComponent, we only need to fake
360 // QQmlComponent construction in init:
361 current.init.body << u"// init QQmlComponent: see QQmlObjectCreator::createComponent()"_s;
362 current.init.body << u"{"_s;
363 // we already called QQmlComponent(parent) constructor. now we need:
364 // 1. QQmlComponent(engine, parent) logic:
365 current.init.body << u"// QQmlComponent(engine, parent):"_s;
366 current.init.body << u"auto d = QQmlComponentPrivate::get(this);"_s;
367 current.init.body << u"Q_ASSERT(d);"_s;
368 current.init.body << u"d->engine = engine;"_s;
369 current.init.body << u"QObject::connect(engine, &QObject::destroyed, this, [d]() {"_s;
370 current.init.body << u" d->state.creator.reset();"_s;
371 current.init.body << u" d->engine = nullptr;"_s;
372 current.init.body << u"});"_s;
373 // 2. QQmlComponent(engine, compilationUnit, start, parent) logic:
374 current.init.body << u"// QQmlComponent(engine, compilationUnit, start, parent):"_s;
375 current.init.body
376 << u"auto compilationUnit = QQmlEnginePrivate::get(engine)->compilationUnitFromUrl("
377 + CodeGenerator::urlMethodName() + u"());";
378 current.init.body << u"d->compilationUnit = compilationUnit;"_s;
379 current.init.body << u"d->start = 0;"_s;
380 current.init.body << u"d->url = compilationUnit->finalUrl();"_s;
381 current.init.body << u"d->progress = 1.0;"_s;
382 // 3. QQmlObjectCreator::createComponent() logic which is left:
383 current.init.body << u"// QQmlObjectCreator::createComponent():"_s;
384 current.init.body << u"d->creationContext = context;"_s;
385 current.init.body << u"Q_ASSERT(QQmlData::get(this, /*create*/ false));"_s;
386 current.init.body << u"}"_s;
387}
388
389/*!
390 \internal
391
392 A generic helper function that generates special qmltc instruction code
393 boilerplate, adding it to a passed \a function. This is a building block
394 used to generate e.g. QML_endInit code.
395*/
397 Method *function, const QQmlJSScope::ConstPtr &type,
398 const QString &baseInstructionArgs, const QString &childInstructionArgs) const
399{
400 using namespace Qt::StringLiterals;
401
402 if (auto base = type->baseType(); base->isComposite()) {
403 function->body << u"// call base's method"_s;
404 const auto isCurrentType = [&](const QQmlJSScope::ConstPtr &qmlType) {
405 return qmlType == type;
406 };
407 const QString creationOffset =
408 generate_typeCount(isCurrentType, type->enclosingInlineComponentName());
409 function->body << u"{"_s;
410 function->body << u"QQmltcObjectCreationHelper subCreator(creator, %1);"_s.arg(
411 creationOffset);
412 if (!baseInstructionArgs.isEmpty()) {
413 function->body << u"%1::%2(&subCreator, %3);"_s.arg(
414 base->internalName(), function->name, baseInstructionArgs);
415 } else {
416 function->body << u"%1::%2(&subCreator);"_s.arg(base->internalName(), function->name);
417 }
418 function->body << u"}"_s;
419 }
420
421 const bool isDocumentRoot = type == visitor->result();
422 const bool isInlineComponent = type->isInlineComponent();
423
424 if (!(isDocumentRoot
425 || isInlineComponent)) // document/inline component root does all the work here
426 return;
427 auto name = isInlineComponent
428 ? InlineComponentOrDocumentRootName(*type->inlineComponentName())
429 : InlineComponentOrDocumentRootName(QQmlJSScope::RootDocumentNameType());
430 const auto types = visitor->pureQmlTypes(name);
431 function->body << u"// call children's methods"_s;
432 for (qsizetype i = 1; i < types.size(); ++i) {
433 const auto &type = types[i];
434 Q_ASSERT(type->componentRootStatus() == QQmlJSScope::IsComponentRoot::No);
435 function->body << u"creator->get<%1>(%2)->%3(%4);"_s.arg(
436 type->internalName(), QString::number(i), function->name, childInstructionArgs);
437 }
438 function->body << u"// call own method code"_s;
439}
440
441/*!
442 \internal
443
444 Generates \a{current.endInit}'s code. The endInit method creates bindings,
445 connects signals with slots and generally performs other within-object
446 initialization. Additionally, the QML document root's endInit calls endInit
447 methods of all the necessary QML types within the document.
448*/
449inline void CodeGenerator::generate_endInitCode(Type &current,
450 const QQmlJSScope::ConstPtr &type) const
451{
452 using namespace Qt::StringLiterals;
453
454 // QML_endInit()'s parameters:
455 // * QQmltcObjectCreationHelper* creator
456 // * QQmlEngine* engine
457 current.endInit.body << u"Q_UNUSED(creator)"_s;
458 current.endInit.body << u"Q_UNUSED(engine)"_s;
459
460 generate_qmltcInstructionCallCode(&current.endInit, type, u"engine"_s, u"creator, engine"_s);
461
462 if (visitor->hasDeferredBindings(type)) {
463 QString icName;
464 if (auto potentialICName = type->enclosingInlineComponentName();
465 std::holds_alternative<QQmlJSScope::InlineComponentNameType>(potentialICName))
466 icName =get<QQmlJSScope::InlineComponentNameType>(potentialICName);
467 else
468 icName = u"{}"_s;
469 current.endInit.body << u"{ // defer bindings"_s;
470 current.endInit.body << u"auto ddata = QQmlData::get(this);"_s;
471 current.endInit.body << u"auto thisContext = ddata->context;"_s;
472 current.endInit.body << u"Q_ASSERT(thisContext);"_s;
473 current.endInit.body << QStringLiteral("ddata->deferData(%1, "
474 "QQmlEnginePrivate::get(engine)->"
475 "compilationUnitFromUrl(%2()), thisContext, %3);")
476 .arg(QString::number(visitor->qmlIrObjectIndex(type)),
477 CodeGenerator::urlMethodName(), icName);
478 current.endInit.body << u"}"_s;
479 }
480}
481
482/*!
483 \internal
484
485 Generates \a{current.setComplexBindings}'s code. The setComplexBindings
486 method creates complex bindings (such as script bindings). Additionally, the
487 QML document root's setComplexBindings calls setComplexBindings methods of
488 all the necessary QML types within the document.
489*/
490inline void
492 const QQmlJSScope::ConstPtr &type) const
493{
494 using namespace Qt::StringLiterals;
495
496 // QML_setComplexBindings()'s parameters:
497 // * QQmltcObjectCreationHelper* creator
498 // * QQmlEngine* engine
499 current.setComplexBindings.body << u"Q_UNUSED(creator)"_s;
500 current.setComplexBindings.body << u"Q_UNUSED(engine)"_s;
501
502 generate_qmltcInstructionCallCode(&current.setComplexBindings, type, u"engine"_s,
503 u"creator, engine"_s);
504}
505
506/*!
507 \internal
508
509 A generic helper function that generates interface code boilerplate, adding
510 it to a passed \a function. This is a building block used to generate e.g.
511 QQmlParserStatus API calls.
512*/
513inline void CodeGenerator::generate_interfaceCallCode(Method *function,
514 const QQmlJSScope::ConstPtr &type,
515 const QString &interfaceName,
516 const QString &interfaceCall) const
517{
518 using namespace Qt::StringLiterals;
519
520 // function's parameters:
521 // * QQmltcObjectCreationHelper* creator
522 // * bool canFinalize [optional, when document root or inline component root]
523 const bool isDocumentRoot = type == visitor->result();
524 const bool isInlineComponent = type->isInlineComponent();
525 function->body << u"Q_UNUSED(creator)"_s;
526 if (isDocumentRoot || isInlineComponent)
527 function->body << u"Q_UNUSED(canFinalize)"_s;
528
529 if (auto base = type->baseType(); base->isComposite()) {
530 function->body << u"// call base's method"_s;
531 const auto isCurrentType = [&](const QQmlJSScope::ConstPtr &qmlType) {
532 return qmlType == type;
533 };
534 const QString creationOffset =
535 generate_typeCount(isCurrentType, type->enclosingInlineComponentName());
536 function->body << u"{"_s;
537 function->body << u"QQmltcObjectCreationHelper subCreator(creator, %1);"_s.arg(
538 creationOffset);
539 function->body << u"%1::%2(&subCreator, /* finalize */ false);"_s.arg(base->internalName(),
540 function->name);
541 function->body << u"}"_s;
542 }
543
544 if (!(isDocumentRoot || isInlineComponent))
545 return;
546
547 auto name = isInlineComponent
548 ? InlineComponentOrDocumentRootName(*type->inlineComponentName())
549 : InlineComponentOrDocumentRootName(QQmlJSScope::RootDocumentNameType());
550
551 const auto types = visitor->pureQmlTypes(name);
552 function->body << u"// call children's methods"_s;
553 for (qsizetype i = 1; i < types.size(); ++i) {
554 const auto &type = types[i];
555 Q_ASSERT(type->componentRootStatus() == QQmlJSScope::IsComponentRoot::No);
556 function->body << u"{"_s;
557 function->body << u"auto child = creator->get<%1>(%2);"_s.arg(type->internalName(),
558 QString::number(i));
559 function->body << u"child->%1(creator);"_s.arg(function->name);
560 if (type->hasInterface(interfaceName)) {
561 function->body << u"static_assert(std::is_base_of<%1, %2>::value);"_s.arg(
562 interfaceName, type->internalName());
563 function->body << u"child->%1();"_s.arg(interfaceCall);
564 }
565 function->body << u"}"_s;
566 }
567
568 if (type->hasInterface(interfaceName)) {
569 function->body << u"if (canFinalize) {"_s;
570 function->body << u" // call own method"_s;
571 function->body << u" static_assert(std::is_base_of<%1, %2>::value);"_s.arg(
572 interfaceName, type->internalName());
573 function->body << u" this->%1();"_s.arg(interfaceCall);
574 function->body << u"}"_s;
575 }
576}
577
578/*!
579 \internal
580
581 Generates \a{current.beginClass}'s code. The beginClass method optionally
582 calls QQmlParserStatus::classBegin() when \a type implements the
583 corresponding interface.
584*/
585inline void CodeGenerator::generate_beginClassCode(Type &current,
586 const QQmlJSScope::ConstPtr &type) const
587{
588 using namespace Qt::StringLiterals;
589 generate_interfaceCallCode(&current.beginClass, type, u"QQmlParserStatus"_s, u"classBegin"_s);
590}
591
592/*!
593 \internal
594
595 Generates \a{current.completeComponent}'s code. The completeComponent method
596 optionally calls QQmlParserStatus::componentComplete() when \a type
597 implements the corresponding interface.
598*/
600 const QQmlJSScope::ConstPtr &type) const
601{
602 using namespace Qt::StringLiterals;
603 generate_interfaceCallCode(&current.completeComponent, type, u"QQmlParserStatus"_s,
604 u"componentComplete"_s);
605}
606
607/*!
608 \internal
609
610 Generates \a{current.finalizeComponent}'s code. The finalizeComponent method
611 optionally calls QQmlFinalizerHook::componentFinalized() when \a type
612 implements the corresponding interface.
613*/
615 const QQmlJSScope::ConstPtr &type) const
616{
617 using namespace Qt::StringLiterals;
618 generate_interfaceCallCode(&current.finalizeComponent, type, u"QQmlFinalizerHook"_s,
619 u"componentFinalized"_s);
620}
621
622/*!
623 \internal
624
625 Generates \a{current.handleOnCompleted}'s code. The handleOnCompleted method
626 optionally calls a Component.onCompleted handler if that is present in \a
627 type.
628*/
630 const QQmlJSScope::ConstPtr &type) const
631{
632 using namespace Qt::StringLiterals;
633
634 // QML_handleOnCompleted()'s parameters:
635 // * QQmltcObjectCreationHelper* creator
636 current.handleOnCompleted.body << u"Q_UNUSED(creator)"_s;
637
638 generate_qmltcInstructionCallCode(&current.handleOnCompleted, type, QString(), u"creator"_s);
639}
640
641/*!
642 \internal
643
644 Generates a constexpr function consisting of a sum of type counts for a
645 current QML document. Predicate \a p acts as a stop condition to prematurely
646 end the sum generation.
647
648 The high-level idea:
649
650 Each qmltc-compiled document root has a notion of type count. Type count is
651 a number of types the current QML document contains (except for
652 Component-wrapped types) plus the sum of all type counts of all the QML
653 documents used in the current document: if current document has a type with
654 QML base type, this type's type count is added to the type count of the
655 current document.
656
657 To be able to lookup created objects during the creation process, one needs
658 to know an index of each object within the document + an offset of the
659 document. Index comes from QmltcVisitor and is basically a serial number of
660 a type in the document (index < type count of the document root type). The
661 offset is more indirect.
662
663 The current document always starts with an offset of 0, each type that has a
664 QML base type also "has a sub-document". Each sub-document has a non-0
665 offset X, where X is calculated as a sum of the current document's type
666 count and a cumulative type count of all the previous sub-documents that
667 appear before the sub-document of interest:
668
669 \code
670 // A.qml
671 Item { // offset: 0; number of types == 1 (document root) + 3 (children)
672
673 QmlBase1 { } // offset: 4 (number of types in A.qml itself)
674
675 QmlBase2 { } // offset: 4 + N, where N == typeCount(QmlBase1.qml)
676
677 QmlBase3 { } // offset: (4 + N) + M, where M == typeCount(QmlBase2.qml)
678
679 } // typeCount(A.qml) == 4 + N + M + O, where O == typeCount(QmlBase3.qml)
680 \endcode
681
682 As all objects are put into an array, schematically you can look at it in
683 the following way:
684
685 ```
686 count: 4 N M O
687 objects: aaaa|xxxxxxxxxxxxx|yyyyyyy|zzz
688 ^ ^ ^ ^
689 files: | QmlBase1.qml | QmlBase3.qml
690 A.qml QmlBase2.qml
691 ```
692
693 For the object lookup logic itself, see QQmltcObjectCreationHelper
694*/
695template<typename Predicate>
697 Predicate p, const InlineComponentOrDocumentRootName &inlinedComponent) const
698{
699 using namespace Qt::StringLiterals;
700
701 const QList<QQmlJSScope::ConstPtr> typesWithBaseTypeCount =
702 visitor->qmlTypesWithQmlBases(inlinedComponent);
703 QStringList components;
704 components.reserve(1 + typesWithBaseTypeCount.size());
705
706 Q_ASSERT(visitor->pureQmlTypes(inlinedComponent).size() > 0);
707 Q_ASSERT(visitor->typeCount(inlinedComponent)
708 >= visitor->pureQmlTypes(inlinedComponent).size());
709 qsizetype typeCount = visitor->typeCount(inlinedComponent);
710
711 // add this document's type counts minus document root (if not an inline component)
712 if (std::holds_alternative<RootDocumentNameType>(inlinedComponent))
713 typeCount--;
714 components << QString::number(typeCount);
715
716 // traverse types with QML base classes
717 for (const QQmlJSScope::ConstPtr &t : typesWithBaseTypeCount) {
718 if (p(t))
719 break;
720 QString typeCountTemplate = u"QQmltcObjectCreationHelper::typeCount<%1>()"_s;
721 if (t == visitor->result()) { // t is this document's root
722 components << typeCountTemplate.arg(t->baseTypeName());
723 } else if (t->isInlineComponent()) {
724 // inline components always have a base class, by definition
725 Q_ASSERT(t->baseType());
726 components << typeCountTemplate.arg(t->baseType()->internalName());
727 } else {
728 components << typeCountTemplate.arg(t->internalName());
729 }
730 }
731
732 return components.join(u" + "_s);
733}
734
735} // namespace QQmltc
736
737QT_END_NAMESPACE
738
739#endif // QQMLTCCOMPILERPIECES_P_H
static QString scopeName(const QQmlJSScope::ConstPtr &scope)
static QByteArray toLiteral(const QByteArray &utf8)
static QString serializeTranslation(const QQmlTranslation::QsTrIdData &data)
static const QString privateEngineName
static void generate_getCompilationUnitFromUrl()
static const QString typeCountName
void generate_qmltcInstructionCallCode(Method *function, const QQmlJSScope::ConstPtr &type, const QString &baseInstructionArgs, const QString &childInstructionArgs) const
static PreparedValue wrap_extensionType(const QQmlJSScope::ConstPtr &type, const QQmlJSMetaProperty &p, const QString &accessor)
void generate_interfaceCallCode(Method *function, const QQmlJSScope::ConstPtr &type, const QString &interfaceName, const QString &interfaceCall) const
void generate_handleOnCompletedCode(Type &current, const QQmlJSScope::ConstPtr &type) const
static QString wrap_addressof(const QString &addressed)
static void generate_callExecuteRuntimeFunction(QStringList *block, const QString &url, QQmlJSMetaMethod::AbsoluteFunctionIndex index, const QString &accessor, const QString &returnType, const QList< Variable > &parameters={})
QString generate_typeCount(const InlineComponentOrDocumentRootName &inlinedComponent) const
static void generate_assignToListProperty(QStringList *block, const QQmlJSScope::ConstPtr &type, const QQmlJSMetaProperty &p, const QStringList &value, const QString &accessor, QString &qmlListVarName)
void generate_finalizeComponentCode(Type &current, const QQmlJSScope::ConstPtr &type) const
static void generate_createTranslationBindingOnProperty(QStringList *block, const TranslationBindingInfo &info)
void generate_initCodeForTopLevelComponent(Type &current, const QQmlJSScope::ConstPtr &type)
QString generate_typeCount(Predicate p, const InlineComponentOrDocumentRootName &inlinedComponent) const
static QString wrap_privateClass(const QString &accessor, const QQmlJSMetaProperty &p)
decltype(auto) generate_initCode(Type &current, const QQmlJSScope::ConstPtr &type) const
static void generate_createBindingOnProperty(QStringList *block, const QString &unitVarName, const QString &scope, qsizetype functionIndex, const QString &target, const QQmlJSScope::ConstPtr &targetType, int propertyIndex, const QQmlJSMetaProperty &p, int valueTypeIndex, const QString &subTarget)
void generate_setComplexBindingsCode(Type &current, const QQmlJSScope::ConstPtr &type) const
void generate_endInitCode(Type &current, const QQmlJSScope::ConstPtr &type) const
void generate_beginClassCode(Type &current, const QQmlJSScope::ConstPtr &type) const
static void generate_setIdValue(QStringList *block, const QString &context, qsizetype index, const QString &accessor, const QString &idString)
static void generate_assignToProperty(QStringList *block, const QQmlJSScope::ConstPtr &type, const QQmlJSMetaProperty &p, const QString &value, const QString &accessor, bool constructFromQObject=false)
void generate_completeComponentCode(Type &current, const QQmlJSScope::ConstPtr &type) const
static PreparedValue wrap_mismatchingTypeConversion(const QQmlJSMetaProperty &p, QString value)