diff options
| author | Olivier De Cannière <olivier.decanniere@qt.io> | 2024-08-02 10:13:44 +0200 |
|---|---|---|
| committer | Olivier De Cannière <olivier.decanniere@qt.io> | 2024-08-21 19:57:58 +0200 |
| commit | d70abd83dc94d722cde6d4b19b9d35c5f4f19946 (patch) | |
| tree | 1119f20b6f64d71b4602e7d4e39f7dc0c2caeec4 /src/qmlcompiler/qqmljscompiler.cpp | |
| parent | 06577c9e80eb150b6b9e76e7805bfed1abbae82d (diff) | |
Compiler: Create infrastructure to support multiple warnings
Currently only one DiagnosticMessage can be stored at a time when using
the compiler. However, we want to be able to show more than one to the
user.
Therefore, use a list that gets passed inside the compiler instead of a
pointer to the sole error.
This also means that the error is valid by its very existence. There is
no need to check validity explicitly anymore.
Task-number: QTBUG-127624
Change-Id: I356db917b86703b508dc1ad52de7825d82eafd71
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src/qmlcompiler/qqmljscompiler.cpp')
| -rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 122 |
1 files changed, 66 insertions, 56 deletions
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp index d55140f964..fa438ad650 100644 --- a/src/qmlcompiler/qqmljscompiler.cpp +++ b/src/qmlcompiler/qqmljscompiler.cpp @@ -272,7 +272,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName, std::sort(bindingsAndFunctions.begin(), bindingsAndFunctions.end()); std::for_each(bindingsAndFunctions.begin(), bindingsAndFunctions.end(), [&](const BindingOrFunction &bindingOrFunction) { - std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> result; + std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> result; if (const auto *binding = bindingOrFunction.binding()) { switch (binding->type()) { case QmlIR::Binding::Type_AttachedProperty: @@ -313,12 +313,13 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName, Q_ASSERT(innerContext); qCDebug(lcAotCompiler) << "Compiling signal handler for" << irDocument.stringAt(binding->propertyNameIndex); - std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> innerResult + std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> innerResult = aotCompiler->compileBinding(innerContext, *binding, inner); - - if (auto *error = std::get_if<QQmlJS::DiagnosticMessage>(&innerResult)) { - qCDebug(lcAotCompiler) << "Compilation failed:" - << diagnosticErrorMessage(inputFileName, *error); + if (auto *errors = std::get_if<QList<QQmlJS::DiagnosticMessage>>(&innerResult)) { + for (const auto &error : *errors) { + qCDebug(lcAotCompiler) << "Compilation failed:" + << diagnosticErrorMessage(inputFileName, error); + } } else if (auto *func = std::get_if<QQmlJSAotFunction>(&innerResult)) { qCDebug(lcAotCompiler) << "Generated code:" << func->code; aotFunctionsByIndex[innerContext->functionIndex] = *func; @@ -343,9 +344,11 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName, Q_UNREACHABLE(); } - if (auto *error = std::get_if<QQmlJS::DiagnosticMessage>(&result)) { - qCDebug(lcAotCompiler) << "Compilation failed:" - << diagnosticErrorMessage(inputFileName, *error); + if (auto *errors = std::get_if<QList<QQmlJS::DiagnosticMessage>>(&result)) { + for (const auto &error : *errors) { + qCDebug(lcAotCompiler) << "Compilation failed:" + << diagnosticErrorMessage(inputFileName, error); + } } else if (auto *func = std::get_if<QQmlJSAotFunction>(&result)) { qCDebug(lcAotCompiler) << "Generated code:" << func->code; aotFunctionsByIndex[object->runtimeFunctionIndices[bindingOrFunction.index()]] = @@ -671,27 +674,30 @@ QQmlJS::DiagnosticMessage QQmlJSAotCompiler::diagnose( }; } -std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::compileBinding( +std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> QQmlJSAotCompiler::compileBinding( const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode) { QQmlJSFunctionInitializer initializer( &m_typeResolver, m_currentObject->location, m_currentScope->location); - QQmlJS::DiagnosticMessage error; + QList<QQmlJS::DiagnosticMessage> errors; const QString name = m_document->stringAt(irBinding.propertyNameIndex); QQmlJSCompilePass::Function function = initializer.run( - context, name, astNode, irBinding, &error); + context, name, astNode, irBinding, &errors); const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats( - context, &function, &error, name, astNode->firstSourceLocation()); - - if (error.isValid()) { - // If it's a signal and the function just returns a closure, it's harmless. - // Otherwise promote the message to warning level. - return diagnose(error.message, - (function.isSignalHandler && error.type == QtDebugMsg) - ? QtDebugMsg - : QtWarningMsg, - error.loc); + context, &function, &errors, name, astNode->firstSourceLocation()); + + if (!errors.isEmpty()) { + for (auto &error : errors) { + // If it's a signal and the function just returns a closure, it's harmless. + // Otherwise promote the message to warning level. + error = diagnose(error.message, + (function.isSignalHandler && error.type == QtDebugMsg) + ? QtDebugMsg : + QtWarningMsg, + error.loc); + } + return errors; } qCDebug(lcAotCompiler()) << "includes:" << aotFunction.includes; @@ -699,18 +705,21 @@ std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::co return aotFunction; } -std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::compileFunction( +std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> QQmlJSAotCompiler::compileFunction( const QV4::Compiler::Context *context, const QString &name, QQmlJS::AST::Node *astNode) { QQmlJSFunctionInitializer initializer( &m_typeResolver, m_currentObject->location, m_currentScope->location); - QQmlJS::DiagnosticMessage error; - QQmlJSCompilePass::Function function = initializer.run(context, name, astNode, &error); + QList<QQmlJS::DiagnosticMessage> errors; + QQmlJSCompilePass::Function function = initializer.run(context, name, astNode, &errors); const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats( - context, &function, &error, name, astNode->firstSourceLocation()); + context, &function, &errors, name, astNode->firstSourceLocation()); - if (error.isValid()) - return diagnose(error.message, QtWarningMsg, error.loc); + if (!errors.isEmpty()) { + for (auto &error : errors) + error = diagnose(error.message, QtWarningMsg, error.loc); + return errors; + } qCDebug(lcAotCompiler()) << "includes:" << aotFunction.includes; qCDebug(lcAotCompiler()) << "binding code:" << aotFunction.code; @@ -744,70 +753,71 @@ QQmlJSAotFunction QQmlJSAotCompiler::globalCode() const QQmlJSAotFunction QQmlJSAotCompiler::doCompile( const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, - QQmlJS::DiagnosticMessage *error) + QList<QQmlJS::DiagnosticMessage> *errors) { const auto compileError = [&]() { - Q_ASSERT(error->isValid()); - error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; + const auto type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; + for (auto &error : *errors) + error.type = type; return QQmlJSAotFunction(); }; - if (error->isValid()) + if (!errors->isEmpty()) return compileError(); bool basicBlocksValidationFailed = false; - QQmlJSBasicBlocks basicBlocks(context, m_unitGenerator, &m_typeResolver, m_logger); + QQmlJSBasicBlocks basicBlocks(context, m_unitGenerator, &m_typeResolver, m_logger, errors); auto passResult = basicBlocks.run(function, m_flags, basicBlocksValidationFailed); auto &[blocks, annotations] = passResult; - QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations); - passResult = propagator.run(function, error); - if (error->isValid()) + QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations); + passResult = propagator.run(function); + if (!errors->isEmpty()) return compileError(); - QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations); - passResult = shadowCheck.run(function, error); - if (error->isValid()) + QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations); + passResult = shadowCheck.run(function); + if (!errors->isEmpty()) return compileError(); - QQmlJSOptimizations optimizer(m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations, + QQmlJSOptimizations optimizer(m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations, basicBlocks.objectAndArrayDefinitions()); - passResult = optimizer.run(function, error); - if (error->isValid()) + passResult = optimizer.run(function); + if (!errors->isEmpty()) return compileError(); QQmlJSStorageInitializer initializer( - m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations); - passResult = initializer.run(function, error); + m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations); + passResult = initializer.run(function); // Generalize all arguments, registers, and the return type. QQmlJSStorageGeneralizer generalizer( - m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations); - passResult = generalizer.run(function, error); - if (error->isValid()) + m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations); + passResult = generalizer.run(function); + if (!errors->isEmpty()) return compileError(); - QQmlJSCodeGenerator codegen(context, m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations); - QQmlJSAotFunction result = codegen.run(function, error, basicBlocksValidationFailed); - return error->isValid() ? compileError() : result; + QQmlJSCodeGenerator codegen(context, m_unitGenerator, &m_typeResolver, m_logger, errors, blocks, annotations); + QQmlJSAotFunction result = codegen.run(function, basicBlocksValidationFailed); + return !errors->isEmpty() ? compileError() : result; } -QQmlJSAotFunction QQmlJSAotCompiler::doCompileAndRecordAotStats( - const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, - QQmlJS::DiagnosticMessage *error, const QString &name, QQmlJS::SourceLocation location) +QQmlJSAotFunction QQmlJSAotCompiler::doCompileAndRecordAotStats(const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, + QList<QQmlJS::DiagnosticMessage> *errors, const QString &name, + QQmlJS::SourceLocation location) { auto t1 = std::chrono::high_resolution_clock::now(); - QQmlJSAotFunction result = doCompile(context, function, error); + QQmlJSAotFunction result = doCompile(context, function, errors); auto t2 = std::chrono::high_resolution_clock::now(); if (QQmlJS::QQmlJSAotCompilerStats::recordAotStats()) { QQmlJS::AotStatsEntry entry; entry.codegenDuration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1); entry.functionName = name; - entry.errorMessage = error->message; + entry.errorMessage = errors->isEmpty() ? u""_s : errors->first().message; entry.line = location.startLine; entry.column = location.startColumn; - entry.codegenSuccessful = !error->isValid(); + entry.codegenSuccessful = errors->isEmpty(); QQmlJS::QQmlJSAotCompilerStats::addEntry( function->qmlScope.containedType()->filePath(), entry); } |
