53 const QQmlJSScope::ConstPtr &type)
const;
55 const QQmlJSScope::ConstPtr &type);
58 const QQmlJSScope::ConstPtr &type,
59 const QString &baseInstructionArgs,
60 const QString &childInstructionArgs)
const;
63 const QQmlJSScope::ConstPtr &type)
const;
66 const QString &interfaceName,
67 const QString &interfaceCall)
const;
70 const QQmlJSScope::ConstPtr &type)
const;
72 const QQmlJSScope::ConstPtr &type)
const;
74 const QQmlJSScope::ConstPtr &type)
const;
77 const QQmlJSMetaProperty &p,
const QString &value,
78 const QString &accessor,
79 bool constructFromQObject =
false);
82 const QQmlJSMetaProperty &p,
const QStringList &value,
83 const QString &accessor, QString &qmlListVarName);
85 static void generate_setIdValue(QStringList *block,
const QString &context, qsizetype index,
86 const QString &accessor,
const QString &idString);
91 return generate_typeCount([](
const QQmlJSScope::ConstPtr &) {
return false; },
96
97
98
99
100 template<
typename Predicate>
103 const InlineComponentOrDocumentRootName &inlinedComponent)
const;
106 QQmlJSMetaMethod::AbsoluteFunctionIndex index,
107 const QString &accessor,
108 const QString &returnType,
109 const QList<Variable> ¶meters = {});
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);
150 const QQmlJSMetaProperty &p,
const QString &accessor);
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'_');
184 const QQmlJSScope::ConstPtr &type)
const
186 using namespace Qt::StringLiterals;
193 const bool isDocumentRoot = type == visitor->result();
194 const bool isInlineComponent = type->isInlineComponent();
196 current.init.body << u"Q_UNUSED(creator)"_s;
198 current.init.body << u"auto context = parentContext;"_s;
204 const auto realQmlScope = [](
const QQmlJSScope::ConstPtr &scope) {
205 if (scope->isArrayScope())
206 return scope->parentScope();
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;
217 if (
auto base = type->baseType(); base->isComposite()) {
221 if (isDocumentRoot || isInlineComponent)
222 lhs = u"context = "_s;
223 current.init.body << u"// 0. call base's init method"_s;
225 const auto isCurrentType = [&](
const QQmlJSScope::ConstPtr &qmlType) {
226 return qmlType == type;
228 const QString creationOffset =
229 generate_typeCount(isCurrentType, type->enclosingInlineComponentName());
231 current.init.body << u"{"_s;
232 current.init.body << u"QQmltcObjectCreationHelper subCreator(creator, %1);"_s.arg(
235 << QStringLiteral(
"%1%2::%3(&subCreator, engine, context, /* finalize */ false);")
236 .arg(lhs, base->internalName(), current.init.name);
238 if (!isDocumentRoot && !isInlineComponent) {
240 << u"QQmlEnginePrivate::setInternalContext("
241 "this, parentContext, QQmlContextData::OrdinaryObject);"_s;
243 current.init.body << u"}"_s;
247 << QStringLiteral(
"auto %1 = QQmlEnginePrivate::get(engine);").arg(privateEngineName);
248 current.init.body << QStringLiteral(
"Q_UNUSED(%1)").arg(privateEngineName);
252 if (isDocumentRoot || isInlineComponent) {
253 current.init.body << u"// 1. create new QML context for this document"_s;
256 "context = %1->createComponentRootContext("
257 "%1->compilationUnitFromUrl(%2()), context, %3);")
258 .arg(privateEngineName, urlMethodName())
259 .arg(
this->visitor->creationIndex(type));
261 current.init.body << u"// 1. use current context as this object's context"_s;
262 current.init.body << u"// context = context;"_s;
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;
277 current.variables.emplaceBack(u"QQmlRefPointer<QQmlContextData>"_s, u"q_qmltc_thisContext"_s,
280 const QString relevantContext
281 = (isDocumentRoot || isInlineComponent) ? u"context"_s : u"parentContext"_s;
283 << u"%1::q_qmltc_thisContext = %2;"_s.arg(type->internalName(), relevantContext);
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 ¤t.init.body, relevantContext, id, u"this"_s, idString);
295 bool hasExtension =
false;
296 for (
auto cppBase = QQmlJSScope::nonCompositeBaseType(type); cppBase;
297 cppBase = cppBase->baseType()) {
299 if (cppBase->internalName() == u"QObject"_s)
301 if (cppBase->extensionType().extensionSpecifier != QQmlJSScope::NotExtension) {
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;
313 const auto generateFinalLines = [¤t, 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);
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(
" }");
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;
337 current.init.body << u"return context;"_s;
340 return QScopeGuard(generateFinalLines);
353 const QQmlJSScope::ConstPtr &type)
357 using namespace Qt::StringLiterals;
361 current.init.body << u"// init QQmlComponent: see QQmlObjectCreator::createComponent()"_s;
362 current.init.body << u"{"_s;
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;
374 current.init.body << u"// QQmlComponent(engine, compilationUnit, start, parent):"_s;
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;
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;
397 Method *function,
const QQmlJSScope::ConstPtr &type,
398 const QString &baseInstructionArgs,
const QString &childInstructionArgs)
const
400 using namespace Qt::StringLiterals;
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;
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(
412 if (!baseInstructionArgs.isEmpty()) {
413 function->body << u"%1::%2(&subCreator, %3);"_s.arg(
414 base->internalName(), function->name, baseInstructionArgs);
416 function->body << u"%1::%2(&subCreator);"_s.arg(base->internalName(), function->name);
418 function->body << u"}"_s;
421 const bool isDocumentRoot = type == visitor->result();
422 const bool isInlineComponent = type->isInlineComponent();
425 || isInlineComponent))
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);
438 function->body << u"// call own method code"_s;
450 const QQmlJSScope::ConstPtr &type)
const
452 using namespace Qt::StringLiterals;
457 current.endInit.body << u"Q_UNUSED(creator)"_s;
458 current.endInit.body << u"Q_UNUSED(engine)"_s;
460 generate_qmltcInstructionCallCode(¤t.endInit, type, u"engine"_s, u"creator, engine"_s);
462 if (visitor->hasDeferredBindings(type)) {
464 if (
auto potentialICName = type->enclosingInlineComponentName();
465 std::holds_alternative<QQmlJSScope::InlineComponentNameType>(potentialICName))
466 icName =get<QQmlJSScope::InlineComponentNameType>(potentialICName);
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;
514 const QQmlJSScope::ConstPtr &type,
515 const QString &interfaceName,
516 const QString &interfaceCall)
const
518 using namespace Qt::StringLiterals;
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;
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;
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(
539 function->body << u"%1::%2(&subCreator, /* finalize */ false);"_s.arg(base->internalName(),
541 function->body << u"}"_s;
544 if (!(isDocumentRoot || isInlineComponent))
547 auto name = isInlineComponent
548 ? InlineComponentOrDocumentRootName(*type->inlineComponentName())
549 : InlineComponentOrDocumentRootName(QQmlJSScope::RootDocumentNameType());
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(),
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);
565 function->body << u"}"_s;
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;
697 Predicate p,
const InlineComponentOrDocumentRootName &inlinedComponent)
const
699 using namespace Qt::StringLiterals;
701 const QList<QQmlJSScope::ConstPtr> typesWithBaseTypeCount =
702 visitor->qmlTypesWithQmlBases(inlinedComponent);
703 QStringList components;
704 components.reserve(1 + typesWithBaseTypeCount.size());
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);
712 if (std::holds_alternative<RootDocumentNameType>(inlinedComponent))
714 components << QString::number(typeCount);
717 for (
const QQmlJSScope::ConstPtr &t : typesWithBaseTypeCount) {
720 QString typeCountTemplate = u"QQmltcObjectCreationHelper::typeCount<%1>()"_s;
721 if (t == visitor->result()) {
722 components << typeCountTemplate.arg(t->baseTypeName());
723 }
else if (t->isInlineComponent()) {
725 Q_ASSERT(t->baseType());
726 components << typeCountTemplate.arg(t->baseType()->internalName());
728 components << typeCountTemplate.arg(t->internalName());
732 return components.join(u" + "_s);