aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2022-03-03 14:03:58 +0100
committerAndrei Golubev <andrei.golubev@qt.io>2022-03-08 18:35:23 +0100
commit44b95b3fb26013ff5dab75d4f894ca4f11298e3d (patch)
tree5a2b58d6de34975f62670ae86d7e507a1a80603a
parent3c680af4e9164b81548c1c633f3c0a2f0583aea4 (diff)
Remove qmltc prototype code (2/N)
- Migrate to the newer output ir classes (with adjustments) - Deduplicate code writer and remove now-unused output helpers from the prototype version - Remove old output ir Change-Id: Ie7fe5e6d47e18477c65af02cabd89a890628442c Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp6
-rw-r--r--tools/qmltc/CMakeLists.txt3
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp115
-rw-r--r--tools/qmltc/prototype/codegenerator.h34
-rw-r--r--tools/qmltc/prototype/codegeneratorutil.cpp15
-rw-r--r--tools/qmltc/prototype/codegeneratorutil.h10
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.cpp480
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.h61
-rw-r--r--tools/qmltc/prototype/generatedcodeprimitives.h130
-rw-r--r--tools/qmltc/prototype/qml2cppcontext.h1
-rw-r--r--tools/qmltc/prototype/qmlcompiler.h173
-rw-r--r--tools/qmltc/qmltccodewriter.cpp218
-rw-r--r--tools/qmltc/qmltccodewriter.h2
-rw-r--r--tools/qmltc/qmltccompiler.cpp62
-rw-r--r--tools/qmltc/qmltccompilerpieces.h2
-rw-r--r--tools/qmltc/qmltcoutputir.h30
16 files changed, 306 insertions, 1036 deletions
diff --git a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
index ddbf3baaaa..122084f1d8 100644
--- a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
+++ b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
@@ -71,15 +71,15 @@ class HelloWorld : public QObject
public:
HelloWorld(QQmlEngine * engine, QObject * parent = nullptr);
+Q_SIGNALS:
+ void created();
+
public:
void setHello(const QString& hello_);
QString hello();
QBindable<QString> bindableHello();
Q_INVOKABLE void printHello(QString prefix, QString suffix);
-signals:
- void created();
-
// ...
};
//! [qmltc-hello-world-generated]
diff --git a/tools/qmltc/CMakeLists.txt b/tools/qmltc/CMakeLists.txt
index 8408e4bd84..7e7941539e 100644
--- a/tools/qmltc/CMakeLists.txt
+++ b/tools/qmltc/CMakeLists.txt
@@ -14,13 +14,10 @@ qt_internal_add_tool(${target_name}
qmltccompilerpieces.h
qmltcpropertyutils.h
- prototype/generatedcodeprimitives.h
prototype/qml2cppcontext.h
prototype/qml2cppdefaultpasses.cpp prototype/qml2cppdefaultpasses.h
prototype/codegenerator.cpp prototype/codegenerator.h
prototype/codegeneratorutil.cpp prototype/codegeneratorutil.h
- prototype/codegeneratorwriter.cpp prototype/codegeneratorwriter.h
- prototype/qmlcompiler.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index 83c4b7d94b..cf1bb719ee 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -30,7 +30,7 @@
#include "prototype/qml2cppdefaultpasses.h"
#include "prototype/qml2cpppropertyutils.h"
#include "prototype/codegeneratorutil.h"
-#include "prototype/codegeneratorwriter.h"
+#include "qmltccodewriter.h"
#include "qmltccompiler.h"
@@ -88,12 +88,12 @@ static QString figureReturnType(const QQmlJSMetaMethod &m)
return type;
}
-static QList<QQmlJSAotVariable>
+static QList<QmltcVariable>
compileMethodParameters(const QStringList &names,
const QList<QSharedPointer<const QQmlJSScope>> &types,
bool allowUnnamed = false)
{
- QList<QQmlJSAotVariable> paramList;
+ QList<QmltcVariable> paramList;
const auto size = names.size();
paramList.reserve(size);
for (qsizetype i = 0; i < size; ++i) {
@@ -102,8 +102,7 @@ compileMethodParameters(const QStringList &names,
Q_ASSERT(allowUnnamed || !name.isEmpty()); // assume verified
if (name.isEmpty() && allowUnnamed)
name = u"unnamed_" + QString::number(i);
- paramList.emplaceBack(
- QQmlJSAotVariable { types[i]->augmentedInternalName(), name, QString() });
+ paramList.emplaceBack(QmltcVariable { types[i]->augmentedInternalName(), name, QString() });
}
return paramList;
}
@@ -295,7 +294,6 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
void CodeGenerator::generate()
{
- GeneratedCode code;
const QString rootClassName = QFileInfo(m_url).baseName();
Q_ASSERT(!rootClassName.isEmpty());
const QString hPath = m_info->outputHFile;
@@ -323,16 +321,16 @@ void CodeGenerator::generate()
};
const auto &root = m_objects.at(0).type;
- QList<QQmlJSAotObject> compiledObjects;
+ QList<QmltcType> compiledObjects;
if (isComponent(root)) {
compiledObjects.reserve(1);
compiledObjects.emplaceBack(); // create new object
- const auto compile = [this](QQmlJSAotObject &current, const CodeGenObject &object) {
+ const auto compile = [this](QmltcType &current, const CodeGenObject &object) {
this->compileQQmlComponentElements(current, object);
};
compileObject(compiledObjects.back(), m_objects.at(0), compile);
} else {
- const auto compile = [this](QQmlJSAotObject &current, const CodeGenObject &object) {
+ const auto compile = [this](QmltcType &current, const CodeGenObject &object) {
this->compileObjectElements(current, object);
};
@@ -359,15 +357,18 @@ void CodeGenerator::generate()
if (m_logger->hasErrors())
return;
- QQmlJSProgram program { compiledObjects, m_urlMethod, url, hPath, cppPath,
- m_info->outputNamespace, requiredCppIncludes };
+ QmltcProgram program {
+ url, cppPath, hPath, m_info->outputNamespace, requiredCppIncludes,
+ m_urlMethod, compiledObjects
+ };
// write everything
- GeneratedCodeUtils codeUtils(code);
- CodeGeneratorWriter::write(codeUtils, program);
+ QmltcOutput code;
+ QmltcOutputWrapper codeUtils(code);
+ QmltcCodeWriter::write(codeUtils, program);
writeToFile(hPath, code.header.toUtf8());
- writeToFile(cppPath, code.implementation.toUtf8());
+ writeToFile(cppPath, code.cpp.toUtf8());
}
QString buildCallSpecialMethodValue(bool documentRoot, const QString &outerFlagName,
@@ -382,8 +383,8 @@ QString buildCallSpecialMethodValue(bool documentRoot, const QString &outerFlagN
}
void CodeGenerator::compileObject(
- QQmlJSAotObject &compiled, const CodeGenObject &object,
- std::function<void(QQmlJSAotObject &, const CodeGenObject &)> compileElements)
+ QmltcType &compiled, const CodeGenObject &object,
+ std::function<void(QmltcType &, const CodeGenObject &)> compileElements)
{
if (object.type->isSingleton()) {
recordError(object.type->sourceLocation(), u"Singleton types are not supported"_qs);
@@ -427,14 +428,14 @@ void CodeGenerator::compileObject(
compiled.handleOnCompleted.name = u"QML_handleOnCompleted"_qs;
compiled.handleOnCompleted.returnType = u"void"_qs;
- QQmlJSAotVariable engine(u"QQmlEngine *"_qs, u"engine"_qs, QString());
- QQmlJSAotVariable parent(u"QObject *"_qs, u"parent"_qs, u"nullptr"_qs);
+ QmltcVariable engine(u"QQmlEngine *"_qs, u"engine"_qs, QString());
+ QmltcVariable parent(u"QObject *"_qs, u"parent"_qs, u"nullptr"_qs);
compiled.baselineCtor.parameterList = { parent };
compiled.externalCtor.parameterList = { engine, parent };
- QQmlJSAotVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData> &"_qs, u"parentContext"_qs,
- QString());
- QQmlJSAotVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs, QString());
- QQmlJSAotVariable callSpecialMethodFlag(u"bool"_qs, u"callSpecialMethodNow"_qs, QString());
+ QmltcVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData> &"_qs, u"parentContext"_qs,
+ QString());
+ QmltcVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs, QString());
+ QmltcVariable callSpecialMethodFlag(u"bool"_qs, u"callSpecialMethodNow"_qs, QString());
if (documentRoot) {
compiled.init.parameterList = { engine, ctxtdata, finalizeFlag, callSpecialMethodFlag };
compiled.endInit.parameterList = { engine, finalizeFlag };
@@ -692,7 +693,7 @@ void CodeGenerator::compileObject(
// compiled.endInit.body << u"Qt::endPropertyUpdateGroup();"_qs;
}
-void CodeGenerator::compileObjectElements(QQmlJSAotObject &compiled, const CodeGenObject &object)
+void CodeGenerator::compileObjectElements(QmltcType &compiled, const CodeGenObject &object)
{
// compile enums
const auto enums = object.type->ownEnumerations();
@@ -785,8 +786,7 @@ void CodeGenerator::compileObjectElements(QQmlJSAotObject &compiled, const CodeG
compileBinding(compiled, **it, object, { object.type, u"this"_qs, u""_qs, false });
}
-void CodeGenerator::compileQQmlComponentElements(QQmlJSAotObject &compiled,
- const CodeGenObject &object)
+void CodeGenerator::compileQQmlComponentElements(QmltcType &compiled, const CodeGenObject &object)
{
Q_UNUSED(object);
@@ -820,7 +820,7 @@ void CodeGenerator::compileQQmlComponentElements(QQmlJSAotObject &compiled,
compiled.init.body << u"}"_qs;
}
-void CodeGenerator::compileEnum(QQmlJSAotObject &current, const QQmlJSMetaEnum &e)
+void CodeGenerator::compileEnum(QmltcType &current, const QQmlJSMetaEnum &e)
{
const auto intValues = e.values();
QStringList values;
@@ -833,7 +833,7 @@ void CodeGenerator::compileEnum(QQmlJSAotObject &current, const QQmlJSMetaEnum &
u"Q_ENUM(%1)"_qs.arg(e.name()));
}
-void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaProperty &p,
+void CodeGenerator::compileProperty(QmltcType &current, const QQmlJSMetaProperty &p,
const QQmlJSScope::ConstPtr &owner)
{
Q_ASSERT(!p.isAlias()); // will be handled separately
@@ -865,10 +865,10 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
// If p.isList(), it's a QQmlListProperty. Then you can write the underlying list through
// the QQmlListProperty object retrieved with the getter. Setting it would make no sense.
if (p.isWritable() && !p.isList()) {
- QQmlJSAotMethod setter {};
+ QmltcMethod setter {};
setter.returnType = u"void"_qs;
setter.name = compilationData.write;
- // QQmlJSAotVariable
+ // QmltcVariable
setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(underlyingType), name + u"_",
u""_qs);
setter.body << variableName + u".setValue(" + name + u"_);";
@@ -878,7 +878,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
mocPieces << u"WRITE"_qs << setter.name;
}
- QQmlJSAotMethod getter {};
+ QmltcMethod getter {};
getter.returnType = underlyingType;
getter.name = compilationData.read;
getter.body << u"return " + variableName + u".value();";
@@ -888,7 +888,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
// 2. add bindable
if (!p.isList()) {
- QQmlJSAotMethod bindable {};
+ QmltcMethod bindable {};
bindable.returnType = u"QBindable<" + underlyingType + u">";
bindable.name = compilationData.bindable;
bindable.body << u"return QBindable<" + underlyingType + u">(std::addressof(" + variableName
@@ -916,7 +916,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
compilationData.notify);
}
-void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaProperty &alias,
+void CodeGenerator::compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
const QQmlJSScope::ConstPtr &owner)
{
const QString aliasName = alias.propertyName();
@@ -1040,7 +1040,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
Qml2CppPropertyData compilationData(aliasName);
// 1. add setter and getter
if (!info.readLine.isEmpty()) {
- QQmlJSAotMethod getter {};
+ QmltcMethod getter {};
getter.returnType = info.underlyingType;
getter.name = compilationData.read;
getter.body += prologue;
@@ -1052,13 +1052,13 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
} // else always an error?
if (!info.writeLine.isEmpty()) {
- QQmlJSAotMethod setter {};
+ QmltcMethod setter {};
setter.returnType = u"void"_qs;
setter.name = compilationData.write;
QList<QQmlJSMetaMethod> methods = type->methods(resultingProperty.write());
if (methods.isEmpty()) {
- // QQmlJSAotVariable
+ // QmltcVariable
setter.parameterList.emplaceBack(QQmlJSUtils::constRefify(info.underlyingType),
aliasName + u"_", u""_qs);
} else {
@@ -1072,7 +1072,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
parameterNames.reserve(setter.parameterList.size());
std::transform(setter.parameterList.cbegin(), setter.parameterList.cend(),
std::back_inserter(parameterNames),
- [](const QQmlJSAotVariable &x) { return x.name; });
+ [](const QmltcVariable &x) { return x.name; });
QString commaSeparatedParameterNames = parameterNames.join(u", "_qs);
setter.body << info.writeLine.arg(commaSeparatedParameterNames) + u";";
} else {
@@ -1086,7 +1086,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
// 2. add bindable
if (!info.bindableLine.isEmpty()) {
- QQmlJSAotMethod bindable {};
+ QmltcMethod bindable {};
bindable.returnType = u"QBindable<" + info.underlyingType + u">";
bindable.name = compilationData.bindable;
bindable.body += prologue;
@@ -1122,7 +1122,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
}
}
-void CodeGenerator::compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMethod &m,
+void CodeGenerator::compileMethod(QmltcType &current, const QQmlJSMetaMethod &m,
const QmlIR::Function *f, const CodeGenObject &object)
{
Q_UNUSED(object);
@@ -1131,7 +1131,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMeth
const auto paramNames = m.parameterNames();
const auto paramTypes = m.parameterTypes();
Q_ASSERT(paramNames.size() == paramTypes.size());
- const QList<QQmlJSAotVariable> paramList = compileMethodParameters(paramNames, paramTypes);
+ const QList<QmltcVariable> paramList = compileMethodParameters(paramNames, paramTypes);
const auto methodType = QQmlJSMetaMethod::Type(m.methodType());
@@ -1146,7 +1146,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMeth
returnType, paramList);
}
- QQmlJSAotMethod compiled {};
+ QmltcMethod compiled {};
compiled.returnType = returnType;
compiled.name = m.methodName();
compiled.parameterList = std::move(paramList);
@@ -1154,7 +1154,7 @@ void CodeGenerator::compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMeth
compiled.type = methodType;
compiled.access = m.access();
if (methodType != QQmlJSMetaMethod::Signal) {
- compiled.declPreambles << u"Q_INVOKABLE"_qs; // TODO: do we need this for signals as well?
+ compiled.declarationPrefixes << u"Q_INVOKABLE"_qs;
compiled.userVisible = m.access() == QQmlJSMetaMethod::Public;
} else {
compiled.userVisible = !m.isImplicitQmlPropertyChangeSignal();
@@ -1169,7 +1169,7 @@ static QString getPropertyOrAliasNameFromIr(const QmlIR::Document *doc, Iterator
return doc->stringAt(first->nameIndex);
}
-void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Binding &binding,
+void CodeGenerator::compileBinding(QmltcType &current, const QmlIR::Binding &binding,
const CodeGenObject &object,
const CodeGenerator::AccessorData &accessor)
{
@@ -1579,26 +1579,26 @@ QString CodeGenerator::makeGensym(const QString &base)
}
// returns compiled script binding for "property changed" handler in a form of object type
-static QQmlJSAotObject compileScriptBindingPropertyChangeHandler(
+static QmltcType compileScriptBindingPropertyChangeHandler(
const QmlIR::Document *doc, const QmlIR::Binding &binding, const QmlIR::Object *irObject,
- const QQmlJSAotMethod &urlMethod, const QString &functorCppType,
- const QString &objectCppType, const QList<QQmlJSAotVariable> &slotParameters)
+ const QmltcMethod &urlMethod, const QString &functorCppType, const QString &objectCppType,
+ const QList<QmltcVariable> &slotParameters)
{
- QQmlJSAotObject bindingFunctor {};
+ QmltcType bindingFunctor {};
bindingFunctor.cppType = functorCppType;
bindingFunctor.ignoreInit = true;
// default member variable and ctor:
const QString pointerToObject = objectCppType + u" *";
bindingFunctor.variables.emplaceBack(
- QQmlJSAotVariable { pointerToObject, u"m_self"_qs, u"nullptr"_qs });
+ QmltcVariable { pointerToObject, u"m_self"_qs, u"nullptr"_qs });
bindingFunctor.baselineCtor.name = functorCppType;
bindingFunctor.baselineCtor.parameterList.emplaceBack(
- QQmlJSAotVariable { pointerToObject, u"self"_qs, QString() });
+ QmltcVariable { pointerToObject, u"self"_qs, QString() });
bindingFunctor.baselineCtor.initializerList.emplaceBack(u"m_self(self)"_qs);
// call operator:
- QQmlJSAotMethod callOperator {};
+ QmltcMethod callOperator {};
callOperator.returnType = u"void"_qs;
callOperator.name = u"operator()"_qs;
callOperator.parameterList = slotParameters;
@@ -1628,7 +1628,7 @@ propertyForChangeHandler(const QQmlJSScope::ConstPtr &scope, QString name)
return {};
}
-void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::Binding &binding,
+void CodeGenerator::compileScriptBinding(QmltcType &current, const QmlIR::Binding &binding,
const QString &bindingSymbolName,
const CodeGenObject &object, const QString &propertyName,
const QQmlJSScope::ConstPtr &propertyType,
@@ -1667,7 +1667,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::
};
// these only make sense when binding is on signal handler
- QList<QQmlJSAotVariable> slotParameters;
+ QList<QmltcVariable> slotParameters;
QString signalName;
QString signalReturnType;
@@ -1755,7 +1755,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::
const QString slotName = makeGensym(signalName + u"_slot");
// SignalHander specific:
- QQmlJSAotMethod slotMethod {};
+ QmltcMethod slotMethod {};
slotMethod.returnType = signalReturnType;
slotMethod.name = slotName;
slotMethod.parameterList = slotParameters;
@@ -1832,7 +1832,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::
+ accessor.name + u"))));";
current.variables.emplaceBack(
- QQmlJSAotVariable { typeOfQmlBinding, bindingSymbolName, QString() });
+ QmltcVariable { typeOfQmlBinding, bindingSymbolName, QString() });
// current.ctor.initializerList << bindingSymbolName + u"()";
break;
}
@@ -1840,7 +1840,7 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::
}
// TODO: should use "compileScriptBinding" instead of custom code
-void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject &current,
+void CodeGenerator::compileScriptBindingOfComponent(QmltcType &current,
const QmlIR::Object *irObject,
const QQmlJSScope::ConstPtr objectType,
const QmlIR::Binding &binding,
@@ -1880,7 +1880,7 @@ void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject &current,
const QString slotName = makeGensym(signalName + u"_slot");
// SignalHander specific:
- QQmlJSAotMethod slotMethod {};
+ QmltcMethod slotMethod {};
slotMethod.returnType = signalReturnType;
slotMethod.name = slotName;
@@ -1898,7 +1898,8 @@ void CodeGenerator::compileScriptBindingOfComponent(QQmlJSAotObject &current,
current.handleOnCompleted.body << slotName + u"();";
} else if (signalName == u"destruction"_qs) {
if (!current.dtor) {
- current.dtor = QQmlJSAotSpecialMethod {};
+ // TODO: double-check that this stuff is actually correct now:
+ current.dtor = QmltcDtor {};
current.dtor->name = u"~" + current.cppType;
}
current.dtor->firstLines << slotName + u"();";
@@ -1913,7 +1914,7 @@ void CodeGenerator::compileUrlMethod()
m_urlMethod.body << u"static QUrl docUrl = %1;"_qs.arg(
CodeGeneratorUtility::toResourcePath(m_info->resourcePath));
m_urlMethod.body << u"return docUrl;"_qs;
- m_urlMethod.declPreambles << u"static"_qs;
+ m_urlMethod.declarationPrefixes << u"static"_qs;
m_urlMethod.modifiers << u"noexcept"_qs;
}
diff --git a/tools/qmltc/prototype/codegenerator.h b/tools/qmltc/prototype/codegenerator.h
index 06cbb3b673..a18699d23c 100644
--- a/tools/qmltc/prototype/codegenerator.h
+++ b/tools/qmltc/prototype/codegenerator.h
@@ -30,8 +30,7 @@
#define CODEGENERATOR_H
#include "qmltctyperesolver.h"
-#include "prototype/qmlcompiler.h"
-#include "prototype/generatedcodeprimitives.h"
+#include "qmltcoutputir.h"
#include "prototype/qml2cppcontext.h"
#include <QtCore/qlist.h>
@@ -80,13 +79,13 @@ private:
// types ignored by the code generator
QSet<QQmlJSScope::ConstPtr> m_ignoredTypes;
- QQmlJSAotMethod m_urlMethod;
+ QmltcMethod m_urlMethod;
// helper struct used for unique string generation
struct UniqueStringId
{
QString combined;
- UniqueStringId(const QQmlJSAotObject &compiled, const QString &value)
+ UniqueStringId(const QmltcType &compiled, const QString &value)
: combined(compiled.cppType + u"_" + value)
{
Q_ASSERT(!compiled.cppType.isEmpty());
@@ -141,19 +140,18 @@ private:
bool m_isAnonymous = false; // crutch to distinguish QML_ELEMENT from QML_ANONYMOUS
// code compilation functions that produce "compiled" entities
- void
- compileObject(QQmlJSAotObject &current, const CodeGenObject &object,
- std::function<void(QQmlJSAotObject &, const CodeGenObject &)> compileElements);
- void compileObjectElements(QQmlJSAotObject &current, const CodeGenObject &object);
- void compileQQmlComponentElements(QQmlJSAotObject &current, const CodeGenObject &object);
-
- void compileEnum(QQmlJSAotObject &current, const QQmlJSMetaEnum &e);
- void compileProperty(QQmlJSAotObject &current, const QQmlJSMetaProperty &p,
+ void compileObject(QmltcType &current, const CodeGenObject &object,
+ std::function<void(QmltcType &, const CodeGenObject &)> compileElements);
+ void compileObjectElements(QmltcType &current, const CodeGenObject &object);
+ void compileQQmlComponentElements(QmltcType &current, const CodeGenObject &object);
+
+ void compileEnum(QmltcType &current, const QQmlJSMetaEnum &e);
+ void compileProperty(QmltcType &current, const QQmlJSMetaProperty &p,
const QQmlJSScope::ConstPtr &owner);
- void compileAlias(QQmlJSAotObject &current, const QQmlJSMetaProperty &alias,
+ void compileAlias(QmltcType &current, const QQmlJSMetaProperty &alias,
const QQmlJSScope::ConstPtr &owner);
- void compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMethod &m,
- const QmlIR::Function *f, const CodeGenObject &object);
+ void compileMethod(QmltcType &current, const QQmlJSMetaMethod &m, const QmlIR::Function *f,
+ const CodeGenObject &object);
void compileUrlMethod(); // special case
// helper structure that holds the information necessary for most bindings,
@@ -167,17 +165,17 @@ private:
QString propertyName; // usually empty
bool isValueType = false; // usually false
};
- void compileBinding(QQmlJSAotObject &current, const QmlIR::Binding &binding,
+ void compileBinding(QmltcType &current, const QmlIR::Binding &binding,
const CodeGenObject &object, const AccessorData &accessor);
// special case (for simplicity)
- void compileScriptBinding(QQmlJSAotObject &current, const QmlIR::Binding &binding,
+ void compileScriptBinding(QmltcType &current, const QmlIR::Binding &binding,
const QString &bindingSymbolName, const CodeGenObject &object,
const QString &propertyName,
const QQmlJSScope::ConstPtr &propertyType,
const AccessorData &accessor);
// TODO: remove this special case
- void compileScriptBindingOfComponent(QQmlJSAotObject &current, const QmlIR::Object *object,
+ void compileScriptBindingOfComponent(QmltcType &current, const QmlIR::Object *object,
const QQmlJSScope::ConstPtr objectType,
const QmlIR::Binding &binding,
const QString &propertyName);
diff --git a/tools/qmltc/prototype/codegeneratorutil.cpp b/tools/qmltc/prototype/codegeneratorutil.cpp
index f9473a4114..878a1f4b07 100644
--- a/tools/qmltc/prototype/codegeneratorutil.cpp
+++ b/tools/qmltc/prototype/codegeneratorutil.cpp
@@ -37,11 +37,10 @@ QT_BEGIN_NAMESPACE
// NB: this variable would behave correctly as long as QML init and QML finalize
// are non-virtual functions
-const QQmlJSAotVariable CodeGeneratorUtility::childrenOffsetVariable = { u"qsizetype"_qs,
- u"QML_choffset"_qs,
- QString() };
+const QmltcVariable CodeGeneratorUtility::childrenOffsetVariable { u"qsizetype"_qs,
+ u"QML_choffset"_qs, QString() };
-const QQmlJSAotVariable CodeGeneratorUtility::compilationUnitVariable = {
+const QmltcVariable CodeGeneratorUtility::compilationUnitVariable {
u"QV4::ExecutableCompilationUnit *"_qs, u"QML_cu"_qs, QString()
};
@@ -143,7 +142,7 @@ QStringList CodeGeneratorUtility::generate_assignToSpecialAlias(
QStringList CodeGeneratorUtility::generate_callExecuteRuntimeFunction(
const QString &url, qsizetype index, const QString &accessor, const QString &returnType,
- const QList<QQmlJSAotVariable> &parameters)
+ const QList<QmltcVariable> &parameters)
{
QStringList code;
code.reserve(12); // should always be enough
@@ -165,7 +164,7 @@ QStringList CodeGeneratorUtility::generate_callExecuteRuntimeFunction(
types << u"QMetaType::fromType<std::decay_t<" + returnType + u">>()";
}
- for (const QQmlJSAotVariable &p : parameters) {
+ for (const QmltcVariable &p : parameters) {
args << u"const_cast<void *>(reinterpret_cast<const void *>(std::addressof(" + p.name
+ u")))";
types << u"QMetaType::fromType<std::decay_t<" + p.cppType + u">>()";
@@ -214,12 +213,12 @@ QStringList CodeGeneratorUtility::generate_createBindingOnProperty(
return code;
}
-QString CodeGeneratorUtility::generate_qOverload(const QList<QQmlJSAotVariable> &params,
+QString CodeGeneratorUtility::generate_qOverload(const QList<QmltcVariable> &params,
const QString &overloaded)
{
QStringList types;
types.reserve(params.size());
- for (const QQmlJSAotVariable &p : params)
+ for (const QmltcVariable &p : params)
types.emplaceBack(p.cppType);
return u"qOverload<" + types.join(u", "_qs) + u">(" + overloaded + u")";
}
diff --git a/tools/qmltc/prototype/codegeneratorutil.h b/tools/qmltc/prototype/codegeneratorutil.h
index 563896637d..4f5518aeed 100644
--- a/tools/qmltc/prototype/codegeneratorutil.h
+++ b/tools/qmltc/prototype/codegeneratorutil.h
@@ -29,7 +29,7 @@
#ifndef CODEGENERATORUTIL_H
#define CODEGENERATORUTIL_H
-#include "prototype/qmlcompiler.h"
+#include "qmltcoutputir.h"
#include <private/qqmljsscope_p.h>
#include <private/qqmljsmetatypes_p.h>
@@ -53,10 +53,10 @@ struct CodeGeneratorUtility
// reference any object in the document by id, which automatically means
// that all ids have to be set up before we get to finalization (and the
// only place for it is init)
- static const QQmlJSAotVariable childrenOffsetVariable;
+ static const QmltcVariable childrenOffsetVariable;
// represents QV4::ExecutableCompilationUnit
- static const QQmlJSAotVariable compilationUnitVariable;
+ static const QmltcVariable compilationUnitVariable;
// helper functions:
static QString toResourcePath(const QString &s)
@@ -84,13 +84,13 @@ struct CodeGeneratorUtility
static QStringList
generate_callExecuteRuntimeFunction(const QString &url, qsizetype index,
const QString &accessor, const QString &returnType,
- const QList<QQmlJSAotVariable> &parameters = {});
+ const QList<QmltcVariable> &parameters = {});
static QStringList
generate_createBindingOnProperty(const QString &unitVarName, const QString &scope,
qsizetype functionIndex, const QString &target,
int propertyIndex, const QQmlJSMetaProperty &p,
int valueTypeIndex, const QString &subTarget);
- static QString generate_qOverload(const QList<QQmlJSAotVariable> &parameters,
+ static QString generate_qOverload(const QList<QmltcVariable> &parameters,
const QString &overloaded);
static QString generate_addressof(const QString &addressed);
static QString generate_getPrivateClass(const QString &accessor, const QQmlJSMetaProperty &p);
diff --git a/tools/qmltc/prototype/codegeneratorwriter.cpp b/tools/qmltc/prototype/codegeneratorwriter.cpp
deleted file mode 100644
index a932012b63..0000000000
--- a/tools/qmltc/prototype/codegeneratorwriter.cpp
+++ /dev/null
@@ -1,480 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "codegeneratorwriter.h"
-
-#include <private/qqmljsmetatypes_p.h>
-
-#include <QtCore/qfileinfo.h>
-
-#include <utility>
-#include <functional>
-
-QT_BEGIN_NAMESPACE
-
-static constexpr char16_t newLine[] =
-#ifdef Q_OS_WIN32
- u"\r\n";
-#else
- u"\n";
-#endif
-static constexpr char newLineLatin1[] =
-#ifdef Q_OS_WIN32
- "\r\n";
-#else
- "\n";
-#endif
-
-static QString urlToMacro(const QString &url)
-{
- QFileInfo fi(url);
- return u"Q_QMLTC_" + fi.baseName().toUpper();
-}
-
-static QString getFunctionCategory(const QQmlJSAotMethodBase &compiled)
-{
- QString category;
- switch (compiled.access) {
- case QQmlJSMetaMethod::Private:
- category = u"private"_qs;
- break;
- case QQmlJSMetaMethod::Protected:
- category = u"protected"_qs;
- break;
- case QQmlJSMetaMethod::Public:
- category = u"public"_qs;
- break;
- }
- return category;
-}
-
-static QString getFunctionCategory(const QQmlJSAotMethod &compiled)
-{
- QString category = getFunctionCategory(static_cast<const QQmlJSAotMethodBase &>(compiled));
- switch (compiled.type) {
- case QQmlJSMetaMethod::Signal:
- category = u"signals"_qs;
- break;
- case QQmlJSMetaMethod::Slot:
- category += u" slots"_qs;
- break;
- case QQmlJSMetaMethod::Method:
- break;
- }
- return category;
-}
-
-void CodeGeneratorWriter::writeGlobalHeader(GeneratedCodeUtils &code, const QString &sourceName,
- const QString &hPath, const QString &cppPath,
- const QString &outNamespace,
- const QSet<QString> &requiredCppIncludes)
-{
- Q_UNUSED(newLineLatin1);
-
- Q_UNUSED(cppPath);
- const QString preamble =
- u"// This code is auto-generated by the qmlcompiler tool from the file '" + sourceName
- + u"'" + newLine + u"// WARNING! All changes made in this file will be lost!" + newLine;
- code.appendToHeader(preamble);
- code.appendToImpl(preamble);
- code.appendToHeader(u"// NOTE: This generated API is to be considered implementation detail.");
- code.appendToHeader(
- u"// It may change from version to version and should not be relied upon.");
-
- const QString headerMacro = urlToMacro(sourceName);
- code.appendToHeader(u"#ifndef %1_H"_qs.arg(headerMacro));
- code.appendToHeader(u"#define %1_H"_qs.arg(headerMacro));
-
- code.appendToHeader(u"#include <QtCore/qproperty.h>");
- code.appendToHeader(u"#include <QtCore/qobject.h>");
- code.appendToHeader(u"#include <QtCore/qcoreapplication.h>");
- code.appendToHeader(u"#include <QtQml/qqmlengine.h>");
- code.appendToHeader(u"#include <QtCore/qurl.h>"); // used in engine execution
- code.appendToHeader(u"#include <QtQml/qqml.h>"); // used for attached properties
-
- code.appendToHeader(u"#include <private/qqmlengine_p.h>"); // NB: private header
-
- code.appendToHeader(u"#include <QQmlListProperty>"); // required by list properties
-
- // include custom C++ includes required by used types
- code.appendToHeader(u"// BEGIN(custom_cpp_includes)");
- for (const auto &requiredInclude : requiredCppIncludes) {
- code.appendToHeader(u"#include \"" + requiredInclude + u"\"");
- }
- code.appendToHeader(u"// END(custom_cpp_includes)");
-
- code.appendToImpl(u"#include \"" + hPath + u"\""); // include own .h file
- code.appendToImpl(u"#include <private/qqmlcppbinding_p.h>"); // QmltcSupportLib
- code.appendToImpl(u"#include <private/qqmlcpponassignment_p.h>"); // QmltcSupportLib
-
- code.appendToImpl(u"#include <private/qqmlobjectcreator_p.h>"); // createComponent()
- code.appendToImpl(u"#include <private/qqmlcomponent_p.h>"); // QQmlComponentPrivate::get()
-
- code.appendToImpl(u"");
- code.appendToImpl(u"#include <private/qobject_p.h>"); // NB: for private properties
- code.appendToImpl(u"#include <private/qqmlobjectcreator_p.h>"); // for finalize callbacks
-
- code.appendToImpl(u""); // blank line
- if (!outNamespace.isEmpty()) {
- code.appendToHeader(u""); // blank line
- code.appendToHeader(u"namespace %1 {"_qs.arg(outNamespace));
- code.appendToImpl(u""); // blank line
- code.appendToImpl(u"namespace %1 {"_qs.arg(outNamespace));
- }
-}
-
-void CodeGeneratorWriter::writeGlobalFooter(GeneratedCodeUtils &code, const QString &sourceName,
- const QString &hPath, const QString &cppPath,
- const QString &outNamespace)
-{
- Q_UNUSED(code);
- Q_UNUSED(hPath);
- Q_UNUSED(cppPath);
-
- if (!outNamespace.isEmpty()) {
- code.appendToImpl(u"} // namespace %1"_qs.arg(outNamespace));
- code.appendToImpl(u""); // blank line
- code.appendToHeader(u"} // namespace %1"_qs.arg(outNamespace));
- code.appendToHeader(u""); // blank line
- }
-
- code.appendToHeader(u"#endif // %1_H"_qs.arg(urlToMacro(sourceName)));
- code.appendToHeader(u""); // blank line
-}
-
-static QString classString(const QQmlJSAotObject &compiled)
-{
- QString str = u"class " + compiled.cppType;
- QStringList nonEmptyBaseClasses;
- nonEmptyBaseClasses.reserve(compiled.baseClasses.size());
- std::copy_if(compiled.baseClasses.cbegin(), compiled.baseClasses.cend(),
- std::back_inserter(nonEmptyBaseClasses),
- [](const QString &entry) { return !entry.isEmpty(); });
- if (!nonEmptyBaseClasses.isEmpty())
- str += u" : public " + nonEmptyBaseClasses.join(u", public "_qs);
- return str;
-}
-
-template<typename Predicate>
-static void dumpFunctions(GeneratedCodeUtils &code, const QList<QQmlJSAotMethod> &functions,
- Predicate pred)
-{
- // functions are _ordered_ by access and kind. ordering is important to
- // provide consistent output
- QMap<QString, QList<const QQmlJSAotMethod *>> orderedFunctions;
- for (const auto &function : functions) {
- if (pred(function))
- orderedFunctions[getFunctionCategory(function)].append(std::addressof(function));
- }
-
- for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
- code.appendToHeader(it.key() + u":", -1);
- for (const QQmlJSAotMethod *function : qAsConst(it.value()))
- CodeGeneratorWriter::write(code, *function);
- }
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject &compiled)
-{
- code.appendToHeader(u""); // just new line
- code.appendToImpl(u""); // just new line
-
- // generate class preamble
- code.appendToHeader(classString(compiled));
- code.appendToHeader(u"{");
- 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);
- {
- GeneratedCodeUtils::HeaderIndentationScope headerIndentScope(code);
- Q_UNUSED(headerIndentScope);
-
- // first, write user-visible code, then everything else. someone might
- // want to look at the generated code, so let's make an effort when
- // writing it down
-
- code.appendToHeader(u"// -----------------");
- code.appendToHeader(u"// External C++ API:");
- code.appendToHeader(u"public:", -1);
-
- // NB: when non-document root, the externalCtor won't be public - but we
- // really don't care about the output format of such types
- if (!compiled.ignoreInit && compiled.externalCtor.access == QQmlJSMetaMethod::Public) {
- // TODO: ignoreInit must be eliminated
-
- CodeGeneratorWriter::write(code, compiled.externalCtor);
- }
- // generate dtor
- if (compiled.dtor)
- CodeGeneratorWriter::write(code, *compiled.dtor);
-
- // generate enums
- for (const auto &enumeration : qAsConst(compiled.enums))
- CodeGeneratorWriter::write(code, enumeration);
-
- // generate (visible) functions
- const auto isUserVisibleFunction = [](const QQmlJSAotMethod &function) {
- return function.userVisible;
- };
- dumpFunctions(code, compiled.functions, isUserVisibleFunction);
-
- code.appendToHeader(u"// -----------------");
- code.appendToHeader(u""); // blank line
- code.appendToHeader(u"// Internal functionality (do NOT use it!):");
-
- // below are the hidden parts of the class
-
- // generate (rest of the) ctors
- if (compiled.ignoreInit) { // TODO: this branch should be eliminated
- Q_ASSERT(compiled.baselineCtor.access == QQmlJSMetaMethod::Public);
- code.appendToHeader(u"public:", -1);
- CodeGeneratorWriter::write(code, compiled.baselineCtor);
- } else {
- code.appendToHeader(u"protected:", -1);
- if (compiled.externalCtor.access != QQmlJSMetaMethod::Public) {
- Q_ASSERT(compiled.externalCtor.access == QQmlJSMetaMethod::Protected);
- CodeGeneratorWriter::write(code, compiled.externalCtor);
- }
- CodeGeneratorWriter::write(code, compiled.baselineCtor);
- CodeGeneratorWriter::write(code, compiled.init);
- 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 child types
- code.appendToHeader(u"// BEGIN(children)");
- for (const auto &child : qAsConst(compiled.children))
- CodeGeneratorWriter::write(code, child);
- code.appendToHeader(u"// END(children)");
-
- // generate functions
- code.appendToHeader(u"// BEGIN(hidden_functions)");
- dumpFunctions(code, compiled.functions, std::not_fn(isUserVisibleFunction));
- code.appendToHeader(u"// END(hidden_functions)");
-
- if (!compiled.variables.isEmpty() || !compiled.properties.isEmpty()) {
- code.appendToHeader(u""); // blank line
- code.appendToHeader(u"protected:", -1);
- }
- // generate variables
- if (!compiled.variables.isEmpty()) {
- code.appendToHeader(u"// BEGIN(variables)");
- for (const auto &variable : qAsConst(compiled.variables))
- CodeGeneratorWriter::write(code, variable);
- code.appendToHeader(u"// END(variables)");
- }
-
- // generate properties
- if (!compiled.properties.isEmpty()) {
- code.appendToHeader(u"// BEGIN(properties)");
- for (const auto &property : qAsConst(compiled.properties))
- CodeGeneratorWriter::write(code, property);
- code.appendToHeader(u"// END(properties)");
- }
- }
-
- code.appendToHeader(u"};");
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotEnum &compiled)
-{
- code.appendToHeader(u"enum " + compiled.cppType + u" {");
- for (qsizetype i = 0; i < compiled.keys.size(); ++i) {
- QString str;
- if (compiled.values.isEmpty()) {
- str += compiled.keys.at(i) + u",";
- } else {
- str += compiled.keys.at(i) + u" = " + compiled.values.at(i) + u",";
- }
- code.appendToHeader(str, 1);
- }
- code.appendToHeader(u"};");
- code.appendToHeader(compiled.ownMocLine);
-}
-
-// NB: property generation is only concerned with property declaration in the header
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotVariable &compiled)
-{
- if (compiled.defaultValue.isEmpty()) {
- code.appendToHeader(compiled.cppType + u" " + compiled.name + u";");
- } else {
- code.appendToHeader(compiled.cppType + u" " + compiled.name + u" = " + compiled.defaultValue
- + u";");
- }
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotProperty &prop)
-{
- Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet
- code.appendToHeader(u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_qs.arg(
- prop.containingClass, prop.cppType, prop.name, prop.signalName));
-}
-
-static QString appendSpace(const QString &s)
-{
- if (s.isEmpty())
- return s;
- return s + u" ";
-}
-
-static QString prependSpace(const QString &s)
-{
- if (s.isEmpty())
- return s;
- return u" " + s;
-}
-
-static std::pair<QString, QString> functionSignatures(const QQmlJSAotMethodBase &m)
-{
- const QString name = m.name;
- const QList<QQmlJSAotVariable> &parameterList = m.parameterList;
- QStringList headerParamList;
- QStringList implParamList;
- for (const QQmlJSAotVariable &variable : parameterList) {
- const QString commonPart = variable.cppType + u" " + variable.name;
- implParamList << commonPart;
- headerParamList << commonPart;
- if (!variable.defaultValue.isEmpty())
- headerParamList.back() += u" = " + variable.defaultValue;
- }
- const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")"
- + prependSpace(m.modifiers.join(u" "));
- const QString implSignature = name + u"(" + implParamList.join(u", "_qs) + u")"
- + prependSpace(m.modifiers.join(u" "));
- return { headerSignature, implSignature };
-}
-
-static QString functionReturnType(const QQmlJSAotMethodBase &m)
-{
- return appendSpace(m.declPreambles.join(u" "_qs)) + m.returnType;
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotMethod &compiled)
-{
- const auto [hSignature, cppSignature] = functionSignatures(compiled);
- // Note: augment return type with preambles in declaration
- code.appendToHeader(functionReturnType(compiled) + u" " + hSignature + u";");
-
- // do not generate method implementation if it is a signal
- const auto methodType = compiled.type;
- if (methodType != QQmlJSMetaMethod::Signal) {
- code.appendToImpl(u""); // just new line
- code.appendToImpl(compiled.returnType);
- code.appendSignatureToImpl(cppSignature);
- code.appendToImpl(u"{");
- {
- GeneratedCodeUtils::ImplIndentationScope indentScope(code);
- Q_UNUSED(indentScope);
- for (const QString &line : qAsConst(compiled.firstLines))
- code.appendToImpl(line);
- for (const QString &line : qAsConst(compiled.body))
- code.appendToImpl(line);
- for (const QString &line : qAsConst(compiled.lastLines))
- code.appendToImpl(line);
- }
- code.appendToImpl(u"}");
- }
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotSpecialMethod &compiled)
-{
- const auto [hSignature, cppSignature] = functionSignatures(compiled);
- const QString returnTypeWithSpace =
- compiled.returnType.isEmpty() ? u""_qs : compiled.returnType + u" ";
-
- code.appendToHeader(returnTypeWithSpace + hSignature + u";");
-
- code.appendToImpl(u""); // just new line
- if (!returnTypeWithSpace.isEmpty())
- code.appendToImpl(returnTypeWithSpace);
- code.appendSignatureToImpl(cppSignature);
- if (!compiled.initializerList.isEmpty()) {
- code.appendToImpl(u":", 1);
- code.appendToImpl(compiled.initializerList.join(u","_qs + newLine + newLine
- + u" "_qs.repeated(code.implIndent + 1)),
- 1);
- }
- code.appendToImpl(u"{");
- {
- GeneratedCodeUtils::ImplIndentationScope indentScope(code);
- Q_UNUSED(indentScope);
- for (const QString &line : qAsConst(compiled.firstLines))
- code.appendToImpl(line);
- for (const QString &line : qAsConst(compiled.body))
- code.appendToImpl(line);
- for (const QString &line : qAsConst(compiled.lastLines))
- code.appendToImpl(line);
- }
- code.appendToImpl(u"}");
-}
-
-void CodeGeneratorWriter::writeUrl(GeneratedCodeUtils &code, const QQmlJSAotMethod &urlMethod)
-{
- const auto [hSignature, _] = functionSignatures(urlMethod);
- Q_UNUSED(_);
- Q_ASSERT(!urlMethod.returnType.isEmpty());
- code.appendToImpl(functionReturnType(urlMethod) + hSignature);
- code.appendToImpl(u"{");
- {
- GeneratedCodeUtils::ImplIndentationScope indentScope(code);
- Q_UNUSED(indentScope);
- Q_ASSERT(urlMethod.firstLines.isEmpty() && urlMethod.lastLines.isEmpty());
- for (const QString &line : qAsConst(urlMethod.body))
- code.appendToImpl(line);
- }
- code.appendToImpl(u"}");
-}
-
-void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSProgram &compiled)
-{
- writeGlobalHeader(code, compiled.url, compiled.hPath, compiled.cppPath, compiled.outNamespace,
- compiled.includes);
-
- code.appendToImpl(u""); // just new line
- writeUrl(code, compiled.urlMethod);
-
- // forward declare objects before writing them
- for (const QQmlJSAotObject &compiled : qAsConst(compiled.compiledObjects))
- code.appendToHeader(u"class " + compiled.cppType + u";");
-
- // write all the objects
- for (const QQmlJSAotObject &compiled : qAsConst(compiled.compiledObjects))
- write(code, compiled);
-
- writeGlobalFooter(code, compiled.url, compiled.hPath, compiled.cppPath, compiled.outNamespace);
-}
-
-QT_END_NAMESPACE
diff --git a/tools/qmltc/prototype/codegeneratorwriter.h b/tools/qmltc/prototype/codegeneratorwriter.h
deleted file mode 100644
index d33a8affd4..0000000000
--- a/tools/qmltc/prototype/codegeneratorwriter.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef CODEGENERATORWRITER_H
-#define CODEGENERATORWRITER_H
-
-#include "generatedcodeprimitives.h"
-#include "qmlcompiler.h"
-
-QT_BEGIN_NAMESPACE
-
-// writes compiled code into the GeneratedCode structure
-struct CodeGeneratorWriter
-{
- static void writeGlobalHeader(GeneratedCodeUtils &code, const QString &sourceName,
- const QString &hPath, const QString &cppPath,
- const QString &outNamespace,
- const QSet<QString> &requiredCppIncludes);
- static void writeGlobalFooter(GeneratedCodeUtils &code, const QString &sourceName,
- const QString &hPath, const QString &cppPath,
- const QString &outNamespace);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotObject &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotEnum &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotVariable &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotProperty &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotMethod &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSAotSpecialMethod &compiled);
- static void write(GeneratedCodeUtils &code, const QQmlJSProgram &compiled);
-
-private:
- static void writeUrl(GeneratedCodeUtils &code, const QQmlJSAotMethod &urlMethod);
-};
-
-QT_END_NAMESPACE
-
-#endif // CODEGENERATORWRITER_H
diff --git a/tools/qmltc/prototype/generatedcodeprimitives.h b/tools/qmltc/prototype/generatedcodeprimitives.h
deleted file mode 100644
index 72007caae3..0000000000
--- a/tools/qmltc/prototype/generatedcodeprimitives.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef GENERATEDCODEPRIMITIVES_H
-#define GENERATEDCODEPRIMITIVES_H
-
-#include <QtCore/qstring.h>
-#include <QtCore/qstack.h>
-
-QT_BEGIN_NAMESPACE
-
-// holds generated code for header and implementation files
-struct GeneratedCode
-{
- QString header;
- QString implementation;
-};
-
-// utility class that provides pretty-printing of the generated code into the
-// GeneratedCode buffer
-struct GeneratedCodeUtils
-{
- GeneratedCode &m_code; // buffer
-
- QStack<QString> memberNamespaceStack; // member names scopes e.g. MyClass::MySubclass::
- int headerIndent = 0; // header indentation level
- int implIndent = 0; // implementation indentation level
-
- GeneratedCodeUtils(GeneratedCode &code) : m_code(code) { }
-
- // manages current scope of the generated code, which is necessary for
- // implementation file generation. Example:
- // class MyClass { MyClass(); }; - in header
- // MyClass::MyClass() {} - in implementation file
- // MemberNamespaceScope exists to be able to record and use "MyClass::"
- struct MemberNamespaceScope
- {
- GeneratedCodeUtils &m_code;
- MemberNamespaceScope(GeneratedCodeUtils &code, const QString &str) : m_code(code)
- {
- m_code.memberNamespaceStack.push(str);
- }
- ~MemberNamespaceScope() { m_code.memberNamespaceStack.pop(); }
- };
-
- // manages current indentation scope: upon creation, increases current
- // scope, which is decreased back upon deletion. this is used by append*
- // functions that work with GeneratedCode::header to correctly indent the
- // input
- struct HeaderIndentationScope
- {
- GeneratedCodeUtils &m_code;
- HeaderIndentationScope(GeneratedCodeUtils &code) : m_code(code) { ++m_code.headerIndent; }
- ~HeaderIndentationScope() { --m_code.headerIndent; }
- };
-
- // manages current indentation scope: upon creation, increases current
- // scope, which is decreased back upon deletion. this is used by append*
- // functions that work with GeneratedCode::implementation to correctly
- // indent the input
- struct ImplIndentationScope
- {
- GeneratedCodeUtils &m_code;
- ImplIndentationScope(GeneratedCodeUtils &code) : m_code(code) { ++m_code.implIndent; }
- ~ImplIndentationScope() { --m_code.implIndent; }
- };
-
- // appends string \a what with extra indentation \a extraIndent to current
- // GeneratedCode::header string
- template<typename String>
- void appendToHeader(const String &what, int extraIndent = 0)
- {
- constexpr char16_t newLine[] = u"\n";
- m_code.header += QString((headerIndent + extraIndent) * 4, u' ') + what + newLine;
- }
-
- // appends string \a what with extra indentation \a extraIndent to current
- // GeneratedCode::implementation string
- template<typename String>
- void appendToImpl(const String &what, int extraIndent = 0)
- {
- constexpr char16_t newLine[] = u"\n";
- m_code.implementation += QString((implIndent + extraIndent) * 4, u' ') + what + newLine;
- }
-
- // appends string \a what with extra indentation \a extraIndent to current
- // GeneratedCode::implementation string. this is a special case function
- // that expects \a what to be a function signature as \a what is prepended
- // with member scope related text. for example, string "foo()" is converted
- // to string "MyClass::foo()" before append
- template<typename String>
- void appendSignatureToImpl(const String &what, int extraIndent = 0)
- {
- constexpr char16_t newLine[] = u"\n";
- QString signatureScope;
- for (const auto &subScope : memberNamespaceStack)
- signatureScope += subScope + u"::";
- m_code.implementation +=
- signatureScope + QString((implIndent + extraIndent) * 4, u' ') + what + newLine;
- }
-};
-
-QT_END_NAMESPACE
-
-#endif // GENERATEDCODEPRIMITIVES_H
diff --git a/tools/qmltc/prototype/qml2cppcontext.h b/tools/qmltc/prototype/qml2cppcontext.h
index a8b6aa7c90..3c17a632df 100644
--- a/tools/qmltc/prototype/qml2cppcontext.h
+++ b/tools/qmltc/prototype/qml2cppcontext.h
@@ -29,7 +29,6 @@
#ifndef QML2CPPCONTEXT_H
#define QML2CPPCONTEXT_H
-#include "prototype/qmlcompiler.h"
#include "qmltctyperesolver.h"
#include <private/qqmljsdiagnosticmessage_p.h>
diff --git a/tools/qmltc/prototype/qmlcompiler.h b/tools/qmltc/prototype/qmlcompiler.h
deleted file mode 100644
index 60174bdab1..0000000000
--- a/tools/qmltc/prototype/qmlcompiler.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QMLCOMPILER_H
-#define QMLCOMPILER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-
-#include <private/qqmljscompiler_p.h>
-#include <private/qqmljsmetatypes_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// TODO: rename the classes into Qmltc* pattern
-
-// Below are the classes that represent a compiled QML types in a string data
-// form. These classes should be used to generate C++ code.
-
-// Represents QML->C++ compiled enumeration type
-struct QQmlJSAotEnum
-{
- QString cppType; // C++ type of enum
- QStringList keys; // enumerator
- QStringList values; // enumerator value
- QString ownMocLine; // special MOC line that follows enum declaration
-
- QQmlJSAotEnum() = default;
- QQmlJSAotEnum(const QString &t, const QStringList &ks, const QStringList &vs, const QString &l)
- : cppType(t), keys(ks), values(vs), ownMocLine(l)
- {
- }
-};
-
-// Represents C++ member variable
-struct QQmlJSAotVariable
-{
- QString cppType; // C++ type of a variable
- QString name; // variable name
- QString defaultValue; // optional default value
-
- QQmlJSAotVariable() = default;
- QQmlJSAotVariable(const QString &t, const QString &n, const QString &v)
- : cppType(t), name(n), defaultValue(v)
- {
- }
-};
-
-struct QQmlJSAotProperty : QQmlJSAotVariable
-{
- QString containingClass;
- QString signalName;
-
- QQmlJSAotProperty() = default;
- QQmlJSAotProperty(const QString t, const QString &n, const QString &c, const QString &s)
- : QQmlJSAotVariable(t, n, QString()), containingClass(c), signalName(s)
- {
- }
-};
-
-struct QQmlJSAotMethodBase
-{
- QString returnType; // C++ return type
- QString name; // C++ function name
- QList<QQmlJSAotVariable> parameterList; // C++ function parameter list
- QStringList body; // C++ code of function body by line
- QStringList declPreambles; // e.g. "static" keyword
- QStringList modifiers; // e.g. cv-qualifiers, ref-qualifier, noexcept, attributes
-
- // TODO: these are only needed for Component.onCompleted -- any better way?
- QStringList firstLines; // C++ to run at the very beginning of a function
- QStringList lastLines; // C++ to run at the very end of a function
-
- QQmlJSMetaMethod::Access access = QQmlJSMetaMethod::Public; // access specifier
-};
-
-// Represents QML->C++ compiled member function
-struct QQmlJSAotMethod : QQmlJSAotMethodBase
-{
- QQmlJSMetaMethod::Type type = QQmlJSMetaMethod::Method; // Qt function type
- bool userVisible = false; // tells if a function is prioritized during the output generation
-};
-
-// Represents C++ special member function
-struct QQmlJSAotSpecialMethod : QQmlJSAotMethodBase
-{
- QStringList initializerList; // C++ ctor initializer list
-};
-
-// Represents QML->C++ compiled class type that is used for C++ code generation
-struct QQmlJSAotObject
-{
- QString cppType; // C++ class name of the QML object
- 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?
-
- // member types: enumerations and child types
- QList<QQmlJSAotEnum> enums;
- QList<QQmlJSAotObject> children; // these are pretty much always empty
- // special member functions
- QQmlJSAotSpecialMethod baselineCtor = {}; // does primary initialization
- QQmlJSAotMethod init = {}; // begins secondary initialization
- QQmlJSAotMethod endInit = {}; // ends initialization (with binding setup)
- QQmlJSAotMethod completeComponent = {}; // calls componentComplete()
- QQmlJSAotMethod finalizeComponent = {}; // invokes finalizer callbacks
- QQmlJSAotMethod handleOnCompleted = {}; // calls Component.onCompleted
- QQmlJSAotSpecialMethod externalCtor = {}; // calls baselineCtor, calls init
- std::optional<QQmlJSAotSpecialMethod> dtor = {};
- // member functions: methods, signals and slots
- QList<QQmlJSAotMethod> functions;
- // member variables
- QList<QQmlJSAotVariable> variables;
- // member properties
- QList<QQmlJSAotProperty> properties;
-
- // TODO: only needed for binding callables - should be revisited
- bool ignoreInit = false; // specifies whether init and externalCtor should be ignored
-};
-
-struct QQmlJSProgram
-{
- QList<QQmlJSAotObject> compiledObjects;
- QQmlJSAotMethod urlMethod;
- QString url;
- QString hPath;
- QString cppPath;
- QString outNamespace;
- QSet<QString> includes;
-};
-
-QT_END_NAMESPACE
-
-#endif // QMLCOMPILER_H
diff --git a/tools/qmltc/qmltccodewriter.cpp b/tools/qmltc/qmltccodewriter.cpp
index 6c2c018833..67e3c7f06b 100644
--- a/tools/qmltc/qmltccodewriter.cpp
+++ b/tools/qmltc/qmltccodewriter.cpp
@@ -74,6 +74,20 @@ static QString getFunctionCategory(const QmltcMethod &method)
return category;
}
+static QString appendSpace(const QString &s)
+{
+ if (s.isEmpty())
+ return s;
+ return s + u" ";
+}
+
+static QString prependSpace(const QString &s)
+{
+ if (s.isEmpty())
+ return s;
+ return u" " + s;
+}
+
static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &method)
{
const QString name = method.name;
@@ -89,11 +103,18 @@ static std::pair<QString, QString> functionSignatures(const QmltcMethodBase &met
headerParamList.back() += u" = " + variable.defaultValue;
}
- const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")";
- const QString cppSignature = name + u"(" + cppParamList.join(u", "_qs) + u")";
+ const QString headerSignature = name + u"(" + headerParamList.join(u", "_qs) + u")"
+ + prependSpace(method.modifiers.join(u" "));
+ const QString cppSignature = name + u"(" + cppParamList.join(u", "_qs) + u")"
+ + prependSpace(method.modifiers.join(u" "));
return { headerSignature, cppSignature };
}
+static QString functionReturnType(const QmltcMethod &m)
+{
+ return appendSpace(m.declarationPrefixes.join(u" "_qs)) + m.returnType;
+}
+
void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString &sourcePath,
const QString &hPath, const QString &cppPath,
const QString &outNamespace,
@@ -129,14 +150,18 @@ void QmltcCodeWriter::writeGlobalHeader(QmltcOutputWrapper &code, const QString
for (const auto &requiredInclude : requiredCppIncludes)
code.rawAppendToHeader(u"#include \"" + requiredInclude + u"\"");
code.rawAppendToHeader(u"// END(custom_cpp_includes)");
- code.rawAppendToHeader(u"// qmltc support library:");
- code.rawAppendToHeader(u"#include <private/qqmltcobjectcreationhelper_p.h>");
code.rawAppendToCpp(u"#include \"" + hPath + u"\""); // include own .h file
+ code.rawAppendToCpp(u"// qmltc support library:");
+ code.rawAppendToCpp(u"#include <private/qqmlcppbinding_p.h>"); // QmltcSupportLib
+ code.rawAppendToCpp(u"#include <private/qqmlcpponassignment_p.h>"); // QmltcSupportLib
- code.rawAppendToCpp(u""); // blank line
+ code.rawAppendToCpp(u"#include <private/qqmlobjectcreator_p.h>"); // createComponent()
+ code.rawAppendToCpp(u"#include <private/qqmlcomponent_p.h>"); // QQmlComponentPrivate::get()
+
+ code.rawAppendToCpp(u"");
code.rawAppendToCpp(u"#include <private/qobject_p.h>"); // NB: for private properties
- code.rawAppendToCpp(u"#include <private/qqmlglobal_p.h>"); // QQml_setParent_noEvent()
+ code.rawAppendToCpp(u"#include <private/qqmlobjectcreator_p.h>"); // for finalize callbacks
code.rawAppendToCpp(u""); // blank line
code.rawAppendToCpp(u"QT_USE_NAMESPACE // avoid issues with QT_NAMESPACE");
@@ -187,10 +212,6 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &progra
{
writeGlobalHeader(code, program.url, program.hPath, program.cppPath, program.outNamespace,
program.includes);
- // TODO: keep the "NOT IMPLEMENTED" as long as we don't actually compile
- // useful code
- code.rawAppendToHeader(u"/* QMLTC: NOT IMPLEMENTED */");
- code.rawAppendToCpp(u"/* QMLTC: NOT IMPLEMENTED */");
// url method comes first
writeUrl(code, program.urlMethod);
@@ -207,12 +228,36 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProgram &progra
writeToFile(program.cppPath, code.code().cpp.toUtf8());
}
+template<typename Predicate>
+static void dumpFunctions(QmltcOutputWrapper &code, const QList<QmltcMethod> &functions,
+ Predicate pred)
+{
+ // functions are _ordered_ by access and kind. ordering is important to
+ // provide consistent output
+ QMap<QString, QList<const QmltcMethod *>> orderedFunctions;
+ for (const auto &function : functions) {
+ if (pred(function))
+ orderedFunctions[getFunctionCategory(function)].append(std::addressof(function));
+ }
+
+ for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
+ code.rawAppendToHeader(it.key() + u":", -1);
+ for (const QmltcMethod *function : qAsConst(it.value()))
+ QmltcCodeWriter::write(code, *function);
+ }
+}
+
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type)
{
const auto constructClassString = [&]() {
QString str = u"class " + type.cppType;
- if (!type.baseClasses.isEmpty())
- str += u" : public " + type.baseClasses.join(u", public "_qs);
+ QStringList nonEmptyBaseClasses;
+ nonEmptyBaseClasses.reserve(type.baseClasses.size());
+ std::copy_if(type.baseClasses.cbegin(), type.baseClasses.cend(),
+ std::back_inserter(nonEmptyBaseClasses),
+ [](const QString &entry) { return !entry.isEmpty(); });
+ if (!nonEmptyBaseClasses.isEmpty())
+ str += u" : public " + nonEmptyBaseClasses.join(u", public "_qs);
return str;
};
@@ -233,42 +278,70 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcType &type)
QmltcOutputWrapper::HeaderIndentationScope headerIndent(&code);
Q_UNUSED(headerIndent);
- // special member functions
- code.rawAppendToHeader(u"protected:", -1);
- write(code, type.basicCtor);
- write(code, type.init);
- write(code, type.finalize);
- // NB: externalCtor might not be public when the type is QML singleton
- code.rawAppendToHeader(getFunctionCategory(type.fullCtor) + u":", -1);
- write(code, type.fullCtor);
+ // first, write user-visible code, then everything else. someone might
+ // want to look at the generated code, so let's make an effort when
+ // writing it down
- // enums
- if (!type.enums.isEmpty()) {
- code.rawAppendToHeader(u""); // blank line
- code.rawAppendToHeader(u"public:", -1);
+ code.rawAppendToHeader(u"/* ----------------- */");
+ code.rawAppendToHeader(u"/* External C++ API */");
+ code.rawAppendToHeader(u"public:", -1);
+
+ // NB: when non-document root, the externalCtor won't be public - but we
+ // really don't care about the output format of such types
+ if (!type.ignoreInit && type.externalCtor.access == QQmlJSMetaMethod::Public) {
+ // TODO: ignoreInit must be eliminated
+
+ QmltcCodeWriter::write(code, type.externalCtor);
}
+
+ // dtor
+ if (type.dtor)
+ QmltcCodeWriter::write(code, *type.dtor);
+
+ // enums
for (const auto &enumeration : qAsConst(type.enums))
- write(code, enumeration);
+ QmltcCodeWriter::write(code, enumeration);
- // child types
- if (!type.children.isEmpty())
- code.rawAppendToHeader(u""); // blank line
- for (const auto &child : qAsConst(type.children))
- write(code, child);
+ // visible functions
+ const auto isUserVisibleFunction = [](const QmltcMethod &function) {
+ return function.userVisible;
+ };
+ dumpFunctions(code, type.functions, isUserVisibleFunction);
- // functions (special case due to functions/signals/slots, etc.)
- QHash<QString, QList<const QmltcMethod *>> functionsByCategory;
- for (const auto &function : qAsConst(type.functions))
- functionsByCategory[getFunctionCategory(function)].append(&function);
+ code.rawAppendToHeader(u"/* ----------------- */");
+ code.rawAppendToHeader(u""); // blank line
+ code.rawAppendToHeader(u"/* Internal functionality (do NOT use it!) */");
- if (!functionsByCategory.isEmpty())
- code.rawAppendToHeader(u""); // blank line
- for (auto it = functionsByCategory.cbegin(); it != functionsByCategory.cend(); ++it) {
- code.rawAppendToHeader(it.key() + u":", -1);
- for (const QmltcMethod *function : qAsConst(it.value()))
- write(code, *function);
+ // below are the hidden parts of the type
+
+ // (rest of the) ctors
+ if (type.ignoreInit) { // TODO: this branch should be eliminated
+ Q_ASSERT(type.baselineCtor.access == QQmlJSMetaMethod::Public);
+ code.rawAppendToHeader(u"public:", -1);
+ QmltcCodeWriter::write(code, type.baselineCtor);
+ } else {
+ code.rawAppendToHeader(u"protected:", -1);
+ if (type.externalCtor.access != QQmlJSMetaMethod::Public) {
+ Q_ASSERT(type.externalCtor.access == QQmlJSMetaMethod::Protected);
+ QmltcCodeWriter::write(code, type.externalCtor);
+ }
+ QmltcCodeWriter::write(code, type.baselineCtor);
+ QmltcCodeWriter::write(code, type.init);
+ QmltcCodeWriter::write(code, type.endInit);
+ QmltcCodeWriter::write(code, type.completeComponent);
+ QmltcCodeWriter::write(code, type.finalizeComponent);
+ QmltcCodeWriter::write(code, type.handleOnCompleted);
+
+ // code.rawAppendToHeader(u"public:", -1);
}
+ // children
+ for (const auto &child : qAsConst(type.children))
+ QmltcCodeWriter::write(code, child);
+
+ // (non-visible) functions
+ dumpFunctions(code, type.functions, std::not_fn(isUserVisibleFunction));
+
// variables and properties
if (!type.variables.isEmpty() || !type.properties.isEmpty()) {
code.rawAppendToHeader(u""); // blank line
@@ -314,10 +387,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method)
{
const auto [hSignature, cppSignature] = functionSignatures(method);
// Note: augment return type with preambles in declaration
- QString prefix = method.declarationPrefixes.join(u' ');
- if (!prefix.isEmpty())
- prefix.append(u' ');
- code.rawAppendToHeader(prefix + method.returnType + u" " + hSignature + u";");
+ code.rawAppendToHeader(functionReturnType(method) + u" " + hSignature + u";");
// do not generate method implementation if it is a signal
const auto methodType = method.type;
@@ -329,39 +399,65 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcMethod &method)
{
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
Q_UNUSED(cppIndent);
+ for (const QString &line : qAsConst(method.firstLines))
+ code.rawAppendToCpp(line);
for (const QString &line : qAsConst(method.body))
code.rawAppendToCpp(line);
+ for (const QString &line : qAsConst(method.lastLines))
+ code.rawAppendToCpp(line);
}
code.rawAppendToCpp(u"}");
}
}
-void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor)
+template<typename WriteInitialization>
+static void writeSpecialMethod(QmltcOutputWrapper &code, const QmltcMethodBase &specialMethod,
+ WriteInitialization writeInit)
{
- const auto [hSignature, cppSignature] = functionSignatures(ctor);
- QString prefix = ctor.declarationPrefixes.join(u' ');
- if (!prefix.isEmpty())
- prefix.append(u' ');
- code.rawAppendToHeader(prefix + hSignature + u";");
+ const auto [hSignature, cppSignature] = functionSignatures(specialMethod);
+ code.rawAppendToHeader(hSignature + u";");
code.rawAppendToCpp(u""); // blank line
code.rawAppendSignatureToCpp(cppSignature);
- if (!ctor.initializerList.isEmpty()) {
- code.rawAppendToCpp(u":", 1);
- // double \n to make separate initializer list lines stand out more
- code.rawAppendToCpp(
- ctor.initializerList.join(u",\n\n" + u" "_qs.repeated(code.cppIndent + 1)), 1);
- }
+
+ writeInit(specialMethod);
+
code.rawAppendToCpp(u"{");
{
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
Q_UNUSED(cppIndent);
- for (const QString &line : qAsConst(ctor.body))
+ for (const QString &line : qAsConst(specialMethod.firstLines))
+ code.rawAppendToCpp(line);
+ for (const QString &line : qAsConst(specialMethod.body))
+ code.rawAppendToCpp(line);
+ for (const QString &line : qAsConst(specialMethod.lastLines))
code.rawAppendToCpp(line);
}
code.rawAppendToCpp(u"}");
}
+void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcCtor &ctor)
+{
+ const auto writeInitializerList = [&](const QmltcMethodBase &ctorBase) {
+ auto ctor = static_cast<const QmltcCtor &>(ctorBase);
+ if (!ctor.initializerList.isEmpty()) {
+ code.rawAppendToCpp(u":", 1);
+ // double \n to make separate initializer list lines stand out more
+ code.rawAppendToCpp(
+ ctor.initializerList.join(u",\n\n" + u" "_qs.repeated(code.cppIndent + 1)),
+ 1);
+ }
+ };
+
+ writeSpecialMethod(code, ctor, writeInitializerList);
+}
+
+void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcDtor &dtor)
+{
+ const auto noop = [](const QmltcMethodBase &) {};
+ writeSpecialMethod(code, dtor, noop);
+}
+
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var)
{
const QString optionalPart = var.defaultValue.isEmpty() ? u""_qs : u" = " + var.defaultValue;
@@ -370,7 +466,7 @@ void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcVariable &var)
void QmltcCodeWriter::write(QmltcOutputWrapper &code, const QmltcProperty &prop)
{
- Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet
+ Q_ASSERT(prop.defaultValue.isEmpty()); // we don't support it yet (or at all?)
code.rawAppendToHeader(u"Q_OBJECT_BINDABLE_PROPERTY(%1, %2, %3, &%1::%4)"_qs.arg(
prop.containingClass, prop.cppType, prop.name, prop.signalName));
}
@@ -382,14 +478,12 @@ void QmltcCodeWriter::writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlM
const auto [hSignature, _] = functionSignatures(urlMethod);
Q_UNUSED(_);
// Note: augment return type with preambles in declaration
- QString prefix = urlMethod.declarationPrefixes.join(u' ');
- if (!prefix.isEmpty())
- prefix.append(u' ');
- code.rawAppendToCpp(prefix + urlMethod.returnType + u" " + hSignature);
+ code.rawAppendToCpp(functionReturnType(urlMethod) + hSignature);
code.rawAppendToCpp(u"{");
{
QmltcOutputWrapper::CppIndentationScope cppIndent(&code);
Q_UNUSED(cppIndent);
+ Q_ASSERT(urlMethod.firstLines.isEmpty() && urlMethod.lastLines.isEmpty());
for (const QString &line : qAsConst(urlMethod.body))
code.rawAppendToCpp(line);
}
diff --git a/tools/qmltc/qmltccodewriter.h b/tools/qmltc/qmltccodewriter.h
index 1d1e023d43..824a3f97db 100644
--- a/tools/qmltc/qmltccodewriter.h
+++ b/tools/qmltc/qmltccodewriter.h
@@ -49,9 +49,11 @@ struct QmltcCodeWriter
static void write(QmltcOutputWrapper &code, const QmltcEnum &enumeration);
static void write(QmltcOutputWrapper &code, const QmltcMethod &method);
static void write(QmltcOutputWrapper &code, const QmltcCtor &ctor);
+ static void write(QmltcOutputWrapper &code, const QmltcDtor &dtor);
static void write(QmltcOutputWrapper &code, const QmltcVariable &var);
static void write(QmltcOutputWrapper &code, const QmltcProperty &prop);
+private:
static void writeUrl(QmltcOutputWrapper &code, const QmltcMethod &urlMethod); // special
};
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index 92007d690a..2b69a81b85 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -115,7 +115,7 @@ void QmltcCompiler::compileType(QmltcType &current, const QQmlJSScope::ConstPtr
current.baseClasses = { baseClass };
if (!documentRoot) {
- // make document root a friend to allow it to access init and finalize
+ // make document root a friend to allow it to access init and endInit
current.otherCode << u"friend class %1;"_qs.arg(rootType->internalName());
} else {
// make QQmltcObjectCreationBase<DocumentRoot> a friend to allow it to
@@ -147,68 +147,70 @@ void QmltcCompiler::compileType(QmltcType &current, const QQmlJSScope::ConstPtr
};
// add special member functions
- current.basicCtor.access = QQmlJSMetaMethod::Protected;
+ current.baselineCtor.access = QQmlJSMetaMethod::Protected;
current.init.access = QQmlJSMetaMethod::Protected;
- current.finalize.access = QQmlJSMetaMethod::Protected;
- current.fullCtor.access = QQmlJSMetaMethod::Public;
+ current.endInit.access = QQmlJSMetaMethod::Protected;
+ current.externalCtor.access = QQmlJSMetaMethod::Public;
- current.basicCtor.name = current.cppType;
- current.fullCtor.name = current.cppType;
+ current.baselineCtor.name = current.cppType;
+ current.externalCtor.name = current.cppType;
current.init.name = u"qmltc_init"_qs;
current.init.returnType = u"QQmlRefPointer<QQmlContextData>"_qs;
- current.finalize.name = u"qmltc_finalize"_qs;
- current.finalize.returnType = u"void"_qs;
+ current.endInit.name = u"qmltc_finalize"_qs;
+ current.endInit.returnType = u"void"_qs;
QmltcVariable creator(u"QQmltcObjectCreationHelper*"_qs, u"creator"_qs);
QmltcVariable engine(u"QQmlEngine*"_qs, u"engine"_qs);
QmltcVariable parent(u"QObject*"_qs, u"parent"_qs, u"nullptr"_qs);
- current.basicCtor.parameterList = { parent };
+ current.baselineCtor.parameterList = { parent };
QmltcVariable ctxtdata(u"const QQmlRefPointer<QQmlContextData>&"_qs, u"parentContext"_qs);
QmltcVariable finalizeFlag(u"bool"_qs, u"canFinalize"_qs);
if (documentRoot) {
- current.fullCtor.parameterList = { engine, parent };
+ current.externalCtor.parameterList = { engine, parent };
current.init.parameterList = { creator, engine, ctxtdata, finalizeFlag };
- current.finalize.parameterList = { creator, engine, finalizeFlag };
+ current.endInit.parameterList = { creator, engine, finalizeFlag };
} else {
- current.fullCtor.parameterList = { creator, engine, parent };
+ current.externalCtor.parameterList = { creator, engine, parent };
current.init.parameterList = { creator, engine, ctxtdata };
- current.finalize.parameterList = { creator, engine };
+ current.endInit.parameterList = { creator, engine };
}
- current.fullCtor.initializerList = { current.basicCtor.name + u"(" + parent.name + u")" };
+ current.externalCtor.initializerList = { current.baselineCtor.name + u"(" + parent.name
+ + u")" };
if (baseTypeIsCompiledQml) {
// call parent's (QML type's) basic ctor from this. that one will take
// care about QObject::setParent()
- current.basicCtor.initializerList = { baseClass + u"(" + parent.name + u")" };
+ current.baselineCtor.initializerList = { baseClass + u"(" + parent.name + u")" };
} else {
// default call to ctor is enough, but QQml_setParent_noEvent() is
// needed (note: faster? version of QObject::setParent())
- current.basicCtor.body << u"QQml_setParent_noEvent(this, " + parent.name + u");";
+ current.baselineCtor.body << u"QQml_setParent_noEvent(this, " + parent.name + u");";
}
QmltcCodeGenerator generator { rootType };
// compilation stub:
- current.fullCtor.body << u"Q_UNUSED(engine);"_qs;
- current.finalize.body << u"Q_UNUSED(engine);"_qs;
- current.finalize.body << u"Q_UNUSED(creator);"_qs;
+ current.externalCtor.body << u"Q_UNUSED(engine);"_qs;
+ current.endInit.body << u"Q_UNUSED(engine);"_qs;
+ current.endInit.body << u"Q_UNUSED(creator);"_qs;
if (documentRoot) {
- current.fullCtor.body << u"// document root:"_qs;
+ current.externalCtor.body << u"// document root:"_qs;
// if it's document root, we want to create our QQmltcObjectCreationBase
// that would store all the created objects
- current.fullCtor.body << u"QQmltcObjectCreationBase<%1> objectHolder;"_qs.arg(
+ current.externalCtor.body << u"QQmltcObjectCreationBase<%1> objectHolder;"_qs.arg(
type->internalName());
- current.fullCtor.body << u"QQmltcObjectCreationHelper creator = objectHolder.view();"_qs;
+ current.externalCtor.body
+ << u"QQmltcObjectCreationHelper creator = objectHolder.view();"_qs;
// now call init
- current.fullCtor.body << current.init.name
+ current.externalCtor.body << current.init.name
+ u"(&creator, engine, QQmlContextData::get(engine->rootContext()), /* "
- u"finalize */ true);";
+ u"endInit */ true);";
- current.finalize.body << u"Q_UNUSED(canFinalize);"_qs;
+ current.endInit.body << u"Q_UNUSED(canFinalize);"_qs;
} else {
- current.fullCtor.body << u"// not document root:"_qs;
+ current.externalCtor.body << u"// not document root:"_qs;
// just call init, we don't do any setup here otherwise
- current.fullCtor.body << current.init.name
+ current.externalCtor.body << current.init.name
+ u"(creator, engine, QQmlData::get(parent)->outerContext);";
}
@@ -353,9 +355,9 @@ void QmltcCompiler::compileProperty(QmltcType &current, const QQmlJSMetaProperty
const QString storageName = variableName + u"_storage";
current.variables.emplaceBack(u"QList<" + p.type()->internalName() + u" *>", storageName,
QString());
- current.basicCtor.initializerList.emplaceBack(variableName + u"(" + underlyingType
- + u"(this, std::addressof(" + storageName
- + u")))");
+ current.baselineCtor.initializerList.emplaceBack(variableName + u"(" + underlyingType
+ + u"(this, std::addressof(" + storageName
+ + u")))");
}
// along with property, also add relevant moc code, so that we can use the
diff --git a/tools/qmltc/qmltccompilerpieces.h b/tools/qmltc/qmltccompilerpieces.h
index e0c587b5f3..d78be5a652 100644
--- a/tools/qmltc/qmltccompilerpieces.h
+++ b/tools/qmltc/qmltccompilerpieces.h
@@ -147,7 +147,7 @@ QmltcCodeGenerator::generate_qmlContextSetup(QmltcType &current, const QQmlJSSco
current.init.body << u"// 4. call finalize in the document root"_qs;
current.init.body << u"if (canFinalize) {"_qs;
current.init.body << QStringLiteral(" %1(creator, engine, /* finalize */ true);")
- .arg(current.finalize.name);
+ .arg(current.endInit.name);
current.init.body << u"}"_qs;
}
current.init.body << u"return context;"_qs;
diff --git a/tools/qmltc/qmltcoutputir.h b/tools/qmltc/qmltcoutputir.h
index 9d000cbc11..0a3e7617bd 100644
--- a/tools/qmltc/qmltcoutputir.h
+++ b/tools/qmltc/qmltcoutputir.h
@@ -92,6 +92,12 @@ struct QmltcMethodBase
QStringList body; // C++ function code
QQmlJSMetaMethod::Access access = QQmlJSMetaMethod::Public; // access specifier
QStringList declarationPrefixes;
+ QStringList modifiers; // cv-qualifiers, ref-qualifier, noexcept, attributes
+
+ // TODO: these are only needed for Component.onCompleted/onDestruction. this
+ // has to be re-written anyhow later
+ QStringList firstLines; // C++ to run at the very beginning of a function
+ QStringList lastLines; // C++ to run at the very end of a function
};
// Represents QML -> C++ compiled function
@@ -99,6 +105,9 @@ struct QmltcMethod : QmltcMethodBase
{
QString returnType; // C++ return type
QQmlJSMetaMethod::Type type = QQmlJSMetaMethod::Method; // Qt function type
+
+ // TODO: should be a better way to handle this
+ bool userVisible = false; // tells if a function is prioritized during the output generation
};
// Represents C++ ctor of a type
@@ -107,6 +116,11 @@ struct QmltcCtor : QmltcMethodBase
QStringList initializerList; // C++ ctor's initializer list
};
+// Represents C++ dtor of a type
+struct QmltcDtor : QmltcMethodBase
+{
+};
+
// Represents QML -> C++ compiled type
struct QmltcType
{
@@ -120,10 +134,15 @@ struct QmltcType
QList<QmltcType> children; // these are pretty much always empty
// special member functions:
- QmltcCtor basicCtor = {}; // does basic contruction
- QmltcCtor fullCtor = {}; // calls basicCtor, calls init
- QmltcMethod init = {}; // starts object initialization (context setup), calls finalize
- QmltcMethod finalize = {}; // finalizes object (bindings, special interface calls, etc.)
+ QmltcCtor baselineCtor {}; // does basic contruction
+ QmltcCtor externalCtor {}; // calls basicCtor, calls init
+ QmltcMethod init {}; // starts object initialization (context setup), calls finalize
+ QmltcMethod endInit {}; // ends object initialization (with binding setup)
+ QmltcMethod completeComponent {}; // calls componentComplete()
+ QmltcMethod finalizeComponent {}; // calls componentFinalized()
+ QmltcMethod handleOnCompleted {}; // calls Component.onCompleted
+
+ std::optional<QmltcDtor> dtor {};
// member functions: methods, signals and slots
QList<QmltcMethod> functions;
@@ -133,6 +152,9 @@ struct QmltcType
// QML document root specific:
std::optional<QmltcVariable> typeCount; // the number of QML types defined in a document
+
+ // TODO: only needed for binding callables - should not be needed, generally
+ bool ignoreInit = false; // specifies whether init and externalCtor should be ignored
};
// Represents whole QML program, compiled to C++