aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/qml/main.cpp11
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp22
-rw-r--r--tools/qmlimportscanner/main.cpp1
-rw-r--r--tools/qmltc/CMakeLists.txt7
-rw-r--r--tools/qmltc/main.cpp58
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp228
-rw-r--r--tools/qmltc/prototype/codegenerator.h51
-rw-r--r--tools/qmltc/prototype/codegeneratorutil.cpp19
-rw-r--r--tools/qmltc/prototype/codegeneratorutil.h14
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.cpp476
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.h57
-rw-r--r--tools/qmltc/prototype/generatedcodeprimitives.h126
-rw-r--r--tools/qmltc/prototype/qml2cppcontext.h13
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.cpp56
-rw-r--r--tools/qmltc/prototype/qml2cppdefaultpasses.h6
-rw-r--r--tools/qmltc/prototype/qml2cpppropertyutils.h4
-rw-r--r--tools/qmltc/prototype/qmlcompiler.h179
-rw-r--r--tools/qmltc/prototype/typeresolver.h64
-rw-r--r--tools/qmltc/prototype/visitor.cpp51
-rw-r--r--tools/qmltc/prototype/visitor.h55
-rw-r--r--tools/qmltc/qmltccodewriter.cpp218
-rw-r--r--tools/qmltc/qmltccodewriter.h2
-rw-r--r--tools/qmltc/qmltccompiler.cpp72
-rw-r--r--tools/qmltc/qmltccompiler.h4
-rw-r--r--tools/qmltc/qmltccompilerpieces.h2
-rw-r--r--tools/qmltc/qmltcoutputir.h30
-rw-r--r--tools/qmltc/qmltctyperesolver.cpp (renamed from tools/qmltc/prototype/typeresolver.cpp)24
-rw-r--r--tools/qmltc/qmltctyperesolver.h24
-rw-r--r--tools/qmltc/qmltcvisitor.cpp46
-rw-r--r--tools/qmltc/qmltcvisitor.h4
31 files changed, 572 insertions, 1354 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 1e8ec2d46f..3392714335 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -61,7 +61,7 @@ endif()
if(QT_FEATURE_thread AND TARGET Qt::QuickTest AND NOT ANDROID AND NOT WASM AND NOT rtems)
add_subdirectory(qmltestrunner)
endif()
-if(QT_FEATURE_private_tests AND QT_FEATURE_thread AND NOT ANDROID AND NOT WASM AND NOT rtems)
+if(QT_FEATURE_private_tests AND QT_FEATURE_thread AND NOT ANDROID AND NOT WASM AND NOT IOS AND NOT rtems)
add_subdirectory(qmljs)
endif()
if (QT_FEATURE_private_tests AND NOT CMAKE_CROSSCOMPILING)
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 076ca28b22..42a1745fd8 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -61,6 +61,7 @@
#include <qqmlfileselector.h>
#include <private/qtqmlglobal_p.h>
+#include <private/qqmlimport_p.h>
#if QT_CONFIG(qml_animation)
#include <private/qabstractanimation_p.h>
#endif
@@ -113,23 +114,23 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f
QFileInfo fi;
fi.setFile(QStandardPaths::locate(QStandardPaths::AppDataLocation, defaultFileName));
if (fi.exists()) {
- settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
+ settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
} else {
// ### If different built-in configs are needed per-platform, just apply QFileSelector to the qrc conf.qml path
fi.setFile(confResourcePath + defaultFileName);
- settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
+ settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
builtIn = true;
}
} else {
QFileInfo fi;
fi.setFile(confResourcePath + override + QLatin1String(".qml"));
if (fi.exists()) {
- settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
+ settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
builtIn = true;
} else {
fi.setFile(QDir(QStandardPaths::locate(QStandardPaths::AppConfigLocation, override, QStandardPaths::LocateDirectory)), customConfFileName);
if (fi.exists())
- settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
+ settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
else
fi.setFile(override);
if (!fi.exists()) {
@@ -137,7 +138,7 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f
qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
exit(1);
}
- settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
+ settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
}
}
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index d6869ab05b..7a715d5d13 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -270,19 +270,15 @@ int main(int argc, char **argv)
QQmlJSLogger logger;
// Always trigger the qFatal() on "pragma Strict" violations.
- logger.setCategoryError(Log_Compiler, true);
+ logger.setCategoryLevel(Log_Compiler, QtCriticalMsg);
+ logger.setCategoryIgnored(Log_Compiler, false);
// By default, we're completely silent,
// as the lcAotCompiler category default is QtFatalMsg
- if (lcAotCompiler().isDebugEnabled())
- logger.setCategoryLevel(Log_Compiler, QtDebugMsg);
- else if (lcAotCompiler().isInfoEnabled())
- logger.setCategoryLevel(Log_Compiler, QtInfoMsg);
- else if (lcAotCompiler().isWarningEnabled())
- logger.setCategoryLevel(Log_Compiler, QtWarningMsg);
- else if (lcAotCompiler().isCriticalEnabled())
- logger.setCategoryLevel(Log_Compiler, QtCriticalMsg);
- else
+ const bool loggingEnabled = lcAotCompiler().isDebugEnabled()
+ || lcAotCompiler().isInfoEnabled() || lcAotCompiler().isWarningEnabled()
+ || lcAotCompiler().isCriticalEnabled();
+ if (!loggingEnabled)
logger.setSilent(true);
QQmlJSAotCompiler cppCodeGen(
@@ -297,9 +293,9 @@ int main(int argc, char **argv)
QList<QQmlJS::DiagnosticMessage> warnings = importer.takeGlobalWarnings();
if (!warnings.isEmpty()) {
- logger.logWarning(QStringLiteral("Type warnings occurred while compiling file:"),
- Log_Import);
- logger.processMessages(warnings, QtWarningMsg, Log_Import);
+ logger.log(QStringLiteral("Type warnings occurred while compiling file:"),
+ Log_Import, QQmlJS::SourceLocation());
+ logger.processMessages(warnings, Log_Import);
}
}
} else if (inputFile.endsWith(QLatin1String(".js")) || inputFile.endsWith(QLatin1String(".mjs"))) {
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 605ea03400..24490e1198 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -43,6 +43,7 @@
#include <QtCore/QMetaObject>
#include <QtCore/QMetaProperty>
#include <QtCore/QVariant>
+#include <QtCore/QVariantMap>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
diff --git a/tools/qmltc/CMakeLists.txt b/tools/qmltc/CMakeLists.txt
index cf35319a3b..7e7941539e 100644
--- a/tools/qmltc/CMakeLists.txt
+++ b/tools/qmltc/CMakeLists.txt
@@ -8,21 +8,16 @@ qt_internal_add_tool(${target_name}
qmltcoutputprimitives.h
qmltccodewriter.h qmltccodewriter.cpp
qmltcoutputir.h
- qmltctyperesolver.h
+ qmltctyperesolver.h qmltctyperesolver.cpp
qmltcvisitor.h qmltcvisitor.cpp
qmltccompiler.h qmltccompiler.cpp
qmltccompilerpieces.h
qmltcpropertyutils.h
- prototype/generatedcodeprimitives.h
prototype/qml2cppcontext.h
- prototype/visitor.cpp prototype/visitor.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
- prototype/typeresolver.cpp prototype/typeresolver.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
diff --git a/tools/qmltc/main.cpp b/tools/qmltc/main.cpp
index c2002235cf..49e218f4fe 100644
--- a/tools/qmltc/main.cpp
+++ b/tools/qmltc/main.cpp
@@ -28,8 +28,10 @@
#include "qmltccommandlineutils.h"
#include "prototype/codegenerator.h"
-#include "prototype/visitor.h"
-#include "prototype/typeresolver.h"
+#include "qmltcvisitor.h"
+#include "qmltctyperesolver.h"
+
+#include "qmltccompiler.h"
#include <QtQml/private/qqmlirbuilder_p.h>
#include <private/qqmljscompiler_p.h>
@@ -46,8 +48,18 @@
void setupLogger(QQmlJSLogger &logger) // prepare logger to work with compiler
{
- // TODO: support object bindings and change to setCategoryLevel(QtInfoMsg)
- logger.setCategoryError(Log_Compiler, true);
+ const QSet<QQmlJSLoggerCategory> exceptions {
+ Log_ControlsSanity, // this category is just weird
+ Log_UnusedImport, // not critical
+ };
+
+ for (int i = 0; i <= static_cast<int>(QQmlJSLoggerCategory_Last); ++i) {
+ const auto c = static_cast<QQmlJSLoggerCategory>(i);
+ if (exceptions.contains(c))
+ continue;
+ logger.setCategoryLevel(c, QtCriticalMsg);
+ logger.setCategoryIgnored(c, false);
+ }
}
int main(int argc, char **argv)
@@ -175,11 +187,11 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- Options options;
- options.outputCppFile = parser.value(outputCppOption);
- options.outputHFile = parser.value(outputHOption);
- options.resourcePath = paths.first();
- options.outNamespace = parser.value(namespaceOption);
+ QmltcCompilerInfo info;
+ info.outputCppFile = parser.value(outputCppOption);
+ info.outputHFile = parser.value(outputHOption);
+ info.resourcePath = paths.first();
+ info.outputNamespace = parser.value(namespaceOption);
QQmlJSImporter importer { importPaths, &mapper };
QQmlJSLogger logger;
@@ -187,29 +199,27 @@ int main(int argc, char **argv)
logger.setCode(sourceCode);
setupLogger(logger);
- Qmltc::Visitor visitor(&importer, &logger,
- QQmlJSImportVisitor::implicitImportDirectory(url, &mapper), qmldirFiles);
- Qmltc::TypeResolver typeResolver { &importer };
+ QmltcVisitor visitor(&importer, &logger,
+ QQmlJSImportVisitor::implicitImportDirectory(url, &mapper), qmldirFiles);
+ QmltcTypeResolver typeResolver { &importer };
typeResolver.init(visitor, document.program);
- if (logger.hasWarnings() || logger.hasErrors())
+ if (logger.hasErrors())
return EXIT_FAILURE;
- CodeGenerator generator(url, &logger, &document, &typeResolver);
- generator.generate(options);
-
-# if 0 // TODO: Currently disabled due to QTBUG-100103, remove this #if guard once the issue has
- // been addressed
QList<QQmlJS::DiagnosticMessage> warnings = importer.takeGlobalWarnings();
-
if (!warnings.isEmpty()) {
- logger.logWarning(QStringLiteral("Type warnings occurred while compiling file:"),
- Log_Import);
- logger.processMessages(warnings, QtWarningMsg, Log_Import);
+ logger.log(QStringLiteral("Type warnings occurred while compiling file:"), Log_Import,
+ QQmlJS::SourceLocation());
+ logger.processMessages(warnings, Log_Import);
+ // Log_Import is critical for the compiler
+ return EXIT_FAILURE;
}
-# endif
- if (logger.hasWarnings() || logger.hasErrors())
+ CodeGenerator generator(url, &logger, &document, &typeResolver, &info);
+ generator.generate();
+
+ if (logger.hasErrors())
return EXIT_FAILURE;
return EXIT_SUCCESS;
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index ff71db989b..cf1bb719ee 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -30,7 +30,9 @@
#include "prototype/qml2cppdefaultpasses.h"
#include "prototype/qml2cpppropertyutils.h"
#include "prototype/codegeneratorutil.h"
-#include "prototype/codegeneratorwriter.h"
+#include "qmltccodewriter.h"
+
+#include "qmltccompiler.h"
#include <QtCore/qfileinfo.h>
#include <QtCore/qhash.h>
@@ -45,12 +47,7 @@
#include <utility>
#include <numeric>
-static constexpr char newLineLatin1[] =
-#ifdef Q_OS_WIN32
- "\r\n";
-#else
- "\n";
-#endif
+QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcCodeGenerator, "qml.qmltc.compiler", QtWarningMsg);
@@ -91,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) {
@@ -105,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;
}
@@ -216,13 +212,12 @@ toOrderedSequence(typename QmlIR::PoolList<QmlIR::Binding>::Iterator first,
Q_LOGGING_CATEGORY(lcCodeGen, "qml.compiler.CodeGenerator", QtWarningMsg);
CodeGenerator::CodeGenerator(const QString &url, QQmlJSLogger *logger, QmlIR::Document *doc,
- const Qmltc::TypeResolver *localResolver)
- : m_url(url),
- m_logger(logger),
- m_doc(doc),
- m_localTypeResolver(localResolver),
- m_qmlSource(doc->code.split(QLatin1String(newLineLatin1)))
+ const QmltcTypeResolver *localResolver, const QmltcCompilerInfo *info)
+ : m_url(url), m_logger(logger), m_doc(doc), m_localTypeResolver(localResolver), m_info(info)
{
+ Q_ASSERT(m_info);
+ Q_ASSERT(!m_info->outputHFile.isEmpty());
+ Q_ASSERT(!m_info->outputCppFile.isEmpty());
}
void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
@@ -291,21 +286,18 @@ void CodeGenerator::constructObjects(QSet<QString> &requiredCppIncludes)
m_ignoredTypes = collectIgnoredTypes(context, objects);
};
executor.addPass(setIgnoredTypes);
+ executor.addPass(&setDeferredBindings);
// run all passes:
executor.run(m_logger);
}
-void CodeGenerator::generate(const Options &options)
+void CodeGenerator::generate()
{
- m_options = options;
- GeneratedCode code;
const QString rootClassName = QFileInfo(m_url).baseName();
Q_ASSERT(!rootClassName.isEmpty());
- Q_ASSERT(!options.outputHFile.isEmpty());
- Q_ASSERT(!options.outputCppFile.isEmpty());
- const QString hPath = options.outputHFile;
- const QString cppPath = options.outputCppFile;
+ const QString hPath = m_info->outputHFile;
+ const QString cppPath = m_info->outputCppFile;
m_isAnonymous = rootClassName.at(0).isLower();
const QString url = QFileInfo(m_url).fileName();
@@ -315,7 +307,7 @@ void CodeGenerator::generate(const Options &options)
QSet<QString> requiredCppIncludes;
constructObjects(requiredCppIncludes); // this populates all the codegen objects
// no point in compiling anything if there are errors
- if (m_logger->hasErrors() || m_logger->hasWarnings())
+ if (m_logger->hasErrors())
return;
if (m_objects.isEmpty()) {
@@ -329,16 +321,16 @@ void CodeGenerator::generate(const Options &options)
};
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);
};
@@ -362,18 +354,21 @@ void CodeGenerator::generate(const Options &options)
}
}
// no point in generating anything if there are errors
- if (m_logger->hasErrors() || m_logger->hasWarnings())
+ if (m_logger->hasErrors())
return;
- QQmlJSProgram program { compiledObjects, m_urlMethod, url, hPath, cppPath,
- options.outNamespace, 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,
@@ -388,9 +383,14 @@ 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);
+ return;
+ }
+
compiled.cppType = object.type->internalName();
const QString baseClass = object.type->baseType()->internalName();
@@ -428,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 };
@@ -645,6 +645,17 @@ void CodeGenerator::compileObject(
+ u"(engine, /* finalize */ false);";
compiled.endInit.body << u"}"_qs;
}
+
+ if (object.irObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
+ compiled.endInit.body << u"{ // defer bindings"_qs;
+ compiled.endInit.body << u"auto ddata = QQmlData::get(this);"_qs;
+ compiled.endInit.body << u"auto thisContext = ddata->outerContext;"_qs;
+ compiled.endInit.body << u"Q_ASSERT(thisContext);"_qs;
+ compiled.endInit.body << u"ddata->deferData(" + QString::number(objectIndex) + u", "
+ + CodeGeneratorUtility::compilationUnitVariable.name + u", thisContext);";
+ compiled.endInit.body << u"}"_qs;
+ }
+
// TODO: decide whether begin/end property update group is needed
// compiled.endInit.body << u"Qt::beginPropertyUpdateGroup(); // defer binding evaluation"_qs;
@@ -682,20 +693,8 @@ 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)
{
- if (object.type->isSingleton()) {
- if (m_isAnonymous) {
- recordError(object.type->sourceLocation(),
- QStringLiteral(u"This singleton type won't be accessible from the outside. "
- "Consider changing the file name so that it starts with a "
- "capital letter."));
- return;
- }
- compiled.mocCode << u"QML_SINGLETON"_qs;
- compiled.externalCtor.access = QQmlJSMetaMethod::Private;
- }
-
// compile enums
const auto enums = object.type->ownEnumerations();
compiled.enums.reserve(enums.size());
@@ -787,15 +786,9 @@ 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)
{
- if (object.type->isSingleton()) {
- // it is unclear what to do with singletons in general, so just reject
- recordError(object.type->sourceLocation(),
- QStringLiteral(u"Singleton Component-based types are not supported"));
- return;
- }
+ Q_UNUSED(object);
// since we create a document root as QQmlComponent, we only need to fake
// QQmlComponent construction in init:
@@ -827,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;
@@ -840,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
@@ -872,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"_);";
@@ -885,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();";
@@ -895,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
@@ -923,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();
@@ -1047,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;
@@ -1059,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 {
@@ -1079,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 {
@@ -1093,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;
@@ -1129,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);
@@ -1138,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());
@@ -1153,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);
@@ -1161,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();
@@ -1176,10 +1169,33 @@ 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)
{
+ // Note: unlike QQmlObjectCreator, we don't have to do a complicated
+ // deferral logic for bindings: if a binding is deferred, it is not compiled
+ // (potentially, with all the bindings inside of it), period.
+ if (binding.flags & QV4::CompiledData::Binding::IsDeferredBinding) {
+ if (binding.type == QmlIR::Binding::Type_GroupProperty) {
+ // TODO: we should warn about this in QmlCompiler library
+ qCWarning(lcCodeGenerator)
+ << QStringLiteral("Binding at line %1 column %2 is not deferred as it is a "
+ "binding on a group property.")
+ .arg(QString::number(binding.location.line),
+ QString::number(binding.location.column));
+ // we do not support PropertyChanges and other types with similar
+ // behavior yet, so this binding is compiled
+ } else {
+ qCDebug(lcCodeGenerator)
+ << QStringLiteral(
+ "Binding at line %1 column %2 is deferred and thus not compiled")
+ .arg(QString::number(binding.location.line),
+ QString::number(binding.location.column));
+ return;
+ }
+ }
+
// TODO: cache property name somehow, so we don't need to look it up again
QString propertyName = m_doc->stringAt(binding.propertyNameIndex);
if (propertyName.isEmpty()) {
@@ -1401,6 +1417,9 @@ void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Bindin
std::for_each(irObject->bindingsBegin(), irObject->bindingsEnd(), compileComponent);
} else {
const QString attachingTypeName = propertyName; // acts as an identifier
+ auto attachingType = m_localTypeResolver->typeForName(attachingTypeName);
+ Q_ASSERT(attachingType); // an error somewhere else
+
QString attachedTypeName = type->attachedTypeName(); // TODO: check if == internalName?
if (attachedTypeName.isEmpty()) // TODO: shouldn't happen ideally
attachedTypeName = type->baseTypeName();
@@ -1413,7 +1432,7 @@ void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Bindin
u"nullptr"_qs);
// Note: getting attached property is fairly expensive
const QString getAttachedPropertyLine = u"qobject_cast<" + attachedTypeName
- + u" *>(qmlAttachedPropertiesObject<" + attachedTypeName
+ + u" *>(qmlAttachedPropertiesObject<" + attachingType->internalName()
+ u">(this, /* create = */ true))";
current.endInit.body
<< attachedMemberName + u" = " + getAttachedPropertyLine + u";";
@@ -1422,9 +1441,10 @@ void CodeGenerator::compileBinding(QQmlJSAotObject &current, const QmlIR::Bindin
// compile bindings of the attached property
auto sortedBindings = toOrderedSequence(
irObject->bindingsBegin(), irObject->bindingsEnd(), irObject->bindingCount());
- for (auto it : qAsConst(sortedBindings))
+ for (auto it : qAsConst(sortedBindings)) {
compileBinding(current, *it, attachedObject,
{ object.type, attachedMemberName, propertyName, false });
+ }
}
break;
}
@@ -1559,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;
@@ -1608,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,
@@ -1647,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;
@@ -1734,15 +1754,8 @@ void CodeGenerator::compileScriptBinding(QQmlJSAotObject &current, const QmlIR::
Q_ASSERT(!objectClassName_slot.isEmpty());
const QString slotName = makeGensym(signalName + u"_slot");
- if (objectType->isSingleton()) { // TODO: support
- recordError(binding.location,
- u"Binding on singleton type '" + objectClassName_signal
- + u"' is not supported");
- return;
- }
-
// SignalHander specific:
- QQmlJSAotMethod slotMethod {};
+ QmltcMethod slotMethod {};
slotMethod.returnType = signalReturnType;
slotMethod.name = slotName;
slotMethod.parameterList = slotParameters;
@@ -1819,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;
}
@@ -1827,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,
@@ -1867,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;
@@ -1885,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"();";
@@ -1898,18 +1912,20 @@ void CodeGenerator::compileUrlMethod()
m_urlMethod.returnType = u"const QUrl &"_qs;
m_urlMethod.name = u"q_qmltc_docUrl"_qs;
m_urlMethod.body << u"static QUrl docUrl = %1;"_qs.arg(
- CodeGeneratorUtility::toResourcePath(m_options.resourcePath));
+ 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;
}
void CodeGenerator::recordError(const QQmlJS::SourceLocation &location, const QString &message)
{
- m_logger->logCritical(message, Log_Compiler, location);
+ m_logger->log(message, Log_Compiler, location);
}
void CodeGenerator::recordError(const QV4::CompiledData::Location &location, const QString &message)
{
recordError(QQmlJS::SourceLocation { 0, 0, location.line, location.column }, message);
}
+
+QT_END_NAMESPACE
diff --git a/tools/qmltc/prototype/codegenerator.h b/tools/qmltc/prototype/codegenerator.h
index 63549ae76e..a18699d23c 100644
--- a/tools/qmltc/prototype/codegenerator.h
+++ b/tools/qmltc/prototype/codegenerator.h
@@ -29,9 +29,8 @@
#ifndef CODEGENERATOR_H
#define CODEGENERATOR_H
-#include "prototype/typeresolver.h"
-#include "prototype/qmlcompiler.h"
-#include "prototype/generatedcodeprimitives.h"
+#include "qmltctyperesolver.h"
+#include "qmltcoutputir.h"
#include "prototype/qml2cppcontext.h"
#include <QtCore/qlist.h>
@@ -40,19 +39,21 @@
#include <QtQml/private/qqmlirbuilder_p.h>
#include <private/qqmljscompiler_p.h>
-#include <private/qqmljstyperesolver_p.h>
#include <variant>
#include <utility>
+QT_BEGIN_NAMESPACE
+
+struct QmltcCompilerInfo;
class CodeGenerator
{
public:
CodeGenerator(const QString &url, QQmlJSLogger *logger, QmlIR::Document *doc,
- const Qmltc::TypeResolver *localResolver);
+ const QmltcTypeResolver *localResolver, const QmltcCompilerInfo *info);
// main function: given compilation options, generates C++ code (implicitly)
- void generate(const Options &options);
+ void generate();
// TODO: this should really be just QQmlJSScope::ConstPtr (and maybe C++
// class name), but bindings are currently not represented in QQmlJSScope,
@@ -63,10 +64,9 @@ private:
QString m_url; // document url
QQmlJSLogger *m_logger = nullptr;
QmlIR::Document *m_doc = nullptr;
- const Qmltc::TypeResolver *m_localTypeResolver = nullptr;
- QStringList m_qmlSource; // QML source code split to lines
+ const QmltcTypeResolver *m_localTypeResolver = nullptr;
- Options m_options = {}; // compilation options
+ const QmltcCompilerInfo *m_info = nullptr;
// convenient object abstraction, laid out as QmlIR::Document.objects
QList<CodeGenObject> m_objects;
@@ -79,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());
@@ -140,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,
@@ -166,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);
@@ -186,4 +185,6 @@ private:
void recordError(const QV4::CompiledData::Location &location, const QString &message);
};
+QT_END_NAMESPACE
+
#endif // CODEGENERATOR_H
diff --git a/tools/qmltc/prototype/codegeneratorutil.cpp b/tools/qmltc/prototype/codegeneratorutil.cpp
index 3d7300e0d8..878a1f4b07 100644
--- a/tools/qmltc/prototype/codegeneratorutil.cpp
+++ b/tools/qmltc/prototype/codegeneratorutil.cpp
@@ -33,13 +33,14 @@
#include <tuple>
+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()
};
@@ -141,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
@@ -163,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">>()";
@@ -212,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")";
}
@@ -245,3 +246,5 @@ QString CodeGeneratorUtility::generate_setIdValue(const QString &context, qsizet
return context + u"->setIdValue(" + QString::number(index) + idComment + u", " + accessor
+ u")";
}
+
+QT_END_NAMESPACE
diff --git a/tools/qmltc/prototype/codegeneratorutil.h b/tools/qmltc/prototype/codegeneratorutil.h
index d8b8defac8..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>
@@ -39,6 +39,8 @@
#include <utility>
+QT_BEGIN_NAMESPACE
+
struct CodeGeneratorUtility
{
// magic variable, necessary for correct handling of object bindings: since
@@ -51,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)
@@ -82,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);
@@ -96,4 +98,6 @@ struct CodeGeneratorUtility
const QString &accessor, const QString &idString);
};
+QT_END_NAMESPACE
+
#endif // CODEGENERATORUTIL_H
diff --git a/tools/qmltc/prototype/codegeneratorwriter.cpp b/tools/qmltc/prototype/codegeneratorwriter.cpp
deleted file mode 100644
index d43a94084e..0000000000
--- a/tools/qmltc/prototype/codegeneratorwriter.cpp
+++ /dev/null
@@ -1,476 +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>
-
-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);
-}
diff --git a/tools/qmltc/prototype/codegeneratorwriter.h b/tools/qmltc/prototype/codegeneratorwriter.h
deleted file mode 100644
index e03a2123ac..0000000000
--- a/tools/qmltc/prototype/codegeneratorwriter.h
+++ /dev/null
@@ -1,57 +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"
-
-// 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);
-};
-
-#endif // CODEGENERATORWRITER_H
diff --git a/tools/qmltc/prototype/generatedcodeprimitives.h b/tools/qmltc/prototype/generatedcodeprimitives.h
deleted file mode 100644
index 46d7b1461f..0000000000
--- a/tools/qmltc/prototype/generatedcodeprimitives.h
+++ /dev/null
@@ -1,126 +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>
-
-// 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;
- }
-};
-
-#endif // GENERATEDCODEPRIMITIVES_H
diff --git a/tools/qmltc/prototype/qml2cppcontext.h b/tools/qmltc/prototype/qml2cppcontext.h
index 56bb5a12db..3c17a632df 100644
--- a/tools/qmltc/prototype/qml2cppcontext.h
+++ b/tools/qmltc/prototype/qml2cppcontext.h
@@ -29,8 +29,7 @@
#ifndef QML2CPPCONTEXT_H
#define QML2CPPCONTEXT_H
-#include "prototype/qmlcompiler.h"
-#include "prototype/typeresolver.h"
+#include "qmltctyperesolver.h"
#include <private/qqmljsdiagnosticmessage_p.h>
#include <QtQml/private/qqmlirbuilder_p.h>
@@ -41,10 +40,12 @@
#include <variant>
#include <functional>
+QT_BEGIN_NAMESPACE
+
struct Qml2CppContext
{
const QmlIR::Document *document = nullptr;
- const Qmltc::TypeResolver *typeResolver = nullptr;
+ const QmltcTypeResolver *typeResolver = nullptr;
QString documentUrl;
QQmlJSLogger *logger = nullptr;
const QHash<QQmlJSScope::ConstPtr, qsizetype> *typeIndices = nullptr; // TODO: remove this?
@@ -52,7 +53,7 @@ struct Qml2CppContext
void recordError(const QQmlJS::SourceLocation &location, const QString &message) const
{
Q_ASSERT(logger);
- logger->logCritical(message, Log_Compiler, location);
+ logger->log(message, Log_Compiler, location);
}
void recordError(const QV4::CompiledData::Location &location, const QString &message) const
@@ -81,7 +82,7 @@ class Qml2CppCompilerPassExecutor
QList<Qml2CppCompilerPass> m_passes;
public:
- Qml2CppCompilerPassExecutor(const QmlIR::Document *doc, const Qmltc::TypeResolver *resolver,
+ Qml2CppCompilerPassExecutor(const QmlIR::Document *doc, const QmltcTypeResolver *resolver,
const QString &url, QList<Qml2CppObject> &objects,
const QHash<QQmlJSScope::ConstPtr, qsizetype> &typeIndices)
: m_context { doc, resolver, url, nullptr, &typeIndices }, m_objects { objects }
@@ -105,4 +106,6 @@ public:
}
};
+QT_END_NAMESPACE
+
#endif // QML2CPPCONTEXT_H
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
index 586cc85754..8372d397d0 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.cpp
@@ -35,6 +35,8 @@
#include <algorithm>
+QT_BEGIN_NAMESPACE
+
static QString const cppKeywords[] = {
u"alignas"_qs,
u"alignof"_qs,
@@ -534,7 +536,7 @@ static void setupQmlCppType(const Qml2CppContext &context, const QQmlJSScope::Pt
context.recordError(type->sourceLocation(), u"QML type has unknown file path"_qs);
return;
}
- if (!type->fileName().isEmpty()) // consider this one to be already set up
+ if (type->filePath().endsWith(u".h")) // consider this one to be already set up
return;
if (!filePath.endsWith(u".qml"_qs)) {
context.recordError(type->sourceLocation(),
@@ -545,7 +547,7 @@ static void setupQmlCppType(const Qml2CppContext &context, const QQmlJSScope::Pt
// TODO: this does not cover QT_QMLTC_FILE_BASENAME renaming
if (filePath != context.documentUrl) {
// this file name will be discovered during findCppIncludes
- type->setFileName(QFileInfo(filePath).baseName().toLower() + u".h"_qs);
+ type->setFilePath(QFileInfo(filePath).baseName().toLower() + u".h"_qs);
}
const auto properties = type->ownProperties();
@@ -786,7 +788,7 @@ static void addFirstCppIncludeFromType(QSet<QString> &cppIncludes,
auto t = QQmlJSScope::nonCompositeBaseType(type);
if (!t)
return;
- if (QString includeFile = t->fileName(); !includeFile.isEmpty())
+ if (QString includeFile = t->filePath(); includeFile.endsWith(u".h"))
cppIncludes.insert(includeFile);
}
@@ -816,7 +818,7 @@ static void populateCppIncludes(QSet<QString> &cppIncludes, const QQmlJSScope::C
for (auto t = type; t; t = t->baseType()) {
// NB: Composite types might have include files - this is custom qmltc
// logic for local imports
- if (QString includeFile = t->fileName(); !includeFile.isEmpty())
+ if (QString includeFile = t->filePath(); includeFile.endsWith(u".h"))
cppIncludes.insert(includeFile);
// look in property types
@@ -824,8 +826,10 @@ static void populateCppIncludes(QSet<QString> &cppIncludes, const QQmlJSScope::C
for (const QQmlJSMetaProperty &p : properties) {
addFirstCppIncludeFromType(cppIncludes, p.type());
- if (p.isPrivate()) {
- const QString ownersInclude = QQmlJSScope::nonCompositeBaseType(t)->fileName();
+ const auto baseType = QQmlJSScope::nonCompositeBaseType(t);
+
+ if (p.isPrivate() && baseType->filePath().endsWith(u".h")) {
+ const QString ownersInclude = baseType->filePath();
QString privateInclude = constructPrivateInclude(ownersInclude);
if (!privateInclude.isEmpty())
cppIncludes.insert(std::move(privateInclude));
@@ -1079,3 +1083,43 @@ QSet<QQmlJSScope::ConstPtr> collectIgnoredTypes(const Qml2CppContext &context,
return ignored;
}
+
+static void setDeferred(const Qml2CppContext &context, qsizetype objectIndex,
+ QList<Qml2CppObject> &objects)
+{
+ Q_UNUSED(objects);
+
+ Qml2CppObject &o = objects[objectIndex];
+
+ // c.f. QQmlDeferredAndCustomParserBindingScanner::scanObject()
+ if (o.irObject->flags & QV4::CompiledData::Object::IsComponent) {
+ // unlike QmlIR compiler, qmltc should not care about anything within a
+ // component (let the QQmlComponent wrapper - at runtime anyway - take
+ // care of this type instead)
+ return;
+ }
+
+ const auto setRecursive = [&](QmlIR::Binding &binding) {
+ if (binding.type >= QmlIR::Binding::Type_Object)
+ setDeferred(context, binding.value.objectIndex, objects); // Note: recursive call here!
+
+ const QString propName = findPropertyName(context, o.type, binding);
+ Q_ASSERT(!propName.isEmpty());
+
+ if (o.type->isNameDeferred(propName)) {
+ binding.flags |= QV4::CompiledData::Binding::IsDeferredBinding;
+ o.irObject->flags |= QV4::CompiledData::Object::HasDeferredBindings;
+ }
+ };
+
+ std::for_each(o.irObject->bindingsBegin(), o.irObject->bindingsEnd(), setRecursive);
+}
+
+void setDeferredBindings(const Qml2CppContext &context, QList<Qml2CppObject> &objects)
+{
+ // as we do not support InlineComponents just yet, we can shortcut the logic
+ // here to only work with root object
+ setDeferred(context, 0, objects);
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qmltc/prototype/qml2cppdefaultpasses.h b/tools/qmltc/prototype/qml2cppdefaultpasses.h
index 29e5acf985..6a1d0ca124 100644
--- a/tools/qmltc/prototype/qml2cppdefaultpasses.h
+++ b/tools/qmltc/prototype/qml2cppdefaultpasses.h
@@ -31,6 +31,8 @@
#include "prototype/qml2cppcontext.h"
+QT_BEGIN_NAMESPACE
+
// verifies that each object, property (and etc.) has valid
// QQmlJSScope::ConstPtr associated with it
void verifyTypes(const Qml2CppContext &context, QList<Qml2CppObject> &objects);
@@ -86,4 +88,8 @@ findImmediateParents(const Qml2CppContext &context, QList<Qml2CppObject> &object
QSet<QQmlJSScope::ConstPtr> collectIgnoredTypes(const Qml2CppContext &context,
QList<Qml2CppObject> &objects);
+void setDeferredBindings(const Qml2CppContext &context, QList<Qml2CppObject> &objects);
+
+QT_END_NAMESPACE
+
#endif // QML2CPPPASSES_H
diff --git a/tools/qmltc/prototype/qml2cpppropertyutils.h b/tools/qmltc/prototype/qml2cpppropertyutils.h
index 4b3e513b90..31f3f73297 100644
--- a/tools/qmltc/prototype/qml2cpppropertyutils.h
+++ b/tools/qmltc/prototype/qml2cpppropertyutils.h
@@ -31,6 +31,8 @@
#include <private/qqmljsmetatypes_p.h>
+QT_BEGIN_NAMESPACE
+
inline QString getUnderlyingType(const QQmlJSMetaProperty &p)
{
QString underlyingType = p.type()->internalName();
@@ -64,4 +66,6 @@ struct Qml2CppPropertyData
QString notify;
};
+QT_END_NAMESPACE
+
#endif // QML2CPPPROPERTYUTILS_H
diff --git a/tools/qmltc/prototype/qmlcompiler.h b/tools/qmltc/prototype/qmlcompiler.h
deleted file mode 100644
index 3c770612cc..0000000000
--- a/tools/qmltc/prototype/qmlcompiler.h
+++ /dev/null
@@ -1,179 +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>
-
-struct Options
-{
- QString outputCppFile;
- QString outputHFile;
- QString moduleUri;
- QString resourcePath;
- QString outNamespace;
- bool debugGenerateLineDirective = false;
-};
-
-// 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;
-};
-
-#endif // QMLCOMPILER_H
diff --git a/tools/qmltc/prototype/typeresolver.h b/tools/qmltc/prototype/typeresolver.h
deleted file mode 100644
index a382c4c07a..0000000000
--- a/tools/qmltc/prototype/typeresolver.h
+++ /dev/null
@@ -1,64 +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 TYPERESOLVER_H
-#define TYPERESOLVER_H
-
-#include "prototype/visitor.h"
-
-#include <private/qqmljsscope_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmlirbuilder_p.h>
-#include <private/qqmljstyperesolver_p.h>
-
-namespace Qmltc {
-class TypeResolver : public QQmlJSTypeResolver
-{
-public:
- TypeResolver(QQmlJSImporter *importer);
-
- void init(Visitor &visitor, QQmlJS::AST::Node *program);
-
- // TODO: this shouldn't be exposed. instead, all the custom passes on
- // QQmlJSScope types must happen inside Visitor
- QQmlJSScope::Ptr root() const { return m_root; }
-
- QQmlJSScope::Ptr scopeForLocation(const QV4::CompiledData::Location &location) const;
-
- // returns an import pair {url, modifiable type} for a given \a type
- QPair<QString, QQmlJSScope::Ptr> importedType(const QQmlJSScope::ConstPtr &type) const;
-
-private:
- QQmlJSImporter *m_importer = nullptr;
-
- QHash<QV4::CompiledData::Location, QQmlJSScope::Ptr> m_objectsByLocationNonConst;
- QQmlJSScope::Ptr m_root;
-};
-}
-
-#endif // TYPERESOLVER_H
diff --git a/tools/qmltc/prototype/visitor.cpp b/tools/qmltc/prototype/visitor.cpp
deleted file mode 100644
index 307cb992ea..0000000000
--- a/tools/qmltc/prototype/visitor.cpp
+++ /dev/null
@@ -1,51 +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 "prototype/visitor.h"
-
-#include <QtCore/qdir.h>
-#include <QtCore/qfileinfo.h>
-
-namespace Qmltc {
-Visitor::Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger,
- const QString &implicitImportDirectory, const QStringList &qmltypesFiles)
- : QQmlJSImportVisitor(importer, logger, implicitImportDirectory, qmltypesFiles)
-{
-}
-
-bool Visitor::visit(QQmlJS::AST::UiInlineComponent *component)
-{
- if (!QQmlJSImportVisitor::visit(component))
- return false;
- m_logger->logCritical(u"Inline components are not supported"_qs, Log_Compiler,
- component->firstSourceLocation());
- // despite the failure, return true here so that we do not assert in
- // QQmlJSImportVisitor::endVisit(UiInlineComponent)
- return true;
-}
-}
diff --git a/tools/qmltc/prototype/visitor.h b/tools/qmltc/prototype/visitor.h
deleted file mode 100644
index 730021b66c..0000000000
--- a/tools/qmltc/prototype/visitor.h
+++ /dev/null
@@ -1,55 +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 VISITOR_H
-#define VISITOR_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 <private/qqmljsimportvisitor_p.h>
-
-namespace Qmltc {
-class Visitor : public QQmlJSImportVisitor
-{
-public:
- Visitor(QQmlJSImporter *importer, QQmlJSLogger *logger, const QString &implicitImportDirectory,
- const QStringList &qmltypesFiles = QStringList());
-
- bool visit(QQmlJS::AST::UiInlineComponent *) override;
-};
-}
-
-#endif // VISITOR_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 6510a6d51d..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
@@ -440,18 +442,18 @@ void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyB
switch (binding.bindingType()) {
case QQmlJSMetaPropertyBinding::BoolLiteral: {
- const bool value = binding.literalValue().toBool();
+ const bool value = binding.boolValue();
generator.generate_assignToProperty(current, type, p, value ? u"true"_qs : u"false"_qs,
accessor.name);
break;
}
case QQmlJSMetaPropertyBinding::NumberLiteral: {
- const QString value = QString::number(binding.literalValue().toDouble());
+ const QString value = QString::number(binding.numberValue());
generator.generate_assignToProperty(current, type, p, value, accessor.name);
break;
}
case QQmlJSMetaPropertyBinding::StringLiteral: {
- const QString value = binding.literalValue().toString();
+ const QString value = binding.stringValue();
generator.generate_assignToProperty(current, type, p, QQmlJSUtils::toLiteral(value),
accessor.name);
break;
@@ -486,8 +488,8 @@ void QmltcCompiler::compileBinding(QmltcType &current, const QQmlJSMetaPropertyB
break;
}
default: {
- m_logger->logWarning(u"Binding type is not supported (yet)"_qs, Log_Compiler,
- binding.sourceLocation());
+ m_logger->log(u"Binding type is not supported (yet)"_qs, Log_Compiler,
+ binding.sourceLocation());
break;
}
}
diff --git a/tools/qmltc/qmltccompiler.h b/tools/qmltc/qmltccompiler.h
index 0574b03088..589c70bafe 100644
--- a/tools/qmltc/qmltccompiler.h
+++ b/tools/qmltc/qmltccompiler.h
@@ -91,13 +91,13 @@ private:
void compileBinding(QmltcType &current, const QQmlJSMetaPropertyBinding &binding,
const QQmlJSScope::ConstPtr &type, const BindingAccessorData &accessor);
- bool hasErrors() const { return m_logger->hasErrors() || m_logger->hasWarnings(); }
+ bool hasErrors() const { return m_logger->hasErrors(); }
void recordError(const QQmlJS::SourceLocation &location, const QString &message,
QQmlJSLoggerCategory category = Log_Compiler)
{
// pretty much any compiler error is a critical error (we cannot
// generate code - compilation fails)
- m_logger->logCritical(message, category, location);
+ m_logger->log(message, category, location);
}
void recordError(const QV4::CompiledData::Location &location, const QString &message,
QQmlJSLoggerCategory category = Log_Compiler)
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++
diff --git a/tools/qmltc/prototype/typeresolver.cpp b/tools/qmltc/qmltctyperesolver.cpp
index 377787830e..2d46cf38b3 100644
--- a/tools/qmltc/prototype/typeresolver.cpp
+++ b/tools/qmltc/qmltctyperesolver.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
@@ -26,8 +26,7 @@
**
****************************************************************************/
-#include "prototype/typeresolver.h"
-#include "prototype/visitor.h"
+#include "qmltctyperesolver.h"
#include <private/qqmljsimporter_p.h>
#include <private/qv4value_p.h>
@@ -37,17 +36,9 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qdiriterator.h>
-Q_LOGGING_CATEGORY(lcTypeResolver2, "qml.compiler.typeresolver", QtInfoMsg);
+Q_LOGGING_CATEGORY(lcTypeResolver2, "qml.qmltc.typeresolver", QtInfoMsg);
-namespace Qmltc {
-
-TypeResolver::TypeResolver(QQmlJSImporter *importer)
- : QQmlJSTypeResolver(importer), m_importer(importer)
-{
- Q_ASSERT(m_importer);
-}
-
-void TypeResolver::init(Visitor &visitor, QQmlJS::AST::Node *program)
+void QmltcTypeResolver::init(QmltcVisitor &visitor, QQmlJS::AST::Node *program)
{
QQmlJSTypeResolver::init(&visitor, program);
m_root = visitor.result();
@@ -67,14 +58,16 @@ void TypeResolver::init(Visitor &visitor, QQmlJS::AST::Node *program)
}
}
-QQmlJSScope::Ptr TypeResolver::scopeForLocation(const QV4::CompiledData::Location &location) const
+QQmlJSScope::Ptr
+QmltcTypeResolver::scopeForLocation(const QV4::CompiledData::Location &location) const
{
qCDebug(lcTypeResolver2()).nospace()
<< "looking for object at " << location.line << ':' << location.column;
return m_objectsByLocationNonConst.value(location);
}
-QPair<QString, QQmlJSScope::Ptr> TypeResolver::importedType(const QQmlJSScope::ConstPtr &type) const
+QPair<QString, QQmlJSScope::Ptr>
+QmltcTypeResolver::importedType(const QQmlJSScope::ConstPtr &type) const
{
const auto files = m_importer->importedFiles();
auto it = std::find_if(files.cbegin(), files.cend(), [&](const QQmlJSScope::Ptr &importedType) {
@@ -84,4 +77,3 @@ QPair<QString, QQmlJSScope::Ptr> TypeResolver::importedType(const QQmlJSScope::C
return {};
return { it.key(), it.value() };
}
-}
diff --git a/tools/qmltc/qmltctyperesolver.h b/tools/qmltc/qmltctyperesolver.h
index 495f78b81d..ae9e98c23e 100644
--- a/tools/qmltc/qmltctyperesolver.h
+++ b/tools/qmltc/qmltctyperesolver.h
@@ -29,6 +29,8 @@
#ifndef QMLTCTYPERESOLVER_H
#define QMLTCTYPERESOLVER_H
+#include "qmltcvisitor.h"
+
#include <QtQml/private/qqmlirbuilder_p.h>
#include <private/qqmljstyperesolver_p.h>
#include <private/qqmljsimporter_p.h>
@@ -39,7 +41,27 @@ QT_BEGIN_NAMESPACE
class QmltcTypeResolver : public QQmlJSTypeResolver
{
public:
- QmltcTypeResolver(QQmlJSImporter *importer) : QQmlJSTypeResolver(importer) {}
+ QmltcTypeResolver(QQmlJSImporter *importer) : QQmlJSTypeResolver(importer), m_importer(importer)
+ {
+ Q_ASSERT(importer);
+ }
+
+ void init(QmltcVisitor &visitor, QQmlJS::AST::Node *program);
+
+ // TODO: this shouldn't be exposed. instead, all the custom passes on
+ // QQmlJSScope types must happen inside Visitor
+ QQmlJSScope::Ptr root() const { return m_root; }
+
+ QQmlJSScope::Ptr scopeForLocation(const QV4::CompiledData::Location &location) const;
+
+ // returns an import pair {url, modifiable type} for a given \a type
+ QPair<QString, QQmlJSScope::Ptr> importedType(const QQmlJSScope::ConstPtr &type) const;
+
+private:
+ QQmlJSImporter *m_importer = nullptr;
+
+ QHash<QV4::CompiledData::Location, QQmlJSScope::Ptr> m_objectsByLocationNonConst;
+ QQmlJSScope::Ptr m_root;
};
QT_END_NAMESPACE
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 691496d7c7..b70e3fe329 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -71,8 +71,8 @@ void QmltcVisitor::findCppIncludes()
if (t != type && visitType(t))
return;
- QString includeFile = t->fileName();
- if (!includeFile.isEmpty())
+ QString includeFile = t->filePath();
+ if (includeFile.endsWith(u".h"))
m_cppIncludes.insert(std::move(includeFile));
};
@@ -97,7 +97,7 @@ void QmltcVisitor::findCppIncludes()
if (visitType(t))
break;
// look in type
- if (auto includeFile = t->fileName(); !includeFile.isEmpty())
+ if (auto includeFile = t->filePath(); includeFile.endsWith(u".h"))
m_cppIncludes.insert(std::move(includeFile));
// look in properties
@@ -105,8 +105,8 @@ void QmltcVisitor::findCppIncludes()
for (const QQmlJSMetaProperty &p : properties) {
populateFromType(p.type());
- if (p.isPrivate()) {
- const QString ownersInclude = t->fileName();
+ if (p.isPrivate() && t->filePath().endsWith(u".h")) {
+ const QString ownersInclude = t->filePath();
QString privateInclude = constructPrivateInclude(ownersInclude);
if (!privateInclude.isEmpty())
m_cppIncludes.insert(std::move(privateInclude));
@@ -187,37 +187,45 @@ bool QmltcVisitor::visit(QQmlJS::AST::UiPublicMember *publicMember)
// augment property: set its write/read/etc. methods
if (publicMember->type == QQmlJS::AST::UiPublicMember::Property) {
const auto name = publicMember->name.toString();
- QQmlJSMetaProperty prop = m_currentScope->ownProperty(name);
- const QString nameWithUppercase = name[0].toUpper() + name.sliced(1);
- prop.setRead(name);
- if (prop.isWritable())
- prop.setWrite(u"set" + nameWithUppercase);
- prop.setBindable(u"bindable" + nameWithUppercase);
- prop.setNotify(name + u"Changed");
+
+ // TODO: we should set the composite type property methods here, but as
+ // of now this is done in the pass over the types after the ast
+ // traversal
+
+ const QString notifyName = name + u"Changed"_qs;
// also check that notify is already a method of m_currentScope
{
- const auto methods = m_currentScope->ownMethods(prop.notify());
+ const auto methods = m_currentScope->ownMethods(notifyName);
if (methods.size() != 1) {
const QString errorString =
methods.isEmpty() ? u"no signal"_qs : u"too many signals"_qs;
- m_logger->logCritical(
+ m_logger->log(
u"internal error: %1 found for property '%2'"_qs.arg(errorString, name),
Log_Compiler, publicMember->identifierToken);
return false;
} else if (methods[0].methodType() != QQmlJSMetaMethod::Signal) {
- m_logger->logCritical(
- u"internal error: method %1 of property %2 must be a signal"_qs.arg(
- prop.notify(), name),
- Log_Compiler, publicMember->identifierToken);
+ m_logger->log(u"internal error: method %1 of property %2 must be a signal"_qs.arg(
+ notifyName, name),
+ Log_Compiler, publicMember->identifierToken);
return false;
}
}
- m_currentScope->addOwnProperty(prop);
}
return true;
}
+bool QmltcVisitor::visit(QQmlJS::AST::UiInlineComponent *component)
+{
+ if (!QQmlJSImportVisitor::visit(component))
+ return false;
+ m_logger->log(u"Inline components are not supported"_qs, Log_Compiler,
+ component->firstSourceLocation());
+ // despite the failure, return true here so that we do not assert in
+ // QQmlJSImportVisitor::endVisit(UiInlineComponent)
+ return true;
+}
+
void QmltcVisitor::endVisit(QQmlJS::AST::UiProgram *program)
{
QQmlJSImportVisitor::endVisit(program);
diff --git a/tools/qmltc/qmltcvisitor.h b/tools/qmltc/qmltcvisitor.h
index d69c84d3ca..a543a4271c 100644
--- a/tools/qmltc/qmltcvisitor.h
+++ b/tools/qmltc/qmltcvisitor.h
@@ -56,10 +56,10 @@ public:
bool visit(QQmlJS::AST::UiPublicMember *) override;
+ bool visit(QQmlJS::AST::UiInlineComponent *) override;
+
void endVisit(QQmlJS::AST::UiProgram *) override;
- // NB: overwrite result() method to return ConstPtr
- QQmlJSScope::ConstPtr result() const { return QQmlJSImportVisitor::result(); }
QList<QQmlJSScope::ConstPtr> qmlScopesWithQmlBases() const { return m_qmlTypesWithQmlBases; }
QSet<QString> cppIncludeFiles() const { return m_cppIncludes; }