diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-11-15 17:48:36 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-11-17 18:04:41 +0100 |
commit | 0c553510e08d57975c91966c42a991ae43ab2e63 (patch) | |
tree | 9682f4f34555227325c373b5e6e28104126e1c96 /tools | |
parent | d44dc4a25bf89931e6fd09433a9ad9ab4ae9dd7d (diff) |
QmlCompiler: Introduce compile passes
Concentrate code likely to be used by more than one pass in a base
class, and adapt the existing users. Also, stub out all the byte code
visitors so that we can easily implement passes that only target part of
the byte code.
Task-number: QTBUG-98305
Change-Id: Ib1e16daf678bf478d9d2d11b3604ded3749f2096
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/qmllint/codegen.cpp | 99 | ||||
-rw-r--r-- | tools/qmllint/codegen.h | 24 |
2 files changed, 50 insertions, 73 deletions
diff --git a/tools/qmllint/codegen.cpp b/tools/qmllint/codegen.cpp index 4b9137316b..849953f613 100644 --- a/tools/qmllint/codegen.cpp +++ b/tools/qmllint/codegen.cpp @@ -125,7 +125,6 @@ Codegen::compileBinding(const QV4::Compiler::Context *context, const QmlIR::Bind } Function function; - function.contextType = QV4::Compiler::ContextType::Binding; function.qmlScope = m_scopeType; const QString propertyName = m_document->stringAt(irBinding.propertyNameIndex); @@ -183,8 +182,8 @@ Codegen::compileBinding(const QV4::Compiler::Context *context, const QmlIR::Bind auto astNode = m_currentObject->functionsAndExpressions->slowAt(irBinding.value.compiledScriptIndex) ->node; - function.ast = astNode->asFunctionDefinition(); - if (!function.ast) { + auto ast = astNode->asFunctionDefinition(); + if (!ast) { QQmlJS::AST::Statement *stmt = astNode->statementCast(); if (!stmt) { Q_ASSERT(astNode->expressionCast()); @@ -195,20 +194,21 @@ Codegen::compileBinding(const QV4::Compiler::Context *context, const QmlIR::Bind body = body->finish(); QString name = "binding for "; // #### - function.ast = new (m_pool) QQmlJS::AST::FunctionDeclaration(m_pool->newString(name), + ast = new (m_pool) QQmlJS::AST::FunctionDeclaration(m_pool->newString(name), /*formals*/ nullptr, body); - function.ast->lbraceToken = astNode->firstSourceLocation(); - function.ast->functionToken = function.ast->lbraceToken; - function.ast->rbraceToken = astNode->lastSourceLocation(); + ast->lbraceToken = astNode->firstSourceLocation(); + ast->functionToken = ast->lbraceToken; + ast->rbraceToken = astNode->lastSourceLocation(); } - if (!generateFunction(context, &function)) { + QQmlJS::DiagnosticMessage error; + if (!generateFunction(QV4::Compiler::ContextType::Binding, context, ast, &function, &error)) { // If it's a signal and the function just returns a closure, it's harmless. // Otherwise promote the message to warning level. - return diagnose(QStringLiteral("Could not compile binding for %1: %2") - .arg(propertyName, function.error.message), - (isSignal && function.error.type == QtDebugMsg) ? QtDebugMsg : QtWarningMsg, - function.error.loc); + return diagnose( + QStringLiteral("Could not compile binding for %1: %2") + .arg(propertyName, error.message), + (isSignal && error.type == QtDebugMsg) ? QtDebugMsg : QtWarningMsg, error.loc); } return QQmlJSAotFunction {}; @@ -224,17 +224,16 @@ Codegen::compileFunction(const QV4::Compiler::Context *context, const QmlIR::Fun const QString functionName = m_document->stringAt(irFunction.nameIndex); Function function; - function.contextType = QV4::Compiler::ContextType::Function; function.qmlScope = m_scopeType; auto astNode = m_currentObject->functionsAndExpressions->slowAt(irFunction.index)->node; - function.ast = astNode->asFunctionDefinition(); - Q_ASSERT(function.ast); - if (!generateFunction(context, &function)) { + QQmlJS::DiagnosticMessage error; + if (!generateFunction(QV4::Compiler::ContextType::Function, context, + astNode->asFunctionDefinition(), &function, &error)) { return diagnose(QStringLiteral("Could not compile function %1: %2") - .arg(functionName, function.error.message), - QtWarningMsg, function.error.loc); + .arg(functionName, error.message), + QtWarningMsg, error.loc); } return QQmlJSAotFunction {}; @@ -266,31 +265,22 @@ QQmlJS::DiagnosticMessage Codegen::diagnose(const QString &message, QtMsgType ty return QQmlJS::DiagnosticMessage { message, type, location }; } -void Codegen::instructionOffsetToSrcLocation(const QV4::Compiler::Context *context, uint offset, - QQmlJS::SourceLocation *srcLoc) const -{ - Q_ASSERT(context->sourceLocationTable); - const auto &entries = context->sourceLocationTable->entries; - auto item = std::lower_bound(entries.begin(), entries.end(), offset, - [](auto entry, uint offset) { return entry.offset < offset; }); - - Q_ASSERT(item != entries.end()); - *srcLoc = item->location; -} - -bool Codegen::generateFunction(const QV4::Compiler::Context *context, Function *function) const +bool Codegen::generateFunction( + QV4::Compiler::ContextType contextType, + const QV4::Compiler::Context *context, + QQmlJS::AST::FunctionExpression *ast, + Function *function, + QQmlJS::DiagnosticMessage *error) const { - const auto error = [&](const QString &message) { - QQmlJS::DiagnosticMessage msg; - msg.loc = function->ast->firstSourceLocation(); - msg.message = message; - function->error = msg; + const auto fail = [&](const QString &message) { + error->loc = ast->firstSourceLocation(); + error->message = message; return false; }; QQmlJS::AST::BoundNames arguments; - if (function->ast->formals) - arguments = function->ast->formals->formals(); + if (ast->formals) + arguments = ast->formals->formals(); if (function->argumentTypes.isEmpty()) { for (const QQmlJS::AST::BoundName &argument : qAsConst(arguments)) { @@ -301,11 +291,11 @@ bool Codegen::generateFunction(const QV4::Compiler::Context *context, Function * function->argumentTypes.append(rawType); continue; } else { - return error(QStringLiteral("Cannot store the argument type %1.") + return fail(QStringLiteral("Cannot store the argument type %1.") .arg(rawType ? rawType->internalName() : "<unknown>")); } } else { - return error( + return fail( QStringLiteral("Functions without type annotations won't be compiled")); return false; } @@ -315,33 +305,30 @@ bool Codegen::generateFunction(const QV4::Compiler::Context *context, Function * QQmlJSTypePropagator propagator(m_unitGenerator, m_typeResolver.get(), m_logger, m_typeInfo); if (!function->returnType) { - if (function->ast->typeAnnotation) { - function->returnType = m_typeResolver->typeFromAST(function->ast->typeAnnotation->type); + if (ast->typeAnnotation) { + function->returnType = m_typeResolver->typeFromAST(ast->typeAnnotation->type); if (!function->returnType) - return error(QStringLiteral("Cannot resolve return type")); + return fail(QStringLiteral("Cannot resolve return type")); } } if (function->returnType) { if (!m_typeResolver->storedType( function->returnType, QQmlJSTypeResolver::ComponentIsGeneric::Yes)) { - return error(QStringLiteral("Cannot store the return type %1.") + return fail(QStringLiteral("Cannot store the return type %1.") .arg(function->returnType->internalName())); } } - QQmlJSTypePropagator::Error propagationError; - auto typePropagationResult = propagator.propagateTypes( - context, arguments, function->returnType, function->qmlScope, - m_typeResolver->objectsById(), - !function->returnType && function->contextType == QV4::Compiler::ContextType::Binding, - &propagationError); - if (propagationError.isSet()) { - QQmlJS::DiagnosticMessage msg; - msg.type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; - instructionOffsetToSrcLocation(context, propagationError.instructionOffset, &msg.loc); - msg.message = propagationError.message; - function->error = msg; + function->isSignalHandler = !function->returnType + && contextType == QV4::Compiler::ContextType::Binding; + function->addressableScopes = m_typeResolver->objectsById(); + function->code = context->code; + function->sourceLocations = context->sourceLocationTable.get(); + + propagator.run(function, error); + if (error->isValid()) { + error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; return false; } diff --git a/tools/qmllint/codegen.h b/tools/qmllint/codegen.h index 9cea0b16d7..1a9dff3ed8 100644 --- a/tools/qmllint/codegen.h +++ b/tools/qmllint/codegen.h @@ -52,6 +52,7 @@ #include <QtQmlCompiler/private/qqmljstyperesolver_p.h> #include <QtQmlCompiler/private/qqmljslogger_p.h> +#include <QtQmlCompiler/private/qqmljscompilepass_p.h> class Codegen : public QQmlJSAotCompiler { @@ -70,20 +71,7 @@ public: QQmlJSAotFunction globalCode() const override; private: - struct Function - { - QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Binding; - QQmlJS::AST::FunctionExpression *ast = nullptr; - bool isQPropertyBinding = false; - - QQmlJSScope::ConstPtr returnType; - QList<QQmlJSScope::ConstPtr> argumentTypes; - QQmlJSScope::ConstPtr qmlScope; - - QString generatedCode; - QStringList includes; - QQmlJS::DiagnosticMessage error; - }; + using Function = QQmlJSCompilePass::Function; const QmlIR::Document *m_document = nullptr; const QString m_fileName; @@ -104,9 +92,11 @@ private: QQmlJS::DiagnosticMessage diagnose(const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location); - bool generateFunction(const QV4::Compiler::Context *context, Function *function) const; - void instructionOffsetToSrcLocation(const QV4::Compiler::Context *context, uint offset, - QQmlJS::SourceLocation *srcLoc) const; + bool generateFunction(QV4::Compiler::ContextType contextType, + const QV4::Compiler::Context *context, + QQmlJS::AST::FunctionExpression *ast, + Function *function, + QQmlJS::DiagnosticMessage *error) const; }; #endif |