diff options
author | Andrei Golubev <andrei.golubev@qt.io> | 2021-12-14 11:09:17 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-12-17 22:48:16 +0000 |
commit | 177d0c57fc511a0c775147c6581095caafac0c25 (patch) | |
tree | 9d4fb5cb523f87185c44f8ddf92040b2634e0b8a /tools/qmltc | |
parent | c1fa37662459c72a9efe3126b81a5f25596020cf (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.cpp | 36 | ||||
-rw-r--r-- | tools/qmltc/prototype/codegenerator.h | 2 | ||||
-rw-r--r-- | tools/qmltc/prototype/codegeneratorwriter.cpp | 12 | ||||
-rw-r--r-- | tools/qmltc/prototype/qml2cppdefaultpasses.cpp | 29 | ||||
-rw-r--r-- | tools/qmltc/prototype/qml2cppdefaultpasses.h | 4 | ||||
-rw-r--r-- | tools/qmltc/prototype/qmlcompiler.h | 1 |
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? |