diff options
Diffstat (limited to 'src')
21 files changed, 264 insertions, 247 deletions
diff --git a/src/qml/common/qqmljsdiagnosticmessage_p.h b/src/qml/common/qqmljsdiagnosticmessage_p.h index 0e7adbc3be..06c4015bf5 100644 --- a/src/qml/common/qqmljsdiagnosticmessage_p.h +++ b/src/qml/common/qqmljsdiagnosticmessage_p.h @@ -41,11 +41,6 @@ struct DiagnosticMessage { return type == QtWarningMsg; } - - bool isValid() const - { - return !message.isEmpty(); - } }; } // namespace QQmlJS diff --git a/src/qmlcompiler/qqmljsbasicblocks_p.h b/src/qmlcompiler/qqmljsbasicblocks_p.h index a443d422ea..a26e0120f9 100644 --- a/src/qmlcompiler/qqmljsbasicblocks_p.h +++ b/src/qmlcompiler/qqmljsbasicblocks_p.h @@ -26,8 +26,9 @@ class Q_QMLCOMPILER_EXPORT QQmlJSBasicBlocks : public QQmlJSCompilePass public: QQmlJSBasicBlocks(const QV4::Compiler::Context *context, const QV4::Compiler::JSUnitGenerator *unitGenerator, - const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger) - : QQmlJSCompilePass(unitGenerator, typeResolver, logger), m_context{ context } + const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, + QList<QQmlJS::DiagnosticMessage> *errors) + : QQmlJSCompilePass(unitGenerator, typeResolver, logger, errors), m_context{ context } { } diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp index df855d429b..cb0ccddef4 100644 --- a/src/qmlcompiler/qqmljscodegenerator.cpp +++ b/src/qmlcompiler/qqmljscodegenerator.cpp @@ -55,9 +55,11 @@ QString QQmlJSCodeGenerator::castTargetName(const QQmlJSScope::ConstPtr &type) c QQmlJSCodeGenerator::QQmlJSCodeGenerator(const QV4::Compiler::Context *compilerContext, const QV4::Compiler::JSUnitGenerator *unitGenerator, const QQmlJSTypeResolver *typeResolver, - QQmlJSLogger *logger, BasicBlocks basicBlocks, + QQmlJSLogger *logger, + QList<QQmlJS::DiagnosticMessage> *errors, + BasicBlocks basicBlocks, InstructionAnnotations annotations) - : QQmlJSCompilePass(unitGenerator, typeResolver, logger, basicBlocks, annotations) + : QQmlJSCompilePass(unitGenerator, typeResolver, logger, errors, basicBlocks, annotations) , m_context(compilerContext) {} @@ -126,12 +128,9 @@ QString QQmlJSCodeGenerator::metaType(const QQmlJSScope::ConstPtr &type) : metaTypeFromName(type); } -QQmlJSAotFunction QQmlJSCodeGenerator::run(const Function *function, - QQmlJS::DiagnosticMessage *error, - bool basicBlocksValidationFailed) +QQmlJSAotFunction QQmlJSCodeGenerator::run(const Function *function, bool basicBlocksValidationFailed) { m_function = function; - m_error = error; QHash<int, int> numRegisterVariablesPerIndex; @@ -2423,7 +2422,7 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv) registerType(argv).storedType(), m_typeResolver->sizeType(), consumedRegisterVariable(argv)) + u");\n"_s; - } else if (!m_error->isValid()) { + } else if (m_errors->isEmpty()) { generateArrayInitializer(argc, argv); } return; @@ -2672,7 +2671,7 @@ void QQmlJSCodeGenerator::generate_DefineArray(int argc, int args) INJECT_TRACE_INFO(generate_DefineArray); rejectIfBadArray(); - if (!m_error->isValid()) + if (m_errors->isEmpty()) generateArrayInitializer(argc, args); } @@ -3247,8 +3246,8 @@ void QQmlJSCodeGenerator::generate_Exp(int lhs) m_state.accumulatorIn(), m_state.readAccumulator(), consumedAccumulatorVariableIn()); - Q_ASSERT(m_error->isValid() || !lhsString.isEmpty()); - Q_ASSERT(m_error->isValid() || !rhsString.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !lhsString.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !rhsString.isEmpty()); const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut()); m_body += m_state.accumulatorVariableOut + u" = "_s; @@ -3280,8 +3279,8 @@ void QQmlJSCodeGenerator::generate_Mod(int lhs) const auto rhsVar = convertStored( m_state.accumulatorIn().storedType(), m_typeResolver->jsPrimitiveType(), consumedAccumulatorVariableIn()); - Q_ASSERT(m_error->isValid() || !lhsVar.isEmpty()); - Q_ASSERT(m_error->isValid() || !rhsVar.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !lhsVar.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !rhsVar.isEmpty()); m_body += m_state.accumulatorVariableOut; m_body += u" = "_s; @@ -3641,8 +3640,8 @@ void QQmlJSCodeGenerator::generateShiftOperation(int lhs, const QString &cppOper void QQmlJSCodeGenerator::generateArithmeticOperation( const QString &lhs, const QString &rhs, const QString &cppOperator) { - Q_ASSERT(m_error->isValid() || !lhs.isEmpty()); - Q_ASSERT(m_error->isValid() || !rhs.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !lhs.isEmpty()); + Q_ASSERT(!m_errors->isEmpty() || !rhs.isEmpty()); const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut()); m_body += m_state.accumulatorVariableOut; @@ -4301,7 +4300,7 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from, void QQmlJSCodeGenerator::reject(const QString &thing) { - setError(u"Cannot generate efficient code for %1"_s.arg(thing)); + addError(u"Cannot generate efficient code for %1"_s.arg(thing)); } QQmlJSCodeGenerator::AccumulatorConverter::AccumulatorConverter(QQmlJSCodeGenerator *generator) diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h index ffa2c80975..b04663e6c6 100644 --- a/src/qmlcompiler/qqmljscodegenerator_p.h +++ b/src/qmlcompiler/qqmljscodegenerator_p.h @@ -33,11 +33,11 @@ public: QQmlJSCodeGenerator(const QV4::Compiler::Context *compilerContext, const QV4::Compiler::JSUnitGenerator *unitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks, InstructionAnnotations annotations); + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks, + InstructionAnnotations annotations); ~QQmlJSCodeGenerator() = default; - QQmlJSAotFunction run(const Function *function, QQmlJS::DiagnosticMessage *error, - bool basicBlocksValidationFailed); + QQmlJSAotFunction run(const Function *function, bool basicBlocksValidationFailed); protected: struct CodegenState : public State diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h index d396efa4de..ce3935ddd7 100644 --- a/src/qmlcompiler/qqmljscompilepass_p.h +++ b/src/qmlcompiler/qqmljscompilepass_p.h @@ -264,10 +264,12 @@ public: QQmlJSCompilePass(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks = {}, InstructionAnnotations annotations = {}) + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks = {}, + InstructionAnnotations annotations = {}) : m_jsUnitGenerator(jsUnitGenerator) , m_typeResolver(typeResolver) , m_logger(logger) + , m_errors(errors) , m_basicBlocks(basicBlocks) , m_annotations(annotations) {} @@ -278,9 +280,9 @@ protected: QQmlJSLogger *m_logger = nullptr; const Function *m_function = nullptr; + QList<QQmlJS::DiagnosticMessage> *m_errors; BasicBlocks m_basicBlocks; InstructionAnnotations m_annotations; - QQmlJS::DiagnosticMessage *m_error = nullptr; int firstRegisterIndex() const { @@ -369,18 +371,17 @@ protected: return sourceLocation(currentInstructionOffset()); } - void setError(const QString &message, int instructionOffset) + void addError(const QString &message, int instructionOffset) { - Q_ASSERT(m_error); - if (m_error->isValid()) - return; - m_error->message = message; - m_error->loc = sourceLocation(instructionOffset); + QQmlJS::DiagnosticMessage diagnostic; + diagnostic.message = message; + diagnostic.loc = sourceLocation(instructionOffset); + m_errors->append(diagnostic); } - void setError(const QString &message) + void addError(const QString &message) { - setError(message, currentInstructionOffset()); + addError(message, currentInstructionOffset()); } static bool instructionManipulatesContext(QV4::Moth::Instr::Type type) 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); } diff --git a/src/qmlcompiler/qqmljscompiler_p.h b/src/qmlcompiler/qqmljscompiler_p.h index 94cf71b884..2e08834eca 100644 --- a/src/qmlcompiler/qqmljscompiler_p.h +++ b/src/qmlcompiler/qqmljscompiler_p.h @@ -70,10 +70,10 @@ public: virtual void setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document); virtual void setScope(const QmlIR::Object *object, const QmlIR::Object *scope); - virtual std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> compileBinding( + virtual std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> compileBinding( const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode); - virtual std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> compileFunction( + virtual std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> compileFunction( const QV4::Compiler::Context *context, const QString &name, QQmlJS::AST::Node *astNode); virtual QQmlJSAotFunction globalCode() const; @@ -100,10 +100,10 @@ protected: private: QQmlJSAotFunction doCompile(const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, - QQmlJS::DiagnosticMessage *error); + QList<QQmlJS::DiagnosticMessage> *error); QQmlJSAotFunction doCompileAndRecordAotStats(const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, - QQmlJS::DiagnosticMessage *error, + QList<QQmlJS::DiagnosticMessage> *erros, const QString &name, QQmlJS::SourceLocation location); }; diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp index 1c90167691..5d0b32a5af 100644 --- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp +++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp @@ -55,12 +55,14 @@ static QString bindingTypeDescription(QmlIR::Binding::Type type) void QQmlJSFunctionInitializer::populateSignature( const QV4::Compiler::Context *context, QQmlJS::AST::FunctionExpression *ast, - QQmlJSCompilePass::Function *function, QQmlJS::DiagnosticMessage *error) + QQmlJSCompilePass::Function *function, QList<QQmlJS::DiagnosticMessage> *errors) { const auto signatureError = [&](const QString &message) { - error->type = QtWarningMsg; - error->loc = ast->firstSourceLocation(); - error->message = message; + QQmlJS::DiagnosticMessage error; + error.type = QtWarningMsg; + error.loc = ast->firstSourceLocation(); + error.message = message; + *errors << error; function->isFullyTyped = false; }; @@ -143,13 +145,9 @@ void QQmlJSFunctionInitializer::populateSignature( static void diagnose( const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location, - QQmlJS::DiagnosticMessage *error) + QList<QQmlJS::DiagnosticMessage> *errors) { - *error = QQmlJS::DiagnosticMessage{ - message, - type, - location - }; + *errors << QQmlJS::DiagnosticMessage{ message, type, location }; } QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( @@ -157,7 +155,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( const QString &propertyName, QQmlJS::AST::Node *astNode, const QmlIR::Binding &irBinding, - QQmlJS::DiagnosticMessage *error) + QList<QQmlJS::DiagnosticMessage> *errors) { QQmlJS::SourceLocation bindingLocation; bindingLocation.startLine = irBinding.location.line(); @@ -169,7 +167,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( if (irBinding.type() != QmlIR::Binding::Type_Script) { diagnose(u"Binding is not a script binding, but %1."_s.arg( bindingTypeDescription(QmlIR::Binding::Type(quint32(irBinding.type())))), - QtDebugMsg, bindingLocation, error); + QtDebugMsg, bindingLocation, errors); } function.isProperty = m_objectType->hasProperty(propertyName); @@ -193,7 +191,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( if (type.isNull()) { diagnose(u"Cannot resolve the argument type %1."_s.arg( arguments[i].typeName()), - QtDebugMsg, bindingLocation, error); + QtDebugMsg, bindingLocation, errors); function.argumentTypes.append( m_typeResolver->tracked( m_typeResolver->globalType(m_typeResolver->varType()))); @@ -208,7 +206,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( if (!function.isSignalHandler) { diagnose(u"Could not compile signal handler for %1: The signal does not exist"_s.arg( *signalName), - QtWarningMsg, bindingLocation, error); + QtWarningMsg, bindingLocation, errors); } } } @@ -218,7 +216,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( if (!function.isProperty) { diagnose(u"Could not compile binding for %1: The property does not exist"_s.arg( propertyName), - QtWarningMsg, bindingLocation, error); + QtWarningMsg, bindingLocation, errors); } const auto property = m_objectType->property(propertyName); @@ -235,7 +233,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( // most commonly used to enable generalized grouped properties. message += u" You may want use ID-based grouped properties here."; } - diagnose(message, QtWarningMsg, bindingLocation, error); + diagnose(message, QtWarningMsg, bindingLocation, errors); } if (!property.bindable().isEmpty() && !property.isPrivate()) @@ -262,14 +260,14 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( ast->rbraceToken = astNode->lastSourceLocation(); } - populateSignature(context, ast, &function, error); + populateSignature(context, ast, &function, errors); return function; } QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( const QV4::Compiler::Context *context, const QString &functionName, QQmlJS::AST::Node *astNode, - QQmlJS::DiagnosticMessage *error) + QList<QQmlJS::DiagnosticMessage> *errors) { Q_UNUSED(functionName); @@ -279,7 +277,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run( auto ast = astNode->asFunctionDefinition(); Q_ASSERT(ast); - populateSignature(context, ast, &function, error); + populateSignature(context, ast, &function, errors); return function; } diff --git a/src/qmlcompiler/qqmljsfunctioninitializer_p.h b/src/qmlcompiler/qqmljsfunctioninitializer_p.h index 424959a4fa..68f55a25ff 100644 --- a/src/qmlcompiler/qqmljsfunctioninitializer_p.h +++ b/src/qmlcompiler/qqmljsfunctioninitializer_p.h @@ -31,20 +31,19 @@ public: , m_objectType(typeResolver->scopeForLocation(objectLocation)) {} - QQmlJSCompilePass::Function run( - const QV4::Compiler::Context *context, - const QString &propertyName, QQmlJS::AST::Node *astNode, - const QmlIR::Binding &irBinding, - QQmlJS::DiagnosticMessage *error); + QQmlJSCompilePass::Function run(const QV4::Compiler::Context *context, + const QString &propertyName, QQmlJS::AST::Node *astNode, + const QmlIR::Binding &irBinding, + QList<QQmlJS::DiagnosticMessage> *errors); QQmlJSCompilePass::Function run( const QV4::Compiler::Context *context, const QString &functionName, QQmlJS::AST::Node *astNode, - QQmlJS::DiagnosticMessage *error); + QList<QQmlJS::DiagnosticMessage> *errors); private: void populateSignature( const QV4::Compiler::Context *context, QQmlJS::AST::FunctionExpression *ast, - QQmlJSCompilePass::Function *function, QQmlJS::DiagnosticMessage *error); + QQmlJSCompilePass::Function *function, QList<QQmlJS::DiagnosticMessage> *errors); const QQmlJSTypeResolver *m_typeResolver = nullptr; const QQmlJSScope::ConstPtr m_scopeType; diff --git a/src/qmlcompiler/qqmljslintercodegen.cpp b/src/qmlcompiler/qqmljslintercodegen.cpp index 314c2087e4..e33fe7139b 100644 --- a/src/qmlcompiler/qqmljslintercodegen.cpp +++ b/src/qmlcompiler/qqmljslintercodegen.cpp @@ -30,50 +30,56 @@ void QQmlJSLinterCodegen::setDocument(const QmlIR::JSCodeGen *codegen, m_unitGenerator = &document->jsGenerator; } -std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> +std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> QQmlJSLinterCodegen::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 initializationError; + QList<QQmlJS::DiagnosticMessage> initializationErrors; const QString name = m_document->stringAt(irBinding.propertyNameIndex); QQmlJSCompilePass::Function function = - initializer.run(context, name, astNode, irBinding, &initializationError); - if (initializationError.isValid()) - diagnose(initializationError.message, initializationError.type, initializationError.loc); + initializer.run(context, name, astNode, irBinding, &initializationErrors); + for (const auto &error : initializationErrors) + diagnose(error.message, error.type, error.loc); - QQmlJS::DiagnosticMessage analyzeError; - if (!analyzeFunction(context, &function, &analyzeError)) { + QList<QQmlJS::DiagnosticMessage> analyzeErrors; + if (!analyzeFunction(context, &function, &analyzeErrors)) { // If it's a signal and the function just returns a closure, it's harmless. // Otherwise promote the message to warning level. - return diagnose(u"Could not compile binding for %1: %2"_s.arg(name, analyzeError.message), - (function.isSignalHandler && analyzeError.type == QtDebugMsg) - ? QtDebugMsg - : QtWarningMsg, - analyzeError.loc); + for (auto &error : analyzeErrors) { + error = diagnose(u"Could not compile binding for %1: %2"_s.arg(name, error.message), + (function.isSignalHandler && error.type == QtDebugMsg) + ? QtDebugMsg + : QtWarningMsg, + error.loc); + } + return analyzeErrors; } return QQmlJSAotFunction {}; } -std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> +std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> QQmlJSLinterCodegen::compileFunction(const QV4::Compiler::Context *context, const QString &name, QQmlJS::AST::Node *astNode) { - QQmlJS::DiagnosticMessage initializationError; + QList<QQmlJS::DiagnosticMessage> initializationErrors; QQmlJSFunctionInitializer initializer( &m_typeResolver, m_currentObject->location, m_currentScope->location); QQmlJSCompilePass::Function function = - initializer.run(context, name, astNode, &initializationError); - if (initializationError.isValid()) - diagnose(initializationError.message, initializationError.type, initializationError.loc); - - QQmlJS::DiagnosticMessage analyzeError; - if (!analyzeFunction(context, &function, &analyzeError)) { - return diagnose(u"Could not compile function %1: %2"_s.arg(name, analyzeError.message), - QtWarningMsg, analyzeError.loc); + initializer.run(context, name, astNode, &initializationErrors); + for (const auto &error : initializationErrors) + diagnose(error.message, error.type, error.loc); + + QList<QQmlJS::DiagnosticMessage> analyzeErrors; + if (!analyzeFunction(context, &function, &analyzeErrors)) { + for (auto &error : analyzeErrors) { + error = diagnose(u"Could not compile function %1: %2"_s.arg(name, error.message), + QtWarningMsg, error.loc); + } + return analyzeErrors; } return QQmlJSAotFunction {}; @@ -88,31 +94,33 @@ void QQmlJSLinterCodegen::setPassManager(QQmlSA::PassManager *passManager) bool QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, - QQmlJS::DiagnosticMessage *error) + QList<QQmlJS::DiagnosticMessage> *errors) { - QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger, - {}, {}, m_passManager); - auto [basicBlocks, annotations] = propagator.run(function, error); - if (!error->isValid()) { - QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger, basicBlocks, - annotations); - shadowCheck.run(function, error); + QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger, errors, {}, {}, + m_passManager); + auto [basicBlocks, annotations] = propagator.run(function); + if (errors->isEmpty()) { + QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger, errors, + basicBlocks, annotations); + shadowCheck.run(function); } - if (!error->isValid()) { - QQmlJSStorageInitializer initializer(m_unitGenerator, &m_typeResolver, m_logger, + if (errors->isEmpty()) { + QQmlJSStorageInitializer initializer(m_unitGenerator, &m_typeResolver, m_logger, errors, basicBlocks, annotations); - initializer.run(function, error); + initializer.run(function); } - if (!error->isValid()) { - QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger, + if (errors->isEmpty()) { + QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger, errors, basicBlocks, annotations); - generalizer.run(function, error); + generalizer.run(function); } - if (error->isValid()) { - error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; + if (!errors->isEmpty()) { + QtMsgType type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; + for (auto &error : *errors) + error.type = type; return false; } diff --git a/src/qmlcompiler/qqmljslintercodegen_p.h b/src/qmlcompiler/qqmljslintercodegen_p.h index 8c9f601166..f58223034c 100644 --- a/src/qmlcompiler/qqmljslintercodegen_p.h +++ b/src/qmlcompiler/qqmljslintercodegen_p.h @@ -42,10 +42,10 @@ public: const QStringList &qmldirFiles, QQmlJSLogger *logger); void setDocument(const QmlIR::JSCodeGen *codegen, const QmlIR::Document *document) override; - std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> + std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> compileBinding(const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode) override; - std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> + std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>> compileFunction(const QV4::Compiler::Context *context, const QString &name, QQmlJS::AST::Node *astNode) override; @@ -64,7 +64,8 @@ private: QQmlSA::PassManager *m_passManager = nullptr; bool analyzeFunction(const QV4::Compiler::Context *context, - QQmlJSCompilePass::Function *function, QQmlJS::DiagnosticMessage *error); + QQmlJSCompilePass::Function *function, + QList<QQmlJS::DiagnosticMessage> *errors); }; QT_END_NAMESPACE diff --git a/src/qmlcompiler/qqmljsoptimizations.cpp b/src/qmlcompiler/qqmljsoptimizations.cpp index 3fe2d89cf7..0603d6fa42 100644 --- a/src/qmlcompiler/qqmljsoptimizations.cpp +++ b/src/qmlcompiler/qqmljsoptimizations.cpp @@ -9,11 +9,9 @@ QT_BEGIN_NAMESPACE using namespace Qt::Literals::StringLiterals; -QQmlJSCompilePass::BlocksAndAnnotations QQmlJSOptimizations::run(const Function *function, - QQmlJS::DiagnosticMessage *error) +QQmlJSCompilePass::BlocksAndAnnotations QQmlJSOptimizations::run(const Function *function) { m_function = function; - m_error = error; populateBasicBlocks(); populateReaderLocations(); @@ -329,7 +327,7 @@ void QQmlJSOptimizations::adjustTypes() return; // Constructed something else. if (!m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values())) - setError(adjustErrorMessage(it->trackedTypes[0], it->typeReaders.values())); + addError(adjustErrorMessage(it->trackedTypes[0], it->typeReaders.values())); // Now we don't adjust the type we store, but rather the type we expect to read. We // can do this because we've tracked the read type when we defined the array in @@ -342,7 +340,7 @@ void QQmlJSOptimizations::adjustTypes() if (mode != ObjectOrArrayDefinition::ArrayConstruct1ArgId || !m_typeResolver->equals(contained, m_typeResolver->realType())) { if (!m_typeResolver->adjustTrackedType(contained, valueType)) - setError(adjustErrorMessage(contained, valueType)); + addError(adjustErrorMessage(contained, valueType)); } } @@ -366,7 +364,7 @@ void QQmlJSOptimizations::adjustTypes() Q_ASSERT(!annotation.readRegisters.isEmpty()); if (!m_typeResolver->adjustTrackedType(resultType, it->typeReaders.values())) - setError(adjustErrorMessage(resultType, it->typeReaders.values())); + addError(adjustErrorMessage(resultType, it->typeReaders.values())); if (m_typeResolver->equals(resultType, m_typeResolver->varType()) || m_typeResolver->equals(resultType, m_typeResolver->variantMapType())) { @@ -385,19 +383,19 @@ void QQmlJSOptimizations::adjustTypes() const QString propName = m_jsUnitGenerator->jsClassMember(object.internalClassId, i); const QQmlJSMetaProperty property = resultType->property(propName); if (!property.isValid()) { - setError(resultType->internalName() + QLatin1String(" has no property called ") + addError(resultType->internalName() + QLatin1String(" has no property called ") + propName); continue; } const QQmlJSScope::ConstPtr propType = property.type(); if (propType.isNull()) { - setError(QLatin1String("Cannot resolve type of property ") + propName); + addError(QLatin1String("Cannot resolve type of property ") + propName); continue; } const QQmlJSRegisterContent content = annotation.readRegisters[object.argv + i].content; const QQmlJSScope::ConstPtr contained = content.containedType(); if (!m_typeResolver->adjustTrackedType(contained, propType)) - setError(adjustErrorMessage(contained, propType)); + addError(adjustErrorMessage(contained, propType)); } // The others cannot be adjusted. We don't know their names, yet. @@ -433,7 +431,7 @@ void QQmlJSOptimizations::adjustTypes() continue; if (!m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values())) - setError(adjustErrorMessage(it->trackedTypes[0], it->typeReaders.values())); + addError(adjustErrorMessage(it->trackedTypes[0], it->typeReaders.values())); } @@ -453,7 +451,7 @@ void QQmlJSOptimizations::adjustTypes() for (const auto &origin : conversionOrigins) newResult = m_typeResolver->merge(newResult, origin); if (!m_typeResolver->adjustTrackedType(conversionResult, newResult)) - setError(adjustErrorMessage(conversionResult, newResult)); + addError(adjustErrorMessage(conversionResult, newResult)); } newRegisters.appendOrdered(conversion); } diff --git a/src/qmlcompiler/qqmljsoptimizations_p.h b/src/qmlcompiler/qqmljsoptimizations_p.h index 519975fbe6..16703c16f0 100644 --- a/src/qmlcompiler/qqmljsoptimizations_p.h +++ b/src/qmlcompiler/qqmljsoptimizations_p.h @@ -25,16 +25,17 @@ public: QQmlJSOptimizations(const QV4::Compiler::JSUnitGenerator *unitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks, InstructionAnnotations annotations, + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks, + InstructionAnnotations annotations, QList<ObjectOrArrayDefinition> objectAndArrayDefinitions) - : QQmlJSCompilePass(unitGenerator, typeResolver, logger, basicBlocks, annotations), + : QQmlJSCompilePass(unitGenerator, typeResolver, logger, errors, basicBlocks, annotations), m_objectAndArrayDefinitions{ objectAndArrayDefinitions } { } ~QQmlJSOptimizations() = default; - BlocksAndAnnotations run(const Function *function, QQmlJS::DiagnosticMessage *error); + BlocksAndAnnotations run(const Function *function); private: struct RegisterAccess diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp index 29de04e2f1..04efe7331f 100644 --- a/src/qmlcompiler/qqmljsshadowcheck.cpp +++ b/src/qmlcompiler/qqmljsshadowcheck.cpp @@ -34,11 +34,9 @@ using namespace Qt::StringLiterals; * arguments and return types into "var". */ -QQmlJSCompilePass::BlocksAndAnnotations QQmlJSShadowCheck::run(const Function *function, - QQmlJS::DiagnosticMessage *error) +QQmlJSCompilePass::BlocksAndAnnotations QQmlJSShadowCheck::run(const Function *function) { m_function = function; - m_error = error; m_state = initialState(function); decode(m_function->code.constData(), static_cast<uint>(m_function->code.size())); @@ -237,7 +235,7 @@ QQmlJSShadowCheck::Shadowability QQmlJSShadowCheck::checkBaseType( { if (!m_adjustedTypes.contains(baseType)) return NotShadowable; - setError(u"Cannot use shadowable base type for further lookups: %1"_s.arg(baseType.descriptiveName())); + addError(u"Cannot use shadowable base type for further lookups: %1"_s.arg(baseType.descriptiveName())); return Shadowable; } diff --git a/src/qmlcompiler/qqmljsshadowcheck_p.h b/src/qmlcompiler/qqmljsshadowcheck_p.h index dfa00134cb..9b763351ce 100644 --- a/src/qmlcompiler/qqmljsshadowcheck_p.h +++ b/src/qmlcompiler/qqmljsshadowcheck_p.h @@ -23,13 +23,14 @@ class Q_QMLCOMPILER_EXPORT QQmlJSShadowCheck : public QQmlJSCompilePass public: QQmlJSShadowCheck(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks, InstructionAnnotations annotations) - : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, basicBlocks, annotations) + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks, + InstructionAnnotations annotations) + : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, errors, basicBlocks, annotations) {} ~QQmlJSShadowCheck() = default; - BlocksAndAnnotations run(const Function *function, QQmlJS::DiagnosticMessage *error); + BlocksAndAnnotations run(const Function *function); private: struct ResettableStore { diff --git a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp index 3ba709b21f..ce9f096ac6 100644 --- a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp +++ b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp @@ -19,18 +19,16 @@ QT_BEGIN_NAMESPACE * operates only on the annotations and the function description. */ -QQmlJSCompilePass::BlocksAndAnnotations -QQmlJSStorageGeneralizer::run(Function *function, QQmlJS::DiagnosticMessage *error) +QQmlJSCompilePass::BlocksAndAnnotations QQmlJSStorageGeneralizer::run(Function *function) { m_function = function; - m_error = error; if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) { if (QQmlJSScope::ConstPtr stored = m_typeResolver->genericType( returnType.storedType(), QQmlJSTypeResolver::ComponentIsGeneric::Yes)) { returnType = returnType.storedIn(stored); } else { - setError(QStringLiteral("Cannot store the return type %1.") + addError(QStringLiteral("Cannot store the return type %1.") .arg(returnType.storedType()->internalName())); return {}; } diff --git a/src/qmlcompiler/qqmljsstoragegeneralizer_p.h b/src/qmlcompiler/qqmljsstoragegeneralizer_p.h index 9ef4699fca..83c9275444 100644 --- a/src/qmlcompiler/qqmljsstoragegeneralizer_p.h +++ b/src/qmlcompiler/qqmljsstoragegeneralizer_p.h @@ -23,11 +23,12 @@ class Q_QMLCOMPILER_EXPORT QQmlJSStorageGeneralizer : public QQmlJSCompilePass public: QQmlJSStorageGeneralizer(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks, InstructionAnnotations annotations) - : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, basicBlocks, annotations) + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks, + InstructionAnnotations annotations) + : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, errors, basicBlocks, annotations) {} - BlocksAndAnnotations run(Function *function, QQmlJS::DiagnosticMessage *error); + BlocksAndAnnotations run(Function *function); protected: // We don't have to use the byte code here. We only transform the instruction annotations. diff --git a/src/qmlcompiler/qqmljsstorageinitializer.cpp b/src/qmlcompiler/qqmljsstorageinitializer.cpp index b0f7d1a49f..27169001f2 100644 --- a/src/qmlcompiler/qqmljsstorageinitializer.cpp +++ b/src/qmlcompiler/qqmljsstorageinitializer.cpp @@ -16,18 +16,16 @@ QT_BEGIN_NAMESPACE * operates only on the annotations and the function description. */ -QQmlJSCompilePass::BlocksAndAnnotations -QQmlJSStorageInitializer::run(Function *function, QQmlJS::DiagnosticMessage *error) +QQmlJSCompilePass::BlocksAndAnnotations QQmlJSStorageInitializer::run(Function *function) { m_function = function; - m_error = error; if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) { if (const QQmlJSScope::ConstPtr stored = m_typeResolver->storedType(returnType.containedType())) { returnType = returnType.storedIn(m_typeResolver->trackedType(stored)); } else { - setError(QStringLiteral("Cannot store the return type %1.") + addError(QStringLiteral("Cannot store the return type %1.") .arg(returnType.containedType()->internalName())); return {}; } @@ -47,7 +45,7 @@ QQmlJSStorageInitializer::run(Function *function, QQmlJS::DiagnosticMessage *err = m_typeResolver->storedType(content.containedType()); if (!m_typeResolver->adjustTrackedType(originalTracked, adjustedStored)) { - setError(QStringLiteral("Cannot adjust stored type for %1.") + addError(QStringLiteral("Cannot adjust stored type for %1.") .arg(content.containedType()->internalName())); } }; diff --git a/src/qmlcompiler/qqmljsstorageinitializer_p.h b/src/qmlcompiler/qqmljsstorageinitializer_p.h index 0644807543..08e07aa073 100644 --- a/src/qmlcompiler/qqmljsstorageinitializer_p.h +++ b/src/qmlcompiler/qqmljsstorageinitializer_p.h @@ -23,11 +23,12 @@ class Q_QMLCOMPILER_EXPORT QQmlJSStorageInitializer : public QQmlJSCompilePass public: QQmlJSStorageInitializer(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks, InstructionAnnotations annotations) - : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, basicBlocks, annotations) + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks, + InstructionAnnotations annotations) + : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, errors, basicBlocks, annotations) {} - BlocksAndAnnotations run(Function *function, QQmlJS::DiagnosticMessage *error); + BlocksAndAnnotations run(Function *function); protected: // We don't have to use the byte code here. We only transform the instruction annotations. diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index 0fc8900015..156f11916e 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -28,25 +28,32 @@ using namespace Qt::StringLiterals; QQmlJSTypePropagator::QQmlJSTypePropagator(const QV4::Compiler::JSUnitGenerator *unitGenerator, const QQmlJSTypeResolver *typeResolver, - QQmlJSLogger *logger, BasicBlocks basicBlocks, + QQmlJSLogger *logger, + QList<QQmlJS::DiagnosticMessage> *errors, + BasicBlocks basicBlocks, InstructionAnnotations annotations, QQmlSA::PassManager *passManager) - : QQmlJSCompilePass(unitGenerator, typeResolver, logger, basicBlocks, annotations), + : QQmlJSCompilePass(unitGenerator, typeResolver, logger, errors, basicBlocks, annotations), m_passManager(passManager) { } -QQmlJSCompilePass::BlocksAndAnnotations QQmlJSTypePropagator::run( - const Function *function, QQmlJS::DiagnosticMessage *error) +QQmlJSCompilePass::BlocksAndAnnotations QQmlJSTypePropagator::run(const Function *function) { m_function = function; - m_error = error; m_returnType = m_function->returnType; + QList<QQmlJS::DiagnosticMessage> oldErrors; + std::swap(oldErrors, *m_errors); + auto restoreErrors = qScopeGuard([&]() { + oldErrors << *std::move(m_errors); + *m_errors = std::move(oldErrors); + }); + do { // Reset the error if we need to do another pass if (m_state.needsMorePasses) - *m_error = QQmlJS::DiagnosticMessage(); + m_errors->clear(); m_prevStateAnnotations = m_state.annotations; m_state = PassState(); @@ -65,7 +72,7 @@ QQmlJSCompilePass::BlocksAndAnnotations QQmlJSTypePropagator::run( } #define INSTR_PROLOGUE_NOT_IMPLEMENTED() \ - setError(u"Instruction \"%1\" not implemented"_s.arg(QString::fromUtf8(__func__))); \ + addError(u"Instruction \"%1\" not implemented"_s.arg(QString::fromUtf8(__func__))); \ return; #define INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE() \ @@ -96,7 +103,7 @@ void QQmlJSTypePropagator::generate_Ret() m_state.accumulatorIn(), m_typeResolver->voidType())) { // You can always return undefined. } else if (!m_returnType.isValid() && m_state.accumulatorIn().isValid()) { - setError(u"function without return type annotation returns %1. This may prevent proper "_s + addError(u"function without return type annotation returns %1. This may prevent proper "_s u"compilation to Cpp."_s.arg(m_state.accumulatorIn().descriptiveName())); if (m_function->isFullyTyped) { @@ -107,7 +114,7 @@ void QQmlJSTypePropagator::generate_Ret() } return; } else if (!canConvertFromTo(m_state.accumulatorIn(), m_returnType)) { - setError(u"cannot convert from %1 to %2"_s + addError(u"cannot convert from %1 to %2"_s .arg(m_state.accumulatorIn().descriptiveName(), m_returnType.descriptiveName())); @@ -263,7 +270,7 @@ void QQmlJSTypePropagator::generate_LoadName(int nameIndex) const QString name = m_jsUnitGenerator->stringForIndex(nameIndex); setAccumulator(m_typeResolver->scopedType(m_function->qmlScope, name)); if (!m_state.accumulatorOut().isValid()) - setError(u"Cannot find name "_s + name); + addError(u"Cannot find name "_s + name); } void QQmlJSTypePropagator::generate_LoadGlobalLookup(int index) @@ -583,7 +590,7 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index) checkDeprecated(qmlScope, name, false); if (!m_state.accumulatorOut().isValid()) { - setError(u"Cannot access value for name "_s + name); + addError(u"Cannot access value for name "_s + name); handleUnqualifiedAccess(name, false); return; } @@ -591,7 +598,7 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index) const QQmlJSRegisterContent accumulatorOut = m_state.accumulatorOut(); if (accumulatorOut.variant() == QQmlJSRegisterContent::ObjectById && !m_typeResolver->genericType(accumulatorOut.containedType())->isReferenceType()) { - setError(u"Cannot retrieve a non-object type by ID: "_s + name); + addError(u"Cannot retrieve a non-object type by ID: "_s + name); return; } @@ -632,7 +639,7 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex) if (!type.isValid()) { handleUnqualifiedAccess(name, false); - setError(u"Cannot find name "_s + name); + addError(u"Cannot find name "_s + name); return; } @@ -643,12 +650,12 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex) // and we lack a better fitting category. We might want to revisit this later. m_logger->log(message.arg(name), qmlReadOnlyProperty, getCurrentSourceLocation()); - setError(u"Cannot assign to non-property "_s + name); + addError(u"Cannot assign to non-property "_s + name); return; } if (!type.isWritable()) { - setError(u"Can't assign to read-only property %1"_s.arg(name)); + addError(u"Can't assign to read-only property %1"_s.arg(name)); m_logger->log(u"Cannot assign to read-only property %1"_s.arg(name), qmlReadOnlyProperty, getCurrentSourceLocation()); @@ -657,7 +664,7 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex) } if (!canConvertFromTo(in, type)) { - setError(u"cannot convert from %1 to %2"_s + addError(u"cannot convert from %1 to %2"_s .arg(in.descriptiveName(), type.descriptiveName())); } @@ -697,7 +704,7 @@ bool QQmlJSTypePropagator::checkForEnumProblems( getCurrentSourceLocation()); const QString error = u"\"%1\" is not an entry of enum \"%2\"."_s .arg(propertyName, metaEn.name()); - setError(error); + addError(error); m_logger->log( error, qmlMissingEnumEntry, getCurrentSourceLocation(), true, true, fixSuggestion); @@ -708,7 +715,7 @@ bool QQmlJSTypePropagator::checkForEnumProblems( if (metaEn.isValid() && !metaEn.isScoped() && !metaEn.isQml()) { const QString error = u"You cannot access unscoped enum \"%1\" from here."_s.arg(propertyName); - setError(error); + addError(error); m_logger->log(error, qmlRestrictedType, getCurrentSourceLocation()); return true; } @@ -859,7 +866,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName, if (checkForEnumProblems(m_state.accumulatorIn(), propertyName)) return; - setError(u"Cannot load property %1 from %2."_s + addError(u"Cannot load property %1 from %2."_s .arg(propertyName, m_state.accumulatorIn().descriptiveName())); const QString typeName = m_state.accumulatorIn().containedTypeName(); @@ -906,7 +913,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName, } if (m_state.accumulatorOut().isMethod() && m_state.accumulatorOut().method().size() != 1) { - setError(u"Cannot determine overloaded method on loadProperty"_s); + addError(u"Cannot determine overloaded method on loadProperty"_s); return; } @@ -929,7 +936,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName, if (m_typeResolver->registerContains( m_state.accumulatorOut(), m_typeResolver->voidType())) { - setError(u"Type %1 does not have a property %2 for reading"_s + addError(u"Type %1 does not have a property %2 for reading"_s .arg(m_state.accumulatorIn().descriptiveName(), propertyName)); return; } @@ -1009,19 +1016,19 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base) QQmlJSRegisterContent property = m_typeResolver->memberType(callBase, propertyName); if (!property.isProperty()) { - setError(u"Type %1 does not have a property %2 for writing"_s + addError(u"Type %1 does not have a property %2 for writing"_s .arg(callBase.descriptiveName(), propertyName)); return; } if (property.containedType().isNull()) { - setError(u"Cannot determine type for property %1 of type %2"_s.arg( + addError(u"Cannot determine type for property %1 of type %2"_s.arg( propertyName, callBase.descriptiveName())); return; } if (!property.isWritable() && !property.containedType()->isListProperty()) { - setError(u"Can't assign to read-only property %1"_s.arg(propertyName)); + addError(u"Can't assign to read-only property %1"_s.arg(propertyName)); m_logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName), qmlReadOnlyProperty, getCurrentSourceLocation()); @@ -1030,7 +1037,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base) } if (!canConvertFromTo(m_state.accumulatorIn(), property)) { - setError(u"cannot convert from %1 to %2"_s + addError(u"cannot convert from %1 to %2"_s .arg(m_state.accumulatorIn().descriptiveName(), property.descriptiveName())); return; } @@ -1224,7 +1231,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar return; } - setError(u"Type %1 does not have a property %2 for calling"_s + addError(u"Type %1 does not have a property %2 for calling"_s .arg(callBase.descriptiveName(), propertyName)); if (callBase.isType() && isCallingProperty(callBase.type(), propertyName)) @@ -1432,11 +1439,11 @@ void QQmlJSTypePropagator::propagateCall( if (methods.size() == 1) { // Cannot have multiple fuzzy matches if there is only one method Q_ASSERT(errors.size() == 1); - setError(errors.first()); + addError(errors.first()); } else if (errors.size() < methods.size()) { - setError(u"Multiple matching overrides found. Cannot determine the right one."_s); + addError(u"Multiple matching overrides found. Cannot determine the right one."_s); } else { - setError(u"No matching override found. Candidates:\n"_s + errors.join(u'\n')); + addError(u"No matching override found. Candidates:\n"_s + errors.join(u'\n')); } return; } @@ -1451,7 +1458,7 @@ void QQmlJSTypePropagator::propagateCall( : QQmlJSRegisterContent::MethodReturnValue, scope)); if (!m_state.accumulatorOut().isValid()) - setError(u"Cannot store return type of method %1()."_s.arg(match.methodName())); + addError(u"Cannot store return type of method %1()."_s.arg(match.methodName())); const auto types = match.parameters(); for (int i = 0; i < argc; ++i) { @@ -1806,10 +1813,10 @@ void QQmlJSTypePropagator::propagateScopeLookupCall(const QString &functionName, } } - setError(u"method %1 cannot be resolved."_s.arg(functionName)); + addError(u"method %1 cannot be resolved."_s.arg(functionName)); setAccumulator(m_typeResolver->globalType(m_typeResolver->jsValueType())); - setError(u"Cannot find function '%1'"_s.arg(functionName)); + addError(u"Cannot find function '%1'"_s.arg(functionName)); handleUnqualifiedAccess(functionName, true); } @@ -1946,7 +1953,7 @@ void QQmlJSTypePropagator::generate_UnwindToLabel(int level, int offset) void QQmlJSTypePropagator::generate_DeadTemporalZoneCheck(int name) { const auto fail = [this, name]() { - setError(u"Cannot statically assert the dead temporal zone check for %1"_s.arg( + addError(u"Cannot statically assert the dead temporal zone check for %1"_s.arg( name ? m_jsUnitGenerator->stringForIndex(name) : u"the anonymous accumulator"_s)); }; @@ -2199,7 +2206,7 @@ void QQmlJSTypePropagator::generate_JumpTrue(int offset) { if (!canConvertFromTo(m_state.accumulatorIn(), m_typeResolver->globalType(m_typeResolver->boolType()))) { - setError(u"cannot convert from %1 to boolean"_s + addError(u"cannot convert from %1 to boolean"_s .arg(m_state.accumulatorIn().descriptiveName())); return; } @@ -2212,7 +2219,7 @@ void QQmlJSTypePropagator::generate_JumpFalse(int offset) { if (!canConvertFromTo(m_state.accumulatorIn(), m_typeResolver->globalType(m_typeResolver->boolType()))) { - setError(u"cannot convert from %1 to boolean"_s + addError(u"cannot convert from %1 to boolean"_s .arg(m_state.accumulatorIn().descriptiveName())); return; } @@ -2446,7 +2453,7 @@ void QQmlJSTypePropagator::generate_As(int lhs) else output = m_typeResolver->cast(input, outContained); } else if (!m_typeResolver->canAddressValueTypes()) { - setError(u"invalid cast from %1 to %2. You can only cast object types."_s + addError(u"invalid cast from %1 to %2. You can only cast object types."_s .arg(input.descriptiveName(), m_state.accumulatorIn().descriptiveName())); return; } else { @@ -2470,7 +2477,7 @@ void QQmlJSTypePropagator::checkConversion( const QQmlJSRegisterContent &from, const QQmlJSRegisterContent &to) { if (!canConvertFromTo(from, to)) { - setError(u"cannot convert from %1 to %2"_s + addError(u"cannot convert from %1 to %2"_s .arg(from.descriptiveName(), to.descriptiveName())); } } @@ -2652,7 +2659,7 @@ void QQmlJSTypePropagator::generate_GetTemplateObject(int index) QV4::Moth::ByteCodeHandler::Verdict QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type) { - if (m_error->isValid()) + if (!m_errors->isEmpty()) return SkipInstruction; if (m_state.jumpTargets.contains(currentInstructionOffset())) { @@ -2691,7 +2698,7 @@ QQmlJSTypePropagator::startInstruction(QV4::Moth::Instr::Type type) auto newType = registerIt.value().content; if (!newType.isValid()) { - setError(u"When reached from offset %1, %2 is undefined"_s + addError(u"When reached from offset %1, %2 is undefined"_s .arg(stateToMerge.originatingOffset) .arg(registerName(registerIndex))); return SkipInstruction; @@ -2743,8 +2750,8 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr) case QV4::Moth::Instr::Type::DeadTemporalZoneCheck: case QV4::Moth::Instr::Type::IteratorNext: case QV4::Moth::Instr::Type::IteratorNextForYieldStar: - if (m_state.changedRegisterIndex() == Accumulator && !m_error->isValid()) { - setError(u"Instruction is not expected to populate the accumulator"_s); + if (m_state.changedRegisterIndex() == Accumulator && m_errors->isEmpty()) { + addError(u"Instruction is not expected to populate the accumulator"_s); return; } break; @@ -2752,21 +2759,22 @@ void QQmlJSTypePropagator::endInstruction(QV4::Moth::Instr::Type instr) // If the instruction is expected to produce output, save it in the register set // for the next instruction. if ((!m_state.changedRegister().isValid() || m_state.changedRegisterIndex() != Accumulator) - && !m_error->isValid()) { - setError(u"Instruction is expected to populate the accumulator"_s); + && m_errors->isEmpty()) { + addError(u"Instruction is expected to populate the accumulator"_s); return; } } - if (!(m_error->isValid() && m_error->isError()) - && instr != QV4::Moth::Instr::Type::DeadTemporalZoneCheck) { + const auto noError = std::none_of(m_errors->cbegin(), m_errors->cend(), + [](const auto &e) { return e.isError(); }); + if (noError && instr != QV4::Moth::Instr::Type::DeadTemporalZoneCheck) { // An instruction needs to have side effects or write to another register otherwise it's a // noop. DeadTemporalZoneCheck is not needed by the compiler and is ignored. Q_ASSERT(m_state.hasSideEffects() || m_state.changedRegisterIndex() != -1); } if (m_state.changedRegisterIndex() != InvalidRegister) { - Q_ASSERT(m_error->isValid() || m_state.changedRegister().isValid()); + Q_ASSERT(!m_errors->isEmpty() || m_state.changedRegister().isValid()); VirtualRegister &r = m_state.registers[m_state.changedRegisterIndex()]; r.content = m_state.changedRegister(); r.canMove = false; @@ -2838,7 +2846,7 @@ QQmlJSRegisterContent QQmlJSTypePropagator::checkedInputRegister(int reg) if (isArgument(reg)) return argumentType(reg); - setError(u"Type error: could not infer the type of an expression"_s); + addError(u"Type error: could not infer the type of an expression"_s); return {}; } return regIt.value().content; diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h index c9bbeb27cc..c7f0c5e049 100644 --- a/src/qmlcompiler/qqmljstypepropagator_p.h +++ b/src/qmlcompiler/qqmljstypepropagator_p.h @@ -28,10 +28,11 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSTypePropagator : public QQmlJSCompilePass { QQmlJSTypePropagator(const QV4::Compiler::JSUnitGenerator *unitGenerator, const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger, - BasicBlocks basicBlocks = {}, InstructionAnnotations annotations = {}, + QList<QQmlJS::DiagnosticMessage> *errors, BasicBlocks basicBlocks = {}, + InstructionAnnotations annotations = {}, QQmlSA::PassManager *passManager = nullptr); - BlocksAndAnnotations run(const Function *m_function, QQmlJS::DiagnosticMessage *error); + BlocksAndAnnotations run(const Function *m_function); void generate_Ret() override; void generate_Debug() override; |
