aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmltc
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2021-12-30 13:29:41 +0100
committerAndrei Golubev <andrei.golubev@qt.io>2022-02-22 09:20:17 +0100
commiteaf00da10a4ae10b6b26684fe5893f671ad8f631 (patch)
tree1a9409d5c81d561bd3c16034cccaefad30121198 /tools/qmltc
parentc07a77c96eb2ff3ce3317da8336d9a6891b50e98 (diff)
qmltc: Handle (simple) deferred properties correctly
Simple deferred properties occur quite often in QML (throughout Qt Quick, for example), so qmltc should be able to deal with them as with deferred properties Ignore generalized group properties, PropertyChanges and similar types for now. They require more testing and are well out of scope of the tech preview Task-number: QTBUG-100053 Change-Id: I0f3588789d188cd6bec81de0b61d3205b665a917 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 68924be5b5282fb9f0276c743cf450f2e2aa5274) Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools/qmltc')
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp38
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.cpp38
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.h2
3 files changed, 77 insertions, 1 deletions
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index f7c13657a7..f0e2ca2993 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -291,6 +291,7 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
m_ignoredTypes = collectIgnoredTypes(context, objects);
};
executor.addPass(setIgnoredTypes);
+ executor.addPass(&setDeferredBindings);
// run all passes:
executor.run(m_logger);
@@ -650,6 +651,17 @@ void CodeGenerator::compileObject(
+ u"(engine, /* finalize */ false);";
compiled.endInit.body << u"}"_qs;
}
+
+ if (object.irObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
+ compiled.endInit.body << u"{ // defer bindings"_qs;
+ compiled.endInit.body << u"auto ddata = QQmlData::get(this);"_qs;
+ compiled.endInit.body << u"auto thisContext = ddata->outerContext;"_qs;
+ compiled.endInit.body << u"Q_ASSERT(thisContext);"_qs;
+ compiled.endInit.body << u"ddata->deferData(" + QString::number(objectIndex) + u", "
+ + CodeGeneratorUtility::compilationUnitVariable.name + u", thisContext);";
+ compiled.endInit.body << u"}"_qs;
+ }
+
// TODO: decide whether begin/end property update group is needed
// compiled.endInit.body << u"Qt::beginPropertyUpdateGroup(); // defer binding evaluation"_qs;
@@ -1168,6 +1180,29 @@ void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Bindin
const CodeGenObject &object,
const CodeGenerator::AccessorData &accessor)
{
+ // Note: unlike QQmlObjectCreator, we don't have to do a complicated
+ // deferral logic for bindings: if a binding is deferred, it is not compiled
+ // (potentially, with all the bindings inside of it), period.
+ if (binding.flags & QV4::CompiledData::Binding::IsDeferredBinding) {
+ if (binding.type == QmlIR::Binding::Type_GroupProperty) {
+ // TODO: we should warn about this in QmlCompiler library
+ qCWarning(lcCodeGenerator)
+ << QStringLiteral("Binding at line %1 column %2 is not deferred as it is a "
+ "binding on a group property.")
+ .arg(QString::number(binding.location.line),
+ QString::number(binding.location.column));
+ // we do not support PropertyChanges and other types with similar
+ // behavior yet, so this binding is compiled
+ } else {
+ qCDebug(lcCodeGenerator)
+ << QStringLiteral(
+ "Binding at line %1 column %2 is deferred and thus not compiled")
+ .arg(QString::number(binding.location.line),
+ QString::number(binding.location.column));
+ return;
+ }
+ }
+
// TODO: cache property name somehow, so we don't need to look it up again
QString propertyName = m_doc->stringAt(binding.propertyNameIndex);
if (propertyName.isEmpty()) {
@@ -1413,9 +1448,10 @@ void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Bindin
// compile bindings of the attached property
auto sortedBindings = toOrderedSequence(
irObject->bindingsBegin(), irObject->bindingsEnd(), irObject->bindingCount());
- for (auto it : qAsConst(sortedBindings))
+ for (auto it : qAsConst(sortedBindings)) {
compileBinding(current, *it, attachedObject,
{ object.type, attachedMemberName, propertyName, false });
+ }
}
break;
}
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
index 586cc85754..611c317490 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
@@ -1079,3 +1079,41 @@ QSet<QQmlJSScope::ConstPtr> collectIgnoredTypes(const Qml2CppContext &context,
return ignored;
}
+
+static void setDeferred(const Qml2CppContext &context, qsizetype objectIndex,
+ QList<Qml2CppObject> &objects)
+{
+ Q_UNUSED(objects);
+
+ Qml2CppObject &o = objects[objectIndex];
+
+ // c.f. QQmlDeferredAndCustomParserBindingScanner::scanObject()
+ if (o.irObject->flags & QV4::CompiledData::Object::IsComponent) {
+ // unlike QmlIR compiler, qmltc should not care about anything within a
+ // component (let the QQmlComponent wrapper - at runtime anyway - take
+ // care of this type instead)
+ return;
+ }
+
+ const auto setRecursive = [&](QmlIR::Binding &binding) {
+ if (binding.type >= QmlIR::Binding::Type_Object)
+ setDeferred(context, binding.value.objectIndex, objects); // Note: recursive call here!
+
+ const QString propName = findPropertyName(context, o.type, binding);
+ Q_ASSERT(!propName.isEmpty());
+
+ if (o.type->isNameDeferred(propName)) {
+ binding.flags |= QV4::CompiledData::Binding::IsDeferredBinding;
+ o.irObject->flags |= QV4::CompiledData::Object::HasDeferredBindings;
+ }
+ };
+
+ std::for_each(o.irObject->bindingsBegin(), o.irObject->bindingsEnd(), setRecursive);
+}
+
+void setDeferredBindings(const Qml2CppContext &context, QList<Qml2CppObject> &objects)
+{
+ // as we do not support InlineComponents just yet, we can shortcut the logic
+ // here to only work with root object
+ setDeferred(context, 0, objects);
+}
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.h b/tools/qmltc/prototype/qml2cppdefaultpasses.h
index 29e5acf985..443292b30f 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.h
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.h
@@ -86,4 +86,6 @@ findImmediateParents(const Qml2CppContext &context, QList<Qml2CppObject> &object
QSet<QQmlJSScope::ConstPtr> collectIgnoredTypes(const Qml2CppContext &context,
QList<Qml2CppObject> &objects);
+void setDeferredBindings(const Qml2CppContext &context, QList<Qml2CppObject> &objects);
+
#endif // QML2CPPPASSES_H