6#include <private/qqmlirbuilder_p.h>
7#include <private/qqmljsbasicblocks_p.h>
8#include <private/qqmljscodegenerator_p.h>
9#include <private/qqmljsfunctioninitializer_p.h>
10#include <private/qqmljsimportvisitor_p.h>
11#include <private/qqmljslexer_p.h>
12#include <private/qqmljsloadergenerator_p.h>
13#include <private/qqmljsoptimizations_p.h>
14#include <private/qqmljsparser_p.h>
15#include <private/qqmljsshadowcheck_p.h>
16#include <private/qqmljsstoragegeneralizer_p.h>
17#include <private/qqmljstypepropagator_p.h>
19#include <QtCore/qfile.h>
20#include <QtCore/qfileinfo.h>
21#include <QtCore/qloggingcategory.h>
23#include <QtQml/private/qqmlsignalnames_p.h>
37 QSet<QString> illegalNames;
62 if (
m.loc.startColumn > 0)
82 const QList<QQmlJS::DiagnosticMessage> &diagnostics)
94 const QString uri = document->stringAt(import->uriIndex);
99 const QString qualifier = document->stringAt(import->qualifierIndex);
102 listElementName.prepend(qualifier);
104 listElementNames.append(listElementName);
107 if (listElementNames.isEmpty())
110 for (
QmlIR::Object *
object : std::as_const(document->objects)) {
111 if (!listElementNames.contains(document->stringAt(
object->inheritedTypeNameIndex)))
116 binding->stringIndex = document->registerString(
object->bindingAsString(document, binding->value.compiledScriptIndex));
125 for (
auto binding =
object->bindingsBegin(); binding !=
object->bindingsEnd(); ++binding) {
131 auto compiledFunction = doc.
jsModule.
functions.value(
object->runtimeFunctionIndices.at(binding->value.compiledScriptIndex));
132 if (!compiledFunction)
136 if (compiledFunction->column > 0)
139 error->message +=
QLatin1String(
" error: The use of eval() or the use of the arguments object in signal handlers is\n"
140 "not supported when compiling qml files ahead of time. That is because it's ambiguous if \n"
141 "any signal parameter is called \"arguments\". Similarly the string passed to eval might use\n"
142 "\"arguments\". Unfortunately we cannot distinguish between it being a parameter or the\n"
143 "JavaScript arguments object at this point.\n"
144 "Consider renaming the parameter of the signal if applicable or moving the code into a\n"
170 ? m_binding->
value.compiledScriptIndex
173 : std::numeric_limits<quint32>::max());
188 storeSourceLocation,
interface, fileContents);
198 if (fileContents !=
nullptr) {
199 sourceCode = *fileContents;
215 if (!irBuilder.generateFromQml(sourceCode, inputFileName, &irDocument)) {
216 error->appendDiagnostics(inputFileName, irBuilder.errors);
228 aotCompiler->setDocument(&v4CodeGen, &irDocument);
230 QHash<QmlIR::Object *, QmlIR::Object *> effectiveScopes;
231 for (
QmlIR::Object *
object: std::as_const(irDocument.objects)) {
232 if (
object->functionsAndExpressions->count == 0 &&
object->bindingCount() == 0)
235 if (!v4CodeGen.generateRuntimeFunctions(
object)) {
237 error->appendDiagnostic(inputFileName, v4CodeGen.error());
245 for (
auto it = effectiveScopes.
constFind(scope),
end = effectiveScopes.constEnd();
250 aotCompiler->setScope(
object, scope);
253 std::vector<BindingOrFunction> bindingsAndFunctions;
254 bindingsAndFunctions.
reserve(
object->bindingCount() +
object->functionCount());
256 std::copy(
object->bindingsBegin(),
object->bindingsEnd(),
257 std::back_inserter(bindingsAndFunctions));
258 std::copy(
object->functionsBegin(),
object->functionsEnd(),
259 std::back_inserter(bindingsAndFunctions));
261 QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
263 foe; foe = foe->next) {
264 functionsToCompile << *foe;
269 auto contextMap = v4CodeGen.module()->contextMap;
270 std::sort(bindingsAndFunctions.begin(), bindingsAndFunctions.end());
271 std::for_each(bindingsAndFunctions.begin(), bindingsAndFunctions.end(),
273 std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> result;
274 if (const auto *binding = bindingOrFunction.binding()) {
275 switch (binding->type()) {
276 case QmlIR::Binding::Type_AttachedProperty:
277 case QmlIR::Binding::Type_GroupProperty:
278 effectiveScopes.insert(
279 irDocument.objects.at(binding->value.objectIndex), scope);
281 case QmlIR::Binding::Type_Boolean:
282 case QmlIR::Binding::Type_Number:
283 case QmlIR::Binding::Type_String:
284 case QmlIR::Binding::Type_Null:
285 case QmlIR::Binding::Type_Object:
286 case QmlIR::Binding::Type_Translation:
287 case QmlIR::Binding::Type_TranslationById:
293 Q_ASSERT(quint32(functionsToCompile.size()) > binding->value.compiledScriptIndex);
294 const auto &functionToCompile
295 = functionsToCompile[binding->value.compiledScriptIndex];
296 auto *parentNode = functionToCompile.parentNode;
297 Q_ASSERT(parentNode);
298 Q_ASSERT(contextMap.contains(parentNode));
299 QV4::Compiler::Context *context = contextMap.take(parentNode);
302 auto *node = functionToCompile.node;
305 if (context->returnsClosure) {
306 QQmlJS::AST::Node *inner
307 = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(
310 QV4::Compiler::Context *innerContext = contextMap.take(inner);
311 Q_ASSERT(innerContext);
312 qCDebug(lcAotCompiler) <<
"Compiling signal handler for"
313 << irDocument.stringAt(binding->propertyNameIndex);
314 std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> innerResult
315 = aotCompiler->compileBinding(innerContext, *binding, inner);
317 if (auto *error = std::get_if<QQmlJS::DiagnosticMessage>(&innerResult)) {
318 qCDebug(lcAotCompiler) <<
"Compilation failed:"
319 << diagnosticErrorMessage(inputFileName, *error);
320 } else if (auto *func = std::get_if<QQmlJSAotFunction>(&innerResult)) {
321 qCDebug(lcAotCompiler) <<
"Generated code:" << func->code;
322 aotFunctionsByIndex[innerContext->functionIndex] = *func;
326 qCDebug(lcAotCompiler) <<
"Compiling binding for property"
327 << irDocument.stringAt(binding->propertyNameIndex);
328 result = aotCompiler->compileBinding(context, *binding, node);
329 }
else if (
const auto *function = bindingOrFunction.function()) {
330 Q_ASSERT(quint32(functionsToCompile.size()) > function->index);
331 auto *node = functionsToCompile[function->index].node;
333 Q_ASSERT(contextMap.contains(node));
334 QV4::Compiler::Context *context = contextMap.take(node);
337 const QString functionName = irDocument.stringAt(function->nameIndex);
338 qCDebug(lcAotCompiler) <<
"Compiling function" << functionName;
339 result = aotCompiler->compileFunction(context, functionName, node);
344 if (
auto *
error = std::get_if<QQmlJS::DiagnosticMessage>(&
result)) {
345 qCDebug(lcAotCompiler) <<
"Compilation failed:"
347 }
else if (
auto *
func = std::get_if<QQmlJSAotFunction>(&
result)) {
348 qCDebug(lcAotCompiler) <<
"Generated code:" <<
func->code;
349 aotFunctionsByIndex[
object->runtimeFunctionIndices[bindingOrFunction.index()]] =
361 irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(
false);
368 irDocument.javaScriptCompilationUnit->unitData(), saveFlags);
369 if (!saveFunction(saveable, aotFunctionsByIndex, &
error->message))
377 QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit;
395 QList<QQmlJS::DiagnosticMessage> diagnostics;
400 error->appendDiagnostics(inputFileName, diagnostics);
401 if (!unit || !unit->unitData())
409 engine->setDirectives(&directivesCollector);
411 engine->setDirectives(oldDirs);
418 lexer.
setCode(sourceCode, 1,
false);
419 QQmlJS::Parser parser(
engine);
421 bool parsed = parser.parseProgram();
423 error->appendDiagnostics(inputFileName, parser.diagnosticMessages());
428 program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
431 parsed = parser.parseProgram();
433 program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
440 v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode,
program,
442 if (v4CodeGen.hasError()) {
443 error->appendDiagnostic(inputFileName, v4CodeGen.error());
448 irDocument.jsModule.fileName.clear();
449 irDocument.jsModule.finalUrl.clear();
451 irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(
false);
454 unit = std::move(irDocument.javaScriptCompilationUnit);
464 [](const QQmlPrivate::AOTCompiledContext *aotContext, void **argv) {
471#if QT_CONFIG(temporaryfile)
472 QSaveFile
f(outputFileName);
477 *errorString =
f.errorString();
483 *errorString =
f.errorString();
498 if (!
writeStr(
"#include <QtQml/qqmlprivate.h>\n"))
501 if (!aotFunctions.isEmpty()) {
504 for (
const auto &function : aotFunctions)
505 includes.append(function.includes);
507 std::sort(includes.begin(), includes.end());
508 const auto end = std::unique(includes.begin(), includes.end());
509 for (
auto it = includes.begin();
it !=
end; ++
it) {
522 "extern const unsigned char qmlData alignas(16) [] = {\n")))
556 if (!
writeStr(
"QT_WARNING_PUSH\nQT_WARNING_DISABLE_MSVC(4573)\n"))
560 if (aotFunctions.size() <= 1) {
562 writeStr(
"extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
563 "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, 0, nullptr, nullptr } };\n");
565 writeStr(
"extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
566 "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {\n");
571 end = aotFunctions.constEnd();
580 "QMetaType *argTypes) {\n%3}, %4 },")
582 .arg(
func->numArguments)
583 .arg(
func->signature, function)
584 .toUtf8().constData());
588 writeStr(
"{ 0, 0, nullptr, nullptr }");
598#if QT_CONFIG(temporaryfile)
600 *errorString =
f.errorString();
611 : m_typeResolver(importer)
612 , m_resourcePath(resourcePath)
613 , m_qmldirFiles(qmldirFiles)
614 , m_importer(importer)
630 resourcePathInfo.canonicalPath() + u
'/',
656 qFatal(
"%s:%d: (strict mode) %s",
684 if (
error.isValid()) {
694 qCDebug(lcAotCompiler()) <<
"includes:" << aotFunction.includes;
695 qCDebug(lcAotCompiler()) <<
"binding code:" << aotFunction.code;
711 qCDebug(lcAotCompiler()) <<
"includes:" << aotFunction.includes;
712 qCDebug(lcAotCompiler()) <<
"binding code:" << aotFunction.code;
720 u
"QtQml/qjsengine.h"_s,
721 u
"QtQml/qjsprimitivevalue.h"_s,
722 u
"QtQml/qjsvalue.h"_s,
723 u
"QtQml/qqmlcomponent.h"_s,
724 u
"QtQml/qqmlcontext.h"_s,
725 u
"QtQml/qqmlengine.h"_s,
726 u
"QtQml/qqmllist.h"_s,
728 u
"QtCore/qdatetime.h"_s,
729 u
"QtCore/qtimezone.h"_s,
730 u
"QtCore/qobject.h"_s,
731 u
"QtCore/qstring.h"_s,
732 u
"QtCore/qstringlist.h"_s,
734 u
"QtCore/qvariant.h"_s,
745 const auto compileError = [&]() {
751 if (
error->isValid())
752 return compileError();
754 bool basicBlocksValidationFailed =
false;
756 auto passResult = basicBlocks.run(function,
m_flags, basicBlocksValidationFailed);
757 auto &[blocks, annotations] = passResult;
760 passResult = propagator.run(function,
error);
761 if (
error->isValid())
762 return compileError();
765 passResult = shadowCheck.run(function,
error);
766 if (
error->isValid())
767 return compileError();
770 basicBlocks.objectAndArrayDefinitions());
771 passResult = optimizer.run(function,
error);
772 if (
error->isValid())
773 return compileError();
777 passResult = generalizer.run(function,
error);
778 if (
error->isValid())
779 return compileError();
const QmlIR::Function * function() const
const QmlIR::Binding * binding() const
friend bool operator<(const BindingOrFunction &lhs, const BindingOrFunction &rhs)
BindingOrFunction(const QmlIR::Function &f)
BindingOrFunction(const QmlIR::Binding &b)
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
\inmodule QtCore\reentrant
const QV4::Compiler::JSUnitGenerator * m_unitGenerator
virtual void setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document)
virtual QQmlJSAotFunction globalCode() const
QQmlJSTypeResolver m_typeResolver
QQmlJSAotCompiler(QQmlJSImporter *importer, const QString &resourcePath, const QStringList &qmldirFiles, QQmlJSLogger *logger)
const QString m_resourcePath
const QStringList m_qmldirFiles
virtual QQmlJS::DiagnosticMessage diagnose(const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location) const
const QmlIR::Document * m_document
virtual void setScope(const QmlIR::Object *object, const QmlIR::Object *scope)
QQmlJSImporter * m_importer
virtual std::variant< QQmlJSAotFunction, QQmlJS::DiagnosticMessage > compileFunction(const QV4::Compiler::Context *context, const QString &name, QQmlJS::AST::Node *astNode)
const QmlIR::Object * m_currentScope
const QmlIR::Object * m_currentObject
virtual std::variant< QQmlJSAotFunction, QQmlJS::DiagnosticMessage > compileBinding(const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode)
QQmlJSCompilePass::Function run(const QV4::Compiler::Context *context, const QString &propertyName, QQmlJS::AST::Node *astNode, const QmlIR::Binding &irBinding, QQmlJS::DiagnosticMessage *error)
void setCode(const QString &code)
void setFileName(const QString &fileName)
bool isCategoryFatal(QQmlJS::LoggerWarningId id) const
void log(const QString &message, QQmlJS::LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation, bool showContext=true, bool showFileName=true, const std::optional< QQmlJSFixSuggestion > &suggestion={}, const QString overrideFileName=QString())
static QQmlJSScope::Ptr create()
void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program)
void setCode(const QString &code, int lineno, bool qmlMode=true, CodeContinuation codeContinuation=CodeContinuation::Reset)
static bool isHandlerName(QStringView signalName)
quint32 generate()
Generates a 32-bit random quantity and returns it.
const_iterator constFind(const T &value) const
void reserve(qsizetype size)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
bool saveToDisk(const std::function< bool(const Char *, quint32)> &writer) const
static const char * s_globalNames[]
static QQmlRefPointer< QV4::CompiledData::CompilationUnit > compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList< QQmlJS::DiagnosticMessage > *diagnostics)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define QByteArrayLiteral(str)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char * interface
DBusConnection const char DBusError * error
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * message
static void writeStr(uchar **p, const QByteArray &str)
static const int FileScopeCodeIndex
static bool isStrict(const QmlIR::Document *doc)
static const char * funcHeaderCode
static QSet< QString > getIllegalNames()
static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc, QQmlJSCompileError *error)
static void annotateListElements(QmlIR::Document *document)
bool qCompileQmlFile(const QString &inputFileName, QQmlJSSaveFunction saveFunction, QQmlJSAotCompiler *aotCompiler, QQmlJSCompileError *error, bool storeSourceLocation, QV4::Compiler::CodegenWarningInterface *interface, const QString *fileContents)
static QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::DiagnosticMessage &m)
bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFileName, const QV4::CompiledData::SaveableUnitPointer &unit, const QQmlJSAotFunctionMap &aotFunctions, QString *errorString)
bool qCompileJSFile(const QString &inputFileName, const QString &inputFileUrl, QQmlJSSaveFunction saveFunction, QQmlJSCompileError *error)
std::function< bool(const QV4::CompiledData::SaveableUnitPointer &, const QQmlJSAotFunctionMap &, QString *)> QQmlJSSaveFunction
QString qQmlJSSymbolNamespaceForPath(const QString &relativePath)
const QQmlSA::LoggerWarningId qmlCompiler
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
#define qPrintable(string)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
if(qFloatDistance(a, b)<(1<< 7))
[0]
QRandomGenerator generator(sseq)
QUrl url("example.com")
[constructor-url-reference]
\inmodule QtCore \reentrant
QQmlJSCompileError augment(const QString &contextErrorMessage) const
void appendDiagnostic(const QString &inputFileName, const QQmlJS::DiagnosticMessage &diagnostic)
void appendDiagnostics(const QString &inputFileName, const QList< QQmlJS::DiagnosticMessage > &diagnostics)
union QV4::CompiledData::Binding::@540 value
QList< Context * > functions
QVector< Object * > objects
QString stringAt(int index) const
QV4::Compiler::Module jsModule
QList< Pragma * > pragmas
QV4::CompiledData::Location location