aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2022-04-22 12:51:41 +0200
committerAndrei Golubev <andrei.golubev@qt.io>2022-05-03 15:25:11 +0200
commit229903122536a2ebeaf91e41dc9376c464b1c2e0 (patch)
tree147bcfcb00c8b00a1663a21c1d8ff5ef7eabcda4 /tools
parent82b76e4eb57b4da46d8e7c24bd0b83310c2164b2 (diff)
qmltc: Move alias compilation to qqmltccompiler
Introduce an alias resolution procedure to query the origin property and its owner for a given alias Add alias compilation to the "proper" qmltc code and remove the equivalent one from the prototype Change-Id: I55bc1e3e6206b4cfce259526d1bc2813e8ea7cfb Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp222
-rw-r--r--tools/qmltc/prototype/codegenerator.h3
-rw-r--r--tools/qmltc/qmltccompiler.cpp226
-rw-r--r--tools/qmltc/qmltccompiler.h2
-rw-r--r--tools/qmltc/qmltccompilerpieces.h12
5 files changed, 230 insertions, 235 deletions
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index eb2e0ef23b..129ff681af 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -327,234 +327,12 @@ bool CodeGenerator::ignoreObject(const CodeGenObject &object) const
return false;
}
-QString buildCallSpecialMethodValue(bool documentRoot, const QString &outerFlagName,
- bool overridesInterface)
-{
- const QString callInBase = overridesInterface ? u"false"_s : u"true"_s;
- if (documentRoot) {
- return outerFlagName + u" && " + callInBase;
- } else {
- return callInBase;
- }
-}
-
static QString generate_callCompilationUnit(const QString &urlMethodName)
{
// NB: assume `engine` variable always exists
return u"QQmlEnginePrivate::get(engine)->compilationUnitFromUrl(%1())"_s.arg(urlMethodName);
}
-void CodeGenerator::compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
- const QQmlJSScope::ConstPtr &owner)
-{
- const QString aliasName = alias.propertyName();
- Q_ASSERT(!aliasName.isEmpty());
-
- QStringList aliasExprBits = alias.aliasExpression().split(u'.');
- Q_ASSERT(!aliasExprBits.isEmpty());
- QString idString = aliasExprBits.front();
- Q_ASSERT(!idString.isEmpty());
- QQmlJSScope::ConstPtr type = m_localTypeResolver->scopeForId(idString, owner);
- Q_ASSERT(type);
- const bool aliasToProperty = aliasExprBits.size() > 1; // and not an object
-
- QString latestAccessor = u"this"_s;
- QString latestAccessorNonPrivate; // TODO: crutch for notify
- QStringList prologue;
- QStringList writeSpecificEpilogue;
-
- if (owner != type) { // cannot start at `this`, need to fetch object through context at run time
- Q_ASSERT(m_typeToObjectIndex.contains(type)
- && m_typeToObjectIndex[type] <= m_objects.size());
- const int id = m_objects[m_typeToObjectIndex[type]].irObject->id;
- Q_ASSERT(id >= 0); // since the type is found by id, it must have an id
-
- // TODO: the context fetching must be done once in the notify code
- // (across multiple alias properties). now there's a huge duplication
- prologue << u"auto context = QQmlData::get(this)->outerContext;"_s;
- // there's a special case: when `this` type has compiled QML type as a base
- // type and it is not a root, it has a non-root first context, so we need to
- // step one level up
- if (m_qmlCompiledBaseTypes.contains(owner->baseTypeName())
- && m_typeToObjectIndex[owner] != 0) {
- Q_ASSERT(!owner->baseTypeName().isEmpty());
- prologue << u"// `this` is special: not a root and its base type is compiled"_s;
- prologue << u"context = context->parent().data();"_s;
- }
- // doing the above allows us to lookup id object by integer, which is fast
- latestAccessor = u"alias_objectById_" + idString; // unique enough
- if (aliasToProperty) {
- prologue << u"auto " + latestAccessor + u" = static_cast<" + type->internalName()
- + u"*>(context->idValue(" + QString::number(id) + u"));";
- } else {
- // kind of a crutch for object aliases: expect that the user knows
- // what to do and so accept QObject*
- prologue << u"QObject *" + latestAccessor + u" = context->idValue("
- + QString::number(id) + u");";
- }
- prologue << u"Q_ASSERT(" + latestAccessor + u");";
- }
-
- struct AliasData
- {
- QString underlyingType;
- QString readLine;
- QString writeLine;
- QString bindableLine;
- } info; // note, we only really need this crutch to cover the alias to object case
- QQmlJSMetaProperty resultingProperty;
-
- if (aliasToProperty) {
- // the following code goes to prologue section. the idea of that is to
- // construct the necessary code to fetch the resulting property
- for (qsizetype i = 1; i < aliasExprBits.size() - 1; ++i) {
- const QString &bit = qAsConst(aliasExprBits)[i];
- Q_ASSERT(!bit.isEmpty());
- Q_ASSERT(type);
- QQmlJSMetaProperty p = type->property(bit);
-
- QString currAccessor = QmltcCodeGenerator::wrap_privateClass(latestAccessor, p);
- if (p.type()->accessSemantics() == QQmlJSScope::AccessSemantics::Value) {
- // we need to read the property to a local variable and then
- // write the updated value once the actual operation is done
- QString localVariableName = u"alias_" + bit; // should be fairly unique
- prologue << u"auto " + localVariableName + u" = " + currAccessor + u"->" + p.read()
- + u"();";
- writeSpecificEpilogue
- << currAccessor + u"->" + p.write() + u"(" + localVariableName + u");";
- // NB: since accessor becomes a value type, wrap it into an
- // addressof operator so that we could access it as a pointer
- currAccessor = QmltcCodeGenerator::wrap_addressof(localVariableName); // reset
- } else {
- currAccessor += u"->" + p.read() + u"()"; // amend
- }
-
- type = p.type();
- latestAccessor = currAccessor;
- }
-
- resultingProperty = type->property(aliasExprBits.back());
- latestAccessorNonPrivate = latestAccessor;
- latestAccessor = QmltcCodeGenerator::wrap_privateClass(latestAccessor, resultingProperty);
- info.underlyingType = resultingProperty.type()->internalName();
- if (resultingProperty.isList()) {
- info.underlyingType = u"QQmlListProperty<" + info.underlyingType + u">";
- } else if (resultingProperty.type()->isReferenceType()) {
- info.underlyingType += u"*"_s;
- }
- // reset to generic type when having alias to id:
- if (m_aliasesToIds.contains(resultingProperty))
- info.underlyingType = u"QObject*"_s;
-
- // READ must always be present
- info.readLine = latestAccessor + u"->" + resultingProperty.read() + u"()";
- if (QString setName = resultingProperty.write(); !setName.isEmpty())
- info.writeLine = latestAccessor + u"->" + setName + u"(%1)";
- if (QString bindableName = resultingProperty.bindable(); !bindableName.isEmpty())
- info.bindableLine = latestAccessor + u"->" + bindableName + u"()";
- } else {
- info.underlyingType = u"QObject*"_s;
- info.readLine = latestAccessor;
- // NB: id-pointing aliases are read-only, also alias to object is not
- // bindable since it's not a QProperty itself
- }
-
- QStringList mocLines;
- mocLines.reserve(10);
- mocLines << info.underlyingType << aliasName;
-
- QmltcPropertyData compilationData(aliasName);
- // 1. add setter and getter
- if (!info.readLine.isEmpty()) {
- QmltcMethod getter {};
- getter.returnType = info.underlyingType;
- getter.name = compilationData.read;
- getter.body += prologue;
- getter.body << u"return " + info.readLine + u";";
- // getter.body += writeSpecificEpilogue;
- getter.userVisible = true;
- current.functions.emplaceBack(getter);
- mocLines << u"READ"_s << getter.name;
- } // else always an error?
-
- if (!info.writeLine.isEmpty()) {
- QmltcMethod setter {};
- setter.returnType = u"void"_s;
- setter.name = compilationData.write;
-
- QList<QQmlJSMetaMethod> methods = type->methods(resultingProperty.write());
- if (methods.isEmpty()) {
- // QmltcVariable
- setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(info.underlyingType),
- aliasName + u"_", u""_s);
- } else {
- setter.parameterList = compileMethodParameters(methods.at(0).parameterNames(),
- methods.at(0).parameterTypes(), true);
- }
-
- setter.body += prologue;
- if (aliasToProperty) {
- QStringList parameterNames;
- parameterNames.reserve(setter.parameterList.size());
- std::transform(setter.parameterList.cbegin(), setter.parameterList.cend(),
- std::back_inserter(parameterNames),
- [](const QmltcVariable &x) { return x.name; });
- QString commaSeparatedParameterNames = parameterNames.join(u", "_s);
- setter.body << info.writeLine.arg(commaSeparatedParameterNames) + u";";
- } else {
- setter.body << info.writeLine + u";";
- }
- setter.body += writeSpecificEpilogue;
- setter.userVisible = true;
- current.functions.emplaceBack(setter);
- mocLines << u"WRITE"_s << setter.name;
- }
-
- // 2. add bindable
- if (!info.bindableLine.isEmpty()) {
- QmltcMethod bindable {};
- bindable.returnType = u"QBindable<" + info.underlyingType + u">";
- bindable.name = compilationData.bindable;
- bindable.body += prologue;
- bindable.body << u"return " + info.bindableLine + u";";
- bindable.userVisible = true;
- current.functions.emplaceBack(bindable);
- mocLines << u"BINDABLE"_s << bindable.name;
- }
- // 3. add notify - which is pretty special
- if (QString notifyName = resultingProperty.notify(); !notifyName.isEmpty()) {
- // notify is very special (even more than reasonable)
- current.endInit.body << u"{ // alias notify connection:"_s;
- // TODO: part of the prologue (e.g. QQmlData::get(this)->outerContext)
- // must be shared across different notifies (to speed up finalize)
- current.endInit.body += prologue;
- // TODO: use non-private accessor since signals must exist on the public
- // type, not on the private one -- otherwise, they can't be used from
- // C++ which is not what's wanted (this is a mess)
- current.endInit.body << u"QObject::connect(" + latestAccessorNonPrivate + u", &"
- + type->internalName() + u"::" + notifyName + u", this, &" + current.cppType
- + u"::" + compilationData.notify + u");";
- current.endInit.body << u"}"_s;
- }
-
- // 4. add moc entry
- // Q_PROPERTY(QString text READ text WRITE setText BINDABLE bindableText NOTIFY textChanged)
- current.mocCode << u"Q_PROPERTY(" + mocLines.join(u" "_s) + u")";
-
- // 5. add extra moc entry if this alias is default one
- if (aliasName == owner->defaultPropertyName()) {
- // Q_CLASSINFO("DefaultProperty", propertyName)
- current.mocCode << u"Q_CLASSINFO(\"DefaultProperty\", \"%1\")"_s.arg(aliasName);
- }
-}
-
-template<typename Iterator>
-static QString getPropertyOrAliasNameFromIr(const QmlIR::Document *doc, Iterator first, int pos)
-{
- std::advance(first, pos); // assume that first is correct - due to earlier check
- return doc->stringAt(first->nameIndex);
-}
-
void CodeGenerator::compileBinding(QmltcType &current, const QmlIR::Binding &binding,
const CodeGenObject &object,
const CodeGenerator::AccessorData &accessor)
diff --git a/tools/qmltc/prototype/codegenerator.h b/tools/qmltc/prototype/codegenerator.h
index 0e0b7a1bc2..c8c5fff195 100644
--- a/tools/qmltc/prototype/codegenerator.h
+++ b/tools/qmltc/prototype/codegenerator.h
@@ -165,9 +165,6 @@ private:
bool m_isAnonymous = false; // crutch to distinguish QML_ELEMENT from QML_ANONYMOUS
public:
- void compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
- const QQmlJSScope::ConstPtr &owner);
-
// helper structure that holds the information necessary for most bindings,
// such as accessor name, which is used to reference the properties like:
// (accessor.name)->(propertyName): this->myProperty. it is also used in
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index 52d913dfe5..4cb695a0f4 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -345,7 +345,7 @@ void QmltcCompiler::compileTypeElements(QmltcType &current, const QQmlJSScope::C
continue;
}
if (p.isAlias()) {
- m_prototypeCodegen->compileAlias(current, p, type);
+ compileAlias(current, p, type);
} else {
compileProperty(current, p, type);
}
@@ -541,6 +541,230 @@ void QmltcCompiler::compileProperty(QmltcType &current, const QQmlJSMetaProperty
compilationData.notify);
}
+struct AliasResolutionFrame
+{
+ static QString inVar;
+ QStringList prologue;
+ QStringList epilogueForWrite;
+ QString outVar;
+};
+// special string replaced by outVar of the previous frame
+QString AliasResolutionFrame::inVar = QStringLiteral("__QMLTC_ALIAS_FRAME_INPUT_VAR__");
+
+static void unpackFrames(QStack<AliasResolutionFrame> &frames)
+{
+ if (frames.size() < 2)
+ return;
+
+ // assume first frame is fine
+ auto prev = frames.begin();
+ for (auto it = std::next(prev); it != frames.end(); ++it, ++prev) {
+ for (QString &line : it->prologue)
+ line.replace(AliasResolutionFrame::inVar, prev->outVar);
+ for (QString &line : it->epilogueForWrite)
+ line.replace(AliasResolutionFrame::inVar, prev->outVar);
+ it->outVar.replace(AliasResolutionFrame::inVar, prev->outVar);
+ }
+}
+
+template<typename Projection>
+static QStringList joinFrames(const QStack<AliasResolutionFrame> &frames, Projection project)
+{
+ QStringList joined;
+ for (const AliasResolutionFrame &frame : frames)
+ joined += project(frame);
+ return joined;
+}
+
+void QmltcCompiler::compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
+ const QQmlJSScope::ConstPtr &owner)
+{
+ const QString aliasName = alias.propertyName();
+ Q_ASSERT(!aliasName.isEmpty());
+
+ QStringList aliasExprBits = alias.aliasExpression().split(u'.');
+ Q_ASSERT(!aliasExprBits.isEmpty());
+
+ QStack<AliasResolutionFrame> frames;
+
+ QQmlJSUtils::AliasResolutionVisitor aliasVisitor;
+ qsizetype i = 0;
+ aliasVisitor.reset = [&]() {
+ frames.clear();
+ i = 0; // we use it in property processing
+
+ // first frame is a dummy one:
+ frames.push(AliasResolutionFrame { QStringList(), QStringList(), u"this"_s });
+ };
+ aliasVisitor.processResolvedId = [&](const QQmlJSScope::ConstPtr &type) {
+ Q_ASSERT(type);
+ if (owner != type) { // cannot start at `this`, need to fetch object through context
+ const int id = m_visitor->runtimeId(type);
+ Q_ASSERT(id >= 0); // since the type is found by id, it must have an id
+
+ AliasResolutionFrame queryIdFrame {};
+ queryIdFrame.prologue << u"auto context = QQmlData::get(%1)->outerContext;"_s.arg(
+ AliasResolutionFrame::inVar);
+ // there's a special case: when `this` type has compiled QML type as
+ // a base type and it is not a root, it has a non-root first
+ // context, so we need to step one level up
+ if (QQmlJSUtils::hasCompositeBase(owner) && owner != m_visitor->result()) {
+ Q_ASSERT(!owner->baseTypeName().isEmpty());
+ queryIdFrame.prologue
+ << u"// `this` is special: not a root and its base type is compiled"_s;
+ queryIdFrame.prologue << u"context = context->parent().data();"_s;
+ }
+
+ // doing the above allows us to lookup id object by index (fast)
+ queryIdFrame.outVar = u"alias_objectById_" + aliasExprBits.front(); // unique enough
+ queryIdFrame.prologue << u"auto " + queryIdFrame.outVar + u" = static_cast<"
+ + type->internalName() + u"*>(context->idValue(" + QString::number(id)
+ + u"));";
+ queryIdFrame.prologue << u"Q_ASSERT(" + queryIdFrame.outVar + u");";
+
+ frames.push(queryIdFrame);
+ }
+ };
+ aliasVisitor.processResolvedProperty = [&](const QQmlJSMetaProperty &p,
+ const QQmlJSScope::ConstPtr &) {
+ AliasResolutionFrame queryPropertyFrame {};
+
+ QString inVar = QmltcCodeGenerator::wrap_privateClass(AliasResolutionFrame::inVar, p);
+ if (p.type()->accessSemantics() == QQmlJSScope::AccessSemantics::Value) {
+ // we need to read the property to a local variable and then
+ // write the updated value once the actual operation is done
+ const QString aliasVar = u"alias_" + QString::number(i); // should be fairly unique
+ ++i;
+ queryPropertyFrame.prologue
+ << u"auto " + aliasVar + u" = " + inVar + u"->" + p.read() + u"();";
+ queryPropertyFrame.epilogueForWrite
+ << inVar + u"->" + p.write() + u"(" + aliasVar + u");";
+ // NB: since accessor becomes a value type, wrap it into an
+ // addressof operator so that we could access it as a pointer
+ inVar = QmltcCodeGenerator::wrap_addressof(aliasVar); // reset
+ } else {
+ inVar += u"->" + p.read() + u"()"; // update
+ }
+ queryPropertyFrame.outVar = inVar;
+
+ frames.push(queryPropertyFrame);
+ };
+
+ QQmlJSUtils::ResolvedAlias result =
+ QQmlJSUtils::resolveAlias(m_typeResolver, alias, owner, aliasVisitor);
+ Q_ASSERT(result.kind != QQmlJSUtils::AliasTarget_Invalid);
+
+ unpackFrames(frames);
+
+ if (result.kind == QQmlJSUtils::AliasTarget_Property) {
+ // we don't need the last frame here
+ frames.pop();
+
+ // instead, add a custom frame
+ AliasResolutionFrame customFinalFrame {};
+ customFinalFrame.outVar =
+ QmltcCodeGenerator::wrap_privateClass(frames.top().outVar, result.property);
+ frames.push(customFinalFrame);
+ }
+
+ const QString latestAccessor = frames.top().outVar;
+ const QStringList prologue =
+ joinFrames(frames, [](const AliasResolutionFrame &frame) { return frame.prologue; });
+ const QString underlyingType = (result.kind == QQmlJSUtils::AliasTarget_Property)
+ ? getUnderlyingType(result.property)
+ : result.owner->internalName() + u" *";
+
+ QStringList mocLines;
+ mocLines.reserve(10);
+ mocLines << underlyingType << aliasName;
+
+ QmltcPropertyData compilationData(aliasName);
+ // 1. add setter and getter
+ QmltcMethod getter {};
+ getter.returnType = underlyingType;
+ getter.name = compilationData.read;
+ getter.body += prologue;
+ if (result.kind == QQmlJSUtils::AliasTarget_Property)
+ getter.body << u"return " + latestAccessor + u"->" + result.property.read() + u"();";
+ else // AliasTarget_Object
+ getter.body << u"return " + latestAccessor + u";";
+ getter.userVisible = true;
+ current.functions.emplaceBack(getter);
+ mocLines << u"READ"_s << getter.name;
+
+ if (QString setName = result.property.write(); !setName.isEmpty()) {
+ Q_ASSERT(result.kind == QQmlJSUtils::AliasTarget_Property); // property is invalid otherwise
+ QmltcMethod setter {};
+ setter.returnType = u"void"_s;
+ setter.name = compilationData.write;
+
+ QList<QQmlJSMetaMethod> methods = result.owner->methods(setName);
+ if (methods.isEmpty()) { // when we are compiling the property as well
+ // QmltcVariable
+ setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(underlyingType),
+ aliasName + u"_", u""_s);
+ } else {
+ setter.parameterList = compileMethodParameters(methods.at(0).parameterNames(),
+ methods.at(0).parameterTypes(),
+ /* allow unnamed = */ true);
+ }
+
+ setter.body += prologue;
+ QStringList parameterNames;
+ parameterNames.reserve(setter.parameterList.size());
+ std::transform(setter.parameterList.cbegin(), setter.parameterList.cend(),
+ std::back_inserter(parameterNames),
+ [](const QmltcVariable &x) { return x.name; });
+ QString commaSeparatedParameterNames = parameterNames.join(u", "_s);
+ setter.body << latestAccessor + u"->" + setName
+ + u"(%1)"_s.arg(commaSeparatedParameterNames) + u";";
+ setter.body += joinFrames(
+ frames, [](const AliasResolutionFrame &frame) { return frame.epilogueForWrite; });
+ setter.userVisible = true;
+ current.functions.emplaceBack(setter);
+ mocLines << u"WRITE"_s << setter.name;
+ }
+ // 2. add bindable
+ if (QString bindableName = result.property.bindable(); !bindableName.isEmpty()) {
+ Q_ASSERT(result.kind == QQmlJSUtils::AliasTarget_Property); // property is invalid otherwise
+ QmltcMethod bindable {};
+ bindable.returnType = u"QBindable<" + underlyingType + u">";
+ bindable.name = compilationData.bindable;
+ bindable.body += prologue;
+ bindable.body << u"return " + latestAccessor + u"->" + bindableName + u"()" + u";";
+ bindable.userVisible = true;
+ current.functions.emplaceBack(bindable);
+ mocLines << u"BINDABLE"_s << bindable.name;
+ }
+ // 3. add notify - which is pretty special
+ if (QString notifyName = result.property.notify(); !notifyName.isEmpty()) {
+ Q_ASSERT(result.kind == QQmlJSUtils::AliasTarget_Property); // property is invalid otherwise
+
+ // notify is very special
+ current.endInit.body << u"{ // alias notify connection:"_s;
+ current.endInit.body += prologue;
+ // TODO: use non-private accessor since signals must exist on the public
+ // type, not on the private one -- otherwise, you can't connect to a
+ // private property signal in C++ and so it is useless (hence, use
+ // public type)
+ const QString latestAccessorNonPrivate = frames[frames.size() - 2].outVar;
+ current.endInit.body << u"QObject::connect(" + latestAccessorNonPrivate + u", &"
+ + result.owner->internalName() + u"::" + notifyName + u", this, &"
+ + current.cppType + u"::" + compilationData.notify + u");";
+ current.endInit.body << u"}"_s;
+ }
+
+ // 4. add moc entry
+ // Q_PROPERTY(QString text READ text WRITE setText BINDABLE bindableText NOTIFY textChanged)
+ current.mocCode << u"Q_PROPERTY(" + mocLines.join(u" "_s) + u")";
+
+ // 5. add extra moc entry if this alias is default one
+ if (aliasName == owner->defaultPropertyName()) {
+ // Q_CLASSINFO("DefaultProperty", propertyName)
+ current.mocCode << u"Q_CLASSINFO(\"DefaultProperty\", \"%1\")"_s.arg(aliasName);
+ }
+}
+
void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyBinding &binding,
const QQmlJSScope::ConstPtr &type,
const BindingAccessorData &accessor)
diff --git a/tools/qmltc/qmltccompiler.h b/tools/qmltc/qmltccompiler.h
index 0cef51f064..ef33aae393 100644
--- a/tools/qmltc/qmltccompiler.h
+++ b/tools/qmltc/qmltccompiler.h
@@ -79,6 +79,8 @@ private:
const QQmlJSScope::ConstPtr &owner);
void compileProperty(QmltcType &current, const QQmlJSMetaProperty &p,
const QQmlJSScope::ConstPtr &owner);
+ void compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
+ const QQmlJSScope::ConstPtr &owner);
/*!
\internal
diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h
index 282985c30b..1e0f19ad19 100644
--- a/tools/qmltc/qmltccompilerpieces.h
+++ b/tools/qmltc/qmltccompilerpieces.h
@@ -33,6 +33,8 @@
#include <QtCore/qstringbuilder.h>
#include <QtCore/qfileinfo.h>
+#include <private/qqmljsutils_p.h>
+
#include "qmltcoutputir.h"
#include "qmltcvisitor.h"
@@ -160,17 +162,9 @@ inline decltype(auto) QmltcCodeGenerator::generate_initCode(QmltcType &current,
return scope->parentScope();
return scope;
};
- const auto hasQmlBase = [](const QQmlJSScope::ConstPtr &scope) {
- if (!scope)
- return false;
- const auto base = scope->baseType();
- if (!base)
- return false;
- return base->isComposite() && base->scopeType() == QQmlJSScope::QMLScope;
- };
if (auto parentScope = realQmlScope(type->parentScope());
- parentScope != visitor->result() && hasQmlBase(parentScope)) {
+ parentScope != visitor->result() && QQmlJSUtils::hasCompositeBase(parentScope)) {
current.init.body << u"// NB: context->parent() is the context of this document"_s;
current.init.body << u"context = context->parent();"_s;
}