Revision control

++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++ // Qt-Security score:significant
++
++ #include "qqmljslintercodegen_p.h"
++ #include "qqmljslintertypepropagator_p.h"
++
++ #include <private/qqmljsbasicblocks_p.h>
++ #include <private/qqmljsfunctioninitializer_p.h>
++ #include <private/qqmljsimportvisitor_p.h>
++ #include <private/qqmljsshadowcheck_p.h>
++ #include <private/qqmljsstoragegeneralizer_p.h>
++ #include <private/qqmljsstorageinitializer_p.h>
++
++ #include <QFileInfo>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ bool operator==(const IdMemberShadow &lhs, const IdMemberShadow &rhs)
++ {
++ return lhs.name == rhs.name && lhs.idScope == rhs.idScope
++ && lhs.memberOwnerScope == rhs.memberOwnerScope;
++ }
++ bool operator!=(const IdMemberShadow &lhs, const IdMemberShadow &rhs)
++ {
++ return !(lhs == rhs);
++ }
++ size_t qHash(const IdMemberShadow &idShadowsMember, size_t seed)
++ {
++ return qHashMulti(seed, idShadowsMember.name, idShadowsMember.idScope,
++ idShadowsMember.memberOwnerScope);
++ }
++ QQmlJSLinterCodegen::QQmlJSLinterCodegen(QQmlJSImporter *importer, const QString &fileName,
++ const QStringList &qmldirFiles, QQmlJSLogger *logger,
++ const QQmlJS::LinterContext &context)
++ : QQmlJSAotCompiler(importer, fileName, qmldirFiles, logger), m_context(context)
++ {
++ m_flags |= QQmlJSAotCompiler::IsLintCompiler;
++ }
++
++ void QQmlJSLinterCodegen::setDocument(const QmlIR::JSCodeGen *codegen,
++ const QmlIR::Document *document)
++ {
++ Q_UNUSED(codegen);
++ m_document = document;
++ m_unitGenerator = &document->jsGenerator;
++ }
++
++ std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>>
++ QQmlJSLinterCodegen::compileBinding(const QV4::Compiler::Context *context,
++ const QmlIR::Binding &irBinding, QQmlJS::AST::Node *astNode)
++ {
++ const QString name = m_document->stringAt(irBinding.propertyNameIndex);
++ m_logger->setCompileErrorPrefix(
++ u"Could not determine signature of binding for %1: "_s.arg(name));
++
++ QQmlJSFunctionInitializer initializer(
++ &m_typeResolver, m_currentObject->location, m_currentScope->location, m_logger);
++ QQmlJSCompilePass::Function function = initializer.run(context, name, astNode, irBinding);
++
++ m_logger->iterateCurrentFunctionMessages([this](const Message &error) {
++ diagnose(error.message, error.type, error.loc);
++ });
++
++ m_logger->setCompileErrorPrefix(u"Could not compile binding for %1: "_s.arg(name));
++ m_logger->setCompileSkipPrefix(u"Compilation of binding for %1 was skipped: "_s.arg(name));
++
++ analyzeFunction(context, &function);
++ if (const auto errors = finalizeBindingOrFunction())
++ return *errors;
++
++ return QQmlJSAotFunction {};
++ }
++
++ std::variant<QQmlJSAotFunction, QList<QQmlJS::DiagnosticMessage>>
++ QQmlJSLinterCodegen::compileFunction(const QV4::Compiler::Context *context,
++ const QString &name, QQmlJS::AST::Node *astNode)
++ {
++ m_logger->setCompileErrorPrefix(u"Could not determine signature of function %1: "_s.arg(name));
++
++ QQmlJSFunctionInitializer initializer(
++ &m_typeResolver, m_currentObject->location, m_currentScope->location, m_logger);
++ QQmlJSCompilePass::Function function = initializer.run(context, name, astNode);
++
++ m_logger->iterateCurrentFunctionMessages([this](const Message &error) {
++ diagnose(error.message, error.type, error.loc);
++ });
++
++ m_logger->setCompileErrorPrefix(u"Could not compile function %1: "_s.arg(name));
++ m_logger->setCompileSkipPrefix(u"Compilation of function %1 was skipped: "_s.arg(name));
++ analyzeFunction(context, &function);
++
++ if (const auto errors = finalizeBindingOrFunction())
++ return *errors;
++
++ return QQmlJSAotFunction {};
++ }
++
++ void QQmlJSLinterCodegen::setPassManager(QQmlSA::PassManager *passManager)
++ {
++ m_passManager = passManager;
++ auto managerPriv = QQmlSA::PassManagerPrivate::get(passManager);
++ managerPriv->m_typeResolver = typeResolver();
++ }
++
++ void QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context,
++ QQmlJSCompilePass::Function *function)
++ {
++ bool dummy = false;
++ QQmlJSCompilePass::BlocksAndAnnotations blocksAndAnnotations =
++ QQmlJSBasicBlocks(context, m_unitGenerator, &m_typeResolver, m_logger)
++ .run(function, ValidateBasicBlocks, dummy);
++
++ QQmlJSLinterTypePropagator lintTypePropgator(m_unitGenerator, &m_typeResolver, m_logger,
++ m_context, blocksAndAnnotations.basicBlocks,
++ blocksAndAnnotations.annotations, m_passManager);
++ lintTypePropgator.setIdMemberShadows(&m_idMemberShadows);
++ blocksAndAnnotations = lintTypePropgator.run(function);
++
++ if (m_logger->categorySeverity(qmlCompiler) == QQmlJS::WarningSeverity::Disable)
++ return;
++
++ if (!m_logger->currentFunctionHasCompileError()) {
++ blocksAndAnnotations = QQmlJSShadowCheck(m_unitGenerator, &m_typeResolver, m_logger,
++ blocksAndAnnotations.basicBlocks,
++ blocksAndAnnotations.annotations)
++ .run(function);
++ }
++
++ if (!m_logger->currentFunctionHasCompileError()) {
++ blocksAndAnnotations = QQmlJSStorageInitializer(m_unitGenerator, &m_typeResolver, m_logger,
++ blocksAndAnnotations.basicBlocks,
++ blocksAndAnnotations.annotations)
++ .run(function);
++ }
++
++ if (!m_logger->currentFunctionHasCompileError()) {
++ blocksAndAnnotations = QQmlJSStorageGeneralizer(m_unitGenerator, &m_typeResolver, m_logger,
++ blocksAndAnnotations.basicBlocks,
++ blocksAndAnnotations.annotations)
++ .run(function);
++ }
++ }
++
++ QT_END_NAMESPACE