aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler/qqmljslintercodegen.cpp
blob: dd9a8f6a17c147b9ef8b592e4fd84b601e421ae2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "qqmljslintercodegen_p.h"

#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
#include <QtQmlCompiler/private/qqmljsshadowcheck_p.h>
#include <QtQmlCompiler/private/qqmljsstoragegeneralizer_p.h>
#include <QtQmlCompiler/private/qqmljsstorageinitializer_p.h>
#include <QtQmlCompiler/private/qqmljstypepropagator_p.h>
#include <QtQmlCompiler/private/qqmljsfunctioninitializer_p.h>
#include <QtQmlCompiler/private/qqmljsbasicblocks_p.h>

#include <QFileInfo>

QT_BEGIN_NAMESPACE

using namespace Qt::StringLiterals;

QQmlJSLinterCodegen::QQmlJSLinterCodegen(QQmlJSImporter *importer, const QString &fileName,
                                         const QStringList &qmldirFiles, QQmlJSLogger *logger)
    : QQmlJSAotCompiler(importer, fileName, qmldirFiles, logger)
{
}

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);

    blocksAndAnnotations = QQmlJSTypePropagator(m_unitGenerator, &m_typeResolver, m_logger,
                                                blocksAndAnnotations.basicBlocks,
                                                blocksAndAnnotations.annotations, m_passManager)
            .run(function);

    if (m_logger->isCategoryIgnored(qmlCompiler))
        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