aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmltc
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2021-12-14 11:09:17 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-12-17 22:48:16 +0000
commit177d0c57fc511a0c775147c6581095caafac0c25 (patch)
tree9d4fb5cb523f87185c44f8ddf92040b2634e0b8a /tools/qmltc
parentc1fa37662459c72a9efe3126b81a5f25596020cf (diff)
qmltc: Make special functions protected
Special functions are only invoked internally by the qmltc-generated code. There is no reason in making them public as the compiler should know which exact type would use another type (and so can generate meaningful friend declarations) Task-number: QTBUG-84368 Change-Id: I887ca8db7f916dba042f0ccbf19085aa438bf82d Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 9cf864654f9154be52a7279a341948eabacfb397) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tools/qmltc')
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp36
-rw-r--r--tools/qmltc/prototype/codegenerator.h2
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.cpp12
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.cpp29
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.h4
-rw-r--r--tools/qmltc/prototype/qmlcompiler.h1
6 files changed, 70 insertions, 14 deletions
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index d02c98f04b..abb99ab401 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -247,8 +247,8 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
m_objects.emplaceBack(CodeGenObject { irObject, object });
}
- // objects are constructed, now we can run compiler passes to make sure they
- // are in good state
+ // objects are constructed, now we can run compiler passes to make sure the
+ // objects are in good state
Qml2CppCompilerPassExecutor executor(m_doc, m_localTypeResolver, m_url, m_objects,
m_typeToObjectIndex);
executor.addPass(&verifyTypes);
@@ -276,6 +276,11 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
};
executor.addPass(resolveImplicitComponents);
executor.addPass(&setObjectIds);
+ const auto setImmediateParents = [&](const Qml2CppContext &context,
+ QList<Qml2CppObject> &objects) {
+ m_immediateParents = findImmediateParents(context, objects);
+ };
+ executor.addPass(setImmediateParents);
// run all passes:
executor.run(m_logger);
}
@@ -373,14 +378,16 @@ void CodeGenerator::compileObject(QQmlJSAotObject &compiled, const CodeGenObject
// add ctors code
compiled.baselineCtor.access = QQmlJSMetaMethod::Protected;
- compiled.externalCtor.access = QQmlJSMetaMethod::Public;
+ if (documentRoot) {
+ compiled.externalCtor.access = QQmlJSMetaMethod::Public;
+ } else {
+ compiled.externalCtor.access = QQmlJSMetaMethod::Protected;
+ }
compiled.init.access = QQmlJSMetaMethod::Protected;
- // TODO: all below could actually be hidden? (but need to befriend the
- // document root, etc.)
- compiled.endInit.access = QQmlJSMetaMethod::Public;
- compiled.completeComponent.access = QQmlJSMetaMethod::Public;
- compiled.finalizeComponent.access = QQmlJSMetaMethod::Public;
- compiled.handleOnCompleted.access = QQmlJSMetaMethod::Public;
+ compiled.endInit.access = QQmlJSMetaMethod::Protected;
+ compiled.completeComponent.access = QQmlJSMetaMethod::Protected;
+ compiled.finalizeComponent.access = QQmlJSMetaMethod::Protected;
+ compiled.handleOnCompleted.access = QQmlJSMetaMethod::Protected;
compiled.baselineCtor.name = compiled.cppType;
compiled.externalCtor.name = compiled.cppType;
@@ -413,6 +420,17 @@ void CodeGenerator::compileObject(QQmlJSAotObject &compiled, const CodeGenObject
compiled.endInit.parameterList = { engine, CodeGeneratorUtility::compilationUnitVariable };
}
+ if (!documentRoot) {
+ // make document root a friend to allow protected member function access
+ Q_ASSERT(m_objects[0].type);
+ compiled.otherCode << u"friend class %1;"_qs.arg(m_objects[0].type->internalName());
+ // additionally, befriend the immediate parent of this type
+ if (auto parent = m_immediateParents.value(object.type);
+ parent && parent != m_objects[0].type) {
+ compiled.otherCode << u"friend class %1;"_qs.arg(parent->internalName());
+ }
+ }
+
if (baseTypeIsCompiledQml) {
// call baseline ctor of the QML-originated base class. it also takes
// care of QObject::setParent() call
diff --git a/tools/qmltc/prototype/codegenerator.h b/tools/qmltc/prototype/codegenerator.h
index e4a1bb4705..5d37d7f78a 100644
--- a/tools/qmltc/prototype/codegenerator.h
+++ b/tools/qmltc/prototype/codegenerator.h
@@ -72,6 +72,8 @@ private:
QList<CodeGenObject> m_objects;
// mapping from type to m_objects index
QHash<QQmlJSScope::ConstPtr, qsizetype> m_typeToObjectIndex; // TODO: remove this
+ // parents for each type that will (also) create the type
+ QHash<QQmlJSScope::ConstPtr, QQmlJSScope::ConstPtr> m_immediateParents;
// mapping from to-be-wrapped object to the wrapper's object pseudo-index
QHash<int, int> m_implicitComponentMapping;
diff --git a/tools/qmltc/prototype/codegeneratorwriter.cpp b/tools/qmltc/prototype/codegeneratorwriter.cpp
index 5ccd698c63..8aa0bbcf59 100644
--- a/tools/qmltc/prototype/codegeneratorwriter.cpp
+++ b/tools/qmltc/prototype/codegeneratorwriter.cpp
@@ -183,9 +183,11 @@ void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject
// generate class preamble
code.appendToHeader(classString(compiled));
code.appendToHeader(u"{");
- for (const QString &mocLine : qAsConst(compiled.mocCode)) {
+ for (const QString &mocLine : qAsConst(compiled.mocCode))
code.appendToHeader(mocLine, 1);
- }
+
+ for (const QString &otherLine : qAsConst(compiled.otherCode))
+ code.appendToHeader(otherLine, 1);
GeneratedCodeUtils::MemberNamespaceScope thisObjectScope(code, compiled.cppType);
Q_UNUSED(thisObjectScope);
@@ -204,15 +206,15 @@ void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject
CodeGeneratorWriter::write(code, compiled.baselineCtor);
CodeGeneratorWriter::write(code, compiled.init);
- // NB: when singleton, this ctor won't be public
+ // NB: when non-document root, this ctor won't be public
code.appendToHeader(getFunctionCategory(compiled.externalCtor) + u":", -1);
CodeGeneratorWriter::write(code, compiled.externalCtor);
- // TODO: actually should figure how to make this one protected
- code.appendToHeader(u"public:", -1);
+ code.appendToHeader(u"protected:", -1);
CodeGeneratorWriter::write(code, compiled.endInit);
CodeGeneratorWriter::write(code, compiled.completeComponent);
CodeGeneratorWriter::write(code, compiled.finalizeComponent);
CodeGeneratorWriter::write(code, compiled.handleOnCompleted);
+ code.appendToHeader(u"public:", -1);
}
// generate dtor
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
index b8560a39af..85edec372c 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
@@ -33,6 +33,8 @@
#include <QtCore/qqueue.h>
#include <QtCore/qloggingcategory.h>
+#include <algorithm>
+
static QString const cppKeywords[] = {
u"alignas"_qs,
u"alignof"_qs,
@@ -939,3 +941,30 @@ void setObjectIds(const Qml2CppContext &context, QList<Qml2CppObject> &objects)
// ignoring the Components
setObjectId(context, 0, idToObjectIndex);
}
+
+QHash<QQmlJSScope::ConstPtr, QQmlJSScope::ConstPtr>
+findImmediateParents(const Qml2CppContext &context, QList<Qml2CppObject> &objects)
+{
+ Q_UNUSED(context);
+
+ QSet<QQmlJSScope::ConstPtr> suitableParents;
+ std::transform(objects.cbegin(), objects.cend(),
+ std::inserter(suitableParents, suitableParents.end()),
+ [](const Qml2CppObject &object) { return object.type; });
+
+ QHash<QQmlJSScope::ConstPtr, QQmlJSScope::ConstPtr> immediateParents;
+
+ // suitable parents are the ones that would eventually create the child
+ // types (through recursive logic), so the first such parent in a hierarchy
+ // is an immediate parent
+ for (const Qml2CppObject &object : objects) {
+ for (auto parent = object.type->parentScope(); parent; parent = parent->parentScope()) {
+ if (suitableParents.contains(parent)) {
+ immediateParents.insert(object.type, parent);
+ break;
+ }
+ }
+ }
+
+ return immediateParents;
+}
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.h b/tools/qmltc/prototype/qml2cppdefaultpasses.h
index f2635a4dbd..068ab0b24d 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.h
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.h
@@ -72,4 +72,8 @@ QHash<int, int> findAndResolveImplicitComponents(const Qml2CppContext &context,
void setObjectIds(const Qml2CppContext &context, QList<Qml2CppObject> &objects);
+// finds an immediate parent of each to-be-compiled type
+QHash<QQmlJSScope::ConstPtr, QQmlJSScope::ConstPtr>
+findImmediateParents(const Qml2CppContext &context, QList<Qml2CppObject> &objects);
+
#endif // QML2CPPPASSES_H
diff --git a/tools/qmltc/prototype/qmlcompiler.h b/tools/qmltc/prototype/qmlcompiler.h
index c21ccf5f0c..4ac515957f 100644
--- a/tools/qmltc/prototype/qmlcompiler.h
+++ b/tools/qmltc/prototype/qmlcompiler.h
@@ -137,6 +137,7 @@ struct QQmlJSAotObject
QStringList baseClasses; // C++ class names of base classes
// TODO: also add "creation string"?
QStringList mocCode;
+ QStringList otherCode; // code that doesn't fit any category, e.g. friend declarations
// TODO: does it really need to be QHash and not QList?