aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2022-07-26 14:32:23 +0200
committerAndrei Golubev <andrei.golubev@qt.io>2022-07-29 15:23:07 +0200
commitfe11a7dcc71adf017553d430a96a77020ca4c4d8 (patch)
tree055f7b280fb2f9652c5dba2484af65acc481cade
parentddd50b9f2eb211f6a8d58bf3a2aac345c61a4ab0 (diff)
qmltc: Make explicit component ids accessible during object creation
Explicit components could be accessed by id like regular objects. Make this work in qmltc by revisiting the object creation procedure - store explicit components along with pure QML types in QQmltcObjectCreationBase: xxxxxxxx x'x'x'x'x'|yyyyy... ^ ^ ^ pure explicit types from base class types components As a drive by, fix unset required property in one test file and add a bunch of other test files to the initTestCase() check Change-Id: Ibdaa430d692c81101853f51dae1da462a57a9980 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 12ce72825995529e203c98adbe636a01b995ff13)
-rw-r--r--tests/auto/qml/qmltc/QmltcTests/componentTypes.qml8
-rw-r--r--tests/auto/qml/qmltc/QmltcTests/properties.qml1
-rw-r--r--tests/auto/qml/qmltc/tst_qmltc.cpp10
-rw-r--r--tools/qmltc/qmltccompiler.cpp68
-rw-r--r--tools/qmltc/qmltccompilerpieces.h3
-rw-r--r--tools/qmltc/qmltcvisitor.cpp50
-rw-r--r--tools/qmltc/qmltcvisitor.h7
7 files changed, 101 insertions, 46 deletions
diff --git a/tests/auto/qml/qmltc/QmltcTests/componentTypes.qml b/tests/auto/qml/qmltc/QmltcTests/componentTypes.qml
index 48b68e9112..d45f2399b4 100644
--- a/tests/auto/qml/qmltc/QmltcTests/componentTypes.qml
+++ b/tests/auto/qml/qmltc/QmltcTests/componentTypes.qml
@@ -1,5 +1,7 @@
import QtQuick
Item {
+ id: root
+
ComponentType { // normal type here
id: normal
property string text: "indirect component"
@@ -22,4 +24,10 @@ Item {
TableView {
delegate: ComponentType { id: accessibleDelegate }
}
+
+ property alias accessibleNormalProgress: accessibleNormal.progress
+ property alias accessibleNormalUrl: accessibleNormal.url
+ property url urlClone: root.accessibleNormalUrl
+
+ property alias delegateUrlClone: accessibleDelegate.url
}
diff --git a/tests/auto/qml/qmltc/QmltcTests/properties.qml b/tests/auto/qml/qmltc/QmltcTests/properties.qml
index 896cd88eac..ca827519d5 100644
--- a/tests/auto/qml/qmltc/QmltcTests/properties.qml
+++ b/tests/auto/qml/qmltc/QmltcTests/properties.qml
@@ -37,6 +37,7 @@ QtObject {
default property QtObject defaultObjP
readonly property string readonlyStringP: "foobar"
required property real requiredRealP
+ requiredRealP: 3.2
// extra:
property Timer timerP: Timer {
diff --git a/tests/auto/qml/qmltc/tst_qmltc.cpp b/tests/auto/qml/qmltc/tst_qmltc.cpp
index e15870dcaa..5a0d7eea9d 100644
--- a/tests/auto/qml/qmltc/tst_qmltc.cpp
+++ b/tests/auto/qml/qmltc/tst_qmltc.cpp
@@ -121,6 +121,11 @@ void tst_qmltc::initTestCase()
QUrl("qrc:/QmltcTests/ObjectWithId.qml"),
QUrl("qrc:/QmltcTests/documentWithIds.qml"),
QUrl("qrc:/QmltcTests/importNamespace.qml"),
+ QUrl("qrc:/QmltcTests/ComponentType.qml"),
+ QUrl("qrc:/QmltcTests/componentTypes.qml"),
+ QUrl("qrc:/QmltcTests/gradients.qml"),
+ QUrl("qrc:/QmltcTests/qjsvalueAssignments.qml"),
+
QUrl("qrc:/QmltcTests/deferredProperties.qml"),
QUrl("qrc:/QmltcTests/deferredProperties_group.qml"),
QUrl("qrc:/QmltcTests/deferredProperties_attached.qml"),
@@ -582,6 +587,11 @@ void tst_qmltc::componentTypes()
QQuickTableView *table = qobject_cast<QQuickTableView *>(children.at(3));
QVERIFY(table);
QCOMPARE(ctx->objectForName(u"accessibleDelegate"_s), table->delegate());
+
+ QCOMPARE(created.accessibleNormalProgress(),
+ children.at(1)->property("progress").toDouble());
+ QCOMPARE(created.urlClone(), QUrl("qrc:/QmltcTests/componentTypes.qml"));
+ QCOMPARE(created.delegateUrlClone(), QUrl("qrc:/QmltcTests/ComponentType.qml"));
}
}
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index d91ceaadf6..66d10eaa83 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -571,9 +571,11 @@ void QmltcCompiler::compileAlias(QmltcType &current, const QQmlJSMetaProperty &a
// 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"));";
+ const QString cppType = (m_visitor->qmlComponentIndex(type) == -1)
+ ? type->internalName()
+ : u"QQmlComponent"_s;
+ queryIdFrame.prologue << u"auto " + queryIdFrame.outVar + u" = static_cast<" + cppType
+ + u"*>(context->idValue(" + QString::number(id) + u"));";
queryIdFrame.prologue << u"Q_ASSERT(" + queryIdFrame.outVar + u");";
frames.push(queryIdFrame);
@@ -742,10 +744,13 @@ void QmltcCompiler::compileAlias(QmltcType &current, const QQmlJSMetaProperty &a
// 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 cppType = (m_visitor->qmlComponentIndex(result.owner) == -1)
+ ? result.owner->internalName()
+ : u"QQmlComponent"_s;
const QString latestAccessorNonPrivate = notifyFrames.top().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"QObject::connect(" + latestAccessorNonPrivate + u", &" + cppType
+ + u"::" + notifyName + u", this, &" + current.cppType + u"::"
+ + compilationData.notify + u");";
current.endInit.body += notifyEpilogue;
current.endInit.body << u"}"_s;
}
@@ -812,7 +817,7 @@ void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyB
const auto &listName =
m_uniques[UniqueStringId(current, propertyName)].qmlListVariableName;
Q_ASSERT(!listName.isEmpty());
- current.endInit.body << u"%1.append(%2);"_qs.arg(listName, value);
+ current.endInit.body << u"%1.append(%2);"_s.arg(listName, value);
} else {
assignToProperty(p, value, /* constructFromQObject = */ true);
}
@@ -886,38 +891,47 @@ void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyB
// special case of implicit or explicit component:
if (qsizetype index = m_visitor->qmlComponentIndex(object); index >= 0) {
- // TODO: or do this in current.init? - yes, because otherwise
- // components are not going to be id-accessible, which is bad
-
const QString objectName = newSymbol(u"sc"_s);
- current.endInit.body << u"{"_s;
- current.endInit.body << QStringLiteral(
- "auto thisContext = QQmlData::get(%1)->outerContext;")
- .arg(qobjectParent);
- current.endInit.body << QStringLiteral(
- "auto %1 = QQmlObjectCreator::createComponent(engine, "
- "%2, %3, %4, thisContext);")
- .arg(objectName,
- generate_callCompilationUnit(m_urlMethodName),
- QString::number(index), qobjectParent);
- current.endInit.body << QStringLiteral("thisContext->installContext(QQmlData::get(%1), "
- "QQmlContextData::OrdinaryObject);")
- .arg(objectName);
+
+ const qsizetype creationIndex = m_visitor->creationIndex(object);
+
+ QStringList *block = (creationIndex == -1) ? &current.endInit.body : &current.init.body;
+ *block << u"{"_s;
+ *block << QStringLiteral("auto thisContext = QQmlData::get(%1)->outerContext;")
+ .arg(qobjectParent);
+ *block << QStringLiteral("auto %1 = QQmlObjectCreator::createComponent(engine, "
+ "%2, %3, %4, thisContext);")
+ .arg(objectName, generate_callCompilationUnit(m_urlMethodName),
+ QString::number(index), qobjectParent);
+ *block << QStringLiteral("thisContext->installContext(QQmlData::get(%1), "
+ "QQmlContextData::OrdinaryObject);")
+ .arg(objectName);
// objects wrapped in implicit components do not have visible ids,
// however, explicit components can have an id and that one is going
// to be visible in the common document context
- if (!object->isComponentRootElement()) {
+ if (creationIndex != -1) {
+ // explicit component
+ Q_ASSERT(object->isComposite());
+ Q_ASSERT(object->baseType()->internalName() == u"QQmlComponent"_s);
+
if (int id = m_visitor->runtimeId(object); id >= 0) {
QString idString = m_visitor->addressableScopes().id(object);
if (idString.isEmpty())
idString = u"<unknown>"_s;
- QmltcCodeGenerator::generate_setIdValue(&current.endInit.body, u"thisContext"_s,
- id, objectName, idString);
+ QmltcCodeGenerator::generate_setIdValue(block, u"thisContext"_s, id, objectName,
+ idString);
}
+
+ const QString creationIndexStr = QString::number(creationIndex);
+ *block << QStringLiteral("creator->set(%1, %2);").arg(creationIndexStr, objectName);
+ Q_ASSERT(block == &current.init.body);
+ current.endInit.body
+ << QStringLiteral("auto %1 = creator->get<%2>(%3);")
+ .arg(objectName, u"QQmlComponent"_s, creationIndexStr);
}
addObjectBinding(objectName);
- current.endInit.body << u"}"_s;
+ *block << u"}"_s;
break;
}
diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h
index 140a30745d..37eb82d577 100644
--- a/tools/qmltc/qmltccompilerpieces.h
+++ b/tools/qmltc/qmltccompilerpieces.h
@@ -618,7 +618,8 @@ inline QString QmltcCodeGenerator::generate_typeCount(Predicate p) const
// add this document's type counts minus document root
Q_ASSERT(visitor->pureQmlTypes().size() > 0);
- components << QString::number(visitor->pureQmlTypes().size() - 1);
+ Q_ASSERT(visitor->typeCount() >= visitor->pureQmlTypes().size());
+ components << QString::number(visitor->typeCount() - 1);
// traverse types with QML base classes
for (const QQmlJSScope::ConstPtr &t : typesWithBaseTypeCount) {
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 7f6ad4715c..efe573d05d 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -28,19 +28,28 @@ static QString uniqueNameFromPieces(const QStringList &pieces, QHash<QString, in
return possibleName;
}
+static bool isExplicitComponent(const QQmlJSScope::ConstPtr &type)
+{
+ if (!type->isComposite())
+ return false;
+ auto base = type->baseType();
+ return base && base->internalName() == u"QQmlComponent";
+}
+
+static bool isImplicitComponent(const QQmlJSScope::ConstPtr &type)
+{
+ if (!type->isComposite())
+ return false;
+ const auto cppBase = QQmlJSScope::nonCompositeBaseType(type);
+ const bool isComponentBased = (cppBase && cppBase->internalName() == u"QQmlComponent");
+ return type->isComponentRootElement() && !isComponentBased;
+}
+
static bool isOrUnderComponent(QQmlJSScope::ConstPtr type)
{
Q_ASSERT(type->isComposite()); // we're dealing with composite types here
for (; type; type = type->parentScope()) {
- if (type->isWrappedInImplicitComponent())
- return true;
- // for a composite type, its internalName() is guaranteed to not be a
- // QQmlComponent. we need to detect a case with `Component {}` QML type
- // where the *immediate* base type of the current type will be the
- // QQmlComponent. note that non-composite base is different: if our type
- // is not a direct child of QQmlComponent, then it is a good type that
- // we have to compile
- if (auto base = type->baseType(); base && base->internalName() == u"QQmlComponent")
+ if (isExplicitComponent(type) || isImplicitComponent(type))
return true;
}
return false;
@@ -447,6 +456,7 @@ void QmltcVisitor::postVisitResolve(
// find all "pure" QML types
m_pureQmlTypes.reserve(m_qmlTypes.size());
+ QList<QQmlJSScope::ConstPtr> explicitComponents;
for (qsizetype i = 0; i < m_qmlTypes.size(); ++i) {
const QQmlJSScope::ConstPtr &type = m_qmlTypes.at(i);
@@ -454,14 +464,26 @@ void QmltcVisitor::postVisitResolve(
// root is special: we compile Component roots. root is also never
// deferred, so in case `isOrUnderDeferred(type)` returns true, we
// always continue here
- if (type != m_exportedRootScope)
+ if (type != m_exportedRootScope) {
+ // if a type is an explicit component, its id "leaks" into the
+ // document context
+ if (isExplicitComponent(type))
+ explicitComponents.append(type);
continue;
+ }
}
- m_pureTypeIndices[type] = m_pureQmlTypes.size();
+ m_creationIndices[type] = m_pureQmlTypes.size();
m_pureQmlTypes.append(type);
}
+ // add explicit components to the object creation indices
+ {
+ qsizetype index = 0;
+ for (const QQmlJSScope::ConstPtr &c : qAsConst(explicitComponents))
+ m_creationIndices[c] = m_pureQmlTypes.size() + index++;
+ }
+
// filter out deferred types
{
QList<QQmlJSScope::ConstPtr> filteredQmlTypesWithQmlBases;
@@ -498,14 +520,12 @@ void QmltcVisitor::postVisitResolve(
int syntheticCreationIndex = 0;
const auto addSyntheticIndex = [&](const QQmlJSScope::ConstPtr &type) {
// explicit component
- if (auto base = type->baseType(); base && base->internalName() == u"QQmlComponent"_s) {
+ if (isExplicitComponent(type)) {
m_syntheticTypeIndices[type] = m_qmlIrObjectIndices.value(type, -1);
return true;
}
// implicit component
- const auto cppBase = QQmlJSScope::nonCompositeBaseType(type);
- const bool isComponentBased = (cppBase && cppBase->internalName() == u"QQmlComponent"_s);
- if (type->isComponentRootElement() && !isComponentBased) {
+ if (isImplicitComponent(type)) {
const int index = int(qmlScopeCount) + syntheticCreationIndex++;
m_syntheticTypeIndices[type] = index;
return true;
diff --git a/tools/qmltc/qmltcvisitor.h b/tools/qmltc/qmltcvisitor.h
index 0ac0562a6b..04f18b96d5 100644
--- a/tools/qmltc/qmltcvisitor.h
+++ b/tools/qmltc/qmltcvisitor.h
@@ -49,11 +49,12 @@ public:
qsizetype creationIndex(const QQmlJSScope::ConstPtr &type) const
{
- Q_ASSERT(m_pureTypeIndices.contains(type));
Q_ASSERT(type->scopeType() == QQmlJSScope::QMLScope);
- return m_pureTypeIndices[type];
+ return m_creationIndices.value(type, -1);
}
+ qsizetype typeCount() const { return m_creationIndices.size(); }
+
qsizetype qmlComponentIndex(const QQmlJSScope::ConstPtr &type) const
{
Q_ASSERT(type->scopeType() == QQmlJSScope::QMLScope);
@@ -110,7 +111,7 @@ protected:
QSet<QString> m_cppIncludes; // all C++ includes found from QQmlJSScope hierarchy
QList<QQmlJSScope::ConstPtr> m_pureQmlTypes; // the ones not under QQmlComponent
- QHash<QQmlJSScope::ConstPtr, qsizetype> m_pureTypeIndices;
+ QHash<QQmlJSScope::ConstPtr, qsizetype> m_creationIndices;
QHash<QQmlJSScope::ConstPtr, qsizetype> m_syntheticTypeIndices;
QHash<QQmlJSScope::ConstPtr, qsizetype> m_qmlIrObjectIndices;