aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/qmltc/qmltccodewriter.cpp1
-rw-r--r--tools/qmltc/qmltccompiler.cpp23
-rw-r--r--tools/qmltc/qmltccompiler.h11
-rw-r--r--tools/qmltc/qmltccompilerpieces.h32
-rw-r--r--tools/qmltc/qmltcoutputir.h6
5 files changed, 60 insertions, 13 deletions
diff --git a/tools/qmltc/qmltccodewriter.cpp b/tools/qmltc/qmltccodewriter.cpp
index afdfd78d7e..7c9958e215 100644
--- a/tools/qmltc/qmltccodewriter.cpp
+++ b/tools/qmltc/qmltccodewriter.cpp
@@ -323,6 +323,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type)
QmltcCodeWriter::write(code, type.baselineCtor);
QmltcCodeWriter::write(code, type.init);
QmltcCodeWriter::write(code, type.endInit);
+ QmltcCodeWriter::write(code, type.setComplexBindings);
QmltcCodeWriter::write(code, type.beginClass);
QmltcCodeWriter::write(code, type.completeComponent);
QmltcCodeWriter::write(code, type.finalizeComponent);
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index 9a38cca06c..31140e5281 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -188,6 +188,7 @@ void QmltcCompiler::compileType(
current.init.access = QQmlJSMetaMethod::Protected;
current.beginClass.access = QQmlJSMetaMethod::Protected;
current.endInit.access = QQmlJSMetaMethod::Protected;
+ current.setComplexBindings.access = QQmlJSMetaMethod::Protected;
current.completeComponent.access = QQmlJSMetaMethod::Protected;
current.finalizeComponent.access = QQmlJSMetaMethod::Protected;
current.handleOnCompleted.access = QQmlJSMetaMethod::Protected;
@@ -200,6 +201,8 @@ void QmltcCompiler::compileType(
current.beginClass.returnType = u"void"_s;
current.endInit.name = u"QML_endInit"_s;
current.endInit.returnType = u"void"_s;
+ current.setComplexBindings.name = u"QML_setComplexBindings"_s;
+ current.setComplexBindings.returnType = u"void"_s;
current.completeComponent.name = u"QML_completeComponent"_s;
current.completeComponent.returnType = u"void"_s;
current.finalizeComponent.name = u"QML_finalizeComponent"_s;
@@ -217,6 +220,7 @@ void QmltcCompiler::compileType(
current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag };
current.beginClass.parameterList = { creator, finalizeFlag };
current.endInit.parameterList = { creator, engine, finalizeFlag };
+ current.setComplexBindings.parameterList = { creator, engine, finalizeFlag };
current.completeComponent.parameterList = { creator, finalizeFlag };
current.finalizeComponent.parameterList = { creator, finalizeFlag };
current.handleOnCompleted.parameterList = { creator, finalizeFlag };
@@ -225,6 +229,7 @@ void QmltcCompiler::compileType(
current.init.parameterList = { creator, engine, ctxtdata };
current.beginClass.parameterList = { creator };
current.endInit.parameterList = { creator, engine };
+ current.setComplexBindings.parameterList = { creator, engine };
current.completeComponent.parameterList = { creator };
current.finalizeComponent.parameterList = { creator };
current.handleOnCompleted.parameterList = { creator };
@@ -266,6 +271,7 @@ void QmltcCompiler::compileType(
auto postponedQmlContextSetup = generator.generate_initCode(current, type);
generator.generate_endInitCode(current, type);
+ generator.generate_setComplexBindingsCode(current, type);
generator.generate_beginClassCode(current, type);
generator.generate_completeComponentCode(current, type);
generator.generate_finalizeComponentCode(current, type);
@@ -281,9 +287,8 @@ static Iterator partitionBindings(Iterator first, Iterator last)
// later point, so we should sort or partition the range. we do a stable
// partition since the relative order of binding evaluation affects the UI
return std::stable_partition(first, last, [](const QQmlJSMetaPropertyBinding &b) {
- // we want script bindings to be at the end, so do the negation of "is
- // script binding"
- return b.bindingType() != QQmlJSMetaPropertyBinding::Script;
+ // we want complex bindings to be at the end, so do the negation
+ return !QmltcCompiler::isComplexBinding(b);
});
}
@@ -1227,10 +1232,10 @@ void QmltcCompiler::compileScriptBinding(QmltcType &current,
slotMethod.type = QQmlJSMetaMethod::Slot;
current.functions << std::move(slotMethod);
- current.endInit.body << u"QObject::connect(" + This_signal + u", "
- + QmltcCodeGenerator::wrap_qOverload(slotParameters,
- u"&" + objectClassName_signal + u"::"
- + signalName)
+ current.setComplexBindings.body
+ << u"QObject::connect(" + This_signal + u", "
+ + QmltcCodeGenerator::wrap_qOverload(
+ slotParameters, u"&" + objectClassName_signal + u"::" + signalName)
+ u", " + This_slot + u", &" + objectClassName_slot + u"::" + slotName
+ u");";
};
@@ -1269,7 +1274,7 @@ void QmltcCompiler::compileScriptBinding(QmltcType &current,
}
QmltcCodeGenerator::generate_createBindingOnProperty(
- &current.endInit.body, generate_callCompilationUnit(m_urlMethodName),
+ &current.setComplexBindings.body, generate_callCompilationUnit(m_urlMethodName),
u"this"_s, // NB: always using enclosing object as a scope for the binding
static_cast<qsizetype>(objectType->ownRuntimeFunctionIndex(binding.scriptIndex())),
bindingTarget, // binding target
@@ -1314,7 +1319,7 @@ void QmltcCompiler::compileScriptBinding(QmltcType &current,
// TODO: this could be dropped if QQmlEngine::setContextForObject() is
// done before currently generated C++ object is constructed
- current.endInit.body << bindingSymbolName + u".reset(new QPropertyChangeHandler<"
+ current.setComplexBindings.body << bindingSymbolName + u".reset(new QPropertyChangeHandler<"
+ bindingFunctorName + u">("
+ QmltcCodeGenerator::wrap_privateClass(accessor.name, *actualProperty)
+ u"->" + bindableString + u"().onValueChanged(" + bindingFunctorName + u"("
diff --git a/tools/qmltc/qmltccompiler.h b/tools/qmltc/qmltccompiler.h
index 67b21bad25..ede4d3c6a0 100644
--- a/tools/qmltc/qmltccompiler.h
+++ b/tools/qmltc/qmltccompiler.h
@@ -36,6 +36,17 @@ public:
~QmltcCompiler();
+ /*! \internal
+
+ Returns \c true if \a binding is considered complex by the compiler
+ (requires special code generation)
+ */
+ static bool isComplexBinding(const QQmlJSMetaPropertyBinding &binding)
+ {
+ // TODO: translation bindings (once supported) are also complex?
+ return binding.bindingType() == QQmlJSMetaPropertyBinding::Script;
+ }
+
private:
QString m_url; // QML input file url
QmltcTypeResolver *m_typeResolver = nullptr;
diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h
index ebdd5d048c..cbee19485d 100644
--- a/tools/qmltc/qmltccompilerpieces.h
+++ b/tools/qmltc/qmltccompilerpieces.h
@@ -40,6 +40,8 @@ struct QmltcCodeGenerator
const QString &baseInstructionArgs,
const QString &childInstructionArgs) const;
inline void generate_endInitCode(QmltcType &current, const QQmlJSScope::ConstPtr &type) const;
+ inline void generate_setComplexBindingsCode(QmltcType &current,
+ const QQmlJSScope::ConstPtr &type) const;
inline void generate_interfaceCallCode(QmltcMethod *function, const QQmlJSScope::ConstPtr &type,
const QString &interfaceName,
@@ -251,6 +253,8 @@ inline decltype(auto) QmltcCodeGenerator::generate_initCode(QmltcType &current,
.arg(current.beginClass.name);
current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);")
.arg(current.endInit.name);
+ current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);")
+ .arg(current.setComplexBindings.name);
current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
.arg(current.completeComponent.name);
current.init.body << QStringLiteral(" %1(creator, /* finalize */ true);")
@@ -398,6 +402,34 @@ inline void QmltcCodeGenerator::generate_endInitCode(QmltcType &current,
/*!
\internal
+ Generates \a{current.setComplexBindings}'s code. The setComplexBindings
+ method creates complex bindings (such as script bindings). Additionally, the
+ QML document root's setComplexBindings calls setComplexBindings methods of
+ all the necessary QML types within the document.
+*/
+inline void
+QmltcCodeGenerator::generate_setComplexBindingsCode(QmltcType &current,
+ const QQmlJSScope::ConstPtr &type) const
+{
+ using namespace Qt::StringLiterals;
+
+ // QML_setComplexBindings()'s parameters:
+ // * QQmltcObjectCreationHelper* creator
+ // * QQmlEngine* engine
+ // * bool canFinalize [optional, when document root]
+ const bool isDocumentRoot = type == visitor->result();
+ current.setComplexBindings.body << u"Q_UNUSED(creator);"_s;
+ current.setComplexBindings.body << u"Q_UNUSED(engine);"_s;
+ if (isDocumentRoot)
+ current.setComplexBindings.body << u"Q_UNUSED(canFinalize);"_s;
+
+ generate_qmltcInstructionCallCode(&current.setComplexBindings, type,
+ u"engine, /* finalize */ false"_s, u"creator, engine"_s);
+}
+
+/*!
+ \internal
+
A generic helper function that generates interface code boilerplate, adding
it to a passed \a function. This is a building block used to generate e.g.
QQmlParserStatus API calls.
diff --git a/tools/qmltc/qmltcoutputir.h b/tools/qmltc/qmltcoutputir.h
index df4395232d..6e49636980 100644
--- a/tools/qmltc/qmltcoutputir.h
+++ b/tools/qmltc/qmltcoutputir.h
@@ -108,14 +108,12 @@ struct QmltcType
QmltcCtor externalCtor {}; // calls basicCtor, calls init
QmltcMethod init {}; // starts object initialization (context setup), calls finalize
QmltcMethod beginClass {}; // calls QQmlParserStatus::classBegin()
- QmltcMethod endInit {}; // ends object initialization (with binding setup)
+ QmltcMethod endInit {}; // ends object initialization (with "simple" bindings setup)
+ QmltcMethod setComplexBindings {}; // sets up "complex" (e.g. script) bindings
QmltcMethod completeComponent {}; // calls QQmlParserStatus::componentComplete()
QmltcMethod finalizeComponent {}; // calls QQmlFinalizerHook::componentFinalized()
QmltcMethod handleOnCompleted {}; // calls Component.onCompleted
- // TODO: add a separate special member function to set script bindings in a
- // separate step
-
std::optional<QmltcDtor> dtor {};
// member functions: methods, signals and slots