19 Q_ASSERT(scope->isFullyResolved());
20 const auto scopeType = scope->scopeType();
21 if (scopeType == QQmlSA::ScopeType::GroupedPropertyScope
22 || scopeType == QQmlSA::ScopeType::AttachedPropertyScope) {
23 return scope->baseType()->internalName();
25 return scope->internalName();
29 const QQmlJSScope::ConstPtr &type,
const QQmlJSMetaProperty &p,
const QString &accessor)
31 Q_ASSERT(type->isFullyResolved());
34 QString value = accessor;
37 auto [owner, ownerKind] = QQmlJSScope::ownerOfProperty(type, p.propertyName());
39 Q_ASSERT(owner->isFullyResolved());
42 if (ownerKind == QQmlJSScope::ExtensionType) {
44 Q_ASSERT(!owner->isComposite());
49 const QString extensionObjectName = u"extObject"_s;
50 if (type->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) {
55 int extensionIndex = 0;
56 auto cppBase = QQmlJSScope::nonCompositeBaseType(type);
57 for (
auto t = cppBase; t; t = t->baseType()) {
58 if (
auto [ext, kind] = t->extensionType(); kind != QQmlJSScope::NotExtension) {
59 if (ext->isSameType(owner))
65 prologue << u"static_assert(std::is_base_of<%1, %2>::value);"_s.arg(u"QObject"_s,
67 prologue << u"auto %1 = qobject_cast<%2 *>(QQmlPrivate::qmlExtendedObject(%3, %4));"_s
68 .arg(extensionObjectName, owner->internalName(), accessor,
69 QString::number(extensionIndex));
74 prologue << u"static_assert(sizeof(%1) == sizeof(%2));"_s.arg(scopeName(type),
75 owner->internalName());
76 prologue << u"static_assert(alignof(%1) == alignof(%2));"_s.arg(scopeName(type),
77 owner->internalName());
78 prologue << u"auto %1 = reinterpret_cast<%2 *>(%3);"_s.arg(
79 extensionObjectName, owner->internalName(), accessor);
81 prologue << u"Q_ASSERT(%1);"_s.arg(extensionObjectName);
82 value = extensionObjectName;
86 return { prologue, value, epilogue };
90 QStringList *block,
const QQmlJSScope::ConstPtr &type,
const QQmlJSMetaProperty &p,
91 const QStringList &values,
const QString &accessor, QString &qmlListVarName)
94 const bool populateLocalListProperty = qmlListVarName.isEmpty();
96 if (populateLocalListProperty) {
97 auto [extensionPrologue, extensionAccessor, extensionEpilogue] =
98 CodeGenerator::wrap_extensionType(
99 type, p, CodeGenerator::wrap_privateClass(accessor, p));
101 qmlListVarName = u"listprop_%1"_s.arg(p.propertyName());
102 const QQmlJSScope::ConstPtr elementType = p.type()->elementType();
103 *block << u"QQmlListProperty<%1> %2;"_s.arg(elementType->internalName(), qmlListVarName);
104 *block << extensionPrologue;
105 *block << u"%1 = %2->%3();"_s.arg(qmlListVarName, extensionAccessor, p.read());
106 *block << extensionEpilogue;
108 for (
const QString &value : values) {
109 auto [prologue, wrappedValue, epilogue] =
110 CodeGenerator::wrap_mismatchingTypeConversion(p, value);
112 *block << u"%1.append(std::addressof(%1), %2);"_s.arg(qmlListVarName, wrappedValue);
117void CodeGenerator::generate_assignToProperty(QStringList *block,
const QQmlJSScope::ConstPtr &type,
118 const QQmlJSMetaProperty &p,
const QString &value,
119 const QString &accessor,
bool constructFromQObject)
122 Q_ASSERT(p.isValid());
123 Q_ASSERT(!p.isList());
125 const QString propertyName = p.propertyName();
127 if (type->hasOwnProperty(p.propertyName()) && !p.isAlias()) {
128 Q_ASSERT(!p.isPrivate());
130 auto [prologue, wrappedValue, epilogue] =
131 CodeGenerator::wrap_mismatchingTypeConversion(p, value);
133 *block << u"%1->m_%2 = %3;"_s.arg(accessor, propertyName, wrappedValue);
135 }
else if (QString propertySetter = p.write(); !propertySetter.isEmpty()
136 && !QQmlJSUtils::bindablePropertyHasDefaultAccessor(
137 p, QQmlJSUtils::PropertyAccessor_Write)) {
139 auto [prologue, wrappedValue, epilogue] =
140 CodeGenerator::wrap_mismatchingTypeConversion(p, value);
143 auto [extensionPrologue, extensionAccessor, extensionEpilogue] =
144 CodeGenerator::wrap_extensionType(
145 type, p, CodeGenerator::wrap_privateClass(accessor, p));
146 *block += extensionPrologue;
147 *block << extensionAccessor + u"->" + propertySetter + u"(" + wrappedValue + u");";
148 *block += extensionEpilogue;
153 *block << u"{ // couldn't find property setter, so using QObject::setProperty()"_s;
155 if (constructFromQObject) {
156 const QString variantName = u"var_" + propertyName;
157 *block << u"QVariant " + variantName + u";";
158 *block << variantName + u".setValue(" + val + u");";
159 val = u"std::move(" + variantName + u")";
162 *block << accessor + u"->setProperty(\"" + propertyName + u"\", " + val + u");";
167void CodeGenerator::generate_setIdValue(QStringList *block,
const QString &context, qsizetype index,
168 const QString &accessor,
const QString &idString)
170 Q_ASSERT(index >= 0);
171 *block << u"Q_ASSERT(%1 < %2->numIdValues()); // make sure Id is in bounds"_s.arg(index).arg(
173 *block << u"%1->setIdValue(%2 /* id: %3 */, %4);"_s.arg(context, QString::number(index),
178 QStringList *block,
const QString &url, QQmlJSMetaMethod::AbsoluteFunctionIndex index,
179 const QString &accessor,
const QString &returnType,
const QList<Variable> ¶meters)
181 *block << u"QQmlEnginePrivate *e = QQmlEnginePrivate::get(qmlEngine(" + accessor + u"));";
183 const QString returnValueName = u"_ret"_s;
185 args.reserve(parameters.size() + 1);
187 types.reserve(parameters.size() + 1);
188 if (returnType == u"void"_s) {
189 args << u"nullptr"_s;
190 types << u"QMetaType::fromType<void>()"_s;
192 *block << returnType + u" " + returnValueName + u"{};";
193 args << u"const_cast<void *>(reinterpret_cast<const void *>(std::addressof("
194 + returnValueName + u")))";
195 types << u"QMetaType::fromType<std::decay_t<" + returnType + u">>()";
198 for (
const Variable &p : parameters) {
199 args << u"const_cast<void *>(reinterpret_cast<const void *>(std::addressof(" + p.name
201 types << u"QMetaType::fromType<std::decay_t<" + p.cppType + u">>()";
204 *block << u"void *_a[] = { " + args.join(u", "_s) + u" };";
205 *block << u"QMetaType _t[] = { " + types.join(u", "_s) + u" };";
206 const qsizetype runtimeIndex =
static_cast<qsizetype>(index);
207 Q_ASSERT(runtimeIndex >= 0);
208 *block << u"e->executeRuntimeFunction(" + url + u", " + QString::number(runtimeIndex) + u", "
209 + accessor + u", " + QString::number(parameters.size()) + u", _a, _t);";
210 if (returnType != u"void"_s)
211 *block << u"return " + returnValueName + u";";
215 QStringList *block,
const QString &unitVarName,
const QString &scope,
216 qsizetype functionIndex,
const QString &target,
const QQmlJSScope::ConstPtr &targetType,
217 int propertyIndex,
const QQmlJSMetaProperty &p,
int valueTypeIndex,
218 const QString &subTarget)
220 const QString propName = QQmlJSUtils::toLiteral(p.propertyName());
221 if (QString bindable = p.bindable(); !bindable.isEmpty()) {
223 QString createBindingForBindable = u"QT_PREPEND_NAMESPACE(QQmlCppBinding)::"
224 u"createBindingForBindable("
225 + unitVarName + u", " + scope + u", " + QString::number(functionIndex) + u", "
226 + target + u", " + QString::number(propertyIndex) + u", "
227 + QString::number(valueTypeIndex) + u", " + propName + u")";
228 const QString accessor = (valueTypeIndex == -1) ? target : subTarget;
230 QStringList prologue;
231 QString value = CodeGenerator::wrap_privateClass(accessor, p);
232 QStringList epilogue;
234 auto [pro, v, epi] = CodeGenerator::wrap_extensionType(targetType, p, value);
235 std::tie(prologue, value, epilogue) =
std::make_tuple(pro, v, epi);
239 *block << u"if (!initializedCache.contains(QStringLiteral(\"%1\")))"_s.arg(p.propertyName());
240 *block << u" "_s + value + u"->" + bindable + u"().setBinding(" + createBindingForBindable + u");";
243 QString createBindingForNonBindable =
245 + u"QT_PREPEND_NAMESPACE(QQmlCppBinding)::createBindingForNonBindable(" + unitVarName
246 + u", " + scope + u", " + QString::number(functionIndex) + u", " + target + u", "
247 + QString::number(propertyIndex) + u", " + QString::number(valueTypeIndex) + u", "
250 *block << u"if (!initializedCache.contains(QStringLiteral(\"%1\")))"_s.arg(p.propertyName());
251 *block << createBindingForNonBindable + u";";
276 .arg(toLiteral(data.context()),
277 toLiteral(data.text()),
278 toLiteral(data.comment()))
284 return translation.visit(
285 [](
auto &&arg) -> QString {
286 using T = std::decay_t<
decltype(arg)>;
287 if constexpr (!std::is_same_v<T, std::nullptr_t>)
288 return serializeTranslation(arg);
290 Q_ASSERT_X(
false,
"QQmlTranslation",
"Uninitialized Translation");
296void CodeGenerator::generate_createTranslationBindingOnProperty(
299 const QString propName = QQmlJSUtils::toLiteral(info.property.propertyName());
300 const QString qqmlTranslation = serializeTranslation(info.data);
302 if (QString bindable = info.property.bindable(); !bindable.isEmpty()) {
304 QString createTranslationCode = uR"(QT_PREPEND_NAMESPACE(QQmlCppBinding)
305 ::createTranslationBindingForBindable(%1, %2, %3, %4, %5))"_s
306 .arg(info.unitVarName, info.target)
307 .arg(info.propertyIndex)
308 .arg(qqmlTranslation, propName);
310 *block << CodeGenerator::wrap_privateClass(info.target, info.property) + u"->"
311 + bindable + u"().setBinding(" + createTranslationCode + u");";
313 QString locationString =
314 u"QQmlSourceLocation(%1->fileName(), %2, %3)"_s.arg(info.unitVarName)
317 QString createTranslationCode = uR"(QT_PREPEND_NAMESPACE(QQmlCppBinding)
321 %3, //translationData
322 %4, //thisObject
323 %5, //bindingTarget
324 %6, //metaPropertyIndex
325 %7, //propertyName
326 %8) //valueTypePropertyIndex
327 )"_s.arg(info.unitVarName,locationString,qqmlTranslation,info.scope,info.target)
328 .arg(info.propertyIndex)
330 .arg(info.valueTypeIndex);
332 *block << createTranslationCode + u";";
337CodeGenerator::wrap_mismatchingTypeConversion(
const QQmlJSMetaProperty &p, QString value)
339 auto isDerivedFromBuiltin = [](
const QQmlJSScope::ConstPtr &derived,
const QString &builtin) {
340 for (QQmlJSScope::ConstPtr t = derived; t; t = t->baseType()) {
341 if (t->internalName() == builtin)
346 QStringList prologue;
347 QStringList epilogue;
348 const QQmlJSScope::ConstPtr propType = p.type();
349 if (isDerivedFromBuiltin(propType, u"QVariant"_s)) {
351 prologue << u"{ // accepts QVariant"_s;
352 prologue << u"QVariant " + variantName + u";";
353 prologue << variantName + u".setValue(" + value + u");";
355 value = u"std::move(" + variantName + u")";
356 }
else if (isDerivedFromBuiltin(propType, u"QJSValue"_s)) {
357 const QString jsvalueName = u"jsvalue_" + p.propertyName();
358 prologue << u"{ // accepts QJSValue"_s;